-
Notifications
You must be signed in to change notification settings - Fork 990
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
only warn in CMake if build_type is empty and is_multi configuration #14349
only warn in CMake if build_type is empty and is_multi configuration #14349
Conversation
6fd0c6f
to
7a0ae96
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.
Thanks very much for your contribution @thorsten-klein
CMake explicitly recommends defining a build-type, specially for single-config configurations:
https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#default-and-custom-configurations
For single-config generators, the configuration is specified with the CMAKE_BUILD_TYPE variable at configure time and cannot be changed at build time. The default value will often be none of the above standard configurations and will instead be an empty string. A common misunderstanding is that this is the same as Debug, but that is not the case.
Users should always explicitly specify the build type instead to avoid this common problem.
The protection in Conan CMake
helper is implementing this guard, requiring the build_type
to be defined, for sure for multi-config, but this protection is also necessary for single-config scenarios.
I'd like to understand better this proposal, if the reason is to build packages without build_type
against CMake recommendations, and what is the use case. I also assume that this means that you are not using CMakeDeps
at all, because with this change you should have hit that issue too. Could you please clarify?
conan/tools/cmake/cmake.py
Outdated
@@ -108,7 +108,7 @@ def _build(self, build_type=None, target=None, cli_args=None, build_tool_args=No | |||
"single-config build systems") | |||
|
|||
bt = build_type or self._conanfile.settings.get_safe("build_type") | |||
if not bt: | |||
if is_multi and not bt: |
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 protection for not defining the build_type
was in place, necessary for CMake integration, because if build_type
is not defined, it later fails in CMakeDeps
with either a message like
Please, set the CMAKE_BUILD_TYPE variable when calling to CMake "
"adding the '-DCMAKE_BUILD_TYPE=<build_type>' argument
Or directly missing dependencies.
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.
To reproduce this, using a standard conan new cmake_lib -d name=pkg -d version=0.1
and conan create . -pr=myprofile
with a profile that doesn't define build_type
is enough.
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.
We get this error message without using CMakeDeps generator. I will create a unit test for this
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.
It is only that we get some error output in log, but the build succeeds. I will create some test for it to show you
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, it will be good to have some tests. Please add consuming the package with test_package
, for example.
Still the above feedback would be relevant: why going against CMake and not defining the build_type? What is the use case? Thanks!
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.
The setting build_type we want to ignore, so we want to always enforce to build Release
Ok, this is very important. You don't want to build something without build_type
. You want to build it in Release
build-type. This is a fresh perspective that doesn't goes against CMake recommendations, I'll have a new look with this in mind.
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.
There is a recommended flow, that we also implement in ConanCenter:
- Leave the
build_type
defined- This will make sure that everything that needs
build_type
will work. FromCMakeDeps
, to thecmake_layout
- This will make sure that everything that needs
- Remove the
build_type
in thepackage_id()
method, so usage of the package becomes independent frombuild_type
. - Define
build_type=Release
in the profile to build this package, create it and upload it. From now all packages cantool_require
it irrespective of the build_type
There is a further insight for this. Using the 2 profiles "build" and "host", it is no longer an issue or necessary to force or remove the build_type
from tool_requires
, as the "build" context will almost always use the build_type=Release
naturally. This is the most recommended approach, it is easy, built-in, doesn't require changes in recipe and is well tested and used in production by many users.
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, found the gap.
You are right that it can make sense to not raise the exception for that case, and allow to force the Release
in recipes.
However, it might make sense to have to define the recipe with explicit behavior like:
def layout(self):
self.folders.build = "build"
def generate(self):
tc = CMakeToolchain(self)
if self.settings.compiler != "msvc":
tc.cache_variables["CMAKE_BUILD_TYPE"] = "Release"
tc.generate()
def build(self):
cmake = CMake(self)
cmake.configure()
build_type = "Release" if self.settings.compiler == "msvc" else None
cmake.build(build_type=build_type)
def package(self):
cmake = CMake(self)
build_type = "Release" if self.settings.compiler == "msvc" else None
cmake.install(build_type=build_type)
and then apply your change so it doesn't error. But not necessarily changing the error
=> warning
message and still get the warning with would be still not great. It is better to not create the warning in the first place. That means that we might want also to make public some is_multi_configuration()
interface, to simplify recipes and make them possible to do this.
I'll try to move this forward tomorrow, thanks for the feedback
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 any case, please read the comment above, all this would be unnecessary with the "build" profile defining build_type=Release
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.
Thank you very much :-)
So summary from my POV:
- it is very unintuitive that
cmake.build(build_type="Release")
does not have any effect. So it totally makes sense to warn users about this behavior in a WARN/ERR message. - conan should raise exception if build type is not set and it is a multi configuration build
- conan should WARN/ERR users if build_type is empty
- In case of
settings = "os", "compiler", "arch"
theCMAKE_BUILD_TYPE
is empty, even ifbuild_type
setting is specified in the profile. conan could setCMAKE_BUILD_TYPE=Release
by default (at least for single configuration --> proposal see this PR)
7a0ae96
to
722382d
Compare
generators = "CMakeToolchain" | ||
def build(self): | ||
cmake = CMake(self) | ||
cmake.configure() |
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 build, in single-config build systems is not using build_type
at all. What is the purpose of doing a CMake build without build_type
, which is explicitly discouraged by CMake
?
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.
How can I specify a build type then in this case a profile does not specify any build_type?
Using cmake.build(build_type="Release")
does not have any effect (see test above).
Shall I use tc.cache_variables
?
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.
Why not defining the build_type
in the profile?
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.
Refering to settings.yml the build_type
MAY be empty. So we must cover this case as well.
@@ -31,3 +31,52 @@ def run(self, *args, **kwargs): | |||
assert "-something" in client.out | |||
assert "--testverbose" in client.out | |||
assert "-testok" in client.out | |||
|
|||
def test_build_type_single_config_warn(): |
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.
These tests passes in PRs because they run only in Linux in PRs. After merge, they will run in Windows too and fail (these tests fail in Windows due to multi-config VS). It would be better to move them to "functional" folder, so they run in all platforms also in PRs.
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 think the best is to do actual builds, with fully functional examples in the "functional" folder, building libraries with full test_package
functionality. This will make sure things are working.
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 created some tests for my all my use cases under functional. I always set build_type via -s build_type=Debug
.
c750d36
to
8aea393
Compare
8aea393
to
dd2edc1
Compare
b83149e
to
6cfe578
Compare
Quick follow up, I'm working in #14780, trying to publish the necessary public interfaces for the use case in question, plus making sure the scenario works covering it with tests. Hopefully for next 2.0.12 |
Nice, thank you. Then I will close this PR. |
The backport is a bit more challenging, higher risks to break something, let's see how it goes with the PR to 2.0 and we can analyze it. In any case, there is the pending question, why not the standard flow that most of Conan users are doing? The one recommended above, just leave the |
Ok, I understand 👍🏻 Yes, I have started to migrate to the "standard flow".
|
Changelog: (Feature | Fix | Bugfix): Remove error output in case of non existent
build_type
settingIf there is no
build_type
setting existing, cmake will throw an exception duringCMake
build()
. Therefore we must explicitly speciify thebuild_type
argument.Unfortunately we get some ugly error output when using this:
output:
The error output should only happen if it is
is_multi
, sincebt
is only used then.develop
branch, documenting this one.