chiark / gitweb /
Link swig modules with dynamic lookup
authorJulien Schueller <schueller@phimeca.com>
Sat, 13 Oct 2018 07:48:44 +0000 (09:48 +0200)
committerJulien Schueller <schueller@phimeca.com>
Mon, 15 Oct 2018 06:44:33 +0000 (08:44 +0200)
CMakeLists.txt
cmake/TargetLinkLibrariesWithDynamicLookup.cmake [new file with mode: 0644]
src/swig/CMakeLists.txt

index 542d1a2930a124a3a10b86b849c0713cee23c187..2cf3289aa6ef8c35a3d298db810113928b835894 100644 (file)
@@ -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 (file)
index 0000000..6969aab
--- /dev/null
@@ -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()
index d10142c96c191c3e70d8cacccbbfd762a93057e6..341e1db8d406c539fec79c443f30ca723f4c95d5 100644 (file)
@@ -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})