使用组件和可编辑包

可以在 layout() 方法中定义组件,以支持 editable 包的情况。也就是说,如果我们想将一个包置于 editable 模式,并且该包定义了 components,则需要在 layout() 方法中正确定义组件布局。让我们在一个真实的例子中看看它。

请先克隆源代码以重新创建此项目。您可以在 GitHub 上的 examples2 存储库 中找到它们。

$ git clone https://github.com/conan-io/examples2.git
$ cd examples2/examples/conanfile/layout/editable_components

在那里我们找到一个 greetings 子文件夹和包,其中包含 2 个库,hello 库和 bye 库。每个库都被建模为包食谱中的一个 component

greetings/conanfile.py
class GreetingsConan(ConanFile):
    name = "greetings"
    version = "0.1"
    settings = "os", "compiler", "build_type", "arch"
    generators = "CMakeDeps", "CMakeToolchain"
    exports_sources = "src/*"

    def build(self):
        cmake = CMake(self)
        cmake.configure()
        cmake.build()

    def layout(self):
        cmake_layout(self, src_folder="src")
        # This "includedirs" starts in the source folder, which is "src"
        # So the components include dirs is the "src" folder (includes are
        # intended to be included as ``#include "hello/hello.h"``)
        self.cpp.source.components["hello"].includedirs = ["."]
        self.cpp.source.components["bye"].includedirs = ["."]
        # compiled libraries "libdirs" will be inside the "build" folder, depending
        # on the platform they will be in "build/Release" or directly in "build" folder
        bt = "." if self.settings.os != "Windows" else str(self.settings.build_type)
        self.cpp.build.components["hello"].libdirs = [bt]
        self.cpp.build.components["bye"].libdirs = [bt]

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

    def package_info(self):
        self.cpp_info.components["hello"].libs = ["hello"]
        self.cpp_info.components["bye"].libs = ["bye"]

        self.cpp_info.set_property("cmake_file_name", "MYG")
        self.cpp_info.set_property("cmake_target_name", "MyGreetings::MyGreetings")
        self.cpp_info.components["hello"].set_property("cmake_target_name", "MyGreetings::MyHello")
        self.cpp_info.components["bye"].set_property("cmake_target_name", "MyGreetings::MyBye")

虽然 hellobye 库在最终包中的位置位于最终的 lib 文件夹中,那么在 package_info() 方法中不需要任何特殊操作,除了组件的定义之外。在这种情况下,还包括 CMake 生成的文件名和目标的自定义,但这对于此示例来说不是必需的。

重要的部分是 layout() 定义。除了常见的 cmake_layout 之外,还需要定义组件头文件的位置(self.cpp.source,因为它们是源代码)以及本地构建库的位置。由于库的位置取决于平台,因此最终的 self.cpp.build.components["component"].libdirs 取决于平台。

使用此食谱,我们可以将包置于可编辑模式并在本地使用以下命令构建它:

$ conan editable add greetings
$ conan build greetings
# we might want to also build the debug config

app 文件夹中,我们有一个包食谱来构建 2 个可执行文件,它们链接到 greeting 包组件。那里的 app/conanfile.py 食谱很简单,build() 方法构建并运行使用 CMakeLists.txt 构建的 exampleexample2 这两个可执行文件。

# Note the MYG file name, not matching the package name,
# because the recipe defined "cmake_file_name"
find_package(MYG)

add_executable(example example.cpp)
# Note the MyGreetings::MyGreetings target name, not matching the package name,
# because the recipe defined "cmake_target_name"
# "example" is linking with the whole package, both "hello" and "bye" components
target_link_libraries(example MyGreetings::MyGreetings)

add_executable(example2 example2.cpp)
# "example2" is only using and linking "hello" component, but not "bye"
target_link_libraries(example2 MyGreetings::MyHello)
$ conan build app
hello: Release!
bye: Release!

如果您现在转到 bye.cpp 源文件并修改输出消息,然后在本地构建 greetingsapp,则“bye”组件库的最终输出消息应该会发生变化。

$ conan build greetings
$ conan build app
hello: Release!
adios: Release!