cmakepackagetargetconan

Create multiple targets for conan package


as said in the title, I'm trying to create a conan package so that I can install it in any project and choose what library to include in it. For now, what I was able to do, is the following:

I have my package folder (let's call it mypkg) which has a CMakeLists.txt that essentially compiles all the sub-folders in it. Each subfolder has its .cpp / .hpp files and a CMakeLists.txt with the following "pattern":

cmake_minimum_required(VERSION 2.8.12)

project(library1)


if(NOT TARGET ${PROJECT_NAME})
    add_library(${PROJECT_NAME} STATIC
    library1.cpp
    library1.hpp
    )
endif()

This code (repeated for each subfolder), creates N ".a" libraries.

At this point, in my conanfile.py, I have this code:

class mypkg(ConanFile):
    ...
    settings = "os", "arch", "compiler", "build_type"

    options = {"shared": [True, False]}
    default_options = "shared=True"
    generators = "cmake","cmake_find_package"


    def build(self):
        cmake = CMake(self)
        cmake.definitions['CMAKE_EXPORT_COMPILE_COMMANDS'] = "ON"
        cmake.configure()
        cmake.build()

    def package(self):
        self.copy("*.h", dst="include", src="src", keep_path=True)
        self.copy("*.a", dst="lib", keep_path=False)


    def package_info(self):
        self.cpp_info.libs = tools.collect_libs(self)

With all of that, after executing the command conan create ., I create my package but, when I try to include it in my projects from conan, I can only link the whole library and not the single library:

YES:

find_package(mypkg REQUIRED)
target_link_libraries(${PROJECT_NAME} mypkg::mypkg

NO:

find_package(mypkg REQUIRED)
target_link_libraries(${PROJECT_NAME} mypkg::library1

How can I solve this problem? Thank you!


Solution

  • To export individual targets in CMake, you will have to replace self.cpp_info with a self.cpp_info["library1"] etc. with the details for each of the targets filled in.

    This will create a mypkg::library1 target in the output of the CMakeDeps generator. A mypkg::mypkg target is still created by default, which simply depends on each of the components.

    You can override the CMake target names, if necessary, by calling .set_property("cmake_target_name", "mypkg::xyz") on cpp_info or a component.

    from conan import ConanFile
    from conan.tools.cmake import CMakeToolchain, CMakeDeps, CMake
    
    class mypkg(ConanFile):
        name = "mypkg"
        settings = "os", "arch", "compiler", "build_type"
    
        options = {"shared": [True, False]}
        default_options = {"shared": True}
    
        def generate(self):
            tc = CMakeToolchain(self)
            tc.variables["CMAKE_EXPORT_COMPILE_COMMANDS"] = True
            tc.generate()
    
            deps = CMakeDeps(self)
            deps.generate()
    
        def build(self):
            cmake = CMake(self)
            cmake.configure()
            cmake.build()
    
        def package(self):
            cmake = CMake(self)
            cmake.install()
    
        def package_info(self):
            self.cpp_info.components["library1"].libs = ["library1"]
            self.cpp_info.components["library2"].libs = ["library2"]
            # etc.
            # You will have to add any additional cpp_info details to specific components instead of the general self.cpp_info.