使用组件和可编辑包¶
可以在 layout()
方法中定义组件,以支持 editable
包的情况。也就是说,如果我们将一个包置于 editable
模式,并且该包定义了 components
,那么就需要在 layout()
方法中正确定义组件布局。让我们通过一个实际示例来看看。
请首先克隆源代码以重新创建此项目。您可以在 GitHub 的 examples2 仓库中找到它们。
$ git clone https://github.com/conan-io/examples2.git
$ cd examples2/examples/conanfile/layout/editable_components
在那里我们发现了一个名为 greetings
的子文件夹和包,其中包含两个库:hello
库和 bye
库。每个库都在包食谱中被建模为一个 component
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")
虽然最终包中 hello
和 bye
库的位置在最终的 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
文件夹中,我们有一个包食谱,用于构建两个可执行文件,它们链接到 greeting
包组件。app/conanfile.py
食谱很简单,其 build()
方法构建并运行了使用 CMakeLists.txt
构建的 example
和 example2
两个可执行文件。
# 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
源文件并修改输出消息,然后本地构建 greetings
和 app
,则“bye”组件库的最终输出消息应该会改变
$ conan build greetings
$ conan build app
hello: Release!
adios: Release!