conan-io / conan

Conan - The open-source C and C++ package manager
https://conan.io
MIT License
8.26k stars 980 forks source link

Best practices for mixing and matching Release with RelWithDebInfo packages #4221

Open michaelmaguire opened 5 years ago

michaelmaguire commented 5 years ago

We build many open sources packages from scratch and publish internally using Conan, then build our own internal libraries against those with Conan.

In https://github.com/conan-io/conan/issues/1564 "Add RelWithDebInfo as a supported build_type" @memsharded stated:

And linking RelWithDebInfo from consumer packages/projects, with Release packages seems to work well.

This is a use case that appeals to us. How should this work in practice?

If package Current depends on package Base, and Base was built with build_type=Release, if I try to build Current with build_type=RelWithDebInfo it's usually not going to consider the Base libraries of build_type=Release as satisifying dependencies.

What should be our practice here?

Conan version 1.10.1 Windows

To help us debug your issue please explain:

michaelmaguire commented 5 years ago

I've seen people suggesting, e.g.:

        cmake = CMake(self)
        if self.settings.build_type=="Release":
                cmake.build_type = 'RelWithDebInfo'

How does that compare, e.g. to simply:

        if self.settings.build_type=="Release":
                self.settings.build_type="RelWithDebInfo"
progician commented 5 years ago

@michaelmaguire I imagine the true difference there is that when you set the self.settings.build_type you will promote the whole package as RelWithDebInfo which might clash with your previously produced package ids. The first version would just make sure that the build will produce debug info but not going to affect your ABI compatibility.

jake-at-work commented 4 years ago

@michaelmaguire Did you ever find a satisfying solution for a best practice of RelWithDebInfo? I am in the boat where I want to build my library RelWithDebInfo but I don't care if any of the dependencies are RelWithDebInfo or Release.

michaelmaguire commented 4 years ago

@pivotal-jbarrett , for now we have stuck with:

        cmake = CMake(self)
        if self.settings.build_type=="Release":
                cmake.build_type = 'RelWithDebInfo'
daywhirls commented 2 years ago

I came across this issue while trying to figure out how to use Release packages of dependencies with RelWithDebInfo configurations, and I wanted to add my solution here for anyone in the future.

In certain cases where conanfiles are simply packaging pre-built artifacts or copying sources without a build() method, my solution was to modify the package_id() method to choose Release packages rather than requiring separate RelWithDebInfo packages.

def package_id(self):
    if self.settings.build_type == "RelWithDebInfo":
        self.info.settings.build_type = "Release"

I was also interested in the compatibility() method introduced in Conan 1.47.0, and I tried to do something similar there:

def compatibility(self):
    if self.settings.build_type == "RelWithDebInfo":
        return [{"settings": [("build_type", "Release")]}

But it didn't work for me and resulted in some errors that I forget at the moment. But worth mentioning in case anyone else has a use-case for it.

risa2000 commented 1 year ago

I am reviving this issue as I am currently pulling my hair on the exact same subject without a success. I am using CMake, CMakeToolchain and CMakeDeps from the "new approach". The first suggested solution:

def build(self)
    cmake = CMake(self)
    if self.settings.build_type=="Release":
        cmake.build_type = 'RelWithDebInfo'

does not do anything, because the conan build still appends -DCMAKE_BUILD_TYPE=Release to the cmake invocation. It seems like build_type is pretty much baked into all generated files by conan install, using patterns like $<$<CONFIG:Release>:<...>> in generated files. If I just run cmake manually with -DCMAKE_BUILD_TYPE=RelWithDebInfo and then try build, it will fail at the first include from the dependency package, because all the dependencies' includes and what not were hardcoded to Release build type using the aforementioned CMake generator pattern.

So I am trying the other way around. Creating all CMake files for RelWithDebInfo build, but forcing conan to search for the dependencies with Release build_type.

Apparently I am able to force particular package setting in the profile, i.e. using the following semantics:

[settings]
os=Windows
os_build=Windows
arch=x86_64
arch_build=x86_64
compiler=msvc
compiler.version=193
compiler.runtime=dynamic
compiler.cppstd=17
build_type=Release
fmt:build_type=Release
spdlog:build_type=Release
...

But this is a bit cumbersome as I would need to do this override only when the root package build_type=RelWithDebInfo. So some logic in conanfile.py should do trick, the problem is I did not find any programmatic way to change the dependencies' settings in the doc. It seems I can change dependencies' options in configure() and in fact I have no idea if and where the profile based overrides are available in ConanFile.

Is there a way (any way) to build a project with RelWithDebInfo, while pulling the packages with Release build_type?

NightWulfe commented 1 year ago

I had a similar problem. My conan profile has build_type set to "Release", so conan center libraries are downloaded/built in that mode. However, my projects/libraries were configured to CMAKE_BUILD_TYPE equal to "RelWithDebInfo" because we need to be able to debug crash dumps created from release builds.

It took me an hour to figure out this was the cause because the compiler just fails because it can't find the library header files. By sheer chance I tried changing the CMAKE_BUILD_TYPE to "Release" and that fixed the problem.

How can I use CMAKE_BUILD_TYPE=RelWithDebInfo in my projects, but find header files to packages from conan center that use build_type=Release?

I would prefer not to have to manually include an explicit build_type for each library in the conan profile as the previous poster suggested.

risa2000 commented 1 year ago

@NightWulfe I gave up on trying any other BUILD_TYPE with Conan apart from Release and Debug. It is too much of hassle.

I am not sure what platform are you on, but this is how I do it on Windows, using MSVC toolchain. Instead I simply write my CMake files in a way to produce the debug infos for Release build and just enable it via cache var.

# Project options
# ===============
option (DEBUG_INFO "Generate debug info in the current build" OFF)

if (DEBUG_INFO)
    LIST (APPEND COMPILER_OPTIONS_OVERRIDE "/Zi")
    LIST (APPEND LINKER_OPTIONS_OVERRIDE "/DEBUG")
endif()

is what I put into a top level CMakeLists.txt, then in individual modules I have this:

target_compile_options (target PRIVATE ${COMPILER_OPTIONS_OVERRIDE})

# turn on linker optimization back on in RelWithDebInfo config
target_link_options (target PRIVATE $<$<NOT:$<CONFIG:Debug>>:/INCREMENTAL:NO /OPT:REF /OPT:ICF>)
target_link_options (target PRIVATE ${LINKER_OPTIONS_OVERRIDE})

The fist linker options are necessary to enable linker optimization, which the /DEBUG disables by default.

Then I turn on DEBUG_INFO var in Release build type.

memsharded commented 1 year ago

Hi all,

It has been some time since this issue was reported, and probably there are different use cases here.

For having dependencies in one build_type and the "consumer" project in a different build type it can be achieved by defining that in the command line, for example for installing Release dependencies but the current build is RelWithDebInfo:

conan install ... -s build_type=Release -s &:build_type=RelWithDebInfo
...
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo

Could you please clarify if this is what you are looking for, and if this solves your issues.

Another possibility in Conan 2.0 if binary compatibility fallback is desired between different build_types artifacts, I think this would be quite straightforward in the new compatibility.py plugin: https://docs.conan.io/2/reference/extensions/binary_compatibility.html

zabereer commented 1 year ago

I am having similar issues as described here but much simpler case: I always want to use a Release build of a unit testing frameworks (catch/gtest/boost/etc) regardless of the build_type of my project (consumer only project). This worked in conan1 via always doing conan install with profile with build_type=Release, but does not work with conan2.

What does the ampersand in suggested conan install command mean below? I cannot find it in documentation:

conan install ... -s build_type=Release -s &:build_type=RelWithDebInfo
memsharded commented 1 year ago

I always want to use a Release build of a unit testing frameworks (catch/gtest/boost/etc) regardless of the build_type of my project (consumer only project). This worked in conan1 via always doing conan install with profile with build_type=Release, but does not work with conan2.

If you did a conan install . -s build_type=Release in Conan 1.X (with the modern integrations like CMakeDeps+CMakeToolchain), the consumer project will assume it is in Release mode and act consequently, not finding dependencies if it is in RelWithDebInfo mode. I don't think this is something specific of Conan 2.0.

zabereer commented 1 year ago

I always want to use a Release build of a unit testing frameworks (catch/gtest/boost/etc) regardless of the build_type of my project (consumer only project). This worked in conan1 via always doing conan install with profile with build_type=Release, but does not work with conan2.

If you did a conan install . -s build_type=Release in Conan 1.X (with the modern integrations like CMakeDeps+CMakeToolchain), the consumer project will assume it is in Release mode and act consequently, not finding dependencies if it is in RelWithDebInfo mode. I don't think this is something specific of Conan 2.0.

Thanks @memsharded , I am migrating to the modern integrations and conan2 from an older conan1. Is there a correct way to achieve mixed build_type builds? (I am not creating a package, I am only consuming conan packages, def compatibility(self) does not seem to get called in my conanfile.py).

memsharded commented 1 year ago

Thanks @memsharded , I am migrating to the modern integrations and conan2 from an older conan1. Is there a correct way to achieve mixed build_type builds? (I am not creating a package, I am only consuming conan packages, def compatibility(self) does not seem to get called in my conanfile.py).

Yes, compatibility() is for packages, if your conanfile.py is a consumer only, it will not be called.

So in general the approach to achieve mixed build_type builds is exactly the above: specify the build type of the things that you want, for example if you want all dependencies to be Release, except zlib that for some reason you want it with RelWithDebInfo you do:

conan install ... -s build_type=Release -s &:build_type=RelWithDebInfo -s zlib/*:build_type=RelWithDebInfo

That is basically it, you tell each dependency (and the consumer project via &) which build_type you want for it.

In Conan 2.0 you can define the compatibility.py global plugin that applies to dependencies automatically.

zabereer commented 1 year ago

Thank you @memsharded

dariusarnold commented 1 year ago

Are there any other effects of the &:build_type=RelWithDebInfo approach apart from the generated CMake integration being build type specific when you are only using Conan for consuming dependencies?

memsharded commented 1 year ago

Yes, it might have some other (minor) effects, like defining the VS runtime for that configuration in multi-config setup like VS (via conan_toolchain.cmake

garyoberbrunner-gpsw commented 3 months ago

Sorry to revive this old thread. I'm trying to set up my builds so I can do Debug, Release, and RelWithDebInfo (in the latter case I'm fine with the dependencies being in Release mode, though RelWithDebInfo would be ideal). My use of conan is only as a consumer (i.e. to build, install & use dependencies). Is this "&:" syntax documented somewhere so I can see what it does and how to use it effectively?

memsharded commented 3 months ago

Hi @garyoberbrunner-gpsw

It is true that the & is explained in https://docs.conan.io/2/reference/config_files/profiles.html#profile-patterns, but very succinctly. I have recently created from another thread the ticket in the docs repo https://github.com/conan-io/docs/issues/3803, to try to write some more explicit documentation for this use case.