添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

照片: Claudio Schwarz on Unsplash

今天,现代语言(如 Go )通常提供集成的软件包管理,以提取库的所有依赖项。然而,很多软件都是用C/C++创建和维护的,并没有一个开箱即用的软件包管理器。

将一个软件移植到另一个目标平台(macOS、Windows、Linux)通常非常困难。庆幸的是,有第三方软件包管理器可用于此。其中一个叫 vcpkg ,是由微软提供的一个开源项目。在后文中,我将展示一些技巧,涵盖vcpkg中的一些困难。

vcpkg中的所有软件包都是从源代码中下载、打补丁和编译的。所以,当使用大型库,如boost、ITK或OpenCV时,会花费一些时间

开始使用vcpkg

首先,通过使用 Git 克隆仓库来检查vcpkg的最新版本。除此之外,你还需要一个C++编译器(GCC、MinGW、clang、Visual Studio cl、Xcode),具体取决于你的平台(参见 开始使用vcpkg )和 CMake 。在macOS上,我推荐使用 homebrew 来获取依赖项。

brew install cmake

现在你可以安装vcpkg了。

git clone https://github.com/Microsoft/vcpkg.gitcd vcpkg./bootstrap-vcpkg.sh

如果你想减少版本库的大小(这样你就不会看到旧的历史),你可以在克隆命令中添加选项--depth=1 ,然后读取

git clone --depth=1 https://github.com/Microsoft/vcpkg.git

现在更新vcpkg很简单:在你的vcpkg安装路径中调用git pull 。但当你匆忙时要小心这样做。你的项目和依赖的vcpkg库需要在这一步之后重新编译

建议保持vcpkg安装目录的路径简短且没有空白(例如:/opt/vcpkgC:\opt\vcpkg ),特别是对于Windows,因为有些包(boost)的层次相当深。

我们将在后文中把vcpkg的安装目录称为VCPK_ROOT 。下面的做法将使使用更容易,更便于携带。

  • 创建一个环境变量VCPK_ROOT ,指向vcpkg的安装目录。
  • 在你的CMake文件中参考这个变量,以取代硬编码的路径。
  • 或者,你可以用以下调用CMake的方式来输入你的CMake安装:cmake -B cmake-build -DCMAKE_TOOLCHAIN_FILE=<VCPKG_ROOT>/scripts/buildsystems/vcpkg.cmake 。所以你最好使用我提供的vcpkg模板

    然后,将vcpkg安装目录添加到你的搜索中PATH

    使用vcpkg命令行工具

    对于消耗一个库来说,最重要的vcpkg命令是。

    vcpkg help <command> 显示命令行中的一些帮助

    vcpkg search 用于查找库(称为端口)

    vcpkg install 用于安装库

    一个例子是:。

    vcpkg search catch
    
    catch                    alias#1          Deprecated alias for Catch2 unit testing frameworkcatch-classic            1.12.2#1         A modern, header-only test framework for unit testscatch2                   3.0.1#1          A modern, header-only test framework for unit testing.The result may be outdated. Run `git pull` to get the latest results.
    

    如果你决定为catch2 ,你可以用安装包。

    vcpkg install catch2
    

    该库将被编译并安装在你的VCPKG_ROOT ,从而落入$VCPKG_ROOT/packages/<LIBRARY>_<TRIPLET> 。 在安装命令的最后,会有一个使用提示。

    catch2 provides CMake targets:    # this is heuristically generated, and may not be correct    find_package(Catch2 CONFIG REQUIRED)    target_link_libraries(main PRIVATE Catch2::Catch2 Catch2::Catch2WithMain)
    

    而这有时就是问题所在。如果不检查已安装的包,可能会产生误导,不清楚哪些CMake目标可以在target_link_libraries

    现在,什么是三联体?

    一个三联体反映了编译的目标系统(见三联体文件)。在我的例子中,它是x64-osx 。另一个三联体将是例如x64-windows-static 。调用vcpkg help triplet ,列出可能的值。

    当对默认的三联体不满意时,你可以通过在你的CMake文件中指定VCPKG_TARGET_TRIPLET 来控制vcpkg install ,或者像这样用--triplet 选项来安装软件包(以下在macOS上不起作用)。

    vcpkg install catch2 --triplet x64-windows
    

    -static 三元组创建一个静态构建的库的版本。

    有两种不同的模式来安装软件包。在经典模式下,新库可以通过调用vcpkg install <port-name> 全局安装,如上一节所示。在清单模式下,你需要在你的项目目录下创建一个vcpkg.json 文件,列出所有的依赖关系。更多细节请参见清单模式

    这有一个很大的好处,项目所需的所有信息都在一个地方,在编译项目时,所需的包会被自动下载和安装。这类似于Go的mod文件。下面是我的vcpkg模板中的小vcpkg.json 文件。

    {  "name": "vcpkg-template",  "version-string": "0.0.1",  "dependencies": ["catch2"]}
    

    现在当你通过调用git clean -dxf 来清理VCPKG_ROOT 目录时,所有安装的库和下载的文件都会消失,需要重新安装。除此之外,在我的系统(macOS)上,vcpkg在$HOME/.cache/vcpkg 下创建了缓存文件,为了清理,必须将其删除。

    在manifest模式下,在你的项目目录下进行清理也会删除所有已安装的库。所以在下一次构建时,所有东西都将被重新编译。

    控制 vcpkg 的编译

    vcpkg 的行为可以通过 CMake 变量来控制,这些变量可以。

  • CMakelists.txt 文件中设置(在project() 子句之前)或
  • 在命令行中用cmake -D <VARIABLE>=<VALUE> 定义,或
  • 设置为一个环境变量,如<VARIABLE>=<VALUE> make -C
  • 关于目标架构和链接过程(静态或动态),以下变量是最重要的。 VCPKG_TARGET_TRIPLET - 控制构建的目标,如:x64-windows-static 更多信息请参见CMake集成

    包的五个方面

    在vcpkg中,为了使用一个库,你需要知道不同的名字。而这并不总是简单的,需要进行一些搜索

    所以有以下几种情况。

    1.在vcpkg.json dependencies部分或你的vcpkg install <PORT> 命令中的vcpkg port name字段。

    {      "dependencies": [ "boost-asio" ]}
    

    注意,端口名不能包含除[a-zA-Z] 和破折号以外的其他字符-

    2.vcpkg.json 中选择的特征看起来像这样。

    {    "dependencies": [        {           "name": "opencv",           "features": [ "png" ]        }    ]}
    

    3.要通过以下方式找到的CMake包名find_package(<PKG> REQUIRED)

    4.中的CMake组件名称。find_package(<PKG> REQUIRED COMPONENTS <COMP1> <COMP2>)

    5.target_link_library(myApp PRIVATE <DEP1> <DEP2> 的依赖性目标名称。有时target_include_directories() ,除此之外还必须设置!

    这种差异的一个例子是以下情况。

  • vcpkg 端口名称。boost-asio
  • CMake包名:find_package(boost_asio CONFIG REQUIRED) - 目标别名Boost::asio ,以找到链接target_link_library(myApp PRIVATE Boost::asio) 。经过搜索,你发现你可能需要与${Boost_LIBRARIES} 链接,而这并不是从 boost port 使用帮助中得出的。
  • 一些软件包在CMake运行时发出或多或少的帮助信息,试图支持用户如何包含这样的特定库。

    The package boost is compatible with built-in CMake targets:
    

    但你不会轻易发现CMake目标的名字有趣的是,你在ports 目录中发现了一个使用文件,它显示了target_link_libraries() 的正确方法。

    /opt/vcpkg/ports/boost> cat usageThe package boost is compatible with built-in CMake targets:    find_package(Boost REQUIRED [COMPONENTS <libs>...])    target_link_libraries(main PRIVATE ${Boost_LIBRARIES})    target_include_directories(main PRIVATE ${Boost_INCLUDE_DIRS})
    

    还有一篇很好的文章(见《如何用CMake找包:基础知识》)解决了在CMake中找包的一般问题,没有vcpkg。有一种方法是检查vcpkg安装目录下的Find<Package>.cmake 文件。

    然而,boost库中的CMake文件要比这复杂得多。这些包并不都是同质的、直接的。好在所有具有良好的本地CMake支持的包通常都比较简单,可以添加。一个例子是用于JSON流的伟大的nlohmann-json 库。

    在这里,安装后的用法打印真的很有帮助。

    The package nlohmann-json provides CMake targets:    find_package(nlohmann_json CONFIG REQUIRED)    target_link_libraries(main PRIVATE nlohmann_json::nlohmann_json)The package nlohmann-json can be configured to not provide implicit conversions via a custom triplet file:    set(nlohmann-json_IMPLICIT_CONVERSIONS OFF)For more information, see the docs here:    https://json.nlohmann.me/features/macros/#json_use_implicit_conversions
    

    那么问题来了。

    我从哪里得到所有这些名字?

    端口名称可以在网上找到vcpkg.io/en/packages…或者更好的vcpkg.info/,或者使用 vcpkg 命令行工具vcpkg search <name> 。一旦一个端口<PORT> (我们假设你是用vcpkg install 全局安装的),你需要检查$VCPKG_ROOT/ports/<PORT>/portfile.cmake 文件,比如这个boost-asio

    # Automatically generated by scripts/boost/generate-ports.ps1vcpkg_from_github(    OUT_SOURCE_PATH SOURCE_PATH    REPO boostorg/asio    REF boost-1.78.0    SHA512 78c58a64d669eaeabb5ba003200c581065412d33912e641143186ee95c11e0fb0411ed8dbb9a9acced8c8ecd258e0de33872b2e22dfc4a572315cd9a665db8a6    HEAD_REF master    PATCHES windows_alloca_header.patch)include(${CURRENT_INSTALLED_DIR}/share/boost-vcpkg-helpers/boost-modular-headers.cmake)boost_modular_headers(SOURCE_PATH ${SOURCE_PATH})
    

    除此之外,为了找到可能的特性名称,你可以观察这个软件包的$VCPKG_ROOT/ports/<PORT>/vcpkg.json 文件。

    为了好奇,你可以通过调用boost-asio ,列出所有的依赖项。

    vcpkg depend-info boost-asio
    

    当在vcpkg.json 中只指定了端口名称时,所安装的特性是所谓的默认特性。这种行为可以通过在vcpkg.json 文件的dependencies 部分中设置"default-features": false 选项来禁用。因此,一个vcpkg.json 文件可以这样写。

    {  "name": "vcpkg-template",  "version-string": "0.0.1",  "dependencies": [    {        "name": "boost",        "default-features": false    }  ]}
    

    vcpkg.readthedocs.io/en/latest/u…

    我在本文中对vcpkg的使用做了一个简短的调查,并给出了一些技巧和窍门。vcpkg的使用并不总是那么简单。我为新项目创建了一个小型的vcpkg模板。

    你可以在GitHub上查看并重用我的vcpkg模板,了解一个C++项目的基本布局。所以,只要git clone https://github.com/andremueller/vcpkg-template ,就可以开始了。

    另一个有趣的主题是vcpkg的版本支持(见利用版本支持控制你的vcpkg依赖关系)。还有一些vcpkg的替代品,如Conanbuild2

    谢谢你的阅读。请继续关注更多信息

    分类:
    后端
    标签: