From 95d5a390adf67fc269aea60867b4b12ab1ee9f26 Mon Sep 17 00:00:00 2001 From: Drew Smirnoff Date: Sun, 5 Apr 2026 13:50:08 +0400 Subject: [PATCH] ci:cross-compilation linux (#454) --- .github/workflows/nightly.yml | 47 ++++++++++++++++++++++++++++++++++- .github/workflows/release.yml | 47 ++++++++++++++++++++++++++++++++++- .goreleaser.nightly.yml | 4 ++- .goreleaser.yml | 4 ++- 4 files changed, 98 insertions(+), 4 deletions(-) diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 5567e5a4adbc4b0446080197539d0ebe0e632bd1..e286b4b03ee827781e6cf7c7b4483819b519e789 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -40,15 +40,60 @@ jobs: curl -fsSL "$PCSC_URL/pcsclite.h.in" -o "$PCSC_DIR/include/pcsclite.h" sed -i '' 's/@VERSION@/1.9.0/' "$PCSC_DIR/include/pcsclite.h" - # Create pkg-config file (headers-only, no library needed for cross-compilation) + # Build stub library — the real libpcsclite is loaded at runtime on the user's system, + # but the linker needs symbols to resolve during cross-compilation. + cat > "$RUNNER_TEMP/pcsclite_stub.c" << 'STUB' + #include + typedef long LONG; + typedef unsigned long DWORD; + typedef void *LPCVOID; + typedef char *LPSTR; + typedef const char *LPCSTR; + typedef unsigned char *LPBYTE; + typedef unsigned char BYTE; + typedef LONG SCARDCONTEXT; + typedef LONG SCARDHANDLE; + typedef struct { DWORD dwProtocol; DWORD cbPciLength; } SCARD_IO_REQUEST; + typedef struct { LPCSTR szReader; DWORD dwCurrentState; DWORD dwEventState; DWORD cbAtr; unsigned char rgbAtr[36]; void *pvUserData; } SCARD_READERSTATE; + LONG SCardEstablishContext(DWORD s, LPCVOID r1, LPCVOID r2, SCARDCONTEXT *c) { return 0; } + LONG SCardReleaseContext(SCARDCONTEXT c) { return 0; } + LONG SCardIsValidContext(SCARDCONTEXT c) { return 0; } + LONG SCardCancel(SCARDCONTEXT c) { return 0; } + LONG SCardConnect(SCARDCONTEXT c, LPCSTR r, DWORD s, DWORD p, SCARDHANDLE *h, DWORD *ap) { return 0; } + LONG SCardReconnect(SCARDHANDLE h, DWORD s, DWORD p, DWORD d, DWORD *ap) { return 0; } + LONG SCardDisconnect(SCARDHANDLE h, DWORD d) { return 0; } + LONG SCardBeginTransaction(SCARDHANDLE h) { return 0; } + LONG SCardEndTransaction(SCARDHANDLE h, DWORD d) { return 0; } + LONG SCardStatus(SCARDHANDLE h, LPSTR r, DWORD *rl, DWORD *s, DWORD *p, LPBYTE a, DWORD *al) { return 0; } + LONG SCardTransmit(SCARDHANDLE h, const SCARD_IO_REQUEST *si, const BYTE *s, DWORD sl, SCARD_IO_REQUEST *ri, BYTE *r, DWORD *rl) { return 0; } + LONG SCardControl(SCARDHANDLE h, DWORD c, LPCVOID i, DWORD il, void *o, DWORD ol, DWORD *br) { return 0; } + LONG SCardGetAttrib(SCARDHANDLE h, DWORD a, LPBYTE b, DWORD *bl) { return 0; } + LONG SCardSetAttrib(SCARDHANDLE h, DWORD a, const BYTE *b, DWORD bl) { return 0; } + LONG SCardListReaders(SCARDCONTEXT c, LPCSTR g, LPSTR r, DWORD *rl) { return 0; } + LONG SCardListReaderGroups(SCARDCONTEXT c, LPSTR g, DWORD *gl) { return 0; } + LONG SCardGetStatusChange(SCARDCONTEXT c, DWORD t, SCARD_READERSTATE *s, DWORD n) { return 0; } + LONG SCardFreeMemory(SCARDCONTEXT c, LPCVOID m) { return 0; } + const char *pcsc_stringify_error(LONG e) { return "stub"; } + STUB + + zig cc -c -target x86_64-linux-musl -o "$RUNNER_TEMP/pcsclite_stub_amd64.o" "$RUNNER_TEMP/pcsclite_stub.c" + zig cc -c -target aarch64-linux-musl -o "$RUNNER_TEMP/pcsclite_stub_arm64.o" "$RUNNER_TEMP/pcsclite_stub.c" + + mkdir -p "$PCSC_DIR/lib/amd64" "$PCSC_DIR/lib/arm64" + ar rcs "$PCSC_DIR/lib/amd64/libpcsclite.a" "$RUNNER_TEMP/pcsclite_stub_amd64.o" + ar rcs "$PCSC_DIR/lib/arm64/libpcsclite.a" "$RUNNER_TEMP/pcsclite_stub_arm64.o" + + # Create pkg-config file — Libs will be overridden per-arch via CGO_LDFLAGS in goreleaser cat > "$PCSC_DIR/lib/pkgconfig/libpcsclite.pc" << EOF Name: libpcsclite Description: PC/SC Lite Version: 1.9.0 Cflags: -I$PCSC_DIR/include + Libs: -L$PCSC_DIR/lib/amd64 -lpcsclite EOF echo "PKG_CONFIG_PATH=$PCSC_DIR/lib/pkgconfig" >> $GITHUB_ENV + echo "PCSC_DIR=$PCSC_DIR" >> $GITHUB_ENV - name: Get macOS SDK path id: macos_sdk diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 335e121ae0aaf14d82eafa819399276e8ee35db3..0239604674627eddfdf5316bc7dfafd3c8d66153 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -50,15 +50,60 @@ jobs: curl -fsSL "$PCSC_URL/pcsclite.h.in" -o "$PCSC_DIR/include/pcsclite.h" sed -i '' 's/@VERSION@/1.9.0/' "$PCSC_DIR/include/pcsclite.h" - # Create pkg-config file (headers-only, no library needed for cross-compilation) + # Build stub library — the real libpcsclite is loaded at runtime on the user's system, + # but the linker needs symbols to resolve during cross-compilation. + cat > "$RUNNER_TEMP/pcsclite_stub.c" << 'STUB' + #include + typedef long LONG; + typedef unsigned long DWORD; + typedef void *LPCVOID; + typedef char *LPSTR; + typedef const char *LPCSTR; + typedef unsigned char *LPBYTE; + typedef unsigned char BYTE; + typedef LONG SCARDCONTEXT; + typedef LONG SCARDHANDLE; + typedef struct { DWORD dwProtocol; DWORD cbPciLength; } SCARD_IO_REQUEST; + typedef struct { LPCSTR szReader; DWORD dwCurrentState; DWORD dwEventState; DWORD cbAtr; unsigned char rgbAtr[36]; void *pvUserData; } SCARD_READERSTATE; + LONG SCardEstablishContext(DWORD s, LPCVOID r1, LPCVOID r2, SCARDCONTEXT *c) { return 0; } + LONG SCardReleaseContext(SCARDCONTEXT c) { return 0; } + LONG SCardIsValidContext(SCARDCONTEXT c) { return 0; } + LONG SCardCancel(SCARDCONTEXT c) { return 0; } + LONG SCardConnect(SCARDCONTEXT c, LPCSTR r, DWORD s, DWORD p, SCARDHANDLE *h, DWORD *ap) { return 0; } + LONG SCardReconnect(SCARDHANDLE h, DWORD s, DWORD p, DWORD d, DWORD *ap) { return 0; } + LONG SCardDisconnect(SCARDHANDLE h, DWORD d) { return 0; } + LONG SCardBeginTransaction(SCARDHANDLE h) { return 0; } + LONG SCardEndTransaction(SCARDHANDLE h, DWORD d) { return 0; } + LONG SCardStatus(SCARDHANDLE h, LPSTR r, DWORD *rl, DWORD *s, DWORD *p, LPBYTE a, DWORD *al) { return 0; } + LONG SCardTransmit(SCARDHANDLE h, const SCARD_IO_REQUEST *si, const BYTE *s, DWORD sl, SCARD_IO_REQUEST *ri, BYTE *r, DWORD *rl) { return 0; } + LONG SCardControl(SCARDHANDLE h, DWORD c, LPCVOID i, DWORD il, void *o, DWORD ol, DWORD *br) { return 0; } + LONG SCardGetAttrib(SCARDHANDLE h, DWORD a, LPBYTE b, DWORD *bl) { return 0; } + LONG SCardSetAttrib(SCARDHANDLE h, DWORD a, const BYTE *b, DWORD bl) { return 0; } + LONG SCardListReaders(SCARDCONTEXT c, LPCSTR g, LPSTR r, DWORD *rl) { return 0; } + LONG SCardListReaderGroups(SCARDCONTEXT c, LPSTR g, DWORD *gl) { return 0; } + LONG SCardGetStatusChange(SCARDCONTEXT c, DWORD t, SCARD_READERSTATE *s, DWORD n) { return 0; } + LONG SCardFreeMemory(SCARDCONTEXT c, LPCVOID m) { return 0; } + const char *pcsc_stringify_error(LONG e) { return "stub"; } + STUB + + zig cc -c -target x86_64-linux-musl -o "$RUNNER_TEMP/pcsclite_stub_amd64.o" "$RUNNER_TEMP/pcsclite_stub.c" + zig cc -c -target aarch64-linux-musl -o "$RUNNER_TEMP/pcsclite_stub_arm64.o" "$RUNNER_TEMP/pcsclite_stub.c" + + mkdir -p "$PCSC_DIR/lib/amd64" "$PCSC_DIR/lib/arm64" + ar rcs "$PCSC_DIR/lib/amd64/libpcsclite.a" "$RUNNER_TEMP/pcsclite_stub_amd64.o" + ar rcs "$PCSC_DIR/lib/arm64/libpcsclite.a" "$RUNNER_TEMP/pcsclite_stub_arm64.o" + + # Create pkg-config file cat > "$PCSC_DIR/lib/pkgconfig/libpcsclite.pc" << EOF Name: libpcsclite Description: PC/SC Lite Version: 1.9.0 Cflags: -I$PCSC_DIR/include + Libs: -L$PCSC_DIR/lib/amd64 -lpcsclite EOF echo "PKG_CONFIG_PATH=$PCSC_DIR/lib/pkgconfig" >> $GITHUB_ENV + echo "PCSC_DIR=$PCSC_DIR" >> $GITHUB_ENV - name: Get macOS SDK path id: macos_sdk diff --git a/.goreleaser.nightly.yml b/.goreleaser.nightly.yml index 3119c9c12619be54192fbcd33bf7fdbca5de9996..249d452fa101169378e9c88ddfdbb3bd878fd500 100644 --- a/.goreleaser.nightly.yml +++ b/.goreleaser.nightly.yml @@ -31,7 +31,9 @@ builds: - >- {{- if eq .Os "darwin" }}CGO_CFLAGS=-isysroot {{ .Env.SDK_PATH }} -mmacosx-version-min=11.0{{- end }} - >- - {{- if eq .Os "darwin" }}CGO_LDFLAGS=-isysroot {{ .Env.SDK_PATH }}{{- end }} + {{- if eq .Os "darwin" }}CGO_LDFLAGS=-isysroot {{ .Env.SDK_PATH }} + {{- else if eq .Os "linux" }}CGO_LDFLAGS=-L{{ .Env.PCSC_DIR }}/lib/{{ .Arch }} + {{- end }} - >- {{- if eq .Os "darwin" }} {{- if eq .Arch "amd64"}}CC=clang -arch x86_64 -isysroot {{ .Env.SDK_PATH }}{{- end }} diff --git a/.goreleaser.yml b/.goreleaser.yml index 8b38c4994182d78d8261ea73667e62e9e7542904..18191f13c17d74d8ff46ee1a558c9277019c09c7 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -40,7 +40,9 @@ builds: - >- {{- if eq .Os "darwin" }}CGO_CFLAGS=-isysroot {{ .Env.SDK_PATH }} -mmacosx-version-min=11.0{{- end }} - >- - {{- if eq .Os "darwin" }}CGO_LDFLAGS=-isysroot {{ .Env.SDK_PATH }}{{- end }} + {{- if eq .Os "darwin" }}CGO_LDFLAGS=-isysroot {{ .Env.SDK_PATH }} + {{- else if eq .Os "linux" }}CGO_LDFLAGS=-L{{ .Env.PCSC_DIR }}/lib/{{ .Arch }} + {{- end }} - >- {{- if eq .Os "darwin" }} {{- if eq .Arch "amd64"}}CC=clang -arch x86_64 -isysroot {{ .Env.SDK_PATH }}{{- end }}