OSXFixDylibReferences.cmake 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. # OS X requires a Mach-O dynamic library to have a baked "install name", that is used by other modules to link to it. Depending
  2. # on how the library is built, the install name is not always an absolute path, nor necessarily the same as the name of the
  3. # library file itself. This macro takes as input the name of a target, and a list of libraries that it links to (the output of
  4. # FIND_PACKAGE or FIND_LIBRARY calls), and generates a set of custom, post-build commands that, for each linked dylib, changes
  5. # the name the target uses to refer to it with a fully-qualified (absolute) version of the library's own install name. This
  6. # helps ensure that the target can be used from any location while still being able to locate the linked dynamic libraries.
  7. #
  8. # Note that this script does NOT handle the case when a linked library itself refers to another library using a non-absolute
  9. # name (Boost is a notorious example). To avoid such issues, it is recommended to use a static library instead of a shared one
  10. # in a non-standard location. Alternatively, set DYLD_LIBRARY_PATH to include these non-standard locations when running the
  11. # program (not recommended).
  12. #
  13. # Author: Siddhartha Chaudhuri, 2009.
  14. #
  15. # Set the minimum required CMake version
  16. CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
  17. # See cmake --help-policy CMP0011 for details on this one
  18. IF(POLICY CMP0011)
  19. CMAKE_POLICY(SET CMP0011 NEW)
  20. ENDIF(POLICY CMP0011)
  21. # See cmake --help-policy CMP0026 for details on this one
  22. IF(POLICY CMP0026)
  23. CMAKE_POLICY(SET CMP0026 NEW)
  24. ENDIF(POLICY CMP0026)
  25. # See cmake --help-policy CMP0045 for details on this one
  26. IF(POLICY CMP0045)
  27. CMAKE_POLICY(SET CMP0045 NEW)
  28. ENDIF(POLICY CMP0045)
  29. MACRO(OSX_FIX_DYLIB_REFERENCES target libraries)
  30. IF(APPLE)
  31. SET(OFIN_${target}_RPATHS )
  32. FOREACH(OFIN_${target}_Library ${libraries})
  33. IF(${OFIN_${target}_Library} MATCHES "[.]dylib$"
  34. OR ${OFIN_${target}_Library} MATCHES "[.]framework/.+")
  35. # Resolve symlinks and get absolute location
  36. GET_FILENAME_COMPONENT(OFIN_${target}_LibraryAbsolute ${OFIN_${target}_Library} ABSOLUTE)
  37. # Get the baked install name of the library
  38. EXECUTE_PROCESS(COMMAND otool -D ${OFIN_${target}_LibraryAbsolute}
  39. OUTPUT_VARIABLE OFIN_${target}_LibraryInstallNameOutput
  40. OUTPUT_STRIP_TRAILING_WHITESPACE)
  41. STRING(REGEX REPLACE "[\r\n]" " " OFIN_${target}_LibraryInstallNameOutput ${OFIN_${target}_LibraryInstallNameOutput})
  42. SEPARATE_ARGUMENTS(OFIN_${target}_LibraryInstallNameOutput)
  43. LIST(GET OFIN_${target}_LibraryInstallNameOutput 1 OFIN_${target}_LibraryInstallName)
  44. IF(${OFIN_${target}_LibraryInstallName} MATCHES "^[@]rpath/")
  45. # Ideally, we want to eliminate the longest common suffix of the install name and the absolute path. Whatever's left
  46. # will be the desired rpath. But this is difficult to do (especially if there are naming variations, e.g.
  47. # "Versions/Current" vs "Versions/5" is a common culprit). So we'll add various candidate rpaths and hope at least one
  48. # is correct.
  49. # Typically, the rpath to a library within a framework looks like this:
  50. # @rpath/A.framework/Versions/5/libFoo.dylib
  51. #
  52. # Hence, we'll extract for the path unit immediately following the @rpath (in this case A.framework) and then look for
  53. # it in the library's actual path. Everything before this location will be put in the rpath.
  54. SET(OFIN_${target}_PathPrefix ${OFIN_${target}_LibraryInstallName})
  55. SET(OFIN_${target}_RpathFirstChild )
  56. WHILE(NOT OFIN_${target}_PathPrefix STREQUAL "@rpath")
  57. GET_FILENAME_COMPONENT(OFIN_${target}_RpathFirstChild ${OFIN_${target}_PathPrefix} NAME)
  58. GET_FILENAME_COMPONENT(OFIN_${target}_PathPrefix ${OFIN_${target}_PathPrefix} PATH)
  59. IF(NOT OFIN_${target}_PathPrefix) # should never happen but just in case
  60. BREAK()
  61. ENDIF(NOT OFIN_${target}_PathPrefix)
  62. IF(OFIN_${target}_PathPrefix STREQUAL "/") # should never happen but just in case
  63. BREAK()
  64. ENDIF(OFIN_${target}_PathPrefix STREQUAL "/")
  65. ENDWHILE(NOT OFIN_${target}_PathPrefix STREQUAL "@rpath")
  66. IF(OFIN_${target}_RpathFirstChild)
  67. SET(OFIN_${target}_PathPrefix ${OFIN_${target}_LibraryAbsolute})
  68. SET(OFIN_${target}_PathUnit )
  69. WHILE(NOT OFIN_${target}_PathUnit STREQUAL ${OFIN_${target}_RpathFirstChild})
  70. GET_FILENAME_COMPONENT(OFIN_${target}_PathUnit ${OFIN_${target}_PathPrefix} NAME)
  71. GET_FILENAME_COMPONENT(OFIN_${target}_PathPrefix ${OFIN_${target}_PathPrefix} PATH)
  72. IF(NOT OFIN_${target}_PathPrefix)
  73. BREAK()
  74. ENDIF(NOT OFIN_${target}_PathPrefix)
  75. IF(OFIN_${target}_PathPrefix STREQUAL "/")
  76. BREAK()
  77. ENDIF(OFIN_${target}_PathPrefix STREQUAL "/")
  78. ENDWHILE(NOT OFIN_${target}_PathUnit STREQUAL ${OFIN_${target}_RpathFirstChild})
  79. IF(OFIN_${target}_PathPrefix)
  80. SET(OFIN_${target}_RPATHS ${OFIN_${target}_RPATHS} "${OFIN_${target}_PathPrefix}")
  81. ENDIF(OFIN_${target}_PathPrefix)
  82. ENDIF(OFIN_${target}_RpathFirstChild)
  83. # Add the directory containing the library
  84. GET_FILENAME_COMPONENT(OFIN_${target}_LibraryAbsolutePath ${OFIN_${target}_LibraryAbsolute} PATH)
  85. SET(OFIN_${target}_RPATHS ${OFIN_${target}_RPATHS} "${OFIN_${target}_LibraryAbsolutePath}")
  86. # Add paths specified as library search prefixes
  87. FOREACH(prefix ${CMAKE_PREFIX_PATH})
  88. SET(OFIN_${target}_RPATHS ${OFIN_${target}_RPATHS} "${CMAKE_PREFIX_PATH}")
  89. SET(OFIN_${target}_RPATHS ${OFIN_${target}_RPATHS} "${CMAKE_PREFIX_PATH}/lib")
  90. ENDFOREACH()
  91. ELSEIF(NOT ${OFIN_${target}_LibraryInstallName} MATCHES "^[@/]") # just a relative path
  92. # Replace the unqualified filename, if it appears, with the absolute location, either by directly changing the path or
  93. # by editing the rpath
  94. # -- handle the case when the actual filename is baked in
  95. GET_FILENAME_COMPONENT(OFIN_${target}_LibraryFilename ${OFIN_${target}_LibraryAbsolute} NAME)
  96. ADD_CUSTOM_COMMAND(TARGET ${target} POST_BUILD
  97. COMMAND install_name_tool
  98. ARGS -change
  99. ${OFIN_${target}_LibraryFilename}
  100. ${OFIN_${target}_LibraryAbsolute}
  101. $<TARGET_FILE:${target}>)
  102. # -- handle the case when the install name is baked in
  103. ADD_CUSTOM_COMMAND(TARGET ${target} POST_BUILD
  104. COMMAND install_name_tool
  105. ARGS -change
  106. ${OFIN_${target}_LibraryInstallName}
  107. ${OFIN_${target}_LibraryAbsolute}
  108. $<TARGET_FILE:${target}>)
  109. ENDIF()
  110. ENDIF()
  111. ENDFOREACH(OFIN_${target}_Library)
  112. # Add the collected rpaths
  113. IF(OFIN_${target}_RPATHS)
  114. LIST(REMOVE_DUPLICATES OFIN_${target}_RPATHS)
  115. FOREACH(rpath ${OFIN_${target}_RPATHS})
  116. ADD_CUSTOM_COMMAND(TARGET ${target} POST_BUILD
  117. COMMAND bash
  118. ARGS -c "install_name_tool -add_rpath '${rpath}' '$<TARGET_FILE:${target}>' > /dev/null 2>&1 || true"
  119. VERBATIM)
  120. ENDFOREACH()
  121. ENDIF()
  122. ENDIF()
  123. ENDMACRO(OSX_FIX_DYLIB_REFERENCES)