diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1520b30..319c0c0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,6 +12,11 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true +# Use bash everywhere so the same scripts run on the Windows runners too +defaults: + run: + shell: bash + jobs: build-libbitcoinkernel: name: Build libbitcoinkernel (${{ matrix.rid }}) @@ -27,6 +32,13 @@ jobs: - os: macos-latest rid: osx-x64 libname: libbitcoinkernel.dylib + # Bitcoin Core's vs2026 presets need the VS 2026 image + - os: windows-2025-vs2026 + rid: win-x64 + # MSVC builds bitcoinkernel.dll, which clashes with the managed + # BitcoinKernel.dll on case-insensitive file systems, so ship it with a lib prefix + buildname: bitcoinkernel.dll + libname: libbitcoinkernel.dll steps: - name: Checkout code @@ -41,7 +53,7 @@ jobs: uses: actions/cache@v6.1.0 with: path: kernel-out - key: libbitcoinkernel-${{ matrix.rid }}-${{ steps.bitcoin.outputs.commit }} + key: libbitcoinkernel-${{ matrix.rid }}-${{ matrix.libname }}-${{ steps.bitcoin.outputs.commit }} - name: Checkout Bitcoin Core if: steps.cache.outputs.cache-hit != 'true' @@ -61,8 +73,8 @@ jobs: if: steps.cache.outputs.cache-hit != 'true' && runner.os == 'macOS' run: brew install ninja boost - - name: Build libbitcoinkernel - if: steps.cache.outputs.cache-hit != 'true' + - name: Build libbitcoinkernel (Linux/macOS) + if: steps.cache.outputs.cache-hit != 'true' && runner.os != 'Windows' run: | cmake -B bitcoin/build -S bitcoin -G Ninja \ -DCMAKE_BUILD_TYPE=Release \ @@ -84,10 +96,43 @@ jobs: -DENABLE_EXTERNAL_SIGNER=OFF \ -DCMAKE_INSTALL_LIBDIR=lib cmake --build bitcoin/build --target bitcoinkernel --parallel + + - name: Build libbitcoinkernel (Windows) + if: steps.cache.outputs.cache-hit != 'true' && runner.os == 'Windows' + working-directory: bitcoin + run: | + # The presets locate the vcpkg toolchain through VCPKG_ROOT + export VCPKG_ROOT="${VCPKG_ROOT:-$VCPKG_INSTALLATION_ROOT}" + # Static triplet links the MSVC runtime into the DLL, so consumers + # don't need the Visual C++ redistributable installed + cmake -B build --preset=vs2026-static \ + -DVCPKG_MANIFEST_NO_DEFAULT_FEATURES=ON \ + -DBUILD_GUI=OFF \ + -DWITH_ZMQ=OFF \ + -DBUILD_SHARED_LIBS=ON \ + -DBUILD_KERNEL_LIB=ON \ + -DBUILD_BITCOIN_BIN=OFF \ + -DBUILD_DAEMON=OFF \ + -DBUILD_CLI=OFF \ + -DBUILD_TX=OFF \ + -DBUILD_UTIL=OFF \ + -DBUILD_WALLET_TOOL=OFF \ + -DBUILD_TESTS=OFF \ + -DBUILD_BENCH=OFF \ + -DBUILD_FUZZ_BINARY=OFF \ + -DENABLE_WALLET=OFF \ + -DENABLE_IPC=OFF \ + -DENABLE_EXTERNAL_SIGNER=OFF + cmake --build build --config Release --target bitcoinkernel --parallel + + - name: Collect libbitcoinkernel + if: steps.cache.outputs.cache-hit != 'true' + run: | mkdir -p kernel-out - LIB_PATH=$(find bitcoin/build \( -type f -o -type l \) -name '${{ matrix.libname }}' | head -n1) + BUILD_NAME='${{ matrix.buildname || matrix.libname }}' + LIB_PATH=$(find bitcoin/build \( -type f -o -type l \) -name "$BUILD_NAME" | head -n1) if [ -z "$LIB_PATH" ]; then - echo "::error::${{ matrix.libname }} not found in build output:" + echo "::error::$BUILD_NAME not found in build output:" find bitcoin/build -name 'libbitcoinkernel*' exit 1 fi @@ -107,13 +152,15 @@ jobs: needs: build-libbitcoinkernel strategy: matrix: - os: [ubuntu-latest, macos-latest] + os: [ubuntu-latest, macos-latest, windows-latest] dotnet-version: ['10.0.x'] include: - os: ubuntu-latest rid: linux-x64 - os: macos-latest rid: osx-x64 + - os: windows-latest + rid: win-x64 fail-fast: false steps: @@ -199,9 +246,18 @@ jobs: - os: macos-latest platform: darwin_arm64 rid: osx-x64 + archive: tar.gz + exe: '' - os: ubuntu-latest platform: linux_amd64 rid: linux-x64 + archive: tar.gz + exe: '' + - os: windows-latest + platform: windows_amd64 + rid: win-x64 + archive: zip + exe: .exe env: TEST_VERSION: '0.0.4-alpha.pr14.5' @@ -231,14 +287,20 @@ jobs: - name: Download test runner run: | mkdir -p ${{ env.TEST_DIR }} - DOWNLOAD_URL="https://github.com/${{ env.TEST_REPO }}/releases/download/v${{ env.TEST_VERSION }}/kernel-bindings-tests_${{ env.TEST_VERSION }}_${{ matrix.platform }}.tar.gz" + ARCHIVE=${{ env.TEST_DIR }}/test-runner.${{ matrix.archive }} + DOWNLOAD_URL="https://github.com/${{ env.TEST_REPO }}/releases/download/v${{ env.TEST_VERSION }}/kernel-bindings-tests_${{ env.TEST_VERSION }}_${{ matrix.platform }}.${{ matrix.archive }}" echo "Downloading from: $DOWNLOAD_URL" - curl --fail -L -o ${{ env.TEST_DIR }}/test-runner.tar.gz "$DOWNLOAD_URL" - tar -xzf ${{ env.TEST_DIR }}/test-runner.tar.gz -C ${{ env.TEST_DIR }} - chmod +x ${{ env.TEST_DIR }}/runner + curl --fail -L -o "$ARCHIVE" "$DOWNLOAD_URL" + if [ "${{ matrix.archive }}" = "zip" ]; then + # Git Bash's tar can't read zip files, the runner image ships 7-Zip + 7z x -y -o${{ env.TEST_DIR }} "$ARCHIVE" + else + tar -xzf "$ARCHIVE" -C ${{ env.TEST_DIR }} + fi + chmod +x ${{ env.TEST_DIR }}/runner${{ matrix.exe }} - name: Run conformance tests run: | - ${{ env.TEST_DIR }}/runner --handler handler-bin/kernel-bindings-test-handler + ${{ env.TEST_DIR }}/runner${{ matrix.exe }} --handler handler-bin/kernel-bindings-test-handler${{ matrix.exe }} diff --git a/README.md b/README.md index 97c4bb7..143d048 100644 --- a/README.md +++ b/README.md @@ -101,8 +101,12 @@ dotnet test ## Native Library This package includes pre-built `libbitcoinkernel` binaries for: -- macOS (x64, ARM64) -- others will follow + +| Platform | File | +|----------|------| +| Linux x64 | `native/linux-x64/libbitcoinkernel.so` | +| macOS ARM64 (Apple Silicon) | `native/osx-x64/libbitcoinkernel.dylib` | +| Windows x64 | `native/win-x64/libbitcoinkernel.dll` | For other platforms, you'll need to build libbitcoinkernel from the [Bitcoin Core repository](https://github.com/bitcoin/bitcoin). diff --git a/native/win-x64/libbitcoinkernel.dll b/native/win-x64/libbitcoinkernel.dll new file mode 100755 index 0000000..a5608b4 Binary files /dev/null and b/native/win-x64/libbitcoinkernel.dll differ diff --git a/src/BitcoinKernel.Interop/BitcoinKernel.Interop.csproj b/src/BitcoinKernel.Interop/BitcoinKernel.Interop.csproj index 10232ad..f3b4d61 100644 --- a/src/BitcoinKernel.Interop/BitcoinKernel.Interop.csproj +++ b/src/BitcoinKernel.Interop/BitcoinKernel.Interop.csproj @@ -25,6 +25,11 @@ true runtimes/linux-x64/native + + PreserveNewest + true + runtimes/win-x64/native + diff --git a/src/BitcoinKernel.Interop/Helpers/NativeLibraryLoader.cs b/src/BitcoinKernel.Interop/Helpers/NativeLibraryLoader.cs index 6a396d6..c0aaa82 100644 --- a/src/BitcoinKernel.Interop/Helpers/NativeLibraryLoader.cs +++ b/src/BitcoinKernel.Interop/Helpers/NativeLibraryLoader.cs @@ -70,8 +70,8 @@ private static string[] GetLibraryPaths() { return [ - "bitcoinkernel.dll", - Path.Combine(basePath, "runtimes", "win-x64", "native", "bitcoinkernel.dll") + "libbitcoinkernel.dll", + Path.Combine(basePath, "runtimes", "win-x64", "native", "libbitcoinkernel.dll") ]; } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) diff --git a/src/BitcoinKernel.Interop/NativeMethods.cs b/src/BitcoinKernel.Interop/NativeMethods.cs index d897c0c..46482bf 100644 --- a/src/BitcoinKernel.Interop/NativeMethods.cs +++ b/src/BitcoinKernel.Interop/NativeMethods.cs @@ -14,7 +14,10 @@ internal static class NativeMethods { #region Library Configuration - private const string LibName = "bitcoinkernel"; + // Keep the "lib" prefix on every platform. On Windows a plain "bitcoinkernel.dll" + // matches the managed BitcoinKernel.dll (file names are case-insensitive), and + // the loader would bind to the managed assembly instead of the native library. + private const string LibName = "libbitcoinkernel"; // For loading platform-specific libraries static NativeMethods() diff --git a/src/BitcoinKernel/BitcoinKernel.csproj b/src/BitcoinKernel/BitcoinKernel.csproj index 18808ea..a469df3 100644 --- a/src/BitcoinKernel/BitcoinKernel.csproj +++ b/src/BitcoinKernel/BitcoinKernel.csproj @@ -38,9 +38,10 @@ + <_PackageFiles Include="$(OutputPath)runtimes\**\*.*" Condition="Exists('$(OutputPath)runtimes')"> - Content - runtimes/%(RecursiveDir)%(Filename)%(Extension) + None + runtimes/