diff --git a/.gitignore b/.gitignore index 87bac4fd..a1a607e6 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,5 @@ bin/ obj/ .vs/ +libssh2-wincng-manifest/ +libssh2-wincng-installed/ diff --git a/Dockerfile.linux b/Dockerfile.linux index 1f0feec4..104f2c93 100644 --- a/Dockerfile.linux +++ b/Dockerfile.linux @@ -6,6 +6,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ pkg-config \ ca-certificates \ git \ + libssl-dev \ + libssh2-1-dev \ && rm -rf /var/lib/apt/lists/* WORKDIR /nativebinaries diff --git a/Dockerfile.linux-musl b/Dockerfile.linux-musl index 95876143..88cf1bf8 100644 --- a/Dockerfile.linux-musl +++ b/Dockerfile.linux-musl @@ -1,6 +1,6 @@ FROM alpine:3.19 -RUN apk add --no-cache bash build-base cmake +RUN apk add --no-cache bash build-base cmake openssl-dev libssh2-dev WORKDIR /nativebinaries COPY . /nativebinaries/ diff --git a/build.libgit2.ps1 b/build.libgit2.ps1 index 9c86db2c..3ff79d85 100644 --- a/build.libgit2.ps1 +++ b/build.libgit2.ps1 @@ -29,7 +29,7 @@ $x86Directory = Join-Path $projectDirectory "nuget.package\runtimes\win-x86\nati $x64Directory = Join-Path $projectDirectory "nuget.package\runtimes\win-x64\native" $arm64Directory = Join-Path $projectDirectory "nuget.package\runtimes\win-arm64\native" $hashFile = Join-Path $projectDirectory "nuget.package\libgit2\libgit2_hash.txt" -$sha = Get-Content $hashFile +$sha = Get-Content $hashFile $binaryFilename = "git2-" + $sha.Substring(0,7) $build_tests = 'OFF' @@ -101,6 +101,56 @@ function Assert-Consistent-Naming($expected, $path) { Ensure-Property $expected $dll.VersionInfo.OriginalFilename "VersionInfo.OriginalFilename" $dll.Fullname } +function Install-Libssh2($arch) { + $triplet = "$arch-windows" + + $vcpkg = Join-Path $Env:VCPKG_INSTALLATION_ROOT "vcpkg.exe" + if (-not (Test-Path $vcpkg)) { + throw "Error: vcpkg not found at $Env:VCPKG_INSTALLATION_ROOT" + } + + # Install libssh2 with the WinCNG crypto backend (no OpenSSL dependency). + # 'openssl' is a default vcpkg feature for libssh2, so manifest mode is required + # to override it — classic mode has no --no-default-features flag. + # The overlay triplet injects -DENABLE_ECDSA_WINCNG=ON into every package's + # cmake configure step (zlib ignores it; libssh2 uses it). + $manifestDir = Join-Path $projectDirectory "libssh2-wincng-manifest" + New-Item -ItemType Directory -Force -Path $manifestDir | Out-Null + @" +{ + "name": "libssh2-wincng", + "version": "1.0.0", + "dependencies": [ + { + "name": "libssh2", + "default-features": false, + "features": ["zlib"] + } + ] +} +"@ | Set-Content (Join-Path $manifestDir "vcpkg.json") + + $installRoot = Join-Path $projectDirectory "libssh2-wincng-installed" + $overlayTriplets = Join-Path $projectDirectory "libssh2-wincng-triplets" + + Write-Host "Installing libssh2 (WinCNG + ECDSA) for $triplet via vcpkg..." + Push-Location $manifestDir + try { + Run-Command -Fatal -Quiet { & $vcpkg install --vcpkg-root $Env:VCPKG_INSTALLATION_ROOT --triplet $triplet "--x-install-root=$installRoot" "--overlay-triplets=$overlayTriplets" } + } finally { + Pop-Location + } + + $installedDir = Join-Path $installRoot $triplet + + return @{ + IncludeDir = Join-Path $installedDir "include" + LibDir = Join-Path $installedDir "lib" + BinDir = Join-Path $installedDir "bin" + Prefix = $installedDir + } +} + try { if ((!$x86.isPresent -and !$x64.IsPresent) -and !$arm64.IsPresent) { Write-Output -Stderr "Error: usage $MyInvocation.MyCommand [-x86] [-x64] [-arm64]" @@ -118,7 +168,8 @@ try { if ($x86.IsPresent) { Write-Output "Building x86..." - Run-Command -Fatal { & $cmake -A Win32 -D USE_SSH=exec -D USE_HTTPS=Schannel -D "BUILD_TESTS=$build_tests" -D "BUILD_CLI=OFF" -D "LIBGIT2_FILENAME=$binaryFilename" .. } + $ssh2 = Install-Libssh2 "x86" + Run-Command -Fatal { & $cmake -A Win32 -D USE_SSH=ON -D USE_HTTPS=Schannel -D "BUILD_TESTS=$build_tests" -D "BUILD_CLI=OFF" -D "LIBGIT2_FILENAME=$binaryFilename" -D "CMAKE_PREFIX_PATH=$($ssh2.Prefix)" .. } Run-Command -Fatal { & $cmake --build . --config $configuration } if ($test.IsPresent) { Run-Command -Quiet -Fatal { & $ctest -V . } } cd $configuration @@ -127,14 +178,17 @@ try { Run-Command -Quiet { & rm $x86Directory\* -ErrorAction Ignore } Run-Command -Quiet { & mkdir -fo $x86Directory } Run-Command -Quiet -Fatal { & copy -fo * $x86Directory -Exclude *.lib } + Run-Command -Quiet -Fatal { & copy -fo (Join-Path $ssh2.BinDir "*.dll") $x86Directory } + if (-not (Test-Path (Join-Path $x86Directory "libssh2.dll"))) { throw "Error: libssh2.dll was not copied to $x86Directory" } cd .. } if ($x64.IsPresent) { Write-Output "Building x64..." + $ssh2 = Install-Libssh2 "x64" Run-Command -Quiet { & mkdir build64 } cd build64 - Run-Command -Fatal { & $cmake -A x64 -D USE_SSH=exec -D USE_HTTPS=Schannel -D "BUILD_TESTS=$build_tests" -D "BUILD_CLI=OFF" -D "LIBGIT2_FILENAME=$binaryFilename" ../.. } + Run-Command -Fatal { & $cmake -A x64 -D USE_SSH=ON -D USE_HTTPS=Schannel -D "BUILD_TESTS=$build_tests" -D "BUILD_CLI=OFF" -D "LIBGIT2_FILENAME=$binaryFilename" -D "CMAKE_PREFIX_PATH=$($ssh2.Prefix)" ../.. } Run-Command -Fatal { & $cmake --build . --config $configuration } if ($test.IsPresent) { Run-Command -Quiet -Fatal { & $ctest -V . } } cd $configuration @@ -143,13 +197,16 @@ try { Run-Command -Quiet { & rm $x64Directory\* -ErrorAction Ignore } Run-Command -Quiet { & mkdir -fo $x64Directory } Run-Command -Quiet -Fatal { & copy -fo * $x64Directory -Exclude *.lib } + Run-Command -Quiet -Fatal { & copy -fo (Join-Path $ssh2.BinDir "*.dll") $x64Directory } + if (-not (Test-Path (Join-Path $x64Directory "libssh2.dll"))) { throw "Error: libssh2.dll was not copied to $x64Directory" } } if ($arm64.IsPresent) { Write-Output "Building arm64..." + $ssh2 = Install-Libssh2 "arm64" Run-Command -Quiet { & mkdir buildarm64 } cd buildarm64 - Run-Command -Fatal { & $cmake -A ARM64 -D USE_SSH=exec -D USE_HTTPS=Schannel -D "BUILD_TESTS=$build_tests" -D "BUILD_CLI=OFF" -D "LIBGIT2_FILENAME=$binaryFilename" ../.. } + Run-Command -Fatal { & $cmake -A ARM64 -D USE_SSH=ON -D USE_HTTPS=Schannel -D "BUILD_TESTS=$build_tests" -D "BUILD_CLI=OFF" -D "LIBGIT2_FILENAME=$binaryFilename" -D "CMAKE_PREFIX_PATH=$($ssh2.Prefix)" ../.. } Run-Command -Fatal { & $cmake --build . --config $configuration } if ($test.IsPresent) { Run-Command -Quiet -Fatal { & $ctest -V . } } cd $configuration @@ -158,6 +215,8 @@ try { Run-Command -Quiet { & rm $arm64Directory\* -ErrorAction Ignore } Run-Command -Quiet { & mkdir -fo $arm64Directory } Run-Command -Quiet -Fatal { & copy -fo * $arm64Directory -Exclude *.lib } + Run-Command -Quiet -Fatal { & copy -fo (Join-Path $ssh2.BinDir "*.dll") $arm64Directory } + if (-not (Test-Path (Join-Path $arm64Directory "libssh2.dll"))) { throw "Error: libssh2.dll was not copied to $arm64Directory" } } Write-Output "Done!" diff --git a/build.libgit2.sh b/build.libgit2.sh index 3ac9e48e..d8ed8744 100755 --- a/build.libgit2.sh +++ b/build.libgit2.sh @@ -9,6 +9,8 @@ ARCH=`uname -m` PACKAGEPATH="nuget.package/runtimes" OSXARCHITECTURE=$ARCH +EXTRA_CMAKE_FLAGS="" + if [[ $OS == "Darwin" ]]; then USEHTTPS="ON" if [[ $RID == "osx-arm64" ]]; then @@ -18,6 +20,7 @@ if [[ $OS == "Darwin" ]]; then fi else USEHTTPS="OpenSSL-Dynamic" + EXTRA_CMAKE_FLAGS="-DCMAKE_BUILD_RPATH='\$ORIGIN'" fi rm -rf libgit2/build @@ -28,11 +31,12 @@ export _BINPATH=`pwd` cmake -DCMAKE_BUILD_TYPE:STRING=Release \ -DBUILD_TESTS:BOOL=OFF \ - -DUSE_SSH=exec \ + -DUSE_SSH=ON \ -DLIBGIT2_FILENAME=git2-$SHORTSHA \ -DCMAKE_OSX_ARCHITECTURES=$OSXARCHITECTURE \ -DUSE_HTTPS=$USEHTTPS \ -DUSE_BUNDLED_ZLIB=ON \ + $EXTRA_CMAKE_FLAGS \ .. cmake --build . @@ -53,3 +57,22 @@ rm -rf $PACKAGEPATH/$RID mkdir -p $PACKAGEPATH/$RID/native cp libgit2/build/libgit2-$SHORTSHA.$LIBEXT $PACKAGEPATH/$RID/native + +# Bundle libssh2 shared library alongside libgit2 +LIBGIT2_PATH="$PACKAGEPATH/$RID/native/libgit2-$SHORTSHA.$LIBEXT" + +if [[ $OS == "Darwin" ]]; then + echo "macOS: libssh2 sourced from global installation" +else + # Linux: find libssh2 via ldd + LIBSSH2_PATH=$(ldd "$LIBGIT2_PATH" | grep libssh2 | awk '{print $3}') + if [[ -z "$LIBSSH2_PATH" ]]; then + echo "ERROR: libgit2 does not appear to link against libssh2" + exit 1 + fi + + LIBSSH2_BASENAME=$(basename "$LIBSSH2_PATH") + + echo "Bundling $LIBSSH2_BASENAME from $LIBSSH2_PATH" + cp "$LIBSSH2_PATH" "$PACKAGEPATH/$RID/native/$LIBSSH2_BASENAME" +fi diff --git a/libssh2-wincng-triplets/arm64-windows.cmake b/libssh2-wincng-triplets/arm64-windows.cmake new file mode 100644 index 00000000..5bfc0ce0 --- /dev/null +++ b/libssh2-wincng-triplets/arm64-windows.cmake @@ -0,0 +1,2 @@ +set(VCPKG_TARGET_ARCHITECTURE arm64) +include("${CMAKE_CURRENT_LIST_DIR}/wincng-options.cmake") diff --git a/libssh2-wincng-triplets/wincng-options.cmake b/libssh2-wincng-triplets/wincng-options.cmake new file mode 100644 index 00000000..fdd66cbd --- /dev/null +++ b/libssh2-wincng-triplets/wincng-options.cmake @@ -0,0 +1,3 @@ +set(VCPKG_CRT_LINKAGE dynamic) +set(VCPKG_LIBRARY_LINKAGE dynamic) +set(VCPKG_CMAKE_CONFIGURE_OPTIONS "-DENABLE_ECDSA_WINCNG=ON") diff --git a/libssh2-wincng-triplets/x64-windows.cmake b/libssh2-wincng-triplets/x64-windows.cmake new file mode 100644 index 00000000..82b5a780 --- /dev/null +++ b/libssh2-wincng-triplets/x64-windows.cmake @@ -0,0 +1,2 @@ +set(VCPKG_TARGET_ARCHITECTURE x64) +include("${CMAKE_CURRENT_LIST_DIR}/wincng-options.cmake") diff --git a/libssh2-wincng-triplets/x86-windows.cmake b/libssh2-wincng-triplets/x86-windows.cmake new file mode 100644 index 00000000..0244afa3 --- /dev/null +++ b/libssh2-wincng-triplets/x86-windows.cmake @@ -0,0 +1,2 @@ +set(VCPKG_TARGET_ARCHITECTURE x86) +include("${CMAKE_CURRENT_LIST_DIR}/wincng-options.cmake")