# - Create launchers to set working directory, env. vars, etc. # # include(CreateLaunchers) - to make these available # guess_runtime_library_dirs( [ ...]) # create_default_target_launcher( # [COMMAND ] # [ARGS ] # [FORWARD_ARGS] # [RUNTIME_LIBRARY_DIRS ] # [WORKING_DIRECTORY ] # [ENVIRONMENT [...]]) # # create_target_launcher( # [COMMAND ] # [ARGS ] # [FORWARD_ARGS] # [RUNTIME_LIBRARY_DIRS ] # [WORKING_DIRECTORY ] # [ENVIRONMENT [...]]) # # create_generic_launcher( # [COMMAND ] # [RUNTIME_LIBRARY_DIRS ] # [WORKING_DIRECTORY ] # [ENVIRONMENT [...]]) # - sets GENERIC_LAUNCHER_COMMAND and GENERIC_LAUNCHER_FAIL_REGULAR_EXPRESSION # # Requires these CMake modules: # CleanDirectoryList # # Requires CMake 2.6 or newer (uses the 'function' command) # # Original Author: # 2009-2020 Ryan Pavlik # http://academic.cleardefinition.com # # Copyright 2009-2013, Iowa State University. # Copyright 2018-2019, caseymcc # Copyright 2020, Ryan Pavlik # Copyright 2014-2019, Contributors # SPDX-License-Identifier: BSL-1.0 # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) if(__create_launchers) return() endif() set(__create_launchers YES) cmake_policy(PUSH) cmake_policy(SET CMP0053 NEW) include(CleanDirectoryList) # We must run the following at "include" time, not at function call time, # to find the path to this module rather than the path to a calling list file get_filename_component(_launchermoddir ${CMAKE_CURRENT_LIST_FILE} PATH) set(_launchermoddir "${_launchermoddir}/launcher-templates") macro(_launcher_system_settings) if(CMAKE_SIZEOF_VOID_P EQUAL 8) set(BITS 64) else() set(BITS 32) endif() if(WIN32) # Find user and system name set(SYSTEM_NAME $ENV{USERDOMAIN}) set(USER_NAME $ENV{USERNAME}) set(VCPROJ_TYPE vcproj) set(USERFILE_EXTENSION ${SYSTEM_NAME}.${USER_NAME}.user) set(LAUNCHER_LINESEP " ") if(MSVC90) set(USERFILE_VC_VERSION 9.00) elseif(MSVC80) set(USERFILE_VC_VERSION 8.00) elseif(MSVC71) set(USERFILE_VC_VERSION 7.10) elseif(MSVC10 OR (MSVC AND MSVC_VERSION GREATER 1600)) # 2010 or newer set(LAUNCHER_LINESEP "\n") set(USERFILE_VC_VERSION 10.00) set(USERFILE_EXTENSION user) set(VCPROJ_TYPE vcxproj) endif() if(BITS EQUAL 64) set(USERFILE_PLATFORM x64) else() set(USERFILE_PLATFORM Win${BITS}) endif() set(_pathdelim "$") set(_suffix "cmd") else() set(_pathdelim ":") set(USERFILE_PLATFORM ${CMAKE_SYSTEM_NAME}${BITS}) set(_suffix "sh") find_package(GDB QUIET) if(GDB_FOUND) set(LAUNCHERS_GOT_GDB YES) if(GDB_HAS_RETURN_CHILD_RESULT) set(LAUNCHERS_GDB_ARG --return-child-result) endif() else() set(LAUNCHERS_GOT_GDB) endif() endif() if(WIN32 AND NOT USERFILE_REMOTE_MACHINE) site_name(USERFILE_REMOTE_MACHINE) mark_as_advanced(USERFILE_REMOTE_MACHINE) endif() endmacro() macro(_launcher_process_args) set(_nowhere) set(_curdest _nowhere) set(_val_args ARGS COMMAND RUNTIME_LIBRARY_DIRS WORKING_DIRECTORY ENVIRONMENT TARGET_PLATFORM) set(_bool_args FORWARD_ARGS) foreach(_arg ${_val_args} ${_bool_args}) set(${_arg}) endforeach() foreach(_element ${ARGN}) string(REPLACE ";" "\\;" _element "${_element}") list(FIND _val_args "${_element}" _val_arg_find) list(FIND _bool_args "${_element}" _bool_arg_find) if("${_val_arg_find}" GREATER "-1") set(_curdest "${_element}") elseif("${_bool_arg_find}" GREATER "-1") set("${_element}" ON) set(_curdest _nowhere) else() list(APPEND ${_curdest} "${_element}") endif() endforeach() if(_nowhere) message( FATAL_ERROR "Syntax error in use of a function in CreateLaunchers!") endif() # Turn into a list of native paths set(_runtime_lib_dirs) foreach(_dlldir ${RUNTIME_LIBRARY_DIRS}) file(TO_NATIVE_PATH "${_dlldir}" _path) if(NOT EXISTS "${_path}") #this is not a file so lets leave it as is set(_path ${_dlldir}) endif() set(_runtime_lib_dirs "${_runtime_lib_dirs}${_path}${_pathdelim}") endforeach() if(NOT WORKING_DIRECTORY) set(WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}") endif() if(NOT COMMAND) set(COMMAND "$") endif() if(FORWARD_ARGS) if(WIN32) set(FWD_ARGS %*) else() set(FWD_ARGS $*) endif() else() set(FWD_ARGS) endif() if(TARGET_PLATFORM) set(USERFILE_PLATFORM ${TARGET_PLATFORM}) endif() set(USERFILE_WORKING_DIRECTORY "${WORKING_DIRECTORY}") set(USERFILE_COMMAND "${COMMAND}") set(USERFILE_COMMAND_ARGUMENTS "${ARGS}") set(LAUNCHERSCRIPT_COMMAND_ARGUMENTS "${ARGS} ${FWD_ARGS}") if(WIN32) if(_runtime_lib_dirs) set(RUNTIME_LIBRARIES_ENVIRONMENT "PATH=${_runtime_lib_dirs}$%PATH%") endif() file(READ "${_launchermoddir}/launcher.env.cmd.in" _cmdenv) else() if(_runtime_lib_dirs) if(APPLE) set(RUNTIME_LIBRARIES_ENVIRONMENT "DYLD_LIBRARY_PATH=${_runtime_lib_dirs}:$DYLD_LIBRARY_PATH") else() set(RUNTIME_LIBRARIES_ENVIRONMENT "LD_LIBRARY_PATH=${_runtime_lib_dirs}:$LD_LIBRARY_PATH") endif() endif() file(READ "${_launchermoddir}/launcher.env.sh.in" _cmdenv) endif() set(USERFILE_ENVIRONMENT) set(USERFILE_ENV_COMMANDS) foreach(_arg "${RUNTIME_LIBRARIES_ENVIRONMENT}" ${ENVIRONMENT}) if(_arg) string(CONFIGURE "@USERFILE_ENVIRONMENT@@LAUNCHER_LINESEP@@_arg@" USERFILE_ENVIRONMENT @ONLY) endif() string(CONFIGURE "@USERFILE_ENV_COMMANDS@${_cmdenv}" USERFILE_ENV_COMMANDS @ONLY) endforeach() endmacro() #ok, we have gone very hackish on this function as the file(GENERATE) is very hard to work with as the cmake folks really don't #want you writing generator files yourself, yet the user file is not planning to ever be supported macro(_launcher_produce_vcproj_user) if(MSVC) set(CMAKEFILES_PATH "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles") set(TARGET_CMAKE_FILES "${CMAKEFILES_PATH}/${_targetname}") file(READ "${_launchermoddir}/perconfig.${VCPROJ_TYPE}.user.in" _perconfig) #generator expressions do not play well with ">" string(REPLACE ">" "$" _perconfig ${_perconfig}) set(config_types) if(CMAKE_CONFIGURATION_TYPES) foreach(config_type ${CMAKE_CONFIGURATION_TYPES}) set(config_types ${config_types} ${config_type}) endforeach() else() set(config_types ${CMAKE_BUILD_TYPE}) endif() set(USERFILE_CONFIGSECTIONS) foreach(USERFILE_CONFIGNAME ${config_types}) string(CONFIGURE "${_perconfig}" _temp @ONLY ESCAPE_QUOTES) #we are building the per config info with genertator expressions so that when generating the files only the config currently generated is being correctly filled in set(_temp "$,\n${_temp},$>\n" ) #we are putting this info into the target properties so it can be recuresively added back during the generator calls set_target_properties( ${_targetname} PROPERTIES LAUNCHER_USER_ELSE_${USERFILE_CONFIGNAME} ${_temp}) string(CONFIGURE "${USERFILE_CONFIGSECTIONS}${_temp}" USERFILE_CONFIGSECTIONS ESCAPE_QUOTES) endforeach() configure_file( "${_launchermoddir}/${VCPROJ_TYPE}.user.in" ${TARGET_CMAKE_FILES}.${VCPROJ_TYPE}.${USERFILE_EXTENSION}.config @ONLY) #now we are looping thtough each config type loading the previous ones output, hopefully execution order stays the same as the generation request set(launcher_last_config) foreach(USERFILE_CONFIGNAME ${config_types}) if(NOT launcher_last_config) file( GENERATE OUTPUT ${TARGET_CMAKE_FILES}.${VCPROJ_TYPE}.${USERFILE_CONFIGNAME}.usergen INPUT ${TARGET_CMAKE_FILES}.${VCPROJ_TYPE}.${USERFILE_EXTENSION}.config CONDITION $) else() file( GENERATE OUTPUT ${TARGET_CMAKE_FILES}.${VCPROJ_TYPE}.${USERFILE_CONFIGNAME}.usergen INPUT ${TARGET_CMAKE_FILES}.${VCPROJ_TYPE}.${launcher_last_config}.usergen CONDITION $) endif() set(launcher_last_config ${USERFILE_CONFIGNAME}) endforeach() #build the final output from the last generation output file( GENERATE OUTPUT ${VCPROJNAME}.${VCPROJ_TYPE}.${USERFILE_EXTENSION} INPUT ${TARGET_CMAKE_FILES}.${VCPROJ_TYPE}.${launcher_last_config}.usergen ) endif() endmacro() macro(_launcher_configure_executable _src _tmp _target _config) configure_file("${_src}" "${_tmp}" @ONLY) #used to convert generator expressions file( GENERATE OUTPUT "${_target}" INPUT "${_tmp}" CONDITION $) #we lose the ability to change the file permisions as there is no support there in file(GENERATE) (although it has been requested) #and nothing runs after file(GENERATE) durning the cmake call # file(COPY "${_tmp}" # DESTINATION "${_targetpath}" # FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_WRITE GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) endmacro() macro(_launcher_create_target_launcher) if(CMAKE_CONFIGURATION_TYPES) # Multi-config generator - multiple launchers foreach(_config ${CMAKE_CONFIGURATION_TYPES}) set(_fn "launch-${_targetname}-${_config}.${_suffix}") _launcher_configure_executable( "${_launchermoddir}/targetlauncher.${_suffix}.in" "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${_fn}" "${CMAKE_CURRENT_BINARY_DIR}/${_fn}" ${_config}) endforeach() else() # Single-config generator - single launcher _launcher_configure_executable( "${_launchermoddir}/targetlauncher.${_suffix}.in" "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/launch-${_targetname}.${_suffix}" "${CMAKE_CURRENT_BINARY_DIR}/launch-${_targetname}.${_suffix}" ${CMAKE_BUILD_TYPE}) endif() endmacro() function(create_default_target_launcher _targetname) _launcher_system_settings() _launcher_process_args(${ARGN}) set(VCPROJNAME "${CMAKE_BINARY_DIR}/ALL_BUILD") _launcher_produce_vcproj_user() _launcher_create_target_launcher() endfunction() function(create_target_launcher _targetname) _launcher_system_settings() _launcher_process_args(${ARGN}) set(VCPROJNAME "${CMAKE_CURRENT_BINARY_DIR}/${_targetname}") _launcher_produce_vcproj_user() _launcher_create_target_launcher() endfunction() function(create_generic_launcher _launchername) _launcher_system_settings() _launcher_process_args(${ARGN}) if(NOT IS_ABSOLUTE _launchername) set(_launchername "${CMAKE_CURRENT_BINARY_DIR}/${_launchername}.${_suffix}") else() set(_launchername "${_launchername}.${_suffix}") endif() if(WIN32) set(GENERIC_LAUNCHER_COMMAND "${_launchername}" PARENT_SCOPE) set(GENERIC_LAUNCHER_FAIL_REGULAR_EXPRESSION) else() set(GENERIC_LAUNCHER_COMMAND sh "${_launchername}" PARENT_SCOPE) set(GENERIC_LAUNCHER_FAIL_REGULAR_EXPRESSION "Program terminated with signal") endif() if(CMAKE_CONFIGURATION_TYPES) set(_launcher_build_type "${CMAKE_BUILD_TYPE}") else() unset(_launcher_build_type) endif() _launcher_configure_executable( "${_launchermoddir}/genericlauncher.${_suffix}.in" "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/genericlauncher.${_suffix}.in" "${_launchername}" ${_launcher_build_type}) endfunction() function(guess_runtime_library_dirs _var) # Start off with the link directories of the calling listfile's directory get_directory_property(_libdirs LINK_DIRECTORIES) # Add additional libraries passed to the function foreach(_lib ${ARGN}) get_filename_component(_libdir "${_lib}" PATH) list(APPEND _libdirs "${_libdir}") endforeach() # Now, build a list of potential dll directories set(_dlldirs) foreach(_libdir ${_libdirs}) # Add the libdir itself list(APPEND _dlldirs "${_libdir}") # Look also in libdir/../bin since the dll might not be with the lib get_filename_component(_libdir "${_libdir}/../bin" ABSOLUTE) list(APPEND _dlldirs "${_libdir}") endforeach() # Only keep the valid, unique directories clean_directory_list(_dlldirs) # Return _dlldirs set(${_var} "${_dlldirs}" PARENT_SCOPE) endfunction() cmake_policy(POP)