From ffd93c310931699521eb7ae0dce020d1c59010a2 Mon Sep 17 00:00:00 2001 From: Julien Schueller Date: Sat, 13 Oct 2018 09:48:44 +0200 Subject: [PATCH] Link swig modules with dynamic lookup --- CMakeLists.txt | 1 - ...TargetLinkLibrariesWithDynamicLookup.cmake | 99 +++++++++++++++++++ src/swig/CMakeLists.txt | 7 +- 3 files changed, 102 insertions(+), 5 deletions(-) create mode 100644 cmake/TargetLinkLibrariesWithDynamicLookup.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 542d1a2..2cf3289 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -44,7 +44,6 @@ option (NLOPT_OCTAVE "build octave bindings" ON) option (NLOPT_MATLAB "build matlab bindings" ON) option (NLOPT_GUILE "build guile bindings" ON) option (NLOPT_SWIG "use SWIG to build bindings" ON) -option (NLOPT_LINK_PYTHON "link Python libs" ON) if (CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) option (NLOPT_TESTS "build unit tests" ON) diff --git a/cmake/TargetLinkLibrariesWithDynamicLookup.cmake b/cmake/TargetLinkLibrariesWithDynamicLookup.cmake new file mode 100644 index 0000000..6969aab --- /dev/null +++ b/cmake/TargetLinkLibrariesWithDynamicLookup.cmake @@ -0,0 +1,99 @@ +# +# - This module provides the function +# target_link_libraries_with_dynamic_lookup which can be used to +# "weakly" link loadable module. +# +# Link a library to a target such that the symbols are resolved at +# run-time not link-time. This should be used when compiling a +# loadable module when the symbols should be resolve from the run-time +# environment where the module is loaded, and not a specific system +# library. +# +# Specifically, for OSX it uses undefined dynamic_lookup. This is +# similar to using "-shared" on Linux where undefined symbols are +# ignored. +# +# Additionally, the linker is checked to see if it supports undefined +# symbols when linking a shared library. If it does then the library +# is not linked when specified with this function. +# +# http://blog.tim-smith.us/2015/09/python-extension-modules-os-x/ +# + +# Function: _CheckUndefinedSymbolsAllowed +# +# Check if the linker allows undefined symbols for shared libraries. +# +# UNDEFINED_SYMBOLS_ALLOWED - true if the linker will allow +# undefined symbols for shared libraries +# + +function(_CheckUndefinedSymbolsAllowed) + + set(VARIABLE "UNDEFINED_SYMBOLS_ALLOWED") + set(cache_var "${VARIABLE}_hash") + + + # hash the CMAKE_FLAGS passed and check cache to know if we need to rerun + string(MD5 cmake_flags_hash "${CMAKE_SHARED_LINKER_FLAGS}") + + if(NOT DEFINED "${cache_var}" ) + unset("${VARIABLE}" CACHE) + elseif(NOT "${${cache_var}}" STREQUAL "${cmake_flags_hash}" ) + unset("${VARIABLE}" CACHE) + endif() + + if(NOT DEFINED "${VARIABLE}") + set(test_project_dir "${PROJECT_BINARY_DIR}/CMakeTmp/${VARIABLE}") + + file(WRITE "${test_project_dir}/CMakeLists.txt" +" +project(undefined C) +add_library(foo SHARED \"foo.c\") +") + + file(WRITE "${test_project_dir}/foo.c" +" +extern int bar(void); +int foo(void) {return bar()+1;} +") + + if(APPLE AND ${CMAKE_VERSION} VERSION_GREATER 2.8.11) + set( _rpath_arg "-DCMAKE_MACOSX_RPATH='${CMAKE_MACOSX_RPATH}'" ) + else() + set( _rpath_arg ) + endif() + + try_compile(${VARIABLE} + "${test_project_dir}" + "${test_project_dir}" + undefined + CMAKE_FLAGS + "-DCMAKE_SHARED_LINKER_FLAGS='${CMAKE_SHARED_LINKER_FLAGS}'" + ${_rpath_arg} + OUTPUT_VARIABLE output) + + set(${cache_var} "${cmake_flags_hash}" CACHE INTERNAL "hashed try_compile flags") + + if(${VARIABLE}) + message(STATUS "Performing Test ${VARIABLE} - Success") + else() + message(STATUS "Performing Test ${VARIABLE} - Failed") + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log + "Performing Test ${VARIABLE} failed with the following output:\n" + "${OUTPUT}\n") + endif() + endif() +endfunction() + +_CheckUndefinedSymbolsAllowed() + +macro( target_link_libraries_with_dynamic_lookup target ) + if ( ${CMAKE_SYSTEM_NAME} MATCHES "Darwin" ) + set_target_properties( ${target} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup" ) + elseif(UNDEFINED_SYMBOLS_ALLOWED) + # linker allows undefined symbols, let's just not link + else() + target_link_libraries ( ${target} ${ARGN} ) + endif() +endmacro() diff --git a/src/swig/CMakeLists.txt b/src/swig/CMakeLists.txt index d10142c..341e1db 100644 --- a/src/swig/CMakeLists.txt +++ b/src/swig/CMakeLists.txt @@ -1,5 +1,6 @@ include (UseSWIG) +include (TargetLinkLibrariesWithDynamicLookup) if (NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/nlopt-enum-renames.i) file (WRITE ${CMAKE_CURRENT_BINARY_DIR}/nlopt-enum-renames.i "// AUTOMATICALLY GENERATED -- DO NOT EDIT\n") @@ -27,9 +28,7 @@ if (NUMPY_FOUND AND PYTHONLIBS_FOUND) target_include_directories (${SWIG_MODULE_nlopt_REAL_NAME} PUBLIC ${NUMPY_INCLUDE_DIRS}) swig_link_libraries (nlopt ${nlopt_lib}) - if (NLOPT_LINK_PYTHON) - swig_link_libraries (nlopt ${PYTHON_LIBRARIES}) - endif () + target_link_libraries_with_dynamic_lookup (${SWIG_MODULE_nlopt_REAL_NAME} ${PYTHON_LIBRARIES}) set_target_properties (${SWIG_MODULE_nlopt_REAL_NAME} PROPERTIES OUTPUT_NAME _nlopt) @@ -53,7 +52,7 @@ if (GUILE_FOUND AND (SWIG_VERSION VERSION_GREATER 2.0.9)) target_include_directories (${SWIG_MODULE_nlopt_guile_REAL_NAME} PUBLIC ${GUILE_INCLUDE_DIRS}) swig_link_libraries (nlopt_guile ${nlopt_lib}) - swig_link_libraries (nlopt_guile ${GUILE_LIBRARIES}) + target_link_libraries_with_dynamic_lookup (${SWIG_MODULE_nlopt_guile_REAL_NAME} ${GUILE_LIBRARIES}) file (RELATIVE_PATH _REL_GUILE_SITE_PATH ${GUILE_ROOT_DIR} ${GUILE_SITE_DIR}) set (GUILE_SITE_PATH ${_REL_GUILE_SITE_PATH}) -- 2.30.2