包文件:package() 方法¶
我们已经在我们的“hello”包中使用了package()
方法来调用 CMake 的安装步骤。在本教程中,我们将更详细地解释CMake.install()的使用,以及如何修改此方法来执行以下操作
使用conan.tools.files实用程序将生成的工件从构建文件夹复制到包文件夹
复制包许可证
管理如何打包符号链接
请首先克隆源代码以重新创建此项目。您可以在 GitHub 上的examples2 仓库中找到它们
$ git clone https://github.com/conan-io/examples2.git
$ cd examples2/tutorial/creating_packages/package_method
在 package() 方法中使用 CMake 安装步骤¶
当您已经在您的CMakeLists.txt中定义了从构建和源文件夹中提取工件(头文件、库、二进制文件)到预定位置的功能,并可能对这些工件进行一些后处理时,这是最简单的选择。这将在您的CMakeLists.txt中无需更改即可工作,因为 Conan 会将CMAKE_INSTALL_PREFIX
CMake 变量设置为指向配方的package_folder属性。然后,只需在CMakeLists.txt中对创建的目标调用install()就足以让 Conan 将构建的工件移动到 Conan 本地缓存中的正确位置。
cmake_minimum_required(VERSION 3.15)
project(hello CXX)
add_library(hello src/hello.cpp)
target_include_directories(hello PUBLIC include)
set_target_properties(hello PROPERTIES PUBLIC_HEADER "include/hello.h")
...
install(TARGETS hello)
def package(self):
cmake = CMake(self)
cmake.install()
让我们再次构建我们的包,并注意 Conan 本地缓存中关于文件打包的行
$ conan create . --build=missing -tf=""
...
hello/1.0: Build folder /Users/user/.conan2/p/tmp/b5857f2e70d1b2fd/b/build/Release
hello/1.0: Generated conaninfo.txt
hello/1.0: Generating the package
hello/1.0: Temporary package folder /Users/user/.conan2/p/tmp/b5857f2e70d1b2fd/p
hello/1.0: Calling package()
hello/1.0: CMake command: cmake --install "/Users/user/.conan2/p/tmp/b5857f2e70d1b2fd/b/build/Release" --prefix "/Users/user/.conan2/p/tmp/b5857f2e70d1b2fd/p"
hello/1.0: RUN: cmake --install "/Users/user/.conan2/p/tmp/b5857f2e70d1b2fd/b/build/Release" --prefix "/Users/user/.conan2/p/tmp/b5857f2e70d1b2fd/p"
-- Install configuration: "Release"
-- Installing: /Users/user/.conan2/p/tmp/b5857f2e70d1b2fd/p/lib/libhello.a
-- Installing: /Users/user/.conan2/p/tmp/b5857f2e70d1b2fd/p/include/hello.h
hello/1.0 package(): Packaged 1 '.h' file: hello.h
hello/1.0 package(): Packaged 1 '.a' file: libhello.a
hello/1.0: Package 'fd7c4113dad406f7d8211b3470c16627b54ff3af' created
hello/1.0: Created package revision bf7f5b9a3bb2c957742be4be216dfcbb
hello/1.0: Full package reference: hello/1.0#25e0b5c00ae41ef9fbfbbb1e5ac86e1e:fd7c4113dad406f7d8211b3470c16627b54ff3af#bf7f5b9a3bb2c957742be4be216dfcbb
hello/1.0: Package folder /Users/user/.conan2/p/47b4c4c61c8616e5/p
正如您所看到的,在调用cmake.install()
方法后,include和library文件都被复制到了包文件夹。
在 package() 方法中使用 conan.tools.files.copy() 和打包许可证¶
对于您不想依赖 CMake 的安装功能或正在使用其他构建系统的情况,Conan 提供了将选定的文件复制到package_folder的工具。在这种情况下,您可以使用tools.files.copy函数进行复制。我们可以用自定义的文件复制替换之前的cmake.install()
步骤,结果将相同。
请注意,我们还打包了库源代码中licenses文件夹中的LICENSE
文件。这是 Conan 包中的常见模式,也可以使用cmake.install()
添加到前面的示例中,因为CMakeLists.txt不会将此文件复制到package folder。
def package(self):
copy(self, "LICENSE", src=self.source_folder, dst=os.path.join(self.package_folder, "licenses"))
copy(self, pattern="*.h", src=os.path.join(self.source_folder, "include"), dst=os.path.join(self.package_folder, "include"))
copy(self, pattern="*.a", src=self.build_folder, dst=os.path.join(self.package_folder, "lib"), keep_path=False)
copy(self, pattern="*.so", src=self.build_folder, dst=os.path.join(self.package_folder, "lib"), keep_path=False)
copy(self, pattern="*.lib", src=self.build_folder, dst=os.path.join(self.package_folder, "lib"), keep_path=False)
copy(self, pattern="*.dll", src=self.build_folder, dst=os.path.join(self.package_folder, "bin"), keep_path=False)
copy(self, pattern="*.dylib", src=self.build_folder, dst=os.path.join(self.package_folder, "lib"), keep_path=False)
让我们再次构建我们的包,并注意 Conan 本地缓存中关于文件打包的行
$ conan create . --build=missing -tf=""
...
hello/1.0: Build folder /Users/user/.conan2/p/tmp/222db0532bba7cbc/b/build/Release
hello/1.0: Generated conaninfo.txt
hello/1.0: Generating the package
hello/1.0: Temporary package folder /Users/user/.conan2/p/tmp/222db0532bba7cbc/p
hello/1.0: Calling package()
hello/1.0: Copied 1 file: LICENSE
hello/1.0: Copied 1 '.h' file: hello.h
hello/1.0: Copied 1 '.a' file: libhello.a
hello/1.0 package(): Packaged 1 file: LICENSE
hello/1.0 package(): Packaged 1 '.h' file: hello.h
hello/1.0 package(): Packaged 1 '.a' file: libhello.a
hello/1.0: Package 'fd7c4113dad406f7d8211b3470c16627b54ff3af' created
hello/1.0: Created package revision 50f91e204d09b64b24b29df3b87a2f3a
hello/1.0: Full package reference: hello/1.0#96ed9fb1f78bc96708b1abf4841523b0:fd7c4113dad406f7d8211b3470c16627b54ff3af#50f91e204d09b64b24b29df3b87a2f3a
hello/1.0: Package folder /Users/user/.conan2/p/21ec37b931782de8/p
检查include和library文件是如何打包的。LICENSE 文件也如上所述被复制。
在 package() 方法中管理符号链接¶
您可以在 package 方法中执行的另一件事是管理如何打包符号链接。Conan 默认情况下不会操作符号链接,因此我们提供了一些工具来将绝对符号链接转换为相对符号链接,并删除外部或损坏的符号链接。
假设最新示例中打包的一些文件是符号链接,指向 Conan 缓存内的绝对位置。然后,调用conan.tools.files.symlinks.absolute_to_relative_symlinks()
将把这些绝对链接转换为相对路径,并使包可重定位。
from conan.tools.files.symlinks import absolute_to_relative_symlinks
def package(self):
copy(self, "LICENSE", src=self.source_folder, dst=os.path.join(self.package_folder, "licenses"))
copy(self, pattern="*.h", src=os.path.join(self.source_folder, "include"), dst=os.path.join(self.package_folder, "include"))
copy(self, pattern="*.a", src=self.build_folder, dst=os.path.join(self.package_folder, "lib"), keep_path=False)
...
absolute_to_relative_symlinks(self, self.package_folder)