1# - Create launchers to set working directory, env. vars, etc.
2#
3#  include(CreateLaunchers) - to make these available
4#  guess_runtime_library_dirs(<outputvarname> [<extralibrary> ...])
5#  create_default_target_launcher(<targetname>
6#    [ARGS <args...>]
7#    [FORWARD_ARGS]
8#    [RUNTIME_LIBRARY_DIRS <dir...>]
9#    [WORKING_DIRECTORY <dir>]
10#    [ENVIRONMENT <VAR=value> [<VAR=value>...]])
11#
12#  create_target_launcher(<targetname>
13#    [ARGS <args...>]
14#    [FORWARD_ARGS]
15#    [RUNTIME_LIBRARY_DIRS <dir...>]
16#    [WORKING_DIRECTORY <dir>]
17#    [ENVIRONMENT <VAR=value> [<VAR=value>...]])
18#
19#  create_generic_launcher(<launchername>
20#    [RUNTIME_LIBRARY_DIRS <dir...>]
21#    [WORKING_DIRECTORY <dir>]
22#    [ENVIRONMENT <VAR=value> [<VAR=value>...]])
23#    - sets GENERIC_LAUNCHER_COMMAND and GENERIC_LAUNCHER_FAIL_REGULAR_EXPRESSION
24#
25# Requires these CMake modules:
26#  ListFilter
27#  ProgramFilesGlob
28#  CleanDirectoryList
29#
30# Requires CMake 2.6 or newer (uses the 'function' command)
31#
32# Original Author:
33# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
34# http://academic.cleardefinition.com
35# Iowa State University HCI Graduate Program/VRAC
36#
37# Copyright Iowa State University 2009-2010.
38# Distributed under the Boost Software License, Version 1.0.
39# (See accompanying file LICENSE_1_0.txt or copy at
40# http://www.boost.org/LICENSE_1_0.txt)
41
42if(__create_launchers)
43	return()
44endif()
45set(__create_launchers YES)
46
47include(CleanDirectoryList)
48
49# We must run the following at "include" time, not at function call time,
50# to find the path to this module rather than the path to a calling list file
51get_filename_component(_launchermoddir
52	${CMAKE_CURRENT_LIST_FILE}
53	PATH)
54set(_launchermoddir "${_launchermoddir}/launcher-templates")
55
56macro(_launcher_system_settings)
57	if(CMAKE_SIZEOF_VOID_P EQUAL 8)
58		set(BITS 64)
59	else()
60		set(BITS 32)
61	endif()
62
63	if(WIN32)
64		# Find user and system name
65		set(SYSTEM_NAME $ENV{USERDOMAIN})
66		set(USER_NAME $ENV{USERNAME})
67		set(VCPROJ_TYPE vcproj)
68		set(USERFILE_EXTENSION ${SYSTEM_NAME}.${USER_NAME}.user)
69		set(LAUNCHER_LINESEP "&#x0A;")
70		if(MSVC90)
71			set(USERFILE_VC_VERSION 9.00)
72		elseif(MSVC80)
73			set(USERFILE_VC_VERSION 8.00)
74		elseif(MSVC71)
75			set(USERFILE_VC_VERSION 7.10)
76		elseif(MSVC10 OR (MSVC AND MSVC_VERSION GREATER 1600)) # 2010 or newer
77			set(LAUNCHER_LINESEP "\n")
78			set(USERFILE_VC_VERSION 10.00)
79			set(USERFILE_EXTENSION user)
80			set(VCPROJ_TYPE vcxproj)
81		endif()
82		if(BITS EQUAL 64)
83			set(USERFILE_PLATFORM x64)
84		else()
85			set(USERFILE_PLATFORM Win${BITS})
86		endif()
87		set(_pathdelim ";")
88		set(_suffix "cmd")
89	else()
90		set(_pathdelim ":")
91		set(USERFILE_PLATFORM ${CMAKE_SYSTEM_NAME}${BITS})
92		set(_suffix "sh")
93		find_package(GDB QUIET)
94		if(GDB_FOUND)
95			set(LAUNCHERS_GOT_GDB YES)
96			if(GDB_HAS_RETURN_CHILD_RESULT)
97				set(LAUNCHERS_GDB_ARG --return-child-result)
98			endif()
99		else()
100			set(LAUNCHERS_GOT_GDB)
101		endif()
102	endif()
103
104	if(WIN32 AND NOT USERFILE_REMOTE_MACHINE)
105		site_name(USERFILE_REMOTE_MACHINE)
106		mark_as_advanced(USERFILE_REMOTE_MACHINE)
107	endif()
108endmacro()
109
110macro(_launcher_process_args)
111	set(_nowhere)
112	set(_curdest _nowhere)
113	set(_val_args
114		ARGS
115		RUNTIME_LIBRARY_DIRS
116		WORKING_DIRECTORY
117		ENVIRONMENT)
118	set(_bool_args FORWARD_ARGS)
119	foreach(_arg ${_val_args} ${_bool_args})
120		set(${_arg})
121	endforeach()
122	foreach(_element ${ARGN})
123		list(FIND _val_args "${_element}" _val_arg_find)
124		list(FIND _bool_args "${_element}" _bool_arg_find)
125		if("${_val_arg_find}" GREATER "-1")
126			set(_curdest "${_element}")
127		elseif("${_bool_arg_find}" GREATER "-1")
128			set("${_element}" ON)
129			set(_curdest _nowhere)
130		else()
131			list(APPEND ${_curdest} "${_element}")
132		endif()
133	endforeach()
134
135	if(_nowhere)
136		message(FATAL_ERROR
137			"Syntax error in use of a function in CreateLaunchers!")
138	endif()
139
140	# Turn into a list of native paths
141	set(_runtime_lib_dirs)
142	foreach(_dlldir ${RUNTIME_LIBRARY_DIRS})
143		file(TO_NATIVE_PATH "${_dlldir}" _path)
144		set(_runtime_lib_dirs "${_runtime_lib_dirs}${_path}${_pathdelim}")
145	endforeach()
146
147	if(NOT WORKING_DIRECTORY)
148		set(WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}")
149	endif()
150
151	if(FORWARD_ARGS)
152		if(WIN32)
153			set(FWD_ARGS %*)
154		else()
155			set(FWD_ARGS $*)
156		endif()
157	else()
158		set(FWD_ARGS)
159	endif()
160
161	set(USERFILE_WORKING_DIRECTORY "${WORKING_DIRECTORY}")
162	set(USERFILE_COMMAND_ARGUMENTS "${ARGS}")
163	set(LAUNCHERSCRIPT_COMMAND_ARGUMENTS "${ARGS} ${FWD_ARGS}")
164
165	if(WIN32)
166		set(RUNTIME_LIBRARIES_ENVIRONMENT "PATH=${_runtime_lib_dirs};%PATH%")
167		file(READ
168			"${_launchermoddir}/launcher.env.cmd.in"
169			_cmdenv)
170	else()
171		if(APPLE)
172			set(RUNTIME_LIBRARIES_ENVIRONMENT
173				"DYLD_LIBRARY_PATH=${_runtime_lib_dirs}:$DYLD_LIBRARY_PATH")
174		else()
175			set(RUNTIME_LIBRARIES_ENVIRONMENT
176				"LD_LIBRARY_PATH=${_runtime_lib_dirs}:$LD_LIBRARY_PATH")
177		endif()
178		file(READ
179			"${_launchermoddir}/launcher.env.sh.in"
180			_cmdenv)
181	endif()
182	set(USERFILE_ENVIRONMENT "${RUNTIME_LIBRARIES_ENVIRONMENT}")
183
184	set(USERFILE_ENV_COMMANDS)
185	foreach(_arg "${RUNTIME_LIBRARIES_ENVIRONMENT}" ${ENVIRONMENT})
186		string(CONFIGURE
187			"@USERFILE_ENVIRONMENT@@LAUNCHER_LINESEP@@_arg@"
188			USERFILE_ENVIRONMENT
189			@ONLY)
190		string(CONFIGURE
191			"@USERFILE_ENV_COMMANDS@${_cmdenv}"
192			USERFILE_ENV_COMMANDS
193			@ONLY)
194	endforeach()
195endmacro()
196
197macro(_launcher_produce_vcproj_user)
198	if(MSVC)
199		file(READ
200			"${_launchermoddir}/perconfig.${VCPROJ_TYPE}.user.in"
201			_perconfig)
202		file(TO_NATIVE_PATH "${USERFILE_WORKING_DIRECTORY}" NATIVE_WORKING_DIRECTORY)
203		set(USERFILE_CONFIGSECTIONS)
204		foreach(USERFILE_CONFIGNAME ${CMAKE_CONFIGURATION_TYPES})
205			string(CONFIGURE "${_perconfig}" _temp @ONLY ESCAPE_QUOTES)
206			set(USERFILE_CONFIGSECTIONS "${USERFILE_CONFIGSECTIONS}${_temp}")
207		endforeach()
208
209
210		configure_file("${_launchermoddir}/${VCPROJ_TYPE}.user.in"
211			"${VCPROJNAME}.${VCPROJ_TYPE}.${USERFILE_EXTENSION}"
212			@ONLY)
213	endif()
214
215endmacro()
216
217macro(_launcher_configure_executable _src _tmp _target)
218#    get_filename_component(_targetname "${_target}" NAME)
219    get_filename_component(_targetpath "${_target}" PATH)
220	configure_file("${_src}"
221		"${_tmp}"
222		@ONLY)
223	file(COPY "${_tmp}"
224	    DESTINATION "${_targetpath}"
225	    FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_WRITE GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
226endmacro()
227
228macro(_launcher_create_target_launcher)
229	set(TARGET_NAME ${_targetname})
230
231	set(_fn "launch-${_targetname}-generator.${_suffix}")
232
233	configure_file("${_launchermoddir}/targetlauncher.${_suffix}.in"
234					"${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${_fn}"
235					@ONLY)
236
237	file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/launch-${_targetname}-$<CONFIGURATION>.${_suffix}"
238			INPUT "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${_fn}")
239endmacro()
240
241function(create_default_target_launcher _targetname)
242	_launcher_system_settings()
243	_launcher_process_args(${ARGN})
244
245	set(VCPROJNAME "${CMAKE_BINARY_DIR}/ALL_BUILD")
246	_launcher_produce_vcproj_user()
247
248	_launcher_create_target_launcher()
249endfunction()
250
251function(create_target_launcher _targetname)
252	_launcher_system_settings()
253	_launcher_process_args(${ARGN})
254
255	set(VCPROJNAME "${CMAKE_CURRENT_BINARY_DIR}/${_targetname}")
256	_launcher_produce_vcproj_user()
257
258	_launcher_create_target_launcher()
259endfunction()
260
261function(create_generic_launcher _launchername)
262	_launcher_system_settings()
263	_launcher_process_args(${ARGN})
264
265	if(NOT IS_ABSOLUTE _launchername)
266		set(_launchername
267			"${CMAKE_CURRENT_BINARY_DIR}/${_launchername}.${_suffix}")
268	else()
269		set(_launchername "${_launchername}.${_suffix}")
270	endif()
271	if(WIN32)
272		set(GENERIC_LAUNCHER_COMMAND "${_launchername}" PARENT_SCOPE)
273		set(GENERIC_LAUNCHER_FAIL_REGULAR_EXPRESSION)
274	else()
275		set(GENERIC_LAUNCHER_COMMAND sh "${_launchername}" PARENT_SCOPE)
276		set(GENERIC_LAUNCHER_FAIL_REGULAR_EXPRESSION
277			"Program terminated with signal")
278	endif()
279
280	_launcher_configure_executable("${_launchermoddir}/genericlauncher.${_suffix}.in"
281	    "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/genericlauncher.${_suffix}.in"
282		"${_launchername}")
283endfunction()
284
285function(guess_runtime_library_dirs _var)
286	# Start off with the link directories of the calling listfile's directory
287	get_directory_property(_libdirs LINK_DIRECTORIES)
288
289	# Add additional libraries passed to the function
290	foreach(_lib ${ARGN})
291		get_filename_component(_libdir "${_lib}" PATH)
292		list(APPEND _libdirs "${_libdir}")
293	endforeach()
294
295	# Now, build a list of potential dll directories
296	set(_dlldirs)
297	foreach(_libdir ${_libdirs})
298		# Add the libdir itself
299		list(APPEND _dlldirs "${_libdir}")
300
301		# Look also in libdir/../bin since the dll might not be with the lib
302		get_filename_component(_libdir "${_libdir}/../bin" ABSOLUTE)
303		list(APPEND _dlldirs "${_libdir}")
304	endforeach()
305
306	# Only keep the valid, unique directories
307	clean_directory_list(_dlldirs)
308
309	# Return _dlldirs
310	set(${_var} "${_dlldirs}" PARENT_SCOPE)
311endfunction()