6 # The following functions are defined: 8 # .. cmake:command:: mitk_target_link_libraries_with_dynamic_lookup 12 # mitk_target_link_libraries_with_dynamic_lookup(<Target> [<Libraries>]) 15 # Useful to "weakly" link a loadable module. For example, it should be used 16 # when compiling a loadable module when the symbols should be resolve from 17 # the run-time environment where the module is loaded, and not a specific 20 # Like proper linking, except that the given ``<Libraries>`` are not necessarily 21 # linked. Instead, the ``<Target>`` is produced in a manner that allows for 22 # symbols unresolved within it to be resolved at runtime, presumably by the 23 # given ``<Libraries>``. If such a target can be produced, the provided 24 # ``<Libraries>`` are not actually linked. 26 # It links a library to a target such that the symbols are resolved at 27 # run-time not link-time. 29 # The linker is checked to see if it supports undefined 30 # symbols when linking a shared library. If it does then the library 31 # is not linked when specified with this function. 33 # On platforms that do not support weak-linking, this function works just 34 # like ``mitk_target_link_libraries``. 38 # For OSX it uses ``undefined dynamic_lookup``. This is similar to using 39 # ``-shared`` on Linux where undefined symbols are ignored. 41 # For more details, see `blog <http://blog.tim-smith.us/2015/09/python-extension-modules-os-x/>`_ 45 # .. cmake:command:: mitk_check_dynamic_lookup 47 # Check if the linker requires a command line flag to allow leaving symbols 48 # unresolved when producing a target of type ``<TargetType>`` that is 49 # weakly-linked against a dependency of type ``<LibType>``. 52 # can be one of "STATIC", "SHARED", "MODULE", or "EXE". 55 # can be one of "STATIC", "SHARED", or "MODULE". 61 # mitk_check_dynamic_lookup(<TargetType> 71 # mitk_check_dynamic_lookup(<ResultVar>) # <TargetType> set to "MODULE" 72 # # <LibType> set to "SHARED" 75 # The result is cached between invocations and recomputed only when the value 76 # of CMake's linker flag list changes; ``CMAKE_STATIC_LINKER_FLAGS`` if 77 # ``<TargetType>`` is "STATIC", and ``CMAKE_SHARED_LINKER_FLAGS`` otherwise. 83 # Whether the current C toolchain supports weak-linking for target binaries of 84 # type ``<TargetType>`` that are weakly-linked against a dependency target of 88 # List of flags to add to the linker command to produce a working target 89 # binary of type ``<TargetType>`` that is weakly-linked against a dependency 90 # target of type ``<LibType>``. 92 # ``HAS_DYNAMIC_LOOKUP_<TargetType>_<LibType>`` 93 # Cached, global alias for ``<ResultVar>`` 95 # ``DYNAMIC_LOOKUP_FLAGS_<TargetType>_<LibType>`` 96 # Cached, global alias for ``<LinkFlagsVar>`` 102 # The following private functions are defined: 104 # .. warning:: These functions are not part of the scikit-build API. They 105 # exist purely as an implementation detail and may change from version 106 # to version without notice, or even be removed. 111 # .. cmake:command:: _get_target_type 115 # _get_target_type(<ResultVar> <Target>) 118 # Shorthand for querying an abbreviated version of the target type 119 # of the given ``<Target>``. 121 # ``<ResultVar>`` is set to: 123 # - "STATIC" for a STATIC_LIBRARY, 124 # - "SHARED" for a SHARED_LIBRARY, 125 # - "MODULE" for a MODULE_LIBRARY, 126 # - and "EXE" for an EXECUTABLE. 131 # The abbreviated version of the ``<Target>``'s type. 134 # .. cmake:command:: _test_weak_link_project 138 # _test_weak_link_project(<TargetType> 144 # Attempt to compile and run a test project where a target of type 145 # ``<TargetType>`` is weakly-linked against a dependency of type ``<LibType>``: 147 # - ``<TargetType>`` can be one of "STATIC", "SHARED", "MODULE", or "EXE". 148 # - ``<LibType>`` can be one of "STATIC", "SHARED", or "MODULE". 153 # Whether the current C toolchain can produce a working target binary of type 154 # ``<TargetType>`` that is weakly-linked against a dependency target of type 158 # List of flags to add to the linker command to produce a working target 159 # binary of type ``<TargetType>`` that is weakly-linked against a dependency 160 # target of type ``<LibType>``. 164 set(target_type
"SHARED_LIBRARY")
166 get_property(target_type
TARGET ${target} PROPERTY TYPE)
171 if(target_type STREQUAL
"STATIC_LIBRARY")
175 if(target_type STREQUAL
"SHARED_LIBRARY")
179 if(target_type STREQUAL
"MODULE_LIBRARY")
183 if(target_type STREQUAL
"EXECUTABLE")
187 set(${result_var} ${result} PARENT_SCOPE)
197 set(gnu_ld_ignore
"-Wl,--unresolved-symbols=ignore-all")
198 set(osx_dynamic_lookup
"-undefined dynamic_lookup")
201 foreach(link_flag_spec gnu_ld_ignore osx_dynamic_lookup no_flag)
202 set(link_flag
"${${link_flag_spec}}")
204 set(test_project_dir
"${PROJECT_BINARY_DIR}/CMakeTmp")
205 set(test_project_dir
"${test_project_dir}/${project_name}")
206 set(test_project_dir
"${test_project_dir}/${link_flag_spec}")
207 set(test_project_dir
"${test_project_dir}/${target_type}")
208 set(test_project_dir
"${test_project_dir}/${lib_type}")
210 set(test_project_src_dir
"${test_project_dir}/src")
211 set(test_project_bin_dir
"${test_project_dir}/build")
213 file(MAKE_DIRECTORY ${test_project_src_dir})
214 file(MAKE_DIRECTORY ${test_project_bin_dir})
216 set(mod_type
"STATIC")
217 set(link_mod_lib TRUE)
218 set(link_exe_lib TRUE)
219 set(link_exe_mod FALSE)
221 if(
"${target_type}" STREQUAL
"EXE")
222 set(link_exe_lib FALSE)
223 set(link_exe_mod TRUE)
225 set(mod_type
"${target_type}")
228 if(
"${mod_type}" STREQUAL
"MODULE")
229 set(link_mod_lib FALSE)
233 file(WRITE
"${test_project_src_dir}/CMakeLists.txt" " 234 cmake_minimum_required(VERSION ${CMAKE_VERSION}) 235 project(${project_name} C) 237 include_directories(${test_project_src_dir}) 239 add_library(number ${lib_type} number.c) 240 add_library(counter ${mod_type} counter.c) 243 if(
"${mod_type}" STREQUAL
"MODULE")
244 file(APPEND
"${test_project_src_dir}/CMakeLists.txt" " 245 set_target_properties(counter PROPERTIES PREFIX \"\") 250 file(APPEND "${test_project_src_dir}/CMakeLists.txt
" " 251 target_link_libraries(counter number)
253 elseif(NOT link_flag STREQUAL "") 254 file(APPEND "${test_project_src_dir}/CMakeLists.txt
" " 255 set_target_properties(counter PROPERTIES LINK_FLAGS \
"${link_flag}\") 259 file(APPEND "${test_project_src_dir}/CMakeLists.txt
" " 264 file(APPEND "${test_project_src_dir}/CMakeLists.txt
" " 265 target_link_libraries(
main number)
267 elseif(NOT link_flag STREQUAL "") 268 file(APPEND "${test_project_src_dir}/CMakeLists.txt
" " 269 target_link_libraries(
main \
"${link_flag}\") 274 file(APPEND "${test_project_src_dir}/CMakeLists.txt
" " 275 target_link_libraries(
main counter)
278 file(APPEND "${test_project_src_dir}/CMakeLists.txt
" " 279 target_link_libraries(
main \
"${CMAKE_DL_LIBS}\") 283 file(WRITE "${test_project_src_dir}/number.c
" " 287 void set_number(
int number) { _number = number; }
288 int get_number() {
return _number; }
291 file(WRITE "${test_project_src_dir}/number.h
" " 294 extern void set_number(
int);
295 extern int get_number(
void);
299 file(WRITE "${test_project_src_dir}/counter.c
" " 302 int result = get_number();
303 set_number(result + 1);
308 file(WRITE "${test_project_src_dir}/counter.h
" " 311 extern int count(
void);
315 file(WRITE "${test_project_src_dir}/
main.c
" " 322 file(APPEND "${test_project_src_dir}/
main.c
" " 327 file(APPEND "${test_project_src_dir}/
main.c
" " 329 int result = get_number();
330 set_number(result + 1);
334 int main(
int argc,
char **argv) {
339 file(APPEND "${test_project_src_dir}/
main.c
" " 340 void *counter_module;
343 counter_module = dlopen(\
"./counter.so\", RTLD_LAZY | RTLD_GLOBAL); 344 if(!counter_module) goto error; 346 count = dlsym(counter_module, \"count\"); 347 if(!count) goto error; 351 file(APPEND "${test_project_src_dir}/
main.c
" " 352 result = count() != 0 ? EXIT_FAILURE :
353 my_count() != 1 ? EXIT_FAILURE :
354 my_count() != 2 ? EXIT_FAILURE :
355 count() != 3 ? EXIT_FAILURE :
356 count() != 4 ? EXIT_FAILURE :
357 count() != 5 ? EXIT_FAILURE :
358 my_count() != 6 ? EXIT_FAILURE : EXIT_SUCCESS;
362 file(APPEND "${test_project_src_dir}/
main.c
" " 365 fprintf(stderr, \
"Error occured:\\n %s\\n\", dlerror()); 369 if(counter_module) dlclose(counter_module); 373 file(APPEND "${test_project_src_dir}/
main.c
" " 379 if(APPLE AND ${CMAKE_VERSION} VERSION_GREATER 2.8.11) 380 set(_rpath_arg "-DCMAKE_MACOSX_RPATH=
'${CMAKE_MACOSX_RPATH}'") 383 try_compile(project_compiles 384 "${test_project_bin_dir}
" 385 "${test_project_src_dir}
" 388 "-DCMAKE_SHARED_LINKER_FLAGS=
'${CMAKE_SHARED_LINKER_FLAGS}'" 389 "-DCMAKE_ENABLE_EXPORTS=ON
" 391 OUTPUT_VARIABLE compile_output) 397 execute_process(COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} 398 "${test_project_bin_dir}/
main" 399 WORKING_DIRECTORY "${test_project_bin_dir}
" 400 RESULT_VARIABLE project_works 401 OUTPUT_VARIABLE run_output 402 ERROR_VARIABLE run_output) 406 "Weak Link ${target_type} -> ${lib_type} (${link_flag_spec})
") 408 if(project_works EQUAL 0) 409 set(project_works TRUE) 410 message(STATUS "Performing Test ${test_description} - Success
") 412 set(project_works FALSE) 413 message(STATUS "Performing Test ${test_description} - Failed
") 414 file(APPEND ${CMAKE_BINARY_DIR}/${CMAKE_FILES_DIRECTORY}/CMakeError.log 415 "Performing Test ${test_description} failed with the
" 416 "following output:\n
" 417 "BUILD\n-----\n${compile_output}\nRUN\n---\n${run_output}\n
") 420 set(${can_weak_link_var} ${project_works} PARENT_SCOPE) 422 set(${project_name} ${link_flag} PARENT_SCOPE) 428 function(mitk_check_dynamic_lookup) 429 # Two signatures are supported: 433 # mitk_check_dynamic_lookup(<ResultVar>) 435 set(target_type "MODULE
") 436 set(lib_type "SHARED
") 437 set(has_dynamic_lookup_var "${ARGV0}
") 438 set(link_flags_var "unused
") 440 elseif(ARGC GREATER "2
") 442 # mitk_check_dynamic_lookup(<TargetType> 447 set(target_type "${ARGV0}
") 448 set(lib_type "${ARGV1}
") 449 set(has_dynamic_lookup_var "${ARGV2}
") 451 set(link_flags_var "unused
") 453 set(link_flags_var "${ARGV3}
") 456 message(FATAL_ERROR "missing arguments
") 459 _check_dynamic_lookup( 462 ${has_dynamic_lookup_var} 465 set(${has_dynamic_lookup_var} ${${has_dynamic_lookup_var}} PARENT_SCOPE) 466 if(NOT "x${link_flags_var}x
" MATCHES "^xunusedx$
") 467 set(${link_flags_var} ${${link_flags_var}} PARENT_SCOPE) 471 function(_check_dynamic_lookup 474 has_dynamic_lookup_var 478 # hash the CMAKE_FLAGS passed and check cache to know if we need to rerun 479 if("${target_type}
" STREQUAL "STATIC
") 480 string(MD5 cmake_flags_hash "${CMAKE_STATIC_LINKER_FLAGS}
") 482 string(MD5 cmake_flags_hash "${CMAKE_SHARED_LINKER_FLAGS}
") 485 set(cache_var "HAS_DYNAMIC_LOOKUP_${target_type}_${lib_type}
") 486 set(cache_hash_var "HAS_DYNAMIC_LOOKUP_${target_type}_${lib_type}_hash
") 487 set(result_var "DYNAMIC_LOOKUP_FLAGS_${target_type}_${lib_type}
") 489 if( NOT DEFINED ${cache_hash_var} 490 OR NOT "${${cache_hash_var}}
" STREQUAL "${cmake_flags_hash}
") 491 unset(${cache_var} CACHE) 494 if(NOT DEFINED ${cache_var}) 497 if(CMAKE_CROSSCOMPILING AND NOT CMAKE_CROSSCOMPILING_EMULATOR) 502 set(has_dynamic_lookup FALSE) 505 _test_weak_link_project(${target_type} 511 set(caveat " (when linking ${target_type} against ${lib_type})
") 513 set(${cache_var} "${has_dynamic_lookup}
" 515 "linker supports dynamic lookup
for undefined symbols${caveat}
") 516 mark_as_advanced(${cache_var}) 518 set(${result_var} "${link_flags}
" 520 "linker flags
for dynamic lookup${caveat}
") 521 mark_as_advanced(${result_var}) 523 set(${cache_hash_var} "${cmake_flags_hash}
" 524 CACHE INTERNAL "hashed flags
for ${cache_var} check
") 527 set(${has_dynamic_lookup_var} "${${cache_var}}
" PARENT_SCOPE) 528 set(${link_flags_var} "${${result_var}}
" PARENT_SCOPE) 531 function(mitk_target_link_libraries_with_dynamic_lookup target) 532 _get_target_type(target_type ${target}) 539 _get_target_type(lib_type ${lib}) 540 mitk_check_dynamic_lookup(${target_type} 543 dynamic_lookup_flags) 545 if(has_dynamic_lookup) 546 if(dynamic_lookup_flags) 547 if("${target_type}
" STREQUAL "EXE
") 548 list(APPEND link_items "${dynamic_lookup_flags}
") 550 list(APPEND link_props "${dynamic_lookup_flags}
") 554 list(APPEND link_libs "${lib}
") 559 list(REMOVE_DUPLICATES link_props) 563 list(REMOVE_DUPLICATES link_items) 567 list(REMOVE_DUPLICATES link_libs) 571 set_target_properties(${target} 572 PROPERTIES LINK_FLAGS "${link_props}
") 575 set(links "${link_items}
" "${link_libs}
") 577 target_link_libraries(${target} "${links}
") int main(int argc, char **argv)
_test_weak_link_project(target_type, lib_type, can_weak_link_var, project_name)
_get_target_type(result_var, target)