diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..9aa664e --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,91 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + test: + name: test (${{ matrix.label }}) + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - { os: ubuntu-latest, label: linux/amd64 } + - { os: ubuntu-24.04-arm, label: linux/arm64 } + - { os: macos-14, label: darwin/arm64 } + - { os: macos-14, label: darwin/amd64 } # cross-built on arm64, run via Rosetta 2 + - { os: windows-latest, label: windows/amd64 } + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache: true + + - name: Install system deps (Linux) + if: runner.os == 'Linux' + run: | + sudo apt-get update + sudo apt-get install -y build-essential libssl-dev + + - name: Install system deps (darwin/arm64) + if: matrix.label == 'darwin/arm64' + run: brew install openssl@3 + + - name: Install system deps (darwin/amd64 via Rosetta) + if: matrix.label == 'darwin/amd64' + run: | + # Rosetta 2 is needed to exec x86_64 test binaries on Apple Silicon + # runners. Idempotent — a no-op if already installed. + softwareupdate --install-rosetta --agree-to-license || true + # Intel Homebrew at /usr/local provides x86_64 openssl@3, which + # the cgo darwin,amd64 LDFLAGS already point at. + arch -x86_64 /bin/bash -c 'NONINTERACTIVE=1 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"' + arch -x86_64 /usr/local/bin/brew install openssl@3 + + - name: Set up MSYS2 (Windows) + if: runner.os == 'Windows' + uses: msys2/setup-msys2@v2 + with: + msystem: MINGW64 + path-type: inherit + update: true + install: >- + mingw-w64-x86_64-gcc + mingw-w64-x86_64-openssl + + - name: Build & test (native) + if: runner.os != 'Windows' && matrix.label != 'darwin/amd64' + run: | + go vet ./... + go build ./... + go test ./... + + - name: Build & test (darwin/amd64 cross via Rosetta) + if: matrix.label == 'darwin/amd64' + env: + GOARCH: amd64 + CGO_ENABLED: "1" + CC: clang -arch x86_64 + CXX: clang++ -arch x86_64 + run: | + go vet ./... + go build ./... + go test ./... + + - name: Build & test (Windows) + if: runner.os == 'Windows' + shell: msys2 {0} + run: | + go vet ./... + go build ./... + go test ./... diff --git a/internal/crypto/cryptocgo.go b/internal/crypto/cryptocgo.go index e6da8ec..9fbb33c 100644 --- a/internal/crypto/cryptocgo.go +++ b/internal/crypto/cryptocgo.go @@ -35,7 +35,13 @@ package crypto // Intel; both search paths are supplied so the linker picks whichever // exists. Linux assumes system libssl-dev. Windows assumes MSYS2 // mingw-w64-x86_64-openssl. -#cgo CPPFLAGS: -I${SRCDIR}/../../third_party/evi/include +// EVI_STATIC tells EVI/Export.hpp to leave EVI_API empty on all +// platforms. We link against the bundled static archives +// (libevi_c_api.a, libevi_crypto.a), so Windows must not treat the +// API-annotated class/function declarations in km/KeyManager.hpp as +// __declspec(dllimport) — otherwise mingw emits __imp_ +// references that the static archive does not provide. +#cgo CPPFLAGS: -I${SRCDIR}/../../third_party/evi/include -DEVI_STATIC #cgo CXXFLAGS: -std=c++17 #cgo darwin,arm64 LDFLAGS: -L${SRCDIR}/../../third_party/evi/darwin_arm64/lib -levi_c_api -levi_crypto -ldeb -lalea -L/opt/homebrew/opt/openssl@3/lib -L/usr/local/opt/openssl@3/lib -lssl -lcrypto -lc++ -lm #cgo darwin,amd64 LDFLAGS: -L${SRCDIR}/../../third_party/evi/darwin_amd64/lib -levi_c_api -levi_crypto -ldeb -lalea -L/usr/local/opt/openssl@3/lib -L/opt/homebrew/opt/openssl@3/lib -lssl -lcrypto -lc++ -lm