macOS: Implement variation of TARGET_RUNTIME_DLLS for Xcode-based projects
Windows projects can use the TARGET_RUNTIME_DLLS
generator expression to get a list of all DLL dependencies of a executable target, which can then be used by a POST_BUILD
custom command to be copied into the binary output directory (commonly the place where Windows gathers all DLLs as those are in effect EXE files for historical reasons).
While this does not include possible libraries loaded during runtime (mainly libraries of the MODULE
type), this is especially convenient for gathering imported libraries:
- Imported libraries provided via CMake projects can supply different DLL files for specific configurations (populating the
IMPORTED_CONFIGURATIONS
property). As the expression is evaluated at generation time, CMake can pick the correct appropriate variant for the given configuration, or - even more importantly - can generate the correct configuration target for Visual Studio solutions- This enables a Visual Studio build to only copy imported DLLs matching the current(!) build configuration
- Imported libraries provided via Find modules are either single configuration only, or can provide appropriate
IMPORTED_LIBRARY_<CONFIG>
andIMPORTED_CONFIGURATIONS
values on the created target, yielding the same result as above- Notably this requires some extra effort on the part of Find modules, mainly providing the
.lib
import library asIMPLIB_<CONFIG>
and the actual.dll
asIMPORTED_LIBRARY_<CONFIG>
but this is trivial to implement for a Find module
- Notably this requires some extra effort on the part of Find modules, mainly providing the
Recently CMake gained the ability to define targets and files for Xcode's "copy frameworks/extensions/plugins" functionality - it does not support all types actually supported by Xcode yet (e.g. Camera Extensions), but this allows a CMake project to set a list of target names and files as a property on a target:
set_property(
TARGET my_application
APPEND
PROPERTY XCODE_EMBED_FRAMEWORKS ${list_of_dependencies})
This works really well, combined with other project properties such as:
XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY YES
XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY YES
XCODE_EMBED_PLUGINS_REMOVE_HEADERS_ON_COPY YES
XCODE_EMBED_PLUGINS_CODE_SIGN_ON_COPY YES
XCODE_ATTRIBUTE_COPY_PHASE_STRIP NO
Just like with Visual Studio, one gets an almost-complete application bundle in the build directory of the application target, but some parts are missing:
- Contrary to the generator expression, only target names built by the current project can be added
- One has to iterate over all transitive
INTERFACE_LINK_LIBRARIES
of the main target to generate a list of absolute file paths, which requires one to:- Detect possible generator expressions used (which can range from trivial to maddening)
- Detect library paths provided by macOS, Xcode, and the platform SDK
- Ignore static library file names
- This is possible (I implemented this for a bigger project and it works like a charm as long as you are in control of possible generator expressions) but requires quite a bit of CMake code and recursive parsing to find all transitive dependencies.
The biggest issue however is this:
- It is not possible to configure/assign the correct framework/library file for multi-config generators like Xcode
With a generator like Ninja or GNU Makefiles, the current configuration is set as a variable and as such one can look at the _<CONFIG>
target property (if available) and fall back on non-suffixed properties. With a multi-config generator, one cannot set the correct library, as there is no "current" configuration (all 4 have to be set) and the property is config-agnostic.
If one could specify not only names of targets built by the current project, but also target names of linked libraries, CMake could take care of identifying the correct variant of an imported library (matching configurations) and would also remove the need to parse the actual locations and add the absolute file paths to the target property.
(Thanks to @craig.scott for suggesting to open this feature request with motivating example.)
PS: Qt is an often-mentioned example, but Qt will require additional logic anyway as depending on which Qt frameworks were added, a different set of plugins has to be copied to the bundle itself (whose location can also be customised by a qt.conf
in the Contents/Resources
directory of an application bundle. I currently resort to adding each Qt plugin as a target source file, specifying a MACOSX_BUNDLE_LOCATION
source file property. Making this more elegant is out of scope for this request and requires an additional one (assign non-code sources as bundle assets).