1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
|
#
# Somehow "backport" CMakeIngestOSXBundleLibraries.cmake
# rename in OwnIngestOSXBundleLibraries.cmake to not conflict if already present
#
# Only for the Mac build.
#
# Depends on OS tools:
# otool
# install_name_tool
#
# This script ingests libraries and frameworks into an existing .app bundle and
# then uses install_name_tool to fixup the references to the newly embedded
# libraries so that they all refer to each other via "@executable_path."
#
# The main intent (and simplifying assumption used for developing the script)
# is to have a single executable .app bundle that becomes "self-contained" by
# copying all non-system libs that it depends on into itself. The further
# assumption is that all such dependencies are simple .dylib shared library
# files or Mac Framework libraries.
#
# This script can be used as part of the build via ADD_CUSTOM_COMMAND, or used
# only during make install via INSTALL SCRIPT.
#
IF(NOT DEFINED input_file)
MESSAGE(FATAL_ERROR "
${CMAKE_CURRENT_LIST_FILE}(${CMAKE_CURRENT_LIST_LINE}): error: Variable input_file is not defined.
Use a command line like this to use this script:
cmake \"-Dinput_file=filename\" \"-Dextra_libs=/path/to/lib1;/path/to/lib2\" \"-Dlib_path=/path/to/unqualified/libs\" -P \"${CMAKE_CURRENT_LIST_FILE}\"
'input_file' should be the main executable inside a Mac bundle directory structure.
For example, use 'bin/paraview.app/Contents/MacOS/paraview' from a ParaView binary dir.
'extra_libs' should be a semi-colon separated list of full path names to extra libraries
to copy into the bundle that cannot be derived from otool -L output. For example, you may
also want to fixup dynamically loaded plugins from your build tree and copy them into the
bundle.
'lib_path' should be the path where to find libraries referenced without a path name in
otool -L output.
")
ENDIF(NOT DEFINED input_file)
SET(eol_char "E")
IF(APPLE)
SET(dep_tool "otool")
SET(dep_cmd_args "-L")
SET(dep_regex "^\t([^\t]+) \\(compatibility version ([0-9]+.[0-9]+.[0-9]+), current version ([0-9]+.[0-9]+.[0-9]+)\\)${eol_char}$")
ENDIF(APPLE)
MESSAGE("")
MESSAGE("# Script \"${CMAKE_CURRENT_LIST_FILE}\" running...")
MESSAGE("")
MESSAGE("input_file: '${input_file}'")
MESSAGE("extra_libs: '${extra_libs}'")
MESSAGE("lib_path: '${lib_path}'")
MESSAGE("")
GET_FILENAME_COMPONENT(input_file_full "${input_file}" ABSOLUTE)
MESSAGE("input_file_full: '${input_file_full}'")
GET_FILENAME_COMPONENT(bundle "${input_file_full}/../../.." ABSOLUTE)
MESSAGE("bundle: '${bundle}'")
FIND_PROGRAM(dep_cmd ${dep_tool})
MACRO(APPEND_UNIQUE au_list_var au_value)
SET(${au_list_var} ${${au_list_var}} "${au_value}")
ENDMACRO(APPEND_UNIQUE)
MACRO(GATHER_DEPENDENTS gd_target gd_dependents_var)
EXECUTE_PROCESS(
COMMAND ${dep_cmd} ${dep_cmd_args} ${gd_target}
OUTPUT_VARIABLE dep_tool_ov
)
STRING(REGEX REPLACE ";" "\\\\;" dep_candidates "${dep_tool_ov}")
STRING(REGEX REPLACE "\n" "${eol_char};" dep_candidates "${dep_candidates}")
SET(${gd_dependents_var} "")
FOREACH(candidate ${dep_candidates})
IF("${candidate}" MATCHES "${dep_regex}")
STRING(REGEX REPLACE "${dep_regex}" "\\1" raw_item "${candidate}")
STRING(REGEX REPLACE "${dep_regex}" "\\2" raw_compat_version "${candidate}")
STRING(REGEX REPLACE "${dep_regex}" "\\3" raw_current_version "${candidate}")
SET(item "${raw_item}")
STRING(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" compat_major_version "${raw_compat_version}")
STRING(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" compat_minor_version "${raw_compat_version}")
STRING(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" compat_patch_version "${raw_compat_version}")
STRING(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" current_major_version "${raw_current_version}")
STRING(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" current_minor_version "${raw_current_version}")
STRING(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" current_patch_version "${raw_current_version}")
#MESSAGE("${raw_item} - compat ${raw_compat_version} - current ${raw_current_version}")
APPEND_UNIQUE("${gd_dependents_var}" "${item}")
ELSE("${candidate}" MATCHES "${dep_regex}")
IF("${candidate}" STREQUAL "${gd_target}:${eol_char}")
#MESSAGE("info: ignoring target name...")
ELSE("${candidate}" STREQUAL "${gd_target}:${eol_char}")
MESSAGE("error: candidate='${candidate}'")
ENDIF("${candidate}" STREQUAL "${gd_target}:${eol_char}")
ENDIF("${candidate}" MATCHES "${dep_regex}")
ENDFOREACH(candidate)
ENDMACRO(GATHER_DEPENDENTS)
MESSAGE("Gathering dependent libraries for '${input_file_full}'...")
GATHER_DEPENDENTS("${input_file_full}" deps)
MESSAGE("")
# Order lexicographically:
#
LIST(SORT deps)
# Split into separate lists, "system" "embedded" and "nonsystem" libraries.
# System libs are assumed to be available on all target runtime Macs and do not
# need to be copied/fixed-up by this script. Embedded libraries are assumed to
# be in the bundle and fixed-up already. Only non-system, non-embedded libs
# need copying and fixing up...
#
SET(system_deps "")
SET(embedded_deps "")
SET(nonsystem_deps "")
FOREACH(d ${deps})
SET(d_is_embedded_lib 0)
SET(d_is_system_lib 0)
IF("${d}" MATCHES "^(/System/Library|/usr/lib)")
SET(d_is_system_lib 1)
ELSE("${d}" MATCHES "^(/System/Library|/usr/lib)")
IF("${d}" MATCHES "^@executable_path")
SET(d_is_embedded_lib 1)
ENDIF("${d}" MATCHES "^@executable_path")
ENDIF("${d}" MATCHES "^(/System/Library|/usr/lib)")
IF(d_is_system_lib)
SET(system_deps ${system_deps} "${d}")
ELSE(d_is_system_lib)
IF(d_is_embedded_lib)
SET(embedded_deps ${embedded_deps} "${d}")
ELSE(d_is_embedded_lib)
SET(nonsystem_deps ${nonsystem_deps} "${d}")
ENDIF(d_is_embedded_lib)
ENDIF(d_is_system_lib)
ENDFOREACH(d)
MESSAGE("")
MESSAGE("system_deps:")
FOREACH(d ${system_deps})
MESSAGE("${d}")
ENDFOREACH(d ${system_deps})
MESSAGE("")
MESSAGE("embedded_deps:")
FOREACH(d ${embedded_deps})
MESSAGE("${d}")
ENDFOREACH(d ${embedded_deps})
MESSAGE("")
MESSAGE("nonsystem_deps:")
FOREACH(d ${nonsystem_deps})
MESSAGE("${d}")
ENDFOREACH(d ${nonsystem_deps})
MESSAGE("")
MACRO(COPY_LIBRARY_INTO_BUNDLE clib_bundle clib_libsrc clib_dstlibs clib_fixups)
#
# If the source library is a framework, copy just the shared lib bit of the framework
# into the bundle under "${clib_bundle}/Contents/Frameworks" - if it is just a dylib
# copy it into the same directory with the main bundle executable under
# "${clib_bundle}/Contents/MacOS"
#
IF("${clib_libsrc}" MATCHES ".framework/.*/.*/.*")
# SET(fw_src "/Library/Frameworks/${clib_libsrc}")
SET(fw_src "${clib_libsrc}")
GET_FILENAME_COMPONENT(fw_srcdir "${fw_src}/../../.." ABSOLUTE)
GET_FILENAME_COMPONENT(fwdirname "${fw_srcdir}" NAME)
STRING(REGEX REPLACE "^(.*)\\.framework$" "\\1" fwname "${fwdirname}")
STRING(REGEX REPLACE "^.*/${fwname}\\.framework/(.*)$" "\\1" fwlibname "${clib_libsrc}")
SET(fw_dstdir "${clib_bundle}/Contents/Frameworks/${fwdirname}")
# MESSAGE("")
# MESSAGE("fwdirname: '${fwdirname}'")
# MESSAGE("fwname: '${fwname}'")
# MESSAGE("fwlibname: '${fwlibname}'")
# MESSAGE("fw_src: '${fw_src}'")
# MESSAGE("fw_srcdir: '${fw_srcdir}'")
# MESSAGE("fw_dstdir: '${fw_dstdir}'")
# MESSAGE("new_name: '@executable_path/../Frameworks/${fwdirname}/${fwlibname}'")
# MESSAGE("")
MESSAGE("Copying ${fw_srcdir} into bundle...")
# This command copies the *entire* framework recursively:
#
# EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E copy_directory
# "${fw_srcdir}" "${fw_dstdir}"
# )
# This command copies just the main shared lib of the framework:
# (This technique will not work for frameworks that have necessary
# resource or auxiliary files...)
#
EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E copy
"${fw_src}" "${fw_dstdir}/${fwlibname}"
)
EXECUTE_PROCESS(COMMAND install_name_tool
-id "@executable_path/../Frameworks/${fwdirname}/${fwlibname}"
"${clib_bundle}/Contents/Frameworks/${fwdirname}/${fwlibname}"
)
SET(${clib_dstlibs} ${${clib_dstlibs}}
"${clib_bundle}/Contents/Frameworks/${fwdirname}/${fwlibname}"
)
SET(${clib_fixups} ${${clib_fixups}}
"-change"
"${clib_libsrc}"
"@executable_path/../Frameworks/${fwdirname}/${fwlibname}"
)
ELSE("${clib_libsrc}" MATCHES ".framework/.*/.*/.*")
IF("${clib_libsrc}" MATCHES "/")
SET(clib_libsrcfull "${clib_libsrc}")
ELSE("${clib_libsrc}" MATCHES "/")
SET(clib_libsrcfull "${lib_path}/${clib_libsrc}")
IF(NOT EXISTS "${clib_libsrcfull}")
MESSAGE(FATAL_ERROR "error: '${clib_libsrcfull}' does not exist...")
ENDIF(NOT EXISTS "${clib_libsrcfull}")
ENDIF("${clib_libsrc}" MATCHES "/")
GET_FILENAME_COMPONENT(dylib_src "${clib_libsrcfull}" ABSOLUTE)
GET_FILENAME_COMPONENT(dylib_name "${dylib_src}" NAME)
SET(dylib_dst "${clib_bundle}/Contents/MacOS/${dylib_name}")
# MESSAGE("dylib_src: ${dylib_src}")
# MESSAGE("dylib_dst: ${dylib_dst}")
# MESSAGE("new_name: '@executable_path/${dylib_name}'")
MESSAGE("Copying ${dylib_src} into bundle...")
EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E copy
"${dylib_src}" "${dylib_dst}")
EXECUTE_PROCESS(COMMAND install_name_tool
-id "@executable_path/${dylib_name}"
"${dylib_dst}"
)
SET(${clib_dstlibs} ${${clib_dstlibs}}
"${dylib_dst}"
)
SET(${clib_fixups} ${${clib_fixups}}
"-change"
"${clib_libsrc}"
"@executable_path/${dylib_name}"
)
ENDIF("${clib_libsrc}" MATCHES ".framework/.*/.*/.*")
ENDMACRO(COPY_LIBRARY_INTO_BUNDLE)
# Copy dependent "nonsystem" libraries into the bundle:
#
MESSAGE("Copying dependent libraries into bundle...")
SET(srclibs ${nonsystem_deps} ${extra_libs})
SET(dstlibs "")
SET(fixups "")
FOREACH(d ${srclibs})
COPY_LIBRARY_INTO_BUNDLE("${bundle}" "${d}" dstlibs fixups)
ENDFOREACH(d)
MESSAGE("")
MESSAGE("dstlibs='${dstlibs}'")
MESSAGE("")
MESSAGE("fixups='${fixups}'")
MESSAGE("")
# Fixup references to copied libraries in the main bundle executable and in the
# copied libraries themselves:
#
IF(NOT "${fixups}" STREQUAL "")
MESSAGE("Fixing up references...")
FOREACH(d ${dstlibs} "${input_file_full}")
MESSAGE("fixing up references in: '${d}'")
EXECUTE_PROCESS(COMMAND install_name_tool ${fixups} "${d}")
ENDFOREACH(d)
MESSAGE("")
ENDIF(NOT "${fixups}" STREQUAL "")
# List all references to eyeball them and make sure they look right:
#
MESSAGE("Listing references...")
FOREACH(d ${dstlibs} "${input_file_full}")
EXECUTE_PROCESS(COMMAND otool -L "${d}")
MESSAGE("")
ENDFOREACH(d)
MESSAGE("")
# Output file:
#
GET_FILENAME_COMPONENT(script_name "${CMAKE_CURRENT_LIST_FILE}" NAME)
FILE(WRITE "${input_file_full}_${script_name}" "# Script \"${CMAKE_CURRENT_LIST_FILE}\" completed.\n")
MESSAGE("")
MESSAGE("# Script \"${CMAKE_CURRENT_LIST_FILE}\" completed.")
MESSAGE("")
|