|
|
(20 intermediate revisions by 6 users not shown) |
Line 1: |
Line 1: |
| ==Issue==
| | {{CMake/Template/Moved}} |
|
| |
|
| On Mac there are several different cases of combinations of bundles, frameworks, and unix tools.
| | This page has moved [https://gitlab.kitware.com/cmake/community/wikis/doc/cmake/platform_dependent_issues/Bundles-And-Frameworks here]. |
| | |
| * What is framework?
| |
| ** Acording to [http://developer.apple.com/documentation/DeveloperTools/Conceptual/MachOTopics/Articles/building_files.html#//apple_ref/doc/uid/TP40001828-97030-TPXREF106] Frameworks are shared libraries that are packaged with associated resources, such as graphics files, developer documentation, and programming interfaces. See "Using Shared Libraries and Frameworks" in “Loading Code at Runtime” for more information.
| |
| * What is bundle?
| |
| ** Acording to [http://developer.apple.com/documentation/DeveloperTools/Conceptual/MachOTopics/Articles/building_files.html#//apple_ref/doc/uid/TP40001828-97030-TPXREF106] Bundles are executable files that your program can load at runtime using dynamic linking functions. Bundles implement plug-in functionality, such as file format importers for a word processor. The term “bundle” has two related meanings in Mac OS X:
| |
| *** The actual object file containing the executable code
| |
| *** A directory containing the object file and associated resources. A bundle need not contain an object file. For more information on bundles, see Bundle Programming Guide.
| |
| ** The latter usage is the more common. However, unless otherwise specified, this document refers to the former.
| |
| | |
| * ADD_LIBRARY and ADD_EXCUTABLE as they exist now do not provide enough functionality
| |
| * The problem is that CMAKE_INSTALL_PREFIX is not enough. Also, when creating bundles and frameworks, auxilary files should be in the proper subdirectory structure.
| |
| | |
| ==Notation==
| |
| | |
| * In all examples, the applications are named appl1, appl2, ...
| |
| * libraries are named libr1, libr2, ...
| |
| * header files are named appl1_header1, appl2_header2, libr1_header1, ...
| |
| * there are auxilary files associated with application and library appl1_aux1, appl2_aux2, libr1_aux1, ...
| |
| * and some resource files associated with application and library appl1_res1, appl2_res2, libr1_res1, ...
| |
| * All versions are ver1, ver2, ...
| |
| * All libraries have lib in their name, while frameworks do not. To differentiate, all frameworks will have names FRlibr1, FRlibr2, ...
| |
| | |
| ==Cases==
| |
| | |
| ===Unix tools only===
| |
| * No issues (just like any other unix)
| |
| | |
| ===Bundle only===
| |
| * Everything in a same directory:
| |
| | |
| <pre>
| |
| /Applications/
| |
| appl1.app/
| |
| Contents/
| |
| Info.plist
| |
| MacOS/
| |
| appl1 -> appl1-1
| |
| appl1-1
| |
| appl1_aux1
| |
| appl1_aux2
| |
| Resources/
| |
| appl1_res1
| |
| appl1_res2
| |
| </pre>
| |
| | |
| * Suggested api:
| |
| | |
| <pre>
| |
| ADD_EXECUTABLE(
| |
| appl1
| |
| MACOSX_BUNDLE
| |
| appl1_src1.cxx
| |
| appl1_src2.cxx
| |
| ...
| |
| MACOSX_BUNDLE_CONTENT
| |
| apple1_aux1
| |
| apple1_aux2
| |
| apple1_res1
| |
| apple1_res2
| |
| )
| |
| | |
| SET_SOURCE_FILES_PROPERTIES(
| |
| apple1_aux1
| |
| apple1_aux2
| |
| PROPERTIES
| |
| MACOSX_BUNDLE_LOCATION MacOSX
| |
| )
| |
| SET_SOURCE_FILES_PROPERTIES(
| |
| apple1_res1
| |
| apple1_res2
| |
| PROPERTIES
| |
| MACOSX_BUNDLE_LOCATION Resources
| |
| )
| |
| </pre>
| |
| | |
| Comment: (submitted by david.cole)
| |
| I like the suggested api. One thing to keep in mind, however, is that some of the file system entities Mac programmers perceive as files are actually bundles themselves... For example, the resource files produced by Interface Builder (the *.nib "files") are actually bundles/directories themselves. As a Mac programmer, I think of the *.nib "file" as just another source file... In reality it's a directory with contents, which is supposed to be recursively copied into the correct location of the target bundle at build time. I would expect to be able to add either ''a file or a directory'' as a MACOSX_BUNDLE_CONTENT element in the ADD_EXECUTABLE/ADD_LIBRARY commands. If it's a file it gets copied into the target bundle at the specified location. If it's a directory, same thing, but recursively. This is '''mandatory''' in my opinion because Apple could decide to add, remove or completely reorganize elements within the *.nib file format with their next version of Xcode. I definitely don't want to mirror the hierarchical structure of a *.nib file in my CMakeLists.txt files. I also definitely don't want to be forced into using FILE(GLOB_RECURSE ...) in order to do things on a file by file basis. As a Mac programmer, I don't necessarily know whether one of these things is a file or directory - I can't tell CMake what I don't know, so CMake should definitely be able to handle either. CMake needs to support copying directories verbatim as bundle elements to make this feature worthwhile.
| |
| | |
| Maybe this concept could be generalized to "any file/directory that needs to be copied from source or binary tree into a location relative to the build exe/dll/lib" on '''any platform'''. Perhaps naming the features AUXILIARY_CONTENT_FILE and AUXILIARY_CONTENT_LOCATION would be more useful. I could see wanting to have different configuration files copied to where the exe is as part of the build step on Windows or Linux also. It's sort of an easier way of guaranteeing that a file is part of the build tree. Rather than explicit CONFIGURE_FILE or cmake -E copy/copy_directory commands, you could just add a source file as an AUXILIARY_CONTENT_FILE and cmake would make sure it gets copied/configured at build time.
| |
| | |
| ===Framework only===
| |
| * Everything in a same directory:
| |
| | |
| <pre>
| |
| /Library/
| |
| Frameworks/
| |
| FRlibr1.framework/
| |
| FRlibr1 -> Versions/Current/FRlibr1
| |
| Resources -> Versions/Current/Resources
| |
| Libraries -> Versions/Current/Libraries
| |
| Headers -> Versions/Current/Headers
| |
| Versions/
| |
| Current -> ver2
| |
| ver2/
| |
| FRlibr1
| |
| Resources/
| |
| Info.plist
| |
| version.plist
| |
| Libraries/
| |
| libr2.dylib
| |
| libr3.dylib
| |
| Headers/
| |
| FRlibr1_header1.h
| |
| FRlibr1_header2.h
| |
| FRlibr1_header3.h
| |
| </pre>
| |
| | |
| | |
| * Suggested api:
| |
| | |
| <pre>
| |
| ADD_LIBRARY(
| |
| FRlibr1
| |
| SHARED MACOSX_FRAMEWORK
| |
| appl1_src1.cxx
| |
| appl1_src2.cxx
| |
| FRlibr1_header4.h
| |
| FRlibr1_header5.h
| |
| FRlibr1_header6.h
| |
| ...
| |
| MACOSX_FRAMEWORK_HEADERS
| |
| FRlibr1_header1.h
| |
| FRlibr1_header2.h
| |
| FRlibr1_header3.h
| |
| )
| |
| | |
| TARGET_LINL_LIBRARIES(
| |
| FRlibr1
| |
| libr2 libr3)
| |
| </pre>
| |
| | |
| ===Bundle + Framework===
| |
| * Bundle stuff in one directory, framework stuff in another one
| |
| | |
| <pre>
| |
| /Applications/
| |
| appl1.app/
| |
| Contents/
| |
| Info.plist
| |
| MacOS/
| |
| appl1 -> appl1-ver1
| |
| appl1-ver2
| |
| appl1_aux1
| |
| appl1_aux2
| |
| Resources/
| |
| appl1_res1
| |
| appl1_res2
| |
| /Library/
| |
| Frameworks/
| |
| FRlibr1.framework/
| |
| FRlibr1 -> Versions/Current/FRlibr1
| |
| Resources -> Versions/Current/Resources
| |
| Libraries -> Versions/Current/Libraries
| |
| Headers -> Versions/Current/Headers
| |
| Versions/
| |
| Current -> ver2
| |
| ver2/
| |
| FRlibr1
| |
| Resources/
| |
| Info.plist
| |
| Version.plist
| |
| Libraries/
| |
| libr2.dylib
| |
| libr3.dylib
| |
| Headers/
| |
| FRlibr1_header1.h
| |
| FRlibr1_header2.h
| |
| FRlibr1_header3.h
| |
| </pre>
| |
| | |
| ===Bundle + Unix tools===
| |
| * Bundle stuff in one directory, unix tools in typical unix location
| |
| | |
| <pre>
| |
| /Applications/
| |
| appl1.app/
| |
| Contents/
| |
| Info.plist
| |
| MacOS/
| |
| appl1 -> appl1-ver1
| |
| appl1-ver2
| |
| appl1_aux1
| |
| appl1_aux2
| |
| Resources/
| |
| appl1_res1
| |
| appl1_res2
| |
| | |
| /usr/
| |
| bin/
| |
| appl2
| |
| share/
| |
| appl2-version/
| |
| appl2_aux1
| |
| appl2_aux2
| |
| </pre>
| |
| | |
| ===Framework + Unix tools===
| |
| * Framework stuff in one directory, unix tools in typical unix location
| |
| | |
| <pre>
| |
| /Library/
| |
| Frameworks/
| |
| FRlibr1.framework/
| |
| FRlibr1 -> Versions/Current/FRlibr1
| |
| Resources -> Versions/Current/Resources
| |
| Libraries -> Versions/Current/Libraries
| |
| Headers -> Versions/Current/Headers
| |
| Commands -> Versions/Current/Commands
| |
| Versions/
| |
| Current -> ver2
| |
| ver2/
| |
| FRlibr1
| |
| Resources/
| |
| Info.plist
| |
| version.plist
| |
| Libraries/
| |
| libr2.dylib
| |
| libr3.dylib
| |
| Headers/
| |
| FRlibr1_header1.h
| |
| FRlibr1_header2.h
| |
| FRlibr1_header3.h
| |
| Commands/
| |
| appl2
| |
| bin/
| |
| appl3
| |
| /usr/
| |
| bin/
| |
| appl1
| |
| appl2 -> /Library/Frameworks/FRlibr1.framework/Commands/appl2
| |
| appl3 -> /Library/Frameworks/FRlibr1.framework/Version/ver1/bin/appl3
| |
| share/
| |
| appl1-version/
| |
| appl1_aux1
| |
| appl1_aux2
| |
| </pre>
| |
| | |
| ===Bundle + Framework + Unix tools===
| |
| * Framework stuff in one directory, unix tools in typical unix location
| |
| | |
| <pre>
| |
| /Applications/
| |
| appl1.app/
| |
| Contents/
| |
| Info.plist
| |
| MacOS/
| |
| appl1 -> appl1-ver1
| |
| appl1-ver2
| |
| appl1_aux1
| |
| appl1_aux2
| |
| Resources/
| |
| appl1_res1
| |
| appl1_res2
| |
| /Library/
| |
| Frameworks/
| |
| FRlibr1.framework/
| |
| FRlibr1 -> Versions/Current/FRlibr1
| |
| Resources -> Versions/Current/Resources
| |
| Libraries -> Versions/Current/Libraries
| |
| Headers -> Versions/Current/Headers
| |
| Commands -> Versions/Current/Commands
| |
| Versions/
| |
| Current -> ver2
| |
| ver2/
| |
| FRlibr1
| |
| Resources/
| |
| Info.plist
| |
| version.plist
| |
| Libraries/
| |
| libr2.dylib
| |
| libr3.dylib
| |
| Headers/
| |
| FRlibr1_header1.h
| |
| FRlibr1_header2.h
| |
| FRlibr1_header3.h
| |
| Commands/
| |
| appl2
| |
| bin/
| |
| appl3
| |
| /usr/
| |
| bin/
| |
| appl1
| |
| appl2 -> /Library/Frameworks/FRlibr1.framework/Commands/appl2
| |
| appl3 -> /Library/Frameworks/FRlibr1.framework/Version/ver1/bin/appl3
| |
| share/
| |
| appl1-version/
| |
| appl1_aux1
| |
| appl1_aux2
| |
| </pre>
| |
| | |
| ==Linking Issues==
| |
| | |
| ===Link a Framework===
| |
| | |
| Assuming:
| |
| <pre>
| |
| /usr/
| |
| lib/
| |
| libr3.dylib
| |
| /Library/
| |
| Frameworks/
| |
| FRlibr1.framework/
| |
| FRlibr1 -> Versions/Current/FRlibr1
| |
| Resources -> Versions/Current/Resources
| |
| Libraries -> Versions/Current/Libraries
| |
| Headers -> Versions/Current/Headers
| |
| Versions/
| |
| Current -> ver2
| |
| ver2/
| |
| FRlibr1
| |
| Resources/
| |
| Libraries/
| |
| libr2.dylib
| |
| Headers/
| |
| </pre>
| |
| | |
| Regular library is linked like this:
| |
| | |
| libtool -dynamic libr3_src1.o libr3_src2.o -o libr3.dylib
| |
| | |
| Framework is linked like this:
| |
| | |
| mkdir -p FRlibr1.framework/Versions/ver2
| |
| gcc -dynamiclib -o FRlibr1.framework/Versions/ver2/FRlibr1 FRlibr1_src1.o FRlibr1_src2.o
| |
| cd ./FRlibr1.framework/Versions && ln -sf ver2 Current
| |
| cd ./FRlibr1.framework && ln -sf Versions/Current/FRlibr1 FRlibr1
| |
| | |
| You link libr2.dylib like this:
| |
| | |
| libtool -dynamic libr1_src1.o libr1_src2.o -o FRlibr1.framework/Versions/ver2/Libraries/libr2.dylib
| |
| | |
| * Looks like the difference between linking framework and linking shared library is:
| |
| ** Framework:
| |
| gcc <b>-dynamiclib</b> -o FRlibr1.framework/Versions/ver2/FRlibr1 <sources>
| |
| ** Shard library:
| |
| gcc <b>-dynamic</b> -o libr2 <sources>
| |
| | |
| ===Private Frameworks===
| |
| Assuming:
| |
| | |
| <pre>
| |
| /Applications/
| |
| appl1.app/
| |
| Contents/
| |
| Info.plist
| |
| MacOS/
| |
| appl1 -> appl1-1
| |
| appl1-1
| |
| Resources/
| |
| Framework/
| |
| libr1-ver1.dylib
| |
| </pre>
| |
| | |
| You have to run:
| |
| | |
| install_name_tool \
| |
| -id @executable_path/../Frameworks/libr-ver1.dylib \
| |
| appl1.app/Contents/Frameworks/libr1-ver1.dylib
| |
| | |
| and
| |
| | |
| install_name_tool \
| |
| -change libr-ver1.dylib \
| |
| @executable_path/../Frameworks/libr-ver1.dylib \
| |
| appl1.app/Contents/MacOS/appl1
| |
| | |
| * It seems that the private frameworks can have a dylib extension and lib prefix or not.
| |
| | |
| Comment: (submitted by seanmcbride) The more common situation is that in appl1.app/Contents/Frameworks/ one will find not just a 'naked' dylib but an entire .framework bundle. But sometimes there are also .bundle files in there (ex iTunes), or indeed naked dylibs.
| |
| | |
| Comment: (submitted by rangerrick) Also keep in mind, in some cases install_name_tool won't work because there won't be enough room in the binary to change it to a longer path (by default, I think it will only work if the name is *shorter* than what's being replaced). This can be mitigated by adding the -headerpad_max_install_names flag when linking.
| |
| | |
| ==Useful Tools==
| |
| (From http://developer.apple.com/documentation/DeveloperTools/Conceptual/MachOTopics/index.html)
| |
| | |
| Tools for analyzing Mach-O files include the following:
| |
| * The <i>/usr/bin/lipo</i> tool allows you to create and analyze binaries that contain images for more than one architecture. An example of such a binary is a universal binary. Universal binaries can be used in PowerPC-based and Intel-based Macintosh computers. Another example is a PPC/PPC64 binary, which can be used in 32-bit PowerPC–based and 64-bit PowerPC–based Macintosh computers.
| |
| * The file-type displaying tool, <i>/usr/bin/file</i>, shows the type of a file. For multi-architecture files, it shows the type of each of the images that make up the archive.
| |
| * The object-file displaying tool, <i>/usr/bin/otool</i>, lists the contents of specific sections and segments within a Mach-O file. It includes symbolic disassemblers for each supported architecture and it knows how to format the contents of many common section types.
| |
| * The page-analysis tool, <i>/usr/bin/pagestuff</i>, displays information on each logical page that compose the image, including the names of the sections and symbols contained in each page. This tool doesn’t work on binaries containing images for more than one architecture.
| |
| * The symbol table display tool, <i>/usr/bin/nm</i>, allows you to view the contents of an object file’s symbol table.
| |
| | |
| ==Related Work==
| |
| | |
| * On mailing list: http://public.kitware.com/pipermail/cmake/2005-December/007725.html
| |
| * From apple:
| |
| ** http://developer.apple.com/documentation/DeveloperTools/Conceptual/MachOTopics/index.html
| |
| ** http://developer.apple.com/documentation/DeveloperTools/Conceptual/MachOTopics/Articles/loading_code.html#//apple_ref/doc/uid/TP40001830
| |
| ** http://developer.apple.com/documentation/CoreFoundation/Conceptual/CFBundles/index.html
| |
| ** http://developer.apple.com/documentation/MacOSX/Conceptual/BPFrameworks/index.html
| |
| * From Trolltech: http://doc.trolltech.com/qq/qq09-mac-deployment.html
| |
| | |
| {{CMake/Template/Footer}}
| |