Open T1T4N opened 2 years ago
Hi @T1T4N
I don't know if you have checked the new integrations in https://docs.conan.io/en/latest/reference/conanfile/tools/cmake.html. Those are the ones that will be valid in Conan 2.0. Our current efforts are on these. From Conan 1.43, they allow defining the property cpp_info.set_property("cmake_target_name", <global target name>)
.
Maybe it would be worth trying with the new integrations, as they are still experimental, much easier to be fixed if necessary, and in any case it will be necessary to migrate to them before 2.0 (we are already in 2.0.0-alpha1)?
Hello @memsharded,
Thanks for sharing the integrations documentation.
I can see here that cpp_info.components
is mentioned. Does that mean that the experimental Components feature is going to be present in Conan 2.0?
Additionally, is there any way to define components info using set_property
?
Regarding my detailed bug description above, I wanted to give the full context to prevent unnecessary questions, but if it is too broad, please focus on the Solution section detailing the issue in conan_find_apple_frameworks
.
As you mentioned that you've focused all efforts on 2.0, I understand that you might be a bit time-constrained. Would you prefer if I open a PR with the bugfix I detailed above?
Hi @T1T4N
We keep figuring out the issue. What I wonder is if it could solve the problem something like this:
def package_info(self):
self.cpp_info.name = self.name # "ExampleFramework"
# Getting the platform name depending on the OS (and ARCH perhaps???)
platform = self._supported_platforms[str(self.settings.os)]
arch_dir = self._arch_for_platform[platform]
framework_path = os.path.join(self.package_folder, f"{self.name}.xcframework", arch_dir)
# Create one unique component
self.cpp_info.components["ComponentPlatform"].names["cmake_find_package"] = platform
self.cpp_info.components["ComponentPlatform"].frameworkdirs = [framework_path]
self.cpp_info.components["ComponentPlatform"].frameworks = [self.name]
I'm saying this because if you have the same Framework name but it depends on the OS/ARCH, why don't you create one component depending directly on your settings? Then, when you consume it in your recipe you'll be sure you're using the correct Framework by pointing out its folder.
Hi @franramirez688,
Thanks for replying on the original issue! Your suggestion would theoretically work, as it avoids the issue (not having 2 components with the same framework name).
It's a fact that Apple's design approach to XCFrameworks is completely orthogonal to Conan's design, and your suggestion is a good solution when different platforms are in question (e.g. not mixing macOS + iOS), but from a usability perspective it is not ideal in the (most common) case of iOS + iOS Simulator, as Xcode parses the metadata in the XCFramework for proper linking of the flavor, which can be dynamically changed in the IDE.
The ideal solution is to get conan_find_apple_frameworks
fixed as IMO it is a purely logical bug.
My current "temporary solution" to the problem is implementing #12088 directly in our conanfile.py
.
Environment Details (include every applicable attribute)
Description
Since CMake does not yet natively support XCFrameworks I'm looking for alternative solutions to integrating Apple's new format into our existing codebase. After some research, I determined that Conan Components together with the
cmake_find_package
generator are a perfect fit for the task at hand. I will not go in detail what XCFrameworks are, but for anyone interested, the following blog post has a lot of useful info: PSPDFKit - Supporting XCFrameworks. An XCFramework is basically a folder (+ some metadata) containing different architecture builds (slices) of a framework. It has the following structure:The
conanfile.py
for Example Framework looks like this (simplified):For each supported architecture of the XCFramework, a component is defined with the name of the platform, e.g: iphoneos, iphonesimulator, macosx (names used by Xcode). NOTE: The framework name specified in
self.cpp_info.components[platform].frameworks
is identical for every component (self.name
) and this can't be trivially renamed (or symlinked) to e.g.ExampleFramework_macosx.framework
.The test_package is a bare minimum CMake project integrating this, with the following
CMakeLists.txt
:Contrary to expectations, running
conan create
yields the following link error:It is very interesting to note that although we specified the macosx component, what
FindExampleFramework.cmake
configured was actually the path leading to the iphoneos framework in the subfolderios-arm64
.After a bit of debugging, by inspecting the variables defined by the custom FindExampleFramework.cmake, we observe the following:
ExampleFramework_macosx_FRAMEWORK_DIRS: /Users/user/.conan/data/ExampleFramework/0.1.0/user/testing/package/<package-id>/ExampleFramework.xcframework/macos-arm64_x86_64
ExampleFramework_macosx_LINK_LIBS: /Users/user/.conan/data/ExampleFramework/0.1.0/user/testing/package/<package-id>/ExampleFramework.xcframework/ios-arm64/ExampleFramework.framework
ExampleFramework_macosx_LIBS_FRAMEWORKS_DEPS: /Users/user/.conan/data/ExampleFramework/0.1.0/user/testing/package/<package-id>/ExampleFramework.xcframework/ios-arm64/ExampleFramework.framework
and from this, the target property is also incorrect: ❌
ExampleFramework::macosx.INTERFACE_LINK_LIBRARIES = "/Users/user/.conan/data/ExampleFramework/0.1.0/user/testing/package/<package-id>/ExampleFramework.xcframework/ios-arm64/ExampleFramework.framework;$<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,SHARED_LIBRARY>:>;$<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,MODULE_LIBRARY>:>;$<$<STREQUAL:$<TARGET_PROPERTY:TYPE>,EXECUTABLE>:>"
Solution
It seems that Conan's cmake_find_package generator cannot deal with different components declaring the same framework name. I have traced the behavior to the macro
conan_find_apple_frameworks
inconans/client/generators/cmake_find_package_common.py
. Specifically, it checksif(CONAN_FRAMEWORK_${_FRAMEWORK}_FOUND)
but this global variable doesn't take the differentFRAMEWORKS_DIRS
given to the macro, which can be a disjoint-sets between different components.The easiest solution to this is to add an
unset(CONAN_FRAMEWORK_${_FRAMEWORK}_FOUND CACHE)
immediately before thefind_library
call. Personally, I think this is acceptable, as the macro throws aFATAL_ERROR
if a framework isn't found.From CMake's find_library documentation:
I verified that this works as expected by monkey-patching the macro in
test_package/conanfile.py
:A more elaborate solution would require defining separate
CONAN_FRAMEWORK_
variables for each component, and e.g. passing the component name to this function as a suffix.In any case, I cannot see a reason why this use-case shouldn't be supported (same framework name in different components) and it would certainly make the lives of all Apple devs using Conan much easier in the future.
I'll be very happy to provide more information and code if necessary, as well as answer any questions that might arise.