自定义vcpkg注册表

vcpkg提供自定义注册表的功能,主要用途可以是:公司私有库的注册表,自己对官方port的补充但是目前还不想提交到官方的port以及自己和官方对同一个库有不同的构建意见。

在自定义注册表中新建port

尽管我经常说vcpkg的本质是git和cmake的组合使用,但其实vcpkg还提供了vcpkg.exe和一整套相关的脚本,如果单纯按照官方博客所说的只建立一个vcpkg注册表且只包含ports和versions两个文件夹,使用是没有问题的,但是在创建过程中没法使用官方vcpkg已经提供的脚本了(create format 和 add version)。我能想到两种办法,一种是先在官方的vcpkg下利用官方脚本新增port调试然后拷贝到自定义注册表中,另一种就是在自己的注册表中实现一套脚本。

利用官方vcpkg新增port

CGraph为例, 先切一个官方vcpkg的分支

git checkout -b feature_add_cgraph

vcpkg.exe提供了相当多的脚本,但是create的命令只能适用于利用压缩包创建的情况

vcpkg create <port-name> <url-to-source> [archive-file-name]

vcpkg create cgraph https://github.com/ChunelFeng/CGraph/archive/refs/tags/v2.5.4.tar.gz cgraph-2.5.4.tar.gz

生成的模板为
portfile.cmake

# Common Ambient Variables:
#   CURRENT_BUILDTREES_DIR    = ${VCPKG_ROOT_DIR}\buildtrees\${PORT}
#   CURRENT_PACKAGES_DIR      = ${VCPKG_ROOT_DIR}\packages\${PORT}_${TARGET_TRIPLET}
#   CURRENT_PORT_DIR          = ${VCPKG_ROOT_DIR}\ports\${PORT}
#   CURRENT_INSTALLED_DIR     = ${VCPKG_ROOT_DIR}\installed\${TRIPLET}
#   DOWNLOADS                 = ${VCPKG_ROOT_DIR}\downloads
#   PORT                      = current port name (zlib, etc)
#   TARGET_TRIPLET            = current triplet (x86-windows, x64-windows-static, etc)
#   VCPKG_CRT_LINKAGE         = C runtime linkage type (static, dynamic)
#   VCPKG_LIBRARY_LINKAGE     = target library linkage type (static, dynamic)
#   VCPKG_ROOT_DIR            = <C:\path\to\current\vcpkg>
#   VCPKG_TARGET_ARCHITECTURE = target architecture (x64, x86, arm)
#   VCPKG_TOOLCHAIN           = ON OFF
#   TRIPLET_SYSTEM_ARCH       = arm x86 x64
#   BUILD_ARCH                = "Win32" "x64" "ARM"
#   DEBUG_CONFIG              = "Debug Static" "Debug Dll"
#   RELEASE_CONFIG            = "Release Static"" "Release DLL"
#   VCPKG_TARGET_IS_WINDOWS
#   VCPKG_TARGET_IS_UWP
#   VCPKG_TARGET_IS_LINUX
#   VCPKG_TARGET_IS_OSX
#   VCPKG_TARGET_IS_FREEBSD
#   VCPKG_TARGET_IS_ANDROID
#   VCPKG_TARGET_IS_MINGW
#   VCPKG_TARGET_EXECUTABLE_SUFFIX
#   VCPKG_TARGET_STATIC_LIBRARY_SUFFIX
#   VCPKG_TARGET_SHARED_LIBRARY_SUFFIX
#
# 	See additional helpful variables in /docs/maintainers/vcpkg_common_definitions.md

# Also consider vcpkg_from_* functions if you can; the generated code here is for any web accessable
# source archive.
#  vcpkg_from_github
#  vcpkg_from_gitlab
#  vcpkg_from_bitbucket
#  vcpkg_from_sourceforge
vcpkg_download_distfile(ARCHIVE
    URLS "https://github.com/ChunelFeng/CGraph/archive/refs/tags/v2.5.4.tar.gz"
    FILENAME "cgraph-2.5.4.tar.gz"
    SHA512 b52e6c8387eb56b02acf5f4d5ae76104885feb7da69fed833967b7fcfea41755d3a9f7c9d4c8edc3356c0df9c3ef036ab191b85c5b889add3c8b4467fb78d4c9
)

vcpkg_extract_source_archive_ex(
    OUT_SOURCE_PATH SOURCE_PATH
    ARCHIVE "${ARCHIVE}"
    # (Optional) A friendly name to use instead of the filename of the archive (e.g.: a version number or tag).
    # REF 1.0.0
    # (Optional) Read the docs for how to generate patches at:
    # https://github.com/microsoft/vcpkg-docs/blob/main/vcpkg/examples/patching.md
    # PATCHES
    #   001_port_fixes.patch
    #   002_more_port_fixes.patch
)

# # Check if one or more features are a part of a package installation.
# # See /docs/maintainers/vcpkg_check_features.md for more details
# vcpkg_check_features(OUT_FEATURE_OPTIONS FEATURE_OPTIONS
#   FEATURES
#     tbb   WITH_TBB
#   INVERTED_FEATURES
#     tbb   ROCKSDB_IGNORE_PACKAGE_TBB
# )

vcpkg_cmake_configure(
    SOURCE_PATH "${SOURCE_PATH}"
    # OPTIONS -DUSE_THIS_IN_ALL_BUILDS=1 -DUSE_THIS_TOO=2
    # OPTIONS_RELEASE -DOPTIMIZE=1
    # OPTIONS_DEBUG -DDEBUGGABLE=1
)

vcpkg_cmake_install()

# # Moves all .cmake files from /debug/share/cgraph/ to /share/cgraph/
# # See /docs/maintainers/ports/vcpkg-cmake-config/vcpkg_cmake_config_fixup.md for more details
# When you uncomment "vcpkg_cmake_config_fixup()", you need to add the following to "dependencies" vcpkg.json:
#{
#    "name": "vcpkg-cmake-config",
#    "host": true
#}
# vcpkg_cmake_config_fixup()

# Uncomment the line below if necessary to install the license file for the port
# as a file named `copyright` to the directory `${CURRENT_PACKAGES_DIR}/share/${PORT}`
# vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE")

vcpkg.json

{
  "name": "cgraph",
  "version": "",
  "homepage": "",
  "description": "",
  "license": "",
  "dependencies": [
    {
      "name": "vcpkg-cmake",
      "host": true
    }
  ],

  "default-features": [],
  "features": {
    "example-feature": {
      "description": "",
      "dependencies": []
    }
  }
}

可以看到在portfile.cmake中源码来源有五种途径

#  vcpkg_from_github
#  vcpkg_from_gitlab
#  vcpkg_from_bitbucket
#  vcpkg_from_sourceforge
vcpkg_download_distfile

脚本自动生成了SHA512码

SHA512 b52e6c8387eb56b02acf5f4d5ae76104885feb7da69fed833967b7fcfea41755d3a9f7c9d4c8edc3356c0df9c3ef036ab191b85c5b889add3c8b4467fb78d4c9

SHA-512是一种加密算法,用于计算文件的哈希值。vcpkg使用SHA-512哈希值来验证下载的软件包的完整性,以确保它们没有被篡改或损坏。vcpkg hash命令可以单独生成。

接着简单完善一下vcpkg.json相关内容,

{
  "name": "cgraph",
  "version": "2.5.4",
  "homepage": "www.chunel.cn",
  "description": "CGraph is a cross-platform Directed Acyclic Graph framework based on pure C++ without any 3rd-party dependencies.",
  "license": "MIT",
  "dependencies": [
    {
      "name": "vcpkg-cmake",
      "host": true
    }
  ],

  "default-features": [],
  "features": {
    "example-feature": {
      "description": "",
      "dependencies": []
    }
  }
}

接着直接添加一下version看看效果

PS C:\src\vcpkg> git add ports/cgraph/
PS C:\src\vcpkg> git commit -m "add port"
PS C:\src\vcpkg> .\vcpkg.exe x-add-version cgraph

报错

error: cgraph is not properly formatted
Run `vcpkg format-manifest "C:\src\vcpkg\ports\cgraph\vcpkg.json"` to format the file
Don't forget to commit the result!

说明vcpkg.json刚刚格式不对,可能是空格问题,直接按提示使用格式化脚本

PS C:\src\vcpkg> ./vcpkg.exe format-manifest  "C:\src\vcpkg\ports\cgraph\vcpkg.json"
PS C:\src\vcpkg> .\vcpkg.exe x-add-version cgraph

versions文件夹中的内容生成完毕

added version 2.5.4 to C:\src\vcpkg\versions\c-\cgraph.json (new file)
added version 2.5.4 to C:\src\vcpkg\versions\baseline.json

执行安装看看效果,这里就是在执行一般的cmake编译过程,虽然大概率会报错。

PS C:\src\vcpkg> .\vcpkg.exe install cgraph

确实报错了

CMake Error at scripts/cmake/vcpkg_execute_build_process.cmake:134 (message):
    Command failed: "C:/Program Files/CMake/bin/cmake.exe" --build . --config Debug --target install -- -v -j9
    Working Directory: C:/src/vcpkg/buildtrees/cgraph/x64-windows-dbg
    See logs for more information:
      C:\src\vcpkg\buildtrees\cgraph\install-x64-windows-dbg-out.log
      C:\src\vcpkg\buildtrees\cgraph\install-x64-windows-dbg-err.log

根据提示查看日志定位问题
ninja: error: unknown target 'install'
查看CGraph 2.5.4的源代码,是的,CGraph的cmake没有提供install部分的内容。vcpkg的理想cmake工程是编译选项清晰,依赖库独立,包含find_packge,add_library,install的modern cmake工程,但是目前很多工程是“将自己作为源代码嵌入用户工程”或者“将依赖库源码嵌入自己”为导向的,这些都造成了必须打补丁的问题。针对这种情况需要自己通过补丁重写部分源代码的cmake内容,使其适配vcpkg的编译机制。

编写补丁

进入本地仓库切到v2.5.4的分支,改写cmake编译相关的部分。修改后的版本

生成补丁文件

git diff v2.5.4 v2.5.4_modify_cmake --binary > cmake.patch

将cmake.patch放到port中

portfile.cmake中加上添加patch,纠正include和share路径以及许可证路径的配置,最终版本:

# Common Ambient Variables:
#   CURRENT_BUILDTREES_DIR    = ${VCPKG_ROOT_DIR}\buildtrees\${PORT}
#   CURRENT_PACKAGES_DIR      = ${VCPKG_ROOT_DIR}\packages\${PORT}_${TARGET_TRIPLET}
#   CURRENT_PORT_DIR          = ${VCPKG_ROOT_DIR}\ports\${PORT}
#   CURRENT_INSTALLED_DIR     = ${VCPKG_ROOT_DIR}\installed\${TRIPLET}
#   DOWNLOADS                 = ${VCPKG_ROOT_DIR}\downloads
#   PORT                      = current port name (zlib, etc)
#   TARGET_TRIPLET            = current triplet (x86-windows, x64-windows-static, etc)
#   VCPKG_CRT_LINKAGE         = C runtime linkage type (static, dynamic)
#   VCPKG_LIBRARY_LINKAGE     = target library linkage type (static, dynamic)
#   VCPKG_ROOT_DIR            = <C:\path\to\current\vcpkg>
#   VCPKG_TARGET_ARCHITECTURE = target architecture (x64, x86, arm)
#   VCPKG_TOOLCHAIN           = ON OFF
#   TRIPLET_SYSTEM_ARCH       = arm x86 x64
#   BUILD_ARCH                = "Win32" "x64" "ARM"
#   DEBUG_CONFIG              = "Debug Static" "Debug Dll"
#   RELEASE_CONFIG            = "Release Static"" "Release DLL"
#   VCPKG_TARGET_IS_WINDOWS
#   VCPKG_TARGET_IS_UWP
#   VCPKG_TARGET_IS_LINUX
#   VCPKG_TARGET_IS_OSX
#   VCPKG_TARGET_IS_FREEBSD
#   VCPKG_TARGET_IS_ANDROID
#   VCPKG_TARGET_IS_MINGW
#   VCPKG_TARGET_EXECUTABLE_SUFFIX
#   VCPKG_TARGET_STATIC_LIBRARY_SUFFIX
#   VCPKG_TARGET_SHARED_LIBRARY_SUFFIX
#
# 	See additional helpful variables in /docs/maintainers/vcpkg_common_definitions.md

# Also consider vcpkg_from_* functions if you can; the generated code here is for any web accessable
# source archive.
#  vcpkg_from_github
#  vcpkg_from_gitlab
#  vcpkg_from_bitbucket
#  vcpkg_from_sourceforge
vcpkg_download_distfile(ARCHIVE
    URLS "https://github.com/ChunelFeng/CGraph/archive/refs/tags/v2.5.4.tar.gz"
    FILENAME "cgraph-2.5.4.tar.gz"
    SHA512 b52e6c8387eb56b02acf5f4d5ae76104885feb7da69fed833967b7fcfea41755d3a9f7c9d4c8edc3356c0df9c3ef036ab191b85c5b889add3c8b4467fb78d4c9
)

vcpkg_extract_source_archive_ex(
    OUT_SOURCE_PATH SOURCE_PATH
    ARCHIVE "${ARCHIVE}"
    # (Optional) A friendly name to use instead of the filename of the archive (e.g.: a version number or tag).
    # REF 1.0.0
    # (Optional) Read the docs for how to generate patches at:
    # https://github.com/microsoft/vcpkg-docs/blob/main/vcpkg/examples/patching.md
    PATCHES
       cmake.patch
    #   002_more_port_fixes.patch
)

# # Check if one or more features are a part of a package installation.
# # See /docs/maintainers/vcpkg_check_features.md for more details
# vcpkg_check_features(OUT_FEATURE_OPTIONS FEATURE_OPTIONS
#   FEATURES
#     tbb   WITH_TBB
#   INVERTED_FEATURES
#     tbb   ROCKSDB_IGNORE_PACKAGE_TBB
# )

vcpkg_cmake_configure(
    SOURCE_PATH "${SOURCE_PATH}"
    # OPTIONS -DUSE_THIS_IN_ALL_BUILDS=1 -DUSE_THIS_TOO=2
    # OPTIONS_RELEASE -DOPTIMIZE=1
    # OPTIONS_DEBUG -DDEBUGGABLE=1
)

vcpkg_cmake_install()

# # Moves all .cmake files from /debug/share/cgraph/ to /share/cgraph/
# # See /docs/maintainers/ports/vcpkg-cmake-config/vcpkg_cmake_config_fixup.md for more details
# When you uncomment "vcpkg_cmake_config_fixup()", you need to add the following to "dependencies" vcpkg.json:
#{
#    "name": "vcpkg-cmake-config",
#    "host": true
#}
vcpkg_cmake_config_fixup()

# this one you just need to have, and sometimes you'll need to delete even more things
# feels like a crutch, but okay
file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include")

# Uncomment the line below if necessary to install the license file for the port
# as a file named `copyright` to the directory `${CURRENT_PACKAGES_DIR}/share/${PORT}`
vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE")

好了,这时候需要的文件已经都准备好了,但是因为我自己的注册表没有写工具脚本,我还在官方vcpkg文件夹中,所以还需要拷贝到自己的注册表本地仓库,version/c-/cgraph中的git-tree代表添加port之后,port/cgraph目录下的所有文件的哈希值,这可以用于比较不同版本的文件的变化或者创建补丁文件,之前的x-add-version就是在执行这个刷新操作,这里得用git命令重新生成一下:

git rev-parse HEAD:./ports/cgraph

至此,自定义注册表中cgraph就添加完成了

创建自己的vcpkg脚本

自定义注册表使用官方工具比较麻烦,此处使用大佬luncliff的脚本,主要用来完成检查格式和生成version的步骤

registry-format.ps1

<#
.SYNOPSIS
    PowerShell script to lint vcpkg.json under the registry's 'ports' folder
.DESCRIPTION
    Runs vcpkg executable and manipulates existing vcpkg.json files.

.LINK
    https://github.com/microsoft/vcpkg
    https://github.com/microsoft/vcpkg-tool/blob/2023-06-15/include/vcpkg/vcpkgcmdarguments.h

.PARAMETER VcpkgRoot
    The root folder to find vcpkg.exe program
.PARAMETER RegistryRoot
    Root folder of the vcpkg registry.
    If not provided, use "${VcpkgRoot}/vcpkg-registry"

.EXAMPLE
    PS> registry-format.ps1 -VcpkgRoot $env:VCPKG_ROOT
    Succeeded in formatting the manifest files.
.EXAMPLE
    PS> registry-format.ps1 -VcpkgRoot "D:/vcpkg" -RegistryRoot $(Get-Location)
    Succeeded in formatting the manifest files.
.EXAMPLE
    PS> registry-format.ps1 -VcpkgRoot $env:VCPKG_ROOT -RegistryRoot "D:/test-registry"
    Line |
      46 |      throw New-Object -TypeName ArgumentException "RegistryRoot doesn' …
         |      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
         | RegistryRoot doesn't exist
#>
using namespace System
param
(
    [Parameter(Mandatory = $true)][String]$VcpkgRoot,
    [String]$RegistryRoot
)

# VcpkgRoot
[Boolean]$RootExists = $(Test-Path -Path $VcpkgRoot)
if ($RootExists -eq $false) {
    throw New-Object -TypeName ArgumentException "VcpkgRoot doesn't exist"
}
${env:Path} = "$VcpkgRoot;${env:Path}"

# RegistryRoot
if ($RegistryRoot.Length -eq 0) {
    $RegistryRoot = (Join-Path -Path $VcpkgRoot "vcpkg-registry")
    Write-Debug "RegistryRoot=${RegistryRoot}"
}
[Boolean]$RegistryExists = $(Test-Path -Path $RegistryRoot)
if ($RegistryExists -eq $false) {
    throw New-Object -TypeName ArgumentException "RegistryRoot doesn't exist"
}

function RunVersion() {
    [String]$Description = $(vcpkg version)
    Write-Debug -Message $Description
}

function RunConvert([String]$PortRoot) {
    vcpkg format-manifest --all --convert-control `
        --vcpkg-root="$VcpkgRoot" `
        --x-builtin-ports-root="$PortRoot"
}

function RunFormat([String]$PortRoot, [String]$VersionRoot) {
    Write-Debug "PortRoot=${PortRoot}"
    Write-Debug "VersionRoot=${VersionRoot}"
    vcpkg format-manifest --all `
        --vcpkg-root="$VcpkgRoot" `
        --x-builtin-ports-root="$PortRoot" `
        --x-builtin-registry-versions-dir="$VersionRoot"
}

RunVersion
# RunConvert -PortRoot $(Join-Path $RegistryRoot "ports") 
RunFormat -PortRoot $(Join-Path $RegistryRoot "ports") -VersionRoot $(Join-Path $RegistryRoot "versions")

registry-add-version.ps1

<#
.SYNOPSIS
    PowerShell script to modify JSON files under the registry's 'versions' folder
.DESCRIPTION
    Runs vcpkg executable and update baseline/version JSON files.

.EXAMPLE
    PS> registry-add-version.ps1 -PortNmae "openssl" -VcpkgRoot $env:VCPKG_ROOT 
.EXAMPLE
    PS> registry-add-version.ps1 "openssl" -VcpkgRoot $env:VCPKG_ROOT 
    version 1.1.1t is already in C:\vcpkg\vcpkg-registry\versions\o-\openssl1.json
    version 1.1.1t is already in C:\vcpkg\vcpkg-registry\versions\baseline.json
    No files were updated for openssl1
#>
using namespace System
param
(
    [Parameter(Position = 0, Mandatory = $true)][String]$PortName,
    [Parameter(Mandatory = $true)][String]$VcpkgRoot,
    [String]$RegistryRoot
)

# VcpkgRoot
[Boolean]$RootExists = $(Test-Path -Path $VcpkgRoot)
if ($RootExists -eq $false) {
    throw New-Object -TypeName ArgumentException "VcpkgRoot doesn't exist"
}
${env:Path} = "$VcpkgRoot;${env:Path}"

# RegistryRoot
if ($RegistryRoot.Length -eq 0) {
    $RegistryRoot = (Join-Path -Path $VcpkgRoot "vcpkg-registry")
    Write-Debug "RegistryRoot=${RegistryRoot}"
}
[Boolean]$RegistryExists = $(Test-Path -Path $RegistryRoot)
if ($RegistryExists -eq $false) {
    throw New-Object -TypeName ArgumentException "RegistryRoot doesn't exist"
}

function RunAddVersion([String]$PortName, [String]$PortRoot, [String]$VersionRoot) {
    vcpkg x-add-version $PortName `
        --overwrite-version `
        --vcpkg-root="$VcpkgRoot" `
        --x-builtin-ports-root="$PortRoot" `
        --x-builtin-registry-versions-dir="$VersionRoot"
}

RunAddVersion -PortName $PortName -PortRoot $(Join-Path $RegistryRoot "ports") -VersionRoot $(Join-Path $RegistryRoot "versions")
posted @ 2024-01-22 10:32  七小丘人  阅读(258)  评论(0)    收藏  举报