MACOSX_PACKAGE_LOCATION and INTERFACE_SOURCES

Hi,

am I doing something wrong with this code, or is there a bug.
(Note: My real project uses this technique to copy a .framework to the main .app, I just changed the code to copy a simple text file, the result being the same)

Here is the main CMakeLists.txt

cmake_minimum_required(VERSION 3.19)

project(test LANGUAGES CXX VERSION 1.0.0.1)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)

# Include definition for an interface library
add_subdirectory(interfaceLib)

## Another interface library
set(INT2_FILE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/myFile2.txt")
set_source_files_properties(${INT2_FILE_PATH} PROPERTIES MACOSX_PACKAGE_LOCATION Frameworks)

add_library(interfaceLibrary2 INTERFACE IMPORTED GLOBAL)

set_target_properties(interfaceLibrary2 PROPERTIES
	INTERFACE_SOURCES "${INT2_FILE_PATH}"
)

## Main app
add_executable(app MACOSX_BUNDLE app.cpp)
target_link_libraries(app PRIVATE interfaceLibrary)
target_link_libraries(app PRIVATE interfaceLibrary2)

And this is the CMakeLists.txt for the interfaceLib sub folder

## Interface lib
set(INT_FILE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/myFile.txt")
set_source_files_properties(${INT_FILE_PATH} PROPERTIES MACOSX_PACKAGE_LOCATION Frameworks)

add_library(interfaceLibrary INTERFACE IMPORTED GLOBAL)

set_target_properties(interfaceLibrary PROPERTIES
	INTERFACE_SOURCES "${INT_FILE_PATH}"
)

What happens here is that myFile2.txt is correctly copied into app.app/Content/Frameworks, but myFile.txt is not copied at all.
What I noticed is that as soon as I use a sub folder to create the interface library, the file is no longer copied, just as if CMake couldn’t find it (but it does as it appears in XCode solution).

Any clues? Am I doing something wrong? Is there a better way to ask CMake to copy a .framework into a .app before Xcode code signing step?

Thanks,
Chris

Ok so, it looks like the culprit is set_source_files_properties which is scoped.

Unfortunately the new option added in 3.18 does not help here, as I cannot know the folder the file will be used in.

It’s too bad a source_property that is directly linked to a target_property is not globally shared when making an interface library (INTERFACE_SOURCES searches for source prop MACOSX_PACKAGE_LOCATION in order to copy the file).

If you’re using the Xcode generator and CMake 3.20 or later, I recommend you take a look at the XCODE_EMBED_FRAMEWORKS target property. This integrates much better into the workflow Xcode uses, including code signing.

Thanks a lot, that’s great!
Although it will not work with Ninja, it might be helpful until a more generic solution is found.

Hum so I did try your proposal but it looks like the target property is not forwarded to the main app bundle.

Since my main bundle is linking with an interface library (that itself wants to copy the framework to the final app as a transitive dependency, the consumer is not supposed to know about the framework), I have to define the XCODE_EMBED_FRAMEWORKS prop in the interface library. I changed my sample back to an actual .framework ofc, not a sample .txt file.

Is there a way to do that with XCODE_EMBED_FRAMEWORKS?
Thanks!

I don’t think you can force this on consumers. It has to be set on the consumer, since that is the only place where you know definitively whether you want it to embed things or not. Otherwise you could end up with multiple levels of embedding (frameworks embedding other frameworks, but are themselves embedded in something else).

Well I disagree.
My use case is very similar to some library being used by an end user (consumer). That library defines some interface link library that is a system framework for exemple. The end user should not be concerned by what is transitively added to the link phase (and it’s not thanks to the interface link libraries in cmake).

So my use case is very similar except that my library requires a framework that is not in the system and thus must be copied into the bundle because that’s how it works in macOS.

To be more specific I made an os-independent wrapper around sparkle (winsparkle on windows). The end user should not be concerned by what my wrapper library requires during copy phase, like it’s not for link phase thanks to cmake transitive link dependencies.

I kind of found a temporary workaround by defining a macro that the end user must call before calling link_libraries with my wrapper. That macro obfuscate what my lib needs during copy phase by declaring the source prop, so in case I need to change anything in my wrapper I can change the content of the macro without having the end user do anything else.

This is a temporary hack, until cmake can handle generic transitive copy of resources into a bundle.