创建vcpkg私有仓库

2023/10/06

Tags: CMake VCPKG

Table of Contents

0.前言

​ 最近在做公司一个新的工程,对标海康的MVS, 基于GENICAM通用协议,目标是适配市场上众多的厂牌的基于GENICAM协议的相机。 由于预计到会引用很多开源项目,且会围绕相机扩展很多公司的业务功能。所以我重新设计了新软件总体的架构,由原来的qmake改为cmake,并使用插件式开发。这即方便于引用其他开源框架,也可以使公司的代码模块化,更容易维护以及复用。但在众多开源模块与公司的模块,以及公司的不同的项目之间要如何处理依赖关系?如何科学的减少重复的工作?满地都是cmake + git submodule,我抬头却看到了vcpkg私有仓库。

1.随便聊聊

1.1 包管理器

​ python有pip, c#有nuget , java有maven, 基本上每一个语言都有一个亲妈背书的包管理器,可以递归解决项目依赖,但是c++没有。

​ 基于上面的问题以及等等,导致c++的包管理不好实现,长久以来,c++开发者如果需要采用其他开源项目,通常需要手动把 其他c++项目的源码,静态链接库,动态链接库集成到自己的项目里,在集成的过程中,往往不是顺利的,可能需要处理依赖关系,环境问题,编译选项问题。

1.2 Cmake

cmake的出现简化了这个过程, 它是一款跨平台c++项目的管工具, 可以很方便的把cmake工程集成到另一个cmake工程中,然后指定生成器,生成各种类型的构建工具的项目,如ninja,visual studio 等,,并且它可以枚举项目的依赖项目,但是它没有版本控制的能力,所以通常与git联合使用 。 目前基本主流的IDE都集成了cmake和git,并且c++开源项目大多数也是以cmake的方式组织工程,因此使用cmake+git可以方便的集成开源项目。这也是我想用cmake的原因之一,除此之外,只要项目没有相互依赖,不管所处何目录结点,cmake都支持并行构建(qmkae子目录构建完才会构建父目录),可以更好的利用多核计算机的性能。所以cmake已经足够好了,为什么还需要vcpkg?

​ 想像一下,你有一个巨大的项目,依赖关系比较复杂,如果说顶层项目是第0层,某个第1层的项目A依赖了开源库D,另一个第1层的项目B的第2层项目BA也依赖了项目D, 你如果不修改优化工程结构,你的项目目录里将存在两份D的源码,并且如果修改了其中一份D的代码,需要把它提交给他的父项目们,直到第0层,然后再到另一份D代码处,拉代码后,再一层一层的提交到第0层。这样别人拉取你的第0层代码时,才能简单的git submodule update --init --recursive,克隆下来。而项目中可能会出现多个D项目这样的存在,这意味着即使使用git submodule,也需要做很多重复工作 。 而vcpkg可以解决这种问题,甚至允许控制每份D的代码版本不一样。

1.3 vcpkg

​ vcpkg是微软推出的c++ 源码级别的跨平台包管理器。虽然vc开头,但不仅限于visual c++, 它基本上=git + cmake,但扩展了包管理器应该有的功能,可以方便的解决项目依赖问题,也可以方便切换依赖项目的ABI,Cpu架构,目标平台。 vcpkg有经典模式和清单模式两种模式。

可以看出 清单模式可以解决我在1.2第二段落中描述的问题。但拿来就用还是有一些局限性。以下两种情况

何以解忧,唯有搭建自己的vcpkg 仓库,这也是本文档想讲的内容(终于酝酿好氛围)

​ 除此这外,vcpkg相对于公司现在的项目管理,还有一个优点,就是减少二进制文件的提交,理论上只提交源码就行,install的时候,vcpkg会根据配置 使用git签出正确分支的源码,构建为本地的二进制文件

2. 搭建公司内私有vcpkg仓库

​ 目标是把开源的项目,如open cv之类的 以及公司的软件模块发布到私有仓库上。理论上,开源的库如果没有额外的修改,直接用vcpkg现有的库就行了,但因为我们在墙内,如果想提升vcpkg安装的速度, 我们最好还是把我们项目中用到的开源库迁移到公司内部git平台上,设置为镜像仓库,定时从github同步。 因此本小节,主要拆分为以下三个步骤

2.1 搭建vcpkg 私有仓库

参考

创建一个空的git repository

mkdir -p ~/source/repos/prism_registry && cd ~/source/repos/prism_registry
git init .

创建一个*** baseline.json*** 文件,放在根目录 versions目录

1
2
mkdir versions && cd versions
vim baseline.json

写入 下面的json内容

1
2
3
{
"default": {}
}

2.2 添加库到vcpkg私有仓库

这里主要演示添加github库 和非github库两种方式

虽然我们应该主要使用第二种方式

2.2.1 添加github仓库示例

不管想添加到vcpkg仓库的项目是不是来自github,都需要执行这两步

2.2.1.1 添加port

创建ports目录,在这里面编辑你想放到你vcpkg私有仓库的信息

例如我想把我的prism 库放到私有库,就在ports目录中再创建一个prism的文件夹

prism是一个只有头文件,且只依赖c++标准库的 c++库

1
mkdir -p ~/source/repos/prism_registry/ports/prism && cd ~/source/repos/prism_registry/ports/prism

然后在prism目录中创建文件 vcpkg.json ,把prism初始版本的信息写进去,因为我这个库没有依赖,所以没有写依赖项,如果有,在json里加"dependencies “:[]就行

1
2
3
4
5
6
{
  "name": "prism",
  "version": "1.0.0",
  "description": "a static reflect library of c++",
  "homepage": "https://github.com/nocanstillbb/prism"
}

同时把vcpkg.json也提交到prism存储库根目录

然后再在 ~/source/repos/prism_registry/ports/prism 中创建一个空的protfile.cmake

做到这一步,你的文件目录应该是这样的

../ prism_registry/ | .git/ | ports/ | | prism/ | | | protfile.cmake | | | vcpkg.json | versions/ | | baseline.json

测试vcpkg能不能正常识别这个json文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
$ cd ~/source/repos/prism_registry/prism_registry
$ vcpkg install prism --overlay-ports=ports/prism
Computing installation plan...
The following packages will be built and installed:
    prism:x64-windows -> 1.0.0 -- D:\source\repos\prism_registry/ports/prism
Detecting compiler hash for triplet x64-windows...
Restored 0 package(s) from C:\Users\kokbi\AppData\Local\vcpkg\archives in 155 us. Use --debug to see more details.
Installing 1/1 prism:x64-windows...
Building prism:x64-windows...
-- Installing port from location: D:\source\repos\prism_registry/ports/prism
CMake Error at scripts/ports.cmake:113 (message):
  Port is missing portfile:
  D:/source/repos/prism_registry/ports/prism/portfile.cmake

error: building prism:x64-windows failed with: BUILD_FAILED
Elapsed time to handle prism:x64-windows: 27 ms
Please ensure you're using the latest port files with `git pull` and `vcpkg update`.
Then check for known issues at:
    https://github.com/microsoft/vcpkg/issues?q=is%3Aissue+is%3Aopen+in%3Atitle+prism
You can submit a new issue at:
    https://github.com/microsoft/vcpkg/issues/new?title=[prism]+Build+error&body=Copy+issue+body+from+D%3A%2Fsource%2Frepos%2Fvcpkg%2Finstalled%2Fvcpkg%2Fissue_body.md

根据打印出来的信息,可以知道vcpkg安装时正确定位到port/prism/vcpkg.json了,只是protfile.cmake中是空的才导致安装失败了

接下来添加protfile.cmake内容

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

vcpkg_from_github(
  OUT_SOURCE_PATH SOURCE_PATH
  REPO nocanstillbb/prism
    REF e4cb55e02bfad354ba86d70f5555fe12d8f70d10
  SHA512 a9eebc68ed045ccac650950b5ba8b1f172fde8244856c4b5e0ac38977711f5e3bbfc305ec831c47787e4994d7faff4ef01bf525e589b140dff8a66b10febb6e6
  HEAD_REF master
)


#https://learn.microsoft.com/en-us/vcpkg/examples/packaging-github-repos
vcpkg_cmake_configure( SOURCE_PATH "${SOURCE_PATH}")
vcpkg_cmake_install()

#vcpkg_cmake_config_fixup(CONFIG_PATH lib/cmake/${PORT})
#vcpkg_cmake_config_fixup()
vcpkg_fixup_pkgconfig()
vcpkg_copy_pdbs()

file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug")

file(
  INSTALL "${SOURCE_PATH}/LICENSE"
  DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}"
  RENAME copyright)
file(
  INSTALL "${SOURCE_PATH}/usage"
  DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}")

其中的shar512是下载的源码归档包的sha512校验和的值,可以自己下载下来校验,填写进去,也可以先写一个0,安装时会安装失败,但会把真正的值打印出来。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
$ vcpkg install prism --overlay-ports=ports/prism
Computing installation plan...
The following packages will be built and installed:
    prism:x64-windows -> 1.0.0 -- D:\source\repos\prism_registry/ports/prism
Detecting compiler hash for triplet x64-windows...
-- Using HTTP(S)_PROXY in environment variables.
Restored 0 package(s) from C:\Users\kokbi\AppData\Local\vcpkg\archives in 171 us. Use --debug to see more details.
Installing 1/1 prism:x64-windows...
Building prism:x64-windows...
-- Installing port from location: D:\source\repos\prism_registry/ports/prism
-- Downloading https://github.com/nocanstillbb/prism/archive/59fc49ca76338364c6351475a4ad5d80578f625.tar.gz -> nocanstillbb-prism-59fc49ca76338364c6351475a4ad5d80578f625.tar.gz...
[DEBUG] To include the environment variables in debug output, pass --debug-env
[DEBUG] Trying to load bundleconfig from D:\source\repos\vcpkg\vcpkg-bundle.json
[DEBUG] Failed to open: D:\source\repos\vcpkg\vcpkg-bundle.json
[DEBUG] Bundle config: readonly=false, usegitregistry=false, embeddedsha=nullopt, deployment=Git, vsversion=nullopt
[DEBUG] Metrics enabled.
[DEBUG] Feature flag 'binarycaching' unset
[DEBUG] Feature flag 'compilertracking' unset
[DEBUG] Feature flag 'registries' unset
[DEBUG] Feature flag 'versions' unset
Downloading https://github.com/nocanstillbb/prism/archive/59fc49ca76338364c6351475a4ad5d80578f625.tar.gz
[DEBUG] Trying to hash D:\source\repos\vcpkg\downloads\nocanstillbb-prism-59fc49ca76338364c6351475a4ad5d80578f625.tar.gz.18080.part
[DEBUG] D:\source\repos\vcpkg\downloads\nocanstillbb-prism-59fc49ca76338364c6351475a4ad5d80578f625.tar.gz.18080.part has hash f03d4c918e5bda46cc1aa129edd192a74274b9c07f6634dedec47b986aad6e0e8689b019620c57507e07fea36adaf9dfbff9b41fcc166da5f0748a3a9d491529
error: Failed to download from mirror set
error: File does not have the expected hash:
url: https://github.com/nocanstillbb/prism/archive/59fc49ca76338364c6351475a4ad5d80578f625.tar.gz
File: D:\source\repos\vcpkg\downloads\nocanstillbb-prism-59fc49ca76338364c6351475a4ad5d80578f625.tar.gz.18080.part
Expected hash: 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Actual hash: f03d4c918e5bda46cc1aa129edd192a74274b9c07f6634dedec47b986aad6e0e8689b019620c57507e07fea36adaf9dfbff9b41fcc166da5f0748a3a9d491529

把Actual hash复制下来写到portfile.cmake 重新测试安装

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
$ vcpkg install prism --overlay-ports=ports/prism
Computing installation plan...
The following packages will be built and installed:
    prism:x64-windows -> 1.0.0 -- D:\source\repos\prism_registry\ports/prism
Detecting compiler hash for triplet x64-windows...
-- Using HTTP(S)_PROXY in environment variables.
Restored 1 package(s) from C:\Users\kokbi\AppData\Local\vcpkg\archives in 44 ms. Use --debug to see more details.
Installing 1/1 prism:x64-windows...
Elapsed time to handle prism:x64-windows: 30.2 ms
Total install time: 30.3 ms
The package prism usage:

    find_package(prism::prism)
    target_include_directories(main INTERFACE ${PRISM_INCLUDE_DIRS})

    more infomation: https://github.com/nocanstillbb/prism

好的项目,安装后不会提示警告和错误,如果这里有提示警告的话,就会提示一个错误,提示你如果要让库被收录到vcpkg的优选目录,要更正portfile.cmake消除这些错误和警告。

正常这里还应该在安装之前执行一下项目的单元测试,这个先不管,不是必须的。接下来测试一下刚才安装的库能不能正常使用,先用vcpkg list查看信息

1
2
PS D:\Downloads> vcpkg list |findstr prism
prism:x64-windows                                 1.0.0               a static reflect library of c++

然后我把我项目中prism源码目录移除后,用ide查看引用时,已经正确定位到vcpkg的安装目录了

image-20231003181231934

编译也没有问题,说明成功了。

2.2.1.2 添加versions

接下来添加version相关的信息

prism_registry/versions 中创建以你的存储库名称头一个字母+ “-”开关的目录, 添加的库是prism,所以创建的目录为p-

1
2
3
mkdir -p ~/source/repos/prism_registry/versions/p-
cd ~/source/repos/prism_registry/versions/p-
vim prism.json

创建prism.json文件写入

1
2
3
4
5
6
7
8
{
  "versions": [
    {
      "version": "1.0.0",
      "git-tree": ""
    }
  ]
}

git-tree 的值如此获取

1
2
git add ports/prism
git commit -m "[prism] new port"

单独提交prism的ports目录, 提交内容以[portName]开头,如果你想要合并到vcpkg master的话,这个是规则之一

然后 先不着急提交

1
git rev-parse HEAD:prots/prism

获取git分支HEAD上的git 目录的分支号,写入/versions/p-/prism.json中,刚才放空的git-tree

然后编辑 versions/baseline.json

1
2
3
4
5
6
7
8
{
  "default": {
    "prism": {
      "baseline": "1.0.0",
      "port-version": 0
    }
  }
}

然后把prism_registry 提交推送到公司forgejo上

2.2.2 添加非github的库示例

上面的示例是vcpkg团队博客上的示例,所以用 vcpkg_from_github导入的,而我们私有的代码库是放在公司forgejo服务器上的,所以应该探索一种通用的方法,我查看vcpkg源码里的Ports,看到有的库使用的是vcpkg_from_git

1
2
3
4
5
6
7
    vcpkg_from_git(
        OUT_SOURCE_PATH LSS_SOURCE_PATH
        URL https://chromium.googlesource.com/linux-syscall-support
        REF 7bde79cc274d06451bf65ae82c012a5d3e476b5a
    )

    file(RENAME "${LSS_SOURCE_PATH}" "${SOURCE_PATH}/src/third_party/lss")

和带git补丁的写法

1
2
3
4
5
6
7
vcpkg_from_git(
    OUT_SOURCE_PATH SOURCE_PATH
    URL https://sourceware.org/git/elfutils
    REF ca4a785fc3061c7d136b198e9ffe0b14cf90c2be #elfutils-0.186

    PATCHES configure.ac.patch
)

除此之外没有什么区别, 反而少了sha512 检验的步骤,更简单了

2.2.3 用vcpkg的简化添加version步骤

添加完port 并提交到git后,可以使用这个方式简单的更新version和baseline.json

如果是在微软vcpkg 叉出来的分支上,添加了使用git添加了ports/prism后,就可以使用x-add-version --all来生成 version/p-/prism.json 以及 version/baseline.json中的prism的条目

如果不是vcpkg叉出来的分支,而是公司的私有库的话,参照教程:使用 Git 将包发布到私有 vcpkg 注册表 |Microsoft学习 加点参数也可以使用这个工具

1
vcpkg --x-builtin-ports-root=./ports --x-builtin-registry-versions-dir=./versions x-add-version --all --verbose

了解这个工具,如果需要ci集成的话,就会方便很多

2.3 在项目中使用私有的vcpkg仓库

首先我在公司的forgejo上开了一个空的存储库,把 vcpkg私有仓库上传上去

然后在测试项目的根目录创建vcpkg-configuration.json

基于github的vcpkg ,扩展我们私有的库, 这种是比较合理的,如果需要对github上的库做定制化修改,只需要把库迁移到内网就行

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{
    "default-registry": {
        "kind": "git",
        "repository": "https://github.com/microsoft/vcpkg",
        "baseline": "0da9fe986d07603da71f35ef8dd55512154a64bd"
    },
    "registries": [
        {
            "kind": "git",
            "repository": "http://10.1.8.8/AL/dv-vcpkg",
            "baseline": "36f0728c26661f67fca9b583bd99084e9491be93",
            "packages": [ "prism" ]
        }
    ]
}

baseline是vcpkg仓库的提交,一般建立一个项目时,初始化的时候更新一下就可以了,后继修改个别的库,可以通过指定库版本,或重写库版本的方式,使项目大部分的引用的库都是稳定的。

关于vcpkg版本控制 可以参考这个文档Versioning reference | Microsoft Learn

然后创建一个vcpkg.json

1
2
3
4
5
6
7
{
    "name": "prismqt-core",
    "version": "0",
    "dependencies": [
        "prism"
    ]
}

这里的prism没有指定任何版本,所以 会从我们私有库的基本版本中获取默认的版本

在测试项目根目录建立好这两个json后, 执行vcpkg install

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
$ vcpkg.exe  install
Detecting compiler hash for triplet x64-windows...
-- Using %HTTP(S)_PROXY% in environment variables.
The following packages will be rebuilt:
  * catch2:x64-windows -> 3.4.0 -- C:\Users\user\AppData\Local\vcpkg\registries\git-trees\5796c1c0513a7b49f135e8acdd1976f53e9944ea
  * vcpkg-cmake:x64-windows -> 2023-05-04 -- C:\Users\user\AppData\Local\vcpkg\registries\git-trees\88a7058fc7fa73a9c4c99cfcae9d79e2abf87a5a
  * vcpkg-cmake-config:x64-windows -> 2022-02-06#1 -- C:\Users\user\AppData\Local\vcpkg\registries\git-trees\8d54cc4f487d51b655abec5f9c9c3f86ca83311f
The following packages will be built and installed:
    prism:x64-windows -> 1.0.0 -- C:\Users\user\AppData\Local\vcpkg\registries\git-trees\668c45ba147cbef160d9c228712f5775cff242b2
Additional packages (*) will be modified to complete this operation.
Restored 3 package(s) from C:\Users\user\AppData\Local\vcpkg\archives in 1.3 s. Use --debug to see more details.
Removing 1/7 catch2:x64-windows
Elapsed time to handle catch2:x64-windows: 217 ms
Removing 2/7 vcpkg-cmake-config:x64-windows
Elapsed time to handle vcpkg-cmake-config:x64-windows: 98 ms
Removing 3/7 vcpkg-cmake:x64-windows
Elapsed time to handle vcpkg-cmake:x64-windows: 113 ms
Installing 4/7 vcpkg-cmake:x64-windows...
Elapsed time to handle vcpkg-cmake:x64-windows: 16 ms
Installing 5/7 vcpkg-cmake-config:x64-windows...
Elapsed time to handle vcpkg-cmake-config:x64-windows: 16.5 ms
Installing 6/7 catch2:x64-windows...
Elapsed time to handle catch2:x64-windows: 58.2 ms
Installing 7/7 prism:x64-windows...
Building prism:x64-windows...
-- Installing port from location: C:\Users\user\AppData\Local\vcpkg\registries\git-trees\668c45ba147cbef160d9c228712f5775cff242b2
-- Using cached D:/Users/user/Documents/source/repos/vcpkg/downloads/prism-62156a21f843168993c8e641f22efb380b8e7e62.tar.gz
-- Cleaning sources at D:/Users/user/Documents/source/repos/vcpkg/buildtrees/prism/src/380b8e7e62-68fffb19a4.clean. Use --editable to skip cleaning for the packages you specify.
-- Extracting source D:/Users/user/Documents/source/repos/vcpkg/downloads/prism-62156a21f843168993c8e641f22efb380b8e7e62.tar.gz
-- Using source at D:/Users/user/Documents/source/repos/vcpkg/buildtrees/prism/src/380b8e7e62-68fffb19a4.clean
-- Found external ninja('1.10.2').
-- Configuring x64-windows
-- Building x64-windows-dbg
-- Building x64-windows-rel
-- Using cached mingw-w64-i686-pkgconf-1~1.8.0-2-any.pkg.tar.zst.
-- Using cached msys2-msys2-runtime-3.4.6-1-x86_64.pkg.tar.zst.
-- Using msys root at D:/Users/user/Documents/source/repos/vcpkg/downloads/tools/msys2/6f3fa1a12ef85a6f
-- Installing: D:/Users/user/Documents/source/repos/vcpkg/packages/prism_x64-windows/share/prism/copyright
-- Installing: D:/Users/user/Documents/source/repos/vcpkg/packages/prism_x64-windows/share/prism/usage
-- Performing post-build validation
Stored binaries in 1 destinations in 58.6 ms.
Elapsed time to handle prism:x64-windows: 21 s
Total install time: 21 s
The package prism usage:

    find_package(prism::prism)
    target_include_directories(main INTERFACE ${PRISM_INCLUDE_DIRS})

    more infomation: https://github.com/nocanstillbb/prism

依赖全部安装完毕,我们只需要把所有依赖列到顶层项目上,就可以用vcpkg安装所有依赖,更新所有依赖,也可以利用vcpkg的版本控制功能来管理依赖, 这样git分支只需要保留一个master分支就可以了,所有依赖的版本可以用根目录的vcpkg.json来控制和查看

>> Home

Comments