-
Notifications
You must be signed in to change notification settings - Fork 993
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CMakeToolchain: proper support of find_*() & include() commands #10186
CMakeToolchain: proper support of find_*() & include() commands #10186
Conversation
- avoid to find host executables in find_program() - support cross-build scenario - support include() of CMake modules coming from build context
Two comments regarding existing code I didn't change:
|
tests fail because:
Maybe I should have added the tests I want to succeed in the first place (same recipe in requirements & build requirements with libs & tools packaged, discovery of module files from build requirements). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have my concerns about the extension of this to "dependencies.build". Things liks libs, headers and frameworks probably shouldn't be added by default. And the executables and shared libs don't need to be added to the path, because they will already be in the PATH and LD_LIBRARY_PATH, because they are put there by the VirtualBuildEnv
(which is a bit more general solution, as it works for every build system)
@@ -425,34 +439,64 @@ def context(self): | |||
if prefer_config is not None and prefer_config.lower() in ("false", "0", "off"): | |||
find_package_prefer_config = "OFF" | |||
|
|||
os_ = self._conanfile.settings.get_safe("os") | |||
android_prefix = "${CMAKE_CURRENT_LIST_DIR}" if os_ == "Android" else None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was necessary at some point, to have the Android build finding the xxx-config.cmake by Conan. Maybe it is no longer needed, but it is difficult to know, because we are not running yet Android build tests in our CI
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it's the same issue than cross-build to iOS/tvOS/watchOS, but 2 different solutions have been implemented. Here it's fixed by forcing CMAKE_FIND_ROOT_PATH_MODE_PACKAGE
to "BOTH"
(same fix than iOS/tvOS/watchOS).
Of course, the best solution would be to not have to manipulate CMAKE_FIND_ROOT_PATH_MODE_*
but other solutions raise other issues (conflicts between host & build context), and I think this one is harmless compare to other solutions.
f2a242d
to
66a93d8
Compare
CMAKE_MODULE_PATH has no side effects in find_program()/find_library()/find_file()/file_path(), so it's fine. What should be avoided is to add root package folder to CMAKE_PREFIX_PATH, otherwise executables of host context would have precedence over executables of build context in find_program() calls.
66a93d8
to
75812f4
Compare
TODO:
|
132f23f
to
e34655a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand these issues (and agree with them) and I see a lot of value in this PR to understand the issues we currently have. But still not convinced about the way to resolve them. Should we use more properties to declare specific things like config file paths
? and maybe more things?
Should we do this in Conan 1.X even if maybe the better fix (not either sure) is to change the cppinfo model or defaults?
Also, I think this PR does some "tricks" like changing the ROOT_PATH_MODE variables and filling CMAKE_FIND_ROOT_PATH
, probably there is not single answer for all cases, I'm afraid it might depend on every project/package/toolchain, in some cases, I would need to find some things in my packages, sometimes I don't, sometimes from build, sometimes from host...All these questions should be answered by the user, the challenge is how to do it understandable and maintainable.
conan/tools/cmake/toolchain.py
Outdated
endif() | ||
|
||
if(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE STREQUAL "ONLY") | ||
set(CMAKE_FIND_ROOT_PATH ${CMAKE_FIND_ROOT_PATH} {{ generators_folder }} {{ host_build_paths_noroot }}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this trick necessary? why not set BOTH
? I'm sure there is an explanation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, the toolchain could force CMAKE_FIND_ROOT_PATH_MODE_PACKAGE
to BOTH. But I would like to avoid to override this variable if set by user toolchain.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wondering if the user toolchain is setting CMAKE_FIND_ROOT_PATH_MODE_PACKAGE STREQUAL "ONLY"
, wouldn't be mostly the same modifying the CMAKE_FIND_ROOT_PATH
?. Why is that ok but not overriding the CMAKE_FIND_ROOT_PATH_MODE_PACKAGE
variable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure to understand the questions. Would you like to set CMAKE_FIND_ROOT_PATH
with generator folder and non-root builddirs of requires, regardless of CMAKE_FIND_ROOT_PATH_MODE_PACKAGE
value?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, just saying that you are protecting the user set value from CMAKE_FIND_ROOT_PATH_MODE_PACKAGE
because I would like to avoid to override this variable if set by user toolchain.
but then you are modifying the CMAKE_FIND_ROOT_PATH
, so I'm wondering if it is not kind of "cheating".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In other words, why is so important to keep the user value of CMAKE_FIND_ROOT_PATH_MODE_PACKAGE
(and others)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, so when CMAKE_FIND_ROOT_PATH_MODE_*
is ONLY
, you have no other choice than manipulating CMAKE_FIND_ROOT_PATH
because all other variables are ignored. CMAKE_FIND_ROOT_PATH
is like CMAKE_PREFIX_PATH
but with higher precedence, so no it's not cheating.
Why is it important to honor CMAKE_FIND_ROOT_PATH_MODE_*
of users? Principle of least surprise.
But as I said before, if ONLY
is overridden by BOTH
, it should not break consumers (other proposal in #10186 (comment)), because system paths have the lowest priority in search paths of find_*()
commands, and BOTH
still look into CMAKE_FIND_ROOT_PATH
first if the user has injected some stuff not managed by conan.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then I would simplify and just override to BOTH
.
Ok, so when CMAKE_FIND_ROOT_PATH_MODE_* is ONLY, you have no other choice than manipulating CMAKE_FIND_ROOT_PATH because all other variables are ignored. CMAKE_FIND_ROOT_PATH is like CMAKE_PREFIX_PATH but with higher precedence, so no it's not cheating.
Yes, I got that, but:
Why is it important to honor CMAKE_FIND_ROOT_PATH_MODE_* of users? Principle of least surprise.
Not sure that changing CMAKE_FIND_ROOT_PATH
is least surprise
either, so I vote for simplifying and just overriding to BOTH when cross_build.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
simplified in 1e89fe9
CMAKE_FIND_ROOT_PATH_MODE_*
of user honored unless it's ONLY
.
conan/tools/cmake/toolchain.py
Outdated
if(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE STREQUAL "ONLY") | ||
set(CMAKE_FIND_ROOT_PATH ${CMAKE_FIND_ROOT_PATH} {{ generators_folder }} {{ host_build_paths_noroot }}) | ||
endif() | ||
if(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM STREQUAL "NEVER") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same question for all "ifs". Sounds very complex :(
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes it's complex, I'll try to explain the all logic when I have time, it's not obvious. I try to address #10186 (comment).
If you want something simple, I can fallback to something like this:
template = textwrap.dedent("""
...
{% if cross_building %}
if(NOT DEFINED CMAKE_FIND_ROOT_PATH_MODE_PACKAGE OR CMAKE_FIND_ROOT_PATH_MODE_PACKAGE STREQUAL "ONLY")
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE "BOTH")
endif()
if(NOT DEFINED CMAKE_FIND_ROOT_PATH_MODE_PROGRAM OR CMAKE_FIND_ROOT_PATH_MODE_PROGRAM STREQUAL "ONLY")
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM "BOTH")
endif()
if(NOT DEFINED CMAKE_FIND_ROOT_PATH_MODE_LIBRARY OR CMAKE_FIND_ROOT_PATH_MODE_LIBRARY STREQUAL "ONLY")
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY "BOTH")
endif()
{% if is_apple %}
if(NOT DEFINED CMAKE_FIND_ROOT_PATH_MODE_FRAMEWORK OR CMAKE_FIND_ROOT_PATH_MODE_FRAMEWORK STREQUAL "ONLY")
set(CMAKE_FIND_ROOT_PATH_MODE_FRAMEWORK "BOTH")
endif()
{% endif %}
if(NOT DEFINED CMAKE_FIND_ROOT_PATH_MODE_INCLUDE OR CMAKE_FIND_ROOT_PATH_MODE_INCLUDE STREQUAL "ONLY")
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE "BOTH")
endif()
{% endif %}
""")
some conflicts to solve |
I am contributing a fix to the broken test in 6bb0be8. The test was failing because we added this new test to run CMake with |
I had to push a few changes more, after merging latest "develop" state in 5d19b4f. The most important thing that changed is that now the |
Changelog: Fix: Improved CMakeToolchain robustness regarding
find_file
,find_path
andfind_program
commands allowing better cross-build scenarios and better differentiation of the right context where to get, for example, executables (build vs host).Docs: conan-io/docs#2383
In
find_program()
, avoid to find executables of host context before executables of build context.support all cross-build scenario (hopefully).
support
include()
of CMake modules coming from build context.remove
CMakeToolchain.find_builddirs
(doesn't make sense anymore).Refer to the issue that supports this Pull Request.
If the issue has missing info, explain the purpose/use case/pain/need that covers this Pull Request.
I've read the Contributing guide.
I've followed the PEP8 style guides for Python code.
I've opened another PR in the Conan docs repo to the
develop
branch, documenting this one.Note: By default this PR will skip the slower tests and will use a limited set of python versions. Check here how to increase the testing level by writing some tags in the current PR body text.
closes #9427
closes #9735
closes #10167