用conan支持不同的C/ c++包范式
一些开发人员认为,默认情况下,C/ c++的包管理器应该将调试和发布工件捆绑在同一个包中,以便开发人员在工作时更改配置时可以轻松使用它们。
但是其他开发人员可能会认为这不是一个好的实践,并且发布和调试包应该是不同的,并且在默认情况下应该分开安装。以Linux的“-dbg”符号包为例。
事实是两者都有优点和缺点,如果我们从开发包管理器的经验中学到了什么,那就是没有绝对的真理,C/ c++包管理器应该为开发人员提供支持他们想要实现的打包范例的方法。我们不断听取用户的反馈,最新的Conan 0.20版本包含了一些帮助支持多包范式的实用程序。
首先,回顾和理解柯南如何处理包是很有趣的:

上图中的每个块都是一个给定包的文件夹。配方包存储在“export”文件夹中,它被复制到“source”文件夹中,这样配方包就可以保存在“source”文件夹中源()方法可以获取包的源代码。然后,对于每个不同的配置(不同的设置,例如不同的编译器版本或体系结构),使用一个新的、干净的构建文件夹,即配方build ()方法触发,最后,构件(通常是头文件和库)由包()方法到最终包文件夹。每个包由配置值的SHA-1散列标识。
单个配置包
这是Conan中最常用的方法,在文档和Conan .io中的大多数包中都有使用。使用这种方法,每个包只包含一个配置的构件。因此,如果有一个构建“hello”库的包配方,那么将会有一个包含“hello”库的发布版本的包hello.lib库和包含hello_d.lib该库的调试版本。名称后缀是可选的,可以将库命名为相同而没有任何问题,但这里使用它是为了使其更清楚。
典型的食谱是这样的(不是完整的食谱):
类HelloConan(ConanFile):设置=“操作系统”,“编译器”,“build_type”,“拱”def构建(自我):cmake=CMake(自我.设置)cmake.配置(自我)#调用“cmake”。-g……”cmake.构建(自我)#调用“cmake——build”。defpackage_info(自我):自我.cpp_info.填词=[“你好”]
非常重要的是要注意,它声明的是build_type作为背景。这意味着将为这种设置的每个不同值生成不同的包。

在安装这些包时,为构建系统生成的文件,如conanbuildinfo.cmake档案由cmake生成器,将根据安装设置包含不同的信息:
集(CONAN_LIBS_HELLO你好)...集(CONAN_LIBS你好$ {CONAN_LIBS})
如果开发人员想要切换依赖项的配置,他通常会使用:
$柯南安装- sbuild_type=释放……//当需要调试时$柯南安装- sbuild_type=调试……
这些切换速度很快,因为所有依赖项都已经在本地缓存了。
这个过程有一些优点:它很容易实现和维护。包的大小最小,因此磁盘空间和传输速度更快,并且从源代码构建也保持在必要的最小值。配置的解耦可能有助于隔离与混合不同类型的工件相关的问题,并且还可以保护有价值的信息免受部署和分发错误的影响。例如,调试工件可能包含符号或源代码,它们可以帮助或直接为逆向工程提供方法。因此,按工件分发调试工件可能是一个非常危险的问题。主要的缺点是,当从调试切换到发布时,必须记住安装依赖的特定配置,反之亦然。这是重度IDE用户(如Visual Studio)会觉得有点不方便的地方。
使用多个调试/发布单一配置包
即使这些包是单配置的,如果最终用户开发人员想要在多配置环境(如Visual Studio)中轻松使用它们,他们也可以通过CMake来实现cmake_multi发电机。使用生成器,安装依赖项的调试和发布配置就足够了:
$柯南安装- gcmake_multi- sbuild_type=释放- scompiler.runtime=医学博士…$柯南安装- gcmake_multi- sbuild_type=调试- scompiler.runtime=MDd……
这些命令将生成3个文件:conanbuildinfo_multi.cmake,conanbuildinfo_debug.cmake和conanbuildinfo_release.cmake.的_debug和_release文件将包含它们自己的cmake变量。
然后,在消费者CMakeLists.txt中使用:
项目(MyHello)cmake_minimum_required(版本2.8.12)包括($ {CMAKE_BINARY_DIR}/ conanbuildinfo_multi.cmake)conan_basic_setup()add_executable(say_hello main.cpp)conan_target_link_libraries(say_hello)
多配置包
在多配置包中,相同的包将包含不同配置的工件。在我们的示例中,同一个包可以包含库“hello”的发布和调试版本。
![]()
这并不意味着每个配方只有一个包或严格来说只有一个构建文件夹,因为您仍然可以针对不同的体系结构或不同的编译器版本拥有不同的包。包创建者可以定义他们独特的打包逻辑。
要实现这种方法,包配方可以这样做:
def构建(自我):cmake=CMake(自我.设置)如果cmake.is_multi_configuration:cmd=让“%s”%s%(自我.conanfile_directory,cmake.command_line)自我.运行(cmd)自我.运行(“制造——建造。——配置调试”)自我.运行(“制造——建造。——配置发布”)其他的:为配置在(“调试”,“发布”):自我.输出.信息(“% s”%配置)自我.运行(' ' dcmake_build_type =%s' '%(自我.conanfile_directory,cmake.command_line,配置))自我.运行(“制造——建造。”)shutil.rmtree(“CMakeFiles”)操作系统.删除(“CMakeCache.txt”)
假设a_d正在使用后缀名(其他方法也是有效的,因为有不同的文件夹)package_info ()方法可以是:
defpackage_info(自我):自我.cpp_info.释放.填词=[“你好”]自我.cpp_info.调试.填词=[“hello_d”]
这些包不需要在安装时指定构建类型,如果提供了,它将被忽略,例如,对于使用cmake生成器的消费者:
$柯南安装- gcmake# no -s build_type=发布/调试
这将为同一使用者构建系统生成不同的变量conanbuildinfo.cmake,如:
集(CONAN_LIBS_HELLO_DEBUG hello_d)集(CONAN_LIBS_HELLO_RELEASE你好)...集(CONAN_LIBS_DEBUG hello_d$ {CONAN_LIBS_DEBUG})集(CONAN_LIBS_RELEASE你好$ {CONAN_LIBS_RELEASE})
这种方法有分发调试工件的风险,如上所述,这是一个可以促进逆向工程的重要问题。此外,包总是更大,需要更多的时间来构建、传输和安装,即使您没有使用所有的工件(如在生产中)。其主要优点是,开发人员可以更轻松地在ide中的调试和发布配置之间切换,而无需做其他任何事情。
构建一次,打包多次
可能已经存在的构建脚本会同时为不同的配置构建二进制文件,比如调试/发布,或者不同的体系结构(32/64位),或者库类型(共享/静态)。如果在以前的“单个配置包”方法中使用这样的构建脚本,它肯定不会有问题,但是我们将浪费宝贵的构建时间,因为我们将为每个包重新构建整个项目,然后为给定的配置提取相关的工件,留下其他的。
在Conan 0.20中,可以指定逻辑,因此可以重用相同的构建来创建不同的包,这将更有效:

这可以通过定义a来实现build_id ()方法,该方法将指定逻辑。
设置=“操作系统”,“编译器”,“拱”,“build_type”defbuild_id(自我):自我.info_build.设置.build_type=“任何”def包(自我):如果自我.设置.build_type= =“调试”:#包调试工件其他的:# package release
请注意build_id ()方法使用self.info_build对象更改构建散列。如果该方法不更改它,则该散列将与包文件夹的散列匹配。通过设置build_type = "任何"在美国,我们正在对两家公司都这么做调试和释放的值build_type,哈希值将是相同的(特定的字符串基本上是无关的,只要它在两种配置中是相同的)。注意构建散列sha3两者都会不同吗sha1和sha2包标识符。
这并不意味着会有一个严格的构建文件夹。每个配置(架构、编译器版本等)都有一个构建文件夹。因此,如果我们只有Debug/Release构建类型,我们为N种不同的配置生成N个包,我们将有N/2个构建文件夹,节省一半的构建时间。
结论
这篇博文说明了Conan如何允许非常不同的包装范例。这是由我们社区的维护者、贡献者和用户推动的持续努力,他们试图提供工具来支持我们在C和c++社区中非常不同的用例和需求。非常感谢他们所有人!