美文网首页
vcpkg和conan的原理和区别

vcpkg和conan的原理和区别

作者: 生活简单些 | 来源:发表于2023-07-06 18:07 被阅读0次

    1. 中心点不一样

    • vcpkg: 以cmake为中心,只做cmake的额外补充,本质上不改变cmake原有的特性,仅仅是为cmake提供了额外的自动依赖库下载,以及版本控制,而且还额外添加了一些自动化成分(比如:自动设置rpath、自动拷贝dll),所有的工作几乎都是非侵入式的 ,可以做到不修改现有代码就能移除vcpkg。

    • conan: 以自己为中心,cmake只是它支持的构建系统其中之一,同时支持Visual Studio Solution、Meson、AutoTools、MakeFile等

    正是因为conan是以自我为中心的,因此,它自己提供了一套自己的API来覆盖别的构建系统的,看起来像是重复造轮子,下面举2个小案例,比如:

    • CMake明明自己可以通过cmake_minimum_required(VERSION 3.0.0)约束最小cmake版本。然而,Conan必须在conanfile.text或者conanfile.py里定义最低cmake版本:
    # conanfile.text
    ----------------------------------
    [tool_requires]
    cmake/3.22.6
    
    • CMake工程内部的子模块可以通过add_subdirectory()的方式加入,可以说构建的时候想加哪几个就加几个,如果你加了一个example子模块,通过add_subdirectory(example)在Conan里却还要接受Conan的管控,还需要在conanfile.py里配置:
    exports_sources = "CMakeLists.txt", "src/*", "example/*"
    

    如果你的项目集成了gtest,即便你能通过find_package(gtest)集成gtest到你的项目里了,然而conan还要插一脚,即:在conanfile.py里通过配置控制是否启用gtest,其实就是启用后往CMake注入一个BUILD_TESTING变量,然后CMake得通过它判断是否要find_pacakge(gtest):

     def build(self):
            cmake = CMake(self)
            cmake.configure()
            cmake.build()
            if not self.conf.get("tools.build:skip_test", default=False):
                test_folder = os.path.join("tests")
                if self.settings.os == "Windows":
                    test_folder = os.path.join("tests", str(self.settings.build_type))
                self.run(os.path.join(test_folder, "test_hello"))
    
    cmake_minimum_required(VERSION 3.15)
    project(hello CXX)
    ...
    
    if (NOT BUILD_TESTING STREQUAL OFF)
        add_subdirectory(tests)
    endif()
    ...
    

    通过设置tools.build:skip_test这个属性往CMake注入BUILD_TESTING变量,这是非常典型的重新发明轮子来覆盖CMake的,其实Conan的很多配置处处在提现重新包装CMake,正常我们的项目只用CMake作为构建系统的话,那么Conan这么个搞法会显得很绕,多此一举。

    其实,当今的C/C++已经全面向CMake转变了,包括Android系统源码从MakeFile转向支持CMake、Qt的源码从QMake构建转向CMake构建,以及Visual Studio也全面支持CMake,多样化构建系统已经慢慢被CMake统一了,Conan的走兼容多构建系统会不会有些过了?而且在Conan的官网教程里所有的篇幅基本都是围绕着CMake,感觉它的理想和现实有点尴尬。

    2. 跨平台的思路不一样

      vcpkg的跨平台是利用C/C++实现的,以及对CMake函数的再次扩充,在使用vcpkg实现包管理的过程中都是通过执行它额外扩充的cmake函数来实现的(可能内部调用了它的C/C++可执行性文件),因为都是cmake函数因此看起来无关平台差异。
      conan的跨平台属于自造体系,自立门户,将python的运行环境搬进来作为跨平台的支持,然后发明了一套适配并操作多构建系统的API,同时又利用了windows的batch和linux的shell,比如:生成了用于自动设置LD_LIBRARY_PATH和DYLD_FRAMEWORK_PATH的shell,不过vcpkg会默默后台帮你做这类事情,让你感觉不到额外的工作和侵入性。

    3. 托管库的策略不一样

      Conan明显走Java Maven的路线,即:用Web文件服务器托管编译好的二进制的思路,跟Java的Maven服务器托管Jar包如出一辙,但别忘记了Java的Jar是跨平台的,同一个库所有平台只要一个Jar,而C/C++就不一样了,多平台多ABI的库文件是不兼容的,正常的C/C++库都有一堆头文件、SO文件、DLL文件、Lib文件,托管一个库的所有平台的二进制库文件压力是很大的,磁盘占用会远比Mava那套占用的多,即便是ConanCenter也做不到所有库全平台托管,想象下所有platform(android、iOS、mac、linux、windows)和所有ABI(arm64、arm-v7a、arm-v8a、mips、mips-64、arm64、x86、x64)来个笛卡尔积——恐怖如斯,也因此,这些巨大的补全工作丢给了社区,然后你会偶尔发现同一个库的不同版本可能是来自不同源码构建出来的,质量良莠不齐——很不幸我们项目就遇到了, 然后不得已自己编译那个库的源码,并托管在私有jfrog里,然后又因为此库在私有托管的jfrog和conancenter里托管的冲突,不得已得将conancenter禁止了,随后所有的别的依赖都得单独在自己的jfrog里重新传一遍——痛啊
      vcpkg不走托管方式,vcpkg只做映射方式,在vcpkg维护了所有主流C、C++的开源库,每一个库都是通过配置文件指向库对应的官网源码下载地址(github, gitlab, bitbucket,文件服务器),并同时指定版本(对于git库则是commit id或者对于zip文件则是SHA265)。Conan引导的方向是即时编译成所在平台所需的库,因此,vcpkg不像conan需要一个单独web文件服务器来存放编译好的二进制库文件,当然编译缓存肯定是重复利用的,不然每次编译会耗费巨大等待时间。可能,你要问了,同样的库代码每个人都要经历一次编译也挺费时间,其实vcpkg是允许配置一个共享服务器来实现缓存共享的,vcpkg建议的策略是通过CI来贡献编译缓存,然后开发者配置共享服务器路径来获取编译缓存,然后本地开发的效率会得到极大提升!即便缓存损坏,只要再跑一遍CI即可,迁移缓存也容易,复制到另外一个共享盘目录下并配置下新的缓存路径即可。

    相关文章

      网友评论

          本文标题:vcpkg和conan的原理和区别

          本文链接:https://www.haomeiwen.com/subject/rkgludtx.html