Search code examples
c++boostcmakeconanconan-2

cmake + conan 2.0 + boost with default cmake_exe template not properly injecting dependencies in generated files


PS C:\Dev\test> conan --version
Conan version 2.0.9
PS C:\Dev\test> cmake --version
cmake version 3.27.1

I am trying to make a boost-cmake-conan 2.0 hello world using the default cmake_exe template.

  1. In an empty folder conan new cmake_exe -d name=myprojectname -d version=0.1

  2. add requirement boost/[>=1.82.0] to conanfile.py

    For reference the conanfile.py now looks like this

    from conan import ConanFile
    from conan.tools.cmake import CMakeToolchain, CMake, cmake_layout, CMakeDeps
    
    
    class myprojectnameRecipe(ConanFile):
        name = "myprojectname"
        version = "0.1"
        package_type = "application"
    
        # Optional metadata
        license = "<Put the package license here>"
        author = "<Put your name here> <And your email here>"
        url = "<Package recipe repository url here, for issues about the package>"
        description = "<Description of myprojectname package here>"
        topics = ("<Put some tag here>", "<here>", "<and here>")
    
        # Binary configuration
        settings = "os", "compiler", "build_type", "arch"
    
        # Sources are located in the same place as this recipe, copy them to the recipe
        exports_sources = "CMakeLists.txt", "src/*"
    
        def requirements(self):
            self.requires("boost/[>=1.82.0]")
    
        def layout(self):
            cmake_layout(self)
    
        def generate(self):
            deps = CMakeDeps(self)
            deps.generate()
            tc = CMakeToolchain(self)
            tc.generate()
    
        def build(self):
            cmake = CMake(self)
            cmake.configure()
            cmake.build()
    
        def package(self):
            cmake = CMake(self)
            cmake.install()
    

    and the cmakelist.txt

    cmake_minimum_required(VERSION 3.15)
    project(myprojectname CXX)
    
    
    
    add_executable(myprojectname src/myprojectname.cpp src/main.cpp)
    
    
    
    install(TARGETS myprojectname DESTINATION "."
            RUNTIME DESTINATION bin
            ARCHIVE DESTINATION lib
            LIBRARY DESTINATION lib
            )
    
  3. Having previously setup my profile, running conan install . --build missing gives all the proper files under /build/ and the following output

======== Finalizing install (deploy, generators) ========
conanfile.py (myprojectname/0.1): Calling generate()
conanfile.py (myprojectname/0.1): Generators folder: C:\Dev\test\build\generators
conanfile.py (myprojectname/0.1): CMakeToolchain generated: conan_toolchain.cmake
conanfile.py (myprojectname/0.1): Preset 'conan-default' added to CMakePresets.json. Invoke it manually using 'cmake --preset conan-default' if using CMake>=3.23
conanfile.py (myprojectname/0.1): If your CMake version is not compatible with CMakePresets (<3.23) call cmake like: 'cmake <path> -G "Visual Studio 16 2019" -DCMAKE_TOOLCHAIN_FILE=C:\Dev\test\build\generators\conan_toolchain.cmake -DCMAKE_POLICY_DEFAULT_CMP0091=NEW'
conanfile.py (myprojectname/0.1): CMakeToolchain generated: CMakePresets.json
conanfile.py (myprojectname/0.1): CMakeToolchain generated: ..\..\CMakeUserPresets.json
conanfile.py (myprojectname/0.1): Generating aggregated env files
conanfile.py (myprojectname/0.1): Generated aggregated env files: ['conanbuild.bat', 'conanrun.bat']
Install finished successfully
  1. And adding a simple hello world taken from Boost documentation
#include <boost/lambda/lambda.hpp>
#include <iostream>
#include <iterator>
#include <algorithm>

int main()
{
   typedef std::istream_iterator<int> in;

   std::cout << "Type in any number: ";

   std::for_each(
       in(std::cin), in(), std::cout 
               << (boost::lambda::_1 * 10) 
               << "\nType in another number: " );
}

  1. conan build . will finalize the install and call generate from our conanfile.py, but looking at the generated files no mention of boost either in libs or include directories is created in the Visual Studio project files. Of course this gives the following compiling error
C:\Dev\test\src\main.cpp(14,10): fatal error C1083: Cannot open include file: 'boost/lambda/lambda.hpp': No such file or directory [C:\Dev\test\build\cli 
ent-server-algo-computing-grid.vcxproj]

This error would have been fixed in conan 1.0 by adding a reference to conanbuildinfo.cmake in our cmakelists.txt and calling conan_basic_setup() which is now deprecated and other posts suggest that we don't need to add it anymore.

Of course I could manually add the find_package as suggested in the conan 2.0 documentation, target_link_libraries and target_include_directories clauses, but I'd prefer if I could at least have generic CONAN_LIBS or CONAN_INCLUDE_DIRS variables like in conan 1.0 so I just have to update my conanfile.py if I add another lib. So what's going on and why can't CMakeDeps or CMakeToolchain properly inject boost?


Solution

  • Having to modify a user CMakeLists.txt with CONAN_XXX variables is not a recommended good practice anymore:

    • CMake no longer recommends using variables to define dependencies information. The CMake recommended way is to use find_package() and targets via target_link_libraries(). As an example, imagine adding test_requires("gtest/..."). You certainly don't want your main app to be accidentally linked with gtest library. The CONAN_LIBS approach will likely do that, while with target_link_library() will perfectly define the right package and library dependencies for the right executables and libraries.
    • The resulting CMakeLists.txt is completely standard and Conan-agnostic. This has several advantages as not generating any lock-in.

    CMakeDeps went in this direction following massive feedback from the community towards this fully "transparent" integration in which the CMakeLists.txt does not end with any Conan references.