From e4c5384986b729d8536149184e5fc508c61329e4 Mon Sep 17 00:00:00 2001 From: Li Jie Date: Sat, 22 Aug 2026 13:13:18 +0800 Subject: [PATCH 01/10] test: make archive error assertion portable on Windows --- archive_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/archive_test.go b/archive_test.go index df8e876..db1d476 100644 --- a/archive_test.go +++ b/archive_test.go @@ -10,6 +10,7 @@ package llvm import ( "bytes" + "fmt" "os" "path/filepath" "strings" @@ -74,7 +75,7 @@ func TestWriteArchiveRejectsInvalidMembers(t *testing.T) { {name: "empty path", members: []ArchiveMember{{}}, want: "archive path is empty"}, {name: "no members", path: path, want: "archive has no members"}, {name: "empty member", path: path, members: []ArchiveMember{{}}, want: "has no file or memory buffer"}, - {name: "missing file", path: path, members: []ArchiveMember{NewArchiveMemberFromFile(missing)}, want: missing}, + {name: "missing file", path: path, members: []ArchiveMember{NewArchiveMemberFromFile(missing)}, want: fmt.Sprintf("%q", missing)}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { From 8baef47bc7447c9006d543532a8ec3eab28ece19 Mon Sep 17 00:00:00 2001 From: Li Jie Date: Sat, 22 Aug 2026 13:13:20 +0800 Subject: [PATCH 02/10] llvm: configure Windows LLVM 19 with pkg-config --- llvm_config_llvm19.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/llvm_config_llvm19.go b/llvm_config_llvm19.go index fea3f0b..a7dcfc3 100644 --- a/llvm_config_llvm19.go +++ b/llvm_config_llvm19.go @@ -15,6 +15,8 @@ package llvm // #cgo linux CPPFLAGS: -I/usr/include/llvm-19 -I/usr/include/llvm-c-19 -I/usr/lib64/llvm19/include -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS // #cgo linux CXXFLAGS: -std=c++17 // #cgo linux LDFLAGS: -L/usr/lib/llvm-19/lib -L/usr/lib64/llvm19/lib -lLLVM-19 +// #cgo windows pkg-config: llgo-llvm-19 +// #cgo windows CXXFLAGS: -std=c++17 import "C" type run_build_sh int From dfae085150bfe4fa138874c5a3432aed07c88514 Mon Sep 17 00:00:00 2001 From: Li Jie Date: Sat, 22 Aug 2026 13:21:53 +0800 Subject: [PATCH 03/10] ci: test LLVM 19 bindings on Windows --- .github/workflows/go.yml | 107 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index c3aad07..a29fef7 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -55,6 +55,113 @@ jobs: if: matrix.llvm == 19 run: go test -v + test-windows: + runs-on: windows-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version: '1.22' + - name: Set up MSYS2 + uses: msys2/setup-msys2@v2 + with: + msystem: CLANG64 + path-type: inherit + update: true + - name: Install LLVM 19 + shell: msys2 {0} + env: + LLVM_VERSION: '19.1.7' + MSYS2_LLVM_PACKAGE_VERSION: '19.1.7-1' + run: | + set -euo pipefail + + repo=https://repo.msys2.org/mingw/clang64 + prefix=mingw-w64-clang-x86_64 + packages=( + "clang-$MSYS2_LLVM_PACKAGE_VERSION" + "clang-libs-$MSYS2_LLVM_PACKAGE_VERSION" + "compiler-rt-$MSYS2_LLVM_PACKAGE_VERSION" + "llvm-$MSYS2_LLVM_PACKAGE_VERSION" + "llvm-libs-$MSYS2_LLVM_PACKAGE_VERSION" + "lld-$MSYS2_LLVM_PACKAGE_VERSION" + "libc++-$MSYS2_LLVM_PACKAGE_VERSION" + "libunwind-$MSYS2_LLVM_PACKAGE_VERSION" + 'gettext-runtime-0.22.5-2' + 'libffi-3.4.6-1' + 'libiconv-1.17-4' + 'libxml2-2.12.9-2' + 'xz-5.6.3-3' + 'zlib-1.3.1-1' + 'zstd-1.5.6-2' + ) + urls=() + for package in "${packages[@]}"; do + urls+=("$repo/$prefix-$package-any.pkg.tar.zst") + done + + # These archived LLVM 19 packages predate MSYS2's rename of the + # compiler-runtime virtual dependency from gcc-libs to cc-libs. + # libc++ 19 still supplies that runtime, so satisfy only the renamed + # package metadata rather than upgrading the pinned LLVM toolchain. + assumed_cc_runtime="$prefix-cc-libs=$LLVM_VERSION" + pacman --noconfirm -U \ + --assume-installed "$assumed_cc_runtime" \ + "${urls[@]}" + pacman --noconfirm -S --needed \ + --assume-installed "$assumed_cc_runtime" \ + "$prefix-pkgconf" + + for package in clang clang-libs compiler-rt llvm llvm-libs lld libc++ libunwind; do + installed="$(pacman -Q "$prefix-$package" | awk '{print $2}')" + if [[ "$installed" != "$MSYS2_LLVM_PACKAGE_VERSION" ]]; then + echo "expected $package $MSYS2_LLVM_PACKAGE_VERSION, got $installed" >&2 + exit 1 + fi + done + - name: Test LLVM 19 + shell: msys2 {0} + run: | + set -euo pipefail + + llvm_version="$(llvm-config --version)" + if [[ "$llvm_version" != 19.1.7 ]]; then + echo "expected LLVM 19.1.7, got $llvm_version" >&2 + exit 1 + fi + + # The Windows binding keeps LLVM's host flags package-local through + # pkg-config, so they do not affect unrelated CGO packages. + pc_dir="$(cygpath -u "$RUNNER_TEMP")/llgo-llvm-pkgconfig" + mkdir -p "$pc_dir" + cflags="$(llvm-config --cflags | tr '\r\n' ' ')" + ldflags="$(llvm-config --ldflags --libs all --system-libs | tr '\r\n' ' ')" + printf '%s\n' \ + 'Name: LLGo LLVM 19 host' \ + 'Description: LLVM 19 flags used by the LLGo host compiler' \ + "Version: $llvm_version" \ + "Cflags: $cflags" \ + "Libs: $ldflags" \ + > "$pc_dir/llgo-llvm-19.pc" + + export CC=clang + export CXX=clang++ + export CGO_ENABLED=1 + export PKG_CONFIG_PATH="$(cygpath -m "$pc_dir")" + clang --version + go test -v -tags=llvm19 + - name: Test default LLVM + shell: msys2 {0} + run: | + set -euo pipefail + export CC=clang + export CXX=clang++ + export CGO_ENABLED=1 + pc_dir="$(cygpath -u "$RUNNER_TEMP")/llgo-llvm-pkgconfig" + export PKG_CONFIG_PATH="$(cygpath -m "$pc_dir")" + go test -v test-linux-fedora: # Fedora uses different paths than other systems, so testing it separately. runs-on: ubuntu-24.04 From a7dfe6c95b2730f3748cf83bb22f306dd19705c5 Mon Sep 17 00:00:00 2001 From: Li Jie Date: Sat, 22 Aug 2026 16:26:21 +0800 Subject: [PATCH 04/10] llvm: use a neutral LLVM 19 pkg-config name --- .github/workflows/go.yml | 10 +++++----- llvm_config_llvm19.go | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index a29fef7..3ec9809 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -134,17 +134,17 @@ jobs: # The Windows binding keeps LLVM's host flags package-local through # pkg-config, so they do not affect unrelated CGO packages. - pc_dir="$(cygpath -u "$RUNNER_TEMP")/llgo-llvm-pkgconfig" + pc_dir="$(cygpath -u "$RUNNER_TEMP")/llvm-pkgconfig" mkdir -p "$pc_dir" cflags="$(llvm-config --cflags | tr '\r\n' ' ')" ldflags="$(llvm-config --ldflags --libs all --system-libs | tr '\r\n' ' ')" printf '%s\n' \ - 'Name: LLGo LLVM 19 host' \ - 'Description: LLVM 19 flags used by the LLGo host compiler' \ + 'Name: LLVM 19' \ + 'Description: LLVM 19 host compiler and linker flags' \ "Version: $llvm_version" \ "Cflags: $cflags" \ "Libs: $ldflags" \ - > "$pc_dir/llgo-llvm-19.pc" + > "$pc_dir/llvm-19.pc" export CC=clang export CXX=clang++ @@ -159,7 +159,7 @@ jobs: export CC=clang export CXX=clang++ export CGO_ENABLED=1 - pc_dir="$(cygpath -u "$RUNNER_TEMP")/llgo-llvm-pkgconfig" + pc_dir="$(cygpath -u "$RUNNER_TEMP")/llvm-pkgconfig" export PKG_CONFIG_PATH="$(cygpath -m "$pc_dir")" go test -v test-linux-fedora: diff --git a/llvm_config_llvm19.go b/llvm_config_llvm19.go index a7dcfc3..83a0f1a 100644 --- a/llvm_config_llvm19.go +++ b/llvm_config_llvm19.go @@ -15,7 +15,7 @@ package llvm // #cgo linux CPPFLAGS: -I/usr/include/llvm-19 -I/usr/include/llvm-c-19 -I/usr/lib64/llvm19/include -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS // #cgo linux CXXFLAGS: -std=c++17 // #cgo linux LDFLAGS: -L/usr/lib/llvm-19/lib -L/usr/lib64/llvm19/lib -lLLVM-19 -// #cgo windows pkg-config: llgo-llvm-19 +// #cgo windows pkg-config: llvm-19 // #cgo windows CXXFLAGS: -std=c++17 import "C" From 1573496fd89e25f65ff978711957a36abe2b5c88 Mon Sep 17 00:00:00 2001 From: Li Jie Date: Mon, 24 Aug 2026 11:00:25 +0800 Subject: [PATCH 05/10] ci: harden pinned Windows dependencies --- .github/workflows/go.yml | 34 ++++++++++++++++++++++++++-------- README.markdown | 26 ++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 8 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 3ec9809..52cfcfa 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -65,11 +65,12 @@ jobs: with: go-version: '1.22' - name: Set up MSYS2 - uses: msys2/setup-msys2@v2 + uses: msys2/setup-msys2@66cd2cce69caa17b53920067426061ca1de3a884 # v2.32.0 with: msystem: CLANG64 path-type: inherit update: true + install: curl - name: Install LLVM 19 shell: msys2 {0} env: @@ -80,6 +81,10 @@ jobs: repo=https://repo.msys2.org/mingw/clang64 prefix=mingw-w64-clang-x86_64 + # MSYS2 is a rolling repository and can eventually remove these old + # artifacts. If a URL starts returning 404, refresh the transitive + # dependency versions and signatures together while keeping LLVM 19 + # pinned to the version above. packages=( "clang-$MSYS2_LLVM_PACKAGE_VERSION" "clang-libs-$MSYS2_LLVM_PACKAGE_VERSION" @@ -97,9 +102,18 @@ jobs: 'zlib-1.3.1-1' 'zstd-1.5.6-2' ) - urls=() + download_dir="$(mktemp -d)" + trap 'rm -rf "$download_dir"' EXIT + archives=() for package in "${packages[@]}"; do - urls+=("$repo/$prefix-$package-any.pkg.tar.zst") + archive="$prefix-$package-any.pkg.tar.zst" + curl --fail --location --retry 3 \ + --output "$download_dir/$archive" \ + "$repo/$archive" + curl --fail --location --retry 3 \ + --output "$download_dir/$archive.sig" \ + "$repo/$archive.sig" + archives+=("$download_dir/$archive") done # These archived LLVM 19 packages predate MSYS2's rename of the @@ -107,9 +121,11 @@ jobs: # libc++ 19 still supplies that runtime, so satisfy only the renamed # package metadata rather than upgrading the pinned LLVM toolchain. assumed_cc_runtime="$prefix-cc-libs=$LLVM_VERSION" + # pacman discovers each adjacent .sig file and validates it against + # the MSYS2 package keyring before installing the local archive. pacman --noconfirm -U \ --assume-installed "$assumed_cc_runtime" \ - "${urls[@]}" + "${archives[@]}" pacman --noconfirm -S --needed \ --assume-installed "$assumed_cc_runtime" \ "$prefix-pkgconf" @@ -132,8 +148,8 @@ jobs: exit 1 fi - # The Windows binding keeps LLVM's host flags package-local through - # pkg-config, so they do not affect unrelated CGO packages. + # Supply the installed LLVM's include and library paths through the + # pkg-config name consumed by the Windows LLVM 19 binding. pc_dir="$(cygpath -u "$RUNNER_TEMP")/llvm-pkgconfig" mkdir -p "$pc_dir" cflags="$(llvm-config --cflags | tr '\r\n' ' ')" @@ -149,7 +165,8 @@ jobs: export CC=clang export CXX=clang++ export CGO_ENABLED=1 - export PKG_CONFIG_PATH="$(cygpath -m "$pc_dir")" + PKG_CONFIG_PATH="$(cygpath -m "$pc_dir")" + export PKG_CONFIG_PATH clang --version go test -v -tags=llvm19 - name: Test default LLVM @@ -160,7 +177,8 @@ jobs: export CXX=clang++ export CGO_ENABLED=1 pc_dir="$(cygpath -u "$RUNNER_TEMP")/llvm-pkgconfig" - export PKG_CONFIG_PATH="$(cygpath -m "$pc_dir")" + PKG_CONFIG_PATH="$(cygpath -m "$pc_dir")" + export PKG_CONFIG_PATH go test -v test-linux-fedora: # Fedora uses different paths than other systems, so testing it separately. diff --git a/README.markdown b/README.markdown index e66c391..28cfdc2 100644 --- a/README.markdown +++ b/README.markdown @@ -13,6 +13,7 @@ Currently supported: * LLVM 20, 19, 18, 17, 16, 15 and 14 from [apt.llvm.org](http://apt.llvm.org/) on Debian/Ubuntu. * LLVM 20, 19, 18, 17, 16, 15 and 14 from Homebrew on macOS. + * LLVM 19 in an MSYS2 CLANG64 environment on Windows (see the setup below). * Any of the above versions with a manually built LLVM through the `byollvm` build tag. You need to set up `CFLAGS`/`LDFLAGS` etc yourself in this case. You can select the LLVM version using a build tag, for example `-tags=llvm17` @@ -26,6 +27,31 @@ If you have a supported LLVM installation, you should be able to do a simple `go You can use build tags to select a LLVM version. For example, use `-tags=llvm15` to select LLVM 15. Setting a build tag for a LLVM version that is not supported will be ignored. +### Windows (MSYS2 CLANG64) + +The LLVM 19 binding expects `pkg-config` metadata named `llvm-19`. MSYS2 does +not provide that versioned file, so after installing LLVM 19 and `pkgconf` in a +CLANG64 environment, generate it from `llvm-config`: + + pc_dir="$PWD/.llvm-pkgconfig" + mkdir -p "$pc_dir" + llvm_version="$(llvm-config --version)" + test "$llvm_version" = 19.1.7 + cflags="$(llvm-config --cflags | tr '\r\n' ' ')" + ldflags="$(llvm-config --ldflags --libs all --system-libs | tr '\r\n' ' ')" + printf '%s\n' \ + 'Name: LLVM 19' \ + 'Description: LLVM 19 host compiler and linker flags' \ + "Version: $llvm_version" \ + "Cflags: $cflags" \ + "Libs: $ldflags" \ + > "$pc_dir/llvm-19.pc" + export PKG_CONFIG_PATH="$(cygpath -m "$pc_dir")" + export CC=clang CXX=clang++ CGO_ENABLED=1 + +The Windows CI job in [`.github/workflows/go.yml`](.github/workflows/go.yml) +shows the exact pinned MSYS2 packages used by this project. + ## License These LLVM bindings for Go originally come from LLVM, but they have since been [removed](https://discourse.llvm.org/t/rfc-remove-the-go-bindings/65725). Still, they remain under the same license as they were originally, which is the [Apache License 2.0 (with LLVM exceptions)](http://releases.llvm.org/9.0.0/LICENSE.TXT). Check upstream LLVM for detailed copyright information. From cfe53cde654684623d53546511fcaa2b1c0dc37b Mon Sep 17 00:00:00 2001 From: Li Jie Date: Mon, 24 Aug 2026 11:36:28 +0800 Subject: [PATCH 06/10] ci: follow setup-msys2 v2 updates --- .github/workflows/go.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 52cfcfa..0f2db4d 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -65,7 +65,7 @@ jobs: with: go-version: '1.22' - name: Set up MSYS2 - uses: msys2/setup-msys2@66cd2cce69caa17b53920067426061ca1de3a884 # v2.32.0 + uses: msys2/setup-msys2@v2 with: msystem: CLANG64 path-type: inherit From a0dc14a860837d99bcff383907643460cb8d1b87 Mon Sep 17 00:00:00 2001 From: Li Jie Date: Mon, 24 Aug 2026 12:10:39 +0800 Subject: [PATCH 07/10] ci: test Windows across LLVM 14 through 22 --- .github/workflows/go.yml | 138 +++++++++++++++++++-------------------- README.markdown | 27 ++++---- llvm_config_llvm14.go | 2 + llvm_config_llvm15.go | 2 + llvm_config_llvm16.go | 2 + llvm_config_llvm17.go | 2 + llvm_config_llvm18.go | 2 + llvm_config_llvm20.go | 2 + llvm_config_llvm21.go | 2 + llvm_config_llvm22.go | 2 + 10 files changed, 99 insertions(+), 82 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 0f2db4d..2602392 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -57,6 +57,37 @@ jobs: go test -v test-windows: runs-on: windows-latest + strategy: + fail-fast: false + matrix: + include: + - llvm: 14 + version: '14.0.6' + sha256: a46a843b0899d284f2a1c76e15aa9a6f3e939925ed008fd4b3b68c5f2f0c8231 + - llvm: 15 + version: '15.0.7' + sha256: 8c55ba91a041507bd927c5f82348c36ef3696485afb71c51bbcc35a014d179de + - llvm: 16 + version: '16.0.6' + sha256: 8082a28d7ff50e5dfdace530935e3e59c37d11f1f8b52f43b7dc3b2fa130be66 + - llvm: 17 + version: '17.0.6' + sha256: 773f122cd79a54ecf3cbf1b1aff47543e95b12b4f91278b29c70cade37e3018c + - llvm: 18 + version: '18.1.8' + sha256: 7cb37bafd78874e707d0c323f8e16e81503bc76867638ef1c634ee0451fac0be + - llvm: 19 + version: '19.1.7' + sha256: d39689f23e1143a710a9120741ac3a1621fc4e2a81a143959bc870c60f9b85d1 + - llvm: 20 + version: '20.1.8' + sha256: 0944367aff9c3619f98dd0db78a1489018af9a8501b2533d17cc143a9624d853 + - llvm: 21 + version: '21.1.4' + sha256: f18f364b3aea5e4d09a4ed58d1c34b7220883912662e39935af96fabd603a912 + - llvm: 22 + version: '22.1.0' + sha256: 00199342f0cedfae60421d5d4ce0f1e217a06d7617611c8541372c47269c7084 steps: - name: Checkout uses: actions/checkout@v4 @@ -70,97 +101,61 @@ jobs: msystem: CLANG64 path-type: inherit update: true - install: curl - - name: Install LLVM 19 - shell: msys2 {0} - env: - LLVM_VERSION: '19.1.7' - MSYS2_LLVM_PACKAGE_VERSION: '19.1.7-1' + install: >- + mingw-w64-clang-x86_64-libc++ + mingw-w64-clang-x86_64-pkgconf + - name: Install LLVM ${{ matrix.llvm }} + shell: pwsh run: | - set -euo pipefail + $archiveName = 'llvm-${{ matrix.version }}-windows-gnu.zip' + $archive = Join-Path $env:RUNNER_TEMP $archiveName + $url = "https://github.com/yasuo-ozu/llvm-full/releases/download/v${{ matrix.version }}/$archiveName" + curl.exe --fail --location --retry 3 --output $archive $url + if ($LASTEXITCODE -ne 0) { + throw "failed to download $url" + } - repo=https://repo.msys2.org/mingw/clang64 - prefix=mingw-w64-clang-x86_64 - # MSYS2 is a rolling repository and can eventually remove these old - # artifacts. If a URL starts returning 404, refresh the transitive - # dependency versions and signatures together while keeping LLVM 19 - # pinned to the version above. - packages=( - "clang-$MSYS2_LLVM_PACKAGE_VERSION" - "clang-libs-$MSYS2_LLVM_PACKAGE_VERSION" - "compiler-rt-$MSYS2_LLVM_PACKAGE_VERSION" - "llvm-$MSYS2_LLVM_PACKAGE_VERSION" - "llvm-libs-$MSYS2_LLVM_PACKAGE_VERSION" - "lld-$MSYS2_LLVM_PACKAGE_VERSION" - "libc++-$MSYS2_LLVM_PACKAGE_VERSION" - "libunwind-$MSYS2_LLVM_PACKAGE_VERSION" - 'gettext-runtime-0.22.5-2' - 'libffi-3.4.6-1' - 'libiconv-1.17-4' - 'libxml2-2.12.9-2' - 'xz-5.6.3-3' - 'zlib-1.3.1-1' - 'zstd-1.5.6-2' - ) - download_dir="$(mktemp -d)" - trap 'rm -rf "$download_dir"' EXIT - archives=() - for package in "${packages[@]}"; do - archive="$prefix-$package-any.pkg.tar.zst" - curl --fail --location --retry 3 \ - --output "$download_dir/$archive" \ - "$repo/$archive" - curl --fail --location --retry 3 \ - --output "$download_dir/$archive.sig" \ - "$repo/$archive.sig" - archives+=("$download_dir/$archive") - done + $actualSha256 = (Get-FileHash -Algorithm SHA256 $archive).Hash.ToLowerInvariant() + if ($actualSha256 -ne '${{ matrix.sha256 }}') { + throw "expected SHA-256 ${{ matrix.sha256 }}, got $actualSha256" + } - # These archived LLVM 19 packages predate MSYS2's rename of the - # compiler-runtime virtual dependency from gcc-libs to cc-libs. - # libc++ 19 still supplies that runtime, so satisfy only the renamed - # package metadata rather than upgrading the pinned LLVM toolchain. - assumed_cc_runtime="$prefix-cc-libs=$LLVM_VERSION" - # pacman discovers each adjacent .sig file and validates it against - # the MSYS2 package keyring before installing the local archive. - pacman --noconfirm -U \ - --assume-installed "$assumed_cc_runtime" \ - "${archives[@]}" - pacman --noconfirm -S --needed \ - --assume-installed "$assumed_cc_runtime" \ - "$prefix-pkgconf" + $prefix = Join-Path $env:RUNNER_TEMP 'llvm-${{ matrix.version }}' + New-Item -ItemType Directory -Force -Path $prefix | Out-Null + 7z x $archive "-o$prefix" -y + if ($LASTEXITCODE -ne 0) { + throw "failed to extract $archive" + } + Remove-Item $archive - for package in clang clang-libs compiler-rt llvm llvm-libs lld libc++ libunwind; do - installed="$(pacman -Q "$prefix-$package" | awk '{print $2}')" - if [[ "$installed" != "$MSYS2_LLVM_PACKAGE_VERSION" ]]; then - echo "expected $package $MSYS2_LLVM_PACKAGE_VERSION, got $installed" >&2 - exit 1 - fi - done - - name: Test LLVM 19 + if (-not (Test-Path (Join-Path $prefix 'bin\llvm-config.exe'))) { + throw "llvm-config.exe is missing from $prefix" + } + (Join-Path $prefix 'bin') | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + - name: Test LLVM ${{ matrix.llvm }} shell: msys2 {0} run: | set -euo pipefail llvm_version="$(llvm-config --version)" - if [[ "$llvm_version" != 19.1.7 ]]; then - echo "expected LLVM 19.1.7, got $llvm_version" >&2 + if [[ "$llvm_version" != '${{ matrix.version }}' ]]; then + echo "expected LLVM ${{ matrix.version }}, got $llvm_version" >&2 exit 1 fi # Supply the installed LLVM's include and library paths through the - # pkg-config name consumed by the Windows LLVM 19 binding. + # versioned pkg-config name consumed by the Windows binding. pc_dir="$(cygpath -u "$RUNNER_TEMP")/llvm-pkgconfig" mkdir -p "$pc_dir" cflags="$(llvm-config --cflags | tr '\r\n' ' ')" ldflags="$(llvm-config --ldflags --libs all --system-libs | tr '\r\n' ' ')" printf '%s\n' \ - 'Name: LLVM 19' \ - 'Description: LLVM 19 host compiler and linker flags' \ + 'Name: LLVM ${{ matrix.llvm }}' \ + 'Description: LLVM ${{ matrix.llvm }} host compiler and linker flags' \ "Version: $llvm_version" \ "Cflags: $cflags" \ "Libs: $ldflags" \ - > "$pc_dir/llvm-19.pc" + > "$pc_dir/llvm-${{ matrix.llvm }}.pc" export CC=clang export CXX=clang++ @@ -168,8 +163,9 @@ jobs: PKG_CONFIG_PATH="$(cygpath -m "$pc_dir")" export PKG_CONFIG_PATH clang --version - go test -v -tags=llvm19 + go test -v -tags=llvm${{ matrix.llvm }} - name: Test default LLVM + if: matrix.llvm == 19 shell: msys2 {0} run: | set -euo pipefail diff --git a/README.markdown b/README.markdown index 28cfdc2..a96873c 100644 --- a/README.markdown +++ b/README.markdown @@ -11,9 +11,9 @@ This library provides bindings to a system-installed LLVM. Currently supported: - * LLVM 20, 19, 18, 17, 16, 15 and 14 from [apt.llvm.org](http://apt.llvm.org/) on Debian/Ubuntu. - * LLVM 20, 19, 18, 17, 16, 15 and 14 from Homebrew on macOS. - * LLVM 19 in an MSYS2 CLANG64 environment on Windows (see the setup below). + * LLVM 22, 21, 20, 19, 18, 17, 16, 15 and 14 from [apt.llvm.org](http://apt.llvm.org/) on Debian/Ubuntu. + * LLVM 22, 21, 20, 19, 18, 17, 16, 15 and 14 from Homebrew on macOS. + * LLVM 22, 21, 20, 19, 18, 17, 16, 15 and 14 in an MSYS2 CLANG64 environment on Windows (see the setup below). * Any of the above versions with a manually built LLVM through the `byollvm` build tag. You need to set up `CFLAGS`/`LDFLAGS` etc yourself in this case. You can select the LLVM version using a build tag, for example `-tags=llvm17` @@ -29,28 +29,33 @@ You can use build tags to select a LLVM version. For example, use `-tags=llvm15` ### Windows (MSYS2 CLANG64) -The LLVM 19 binding expects `pkg-config` metadata named `llvm-19`. MSYS2 does -not provide that versioned file, so after installing LLVM 19 and `pkgconf` in a -CLANG64 environment, generate it from `llvm-config`: +The Windows bindings expect `pkg-config` metadata named after the selected LLVM +major version, such as `llvm-19`. After installing a MinGW-compatible LLVM and +`pkgconf` in a CLANG64 environment, generate that file from `llvm-config`: pc_dir="$PWD/.llvm-pkgconfig" mkdir -p "$pc_dir" llvm_version="$(llvm-config --version)" - test "$llvm_version" = 19.1.7 + llvm_major="${llvm_version%%.*}" + case "$llvm_major" in + 14|15|16|17|18|19|20|21|22) ;; + *) echo "unsupported LLVM version: $llvm_version" >&2; exit 1 ;; + esac cflags="$(llvm-config --cflags | tr '\r\n' ' ')" ldflags="$(llvm-config --ldflags --libs all --system-libs | tr '\r\n' ' ')" printf '%s\n' \ - 'Name: LLVM 19' \ - 'Description: LLVM 19 host compiler and linker flags' \ + "Name: LLVM $llvm_major" \ + "Description: LLVM $llvm_major host compiler and linker flags" \ "Version: $llvm_version" \ "Cflags: $cflags" \ "Libs: $ldflags" \ - > "$pc_dir/llvm-19.pc" + > "$pc_dir/llvm-$llvm_major.pc" export PKG_CONFIG_PATH="$(cygpath -m "$pc_dir")" export CC=clang CXX=clang++ CGO_ENABLED=1 + go test -tags="llvm$llvm_major" The Windows CI job in [`.github/workflows/go.yml`](.github/workflows/go.yml) -shows the exact pinned MSYS2 packages used by this project. +shows the exact LLVM versions and SHA-256 checksums used by this project. ## License diff --git a/llvm_config_llvm14.go b/llvm_config_llvm14.go index 9d38a5b..0178894 100644 --- a/llvm_config_llvm14.go +++ b/llvm_config_llvm14.go @@ -11,6 +11,8 @@ package llvm // #cgo linux CPPFLAGS: -I/usr/lib/llvm-14/include -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS // #cgo linux CXXFLAGS: -std=c++14 // #cgo linux LDFLAGS: -L/usr/lib/llvm-14/lib -lLLVM-14 +// #cgo windows pkg-config: llvm-14 +// #cgo windows CXXFLAGS: -std=c++14 import "C" type run_build_sh int diff --git a/llvm_config_llvm15.go b/llvm_config_llvm15.go index 34aebc0..a049045 100644 --- a/llvm_config_llvm15.go +++ b/llvm_config_llvm15.go @@ -11,6 +11,8 @@ package llvm // #cgo linux CPPFLAGS: -I/usr/lib/llvm-15/include -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS // #cgo linux CXXFLAGS: -std=c++14 // #cgo linux LDFLAGS: -L/usr/lib/llvm-15/lib -lLLVM-15 +// #cgo windows pkg-config: llvm-15 +// #cgo windows CXXFLAGS: -std=c++14 import "C" type run_build_sh int diff --git a/llvm_config_llvm16.go b/llvm_config_llvm16.go index 936ca0f..35cc410 100644 --- a/llvm_config_llvm16.go +++ b/llvm_config_llvm16.go @@ -11,6 +11,8 @@ package llvm // #cgo linux CPPFLAGS: -I/usr/lib/llvm-16/include -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS // #cgo linux CXXFLAGS: -std=c++17 // #cgo linux LDFLAGS: -L/usr/lib/llvm-16/lib -lLLVM-16 +// #cgo windows pkg-config: llvm-16 +// #cgo windows CXXFLAGS: -std=c++17 import "C" type run_build_sh int diff --git a/llvm_config_llvm17.go b/llvm_config_llvm17.go index 6a00b39..815b687 100644 --- a/llvm_config_llvm17.go +++ b/llvm_config_llvm17.go @@ -11,6 +11,8 @@ package llvm // #cgo linux CPPFLAGS: -I/usr/include/llvm-17 -I/usr/include/llvm-c-17 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS // #cgo linux CXXFLAGS: -std=c++17 // #cgo linux LDFLAGS: -L/usr/lib/llvm-17/lib -lLLVM-17 +// #cgo windows pkg-config: llvm-17 +// #cgo windows CXXFLAGS: -std=c++17 import "C" type run_build_sh int diff --git a/llvm_config_llvm18.go b/llvm_config_llvm18.go index c41fea0..27dd760 100644 --- a/llvm_config_llvm18.go +++ b/llvm_config_llvm18.go @@ -11,6 +11,8 @@ package llvm // #cgo linux CPPFLAGS: -I/usr/include/llvm-18 -I/usr/include/llvm-c-18 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS // #cgo linux CXXFLAGS: -std=c++17 // #cgo linux LDFLAGS: -L/usr/lib/llvm-18/lib -lLLVM-18 +// #cgo windows pkg-config: llvm-18 +// #cgo windows CXXFLAGS: -std=c++17 import "C" type run_build_sh int diff --git a/llvm_config_llvm20.go b/llvm_config_llvm20.go index d67281a..add4a07 100644 --- a/llvm_config_llvm20.go +++ b/llvm_config_llvm20.go @@ -15,6 +15,8 @@ package llvm // #cgo linux CPPFLAGS: -I/usr/include/llvm-20 -I/usr/include/llvm-c-20 -I/usr/lib64/llvm20/include -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS // #cgo linux CXXFLAGS: -std=c++17 // #cgo linux LDFLAGS: -L/usr/lib/llvm-20/lib -L/usr/lib64/llvm20/lib64 -lLLVM-20 +// #cgo windows pkg-config: llvm-20 +// #cgo windows CXXFLAGS: -std=c++17 import "C" type run_build_sh int diff --git a/llvm_config_llvm21.go b/llvm_config_llvm21.go index 263c2fc..bff0dba 100644 --- a/llvm_config_llvm21.go +++ b/llvm_config_llvm21.go @@ -14,6 +14,8 @@ package llvm // #cgo linux CPPFLAGS: -I/usr/include/llvm-21 -I/usr/include/llvm-c-21 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS // #cgo linux CXXFLAGS: -std=c++17 // #cgo linux LDFLAGS: -L/usr/lib/llvm-21/lib -lLLVM-21 +// #cgo windows pkg-config: llvm-21 +// #cgo windows CXXFLAGS: -std=c++17 import "C" type run_build_sh int diff --git a/llvm_config_llvm22.go b/llvm_config_llvm22.go index 103e930..3ae122f 100644 --- a/llvm_config_llvm22.go +++ b/llvm_config_llvm22.go @@ -14,6 +14,8 @@ package llvm // #cgo linux CPPFLAGS: -I/usr/include/llvm-22 -I/usr/include/llvm-c-22 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS // #cgo linux CXXFLAGS: -std=c++17 // #cgo linux LDFLAGS: -L/usr/lib/llvm-22/lib -lLLVM-22 +// #cgo windows pkg-config: llvm-22 +// #cgo windows CXXFLAGS: -std=c++17 import "C" type run_build_sh int From 16f6e0cf84618bb736ecf91abaf46496af5b9b26 Mon Sep 17 00:00:00 2001 From: Li Jie Date: Mon, 24 Aug 2026 12:14:18 +0800 Subject: [PATCH 08/10] ci: expose matrix LLVM tools to MSYS2 --- .github/workflows/go.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 2602392..4d90e51 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -131,12 +131,14 @@ jobs: if (-not (Test-Path (Join-Path $prefix 'bin\llvm-config.exe'))) { throw "llvm-config.exe is missing from $prefix" } - (Join-Path $prefix 'bin') | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + "LLVM_PREFIX=$prefix" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - name: Test LLVM ${{ matrix.llvm }} shell: msys2 {0} run: | set -euo pipefail + llvm_bin="$(cygpath -u "$LLVM_PREFIX")/bin" + export PATH="$llvm_bin:$PATH" llvm_version="$(llvm-config --version)" if [[ "$llvm_version" != '${{ matrix.version }}' ]]; then echo "expected LLVM ${{ matrix.version }}, got $llvm_version" >&2 @@ -169,6 +171,8 @@ jobs: shell: msys2 {0} run: | set -euo pipefail + llvm_bin="$(cygpath -u "$LLVM_PREFIX")/bin" + export PATH="$llvm_bin:$PATH" export CC=clang export CXX=clang++ export CGO_ENABLED=1 From 5f1001c02ec60a2d7c1fca182a918bb086601a53 Mon Sep 17 00:00:00 2001 From: Li Jie Date: Mon, 24 Aug 2026 12:21:49 +0800 Subject: [PATCH 09/10] ci: match Windows LLVM GNU runtime --- .github/workflows/go.yml | 6 +++--- README.markdown | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 4d90e51..19d7c20 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -98,12 +98,12 @@ jobs: - name: Set up MSYS2 uses: msys2/setup-msys2@v2 with: - msystem: CLANG64 + msystem: MINGW64 path-type: inherit update: true install: >- - mingw-w64-clang-x86_64-libc++ - mingw-w64-clang-x86_64-pkgconf + mingw-w64-x86_64-gcc + mingw-w64-x86_64-pkgconf - name: Install LLVM ${{ matrix.llvm }} shell: pwsh run: | diff --git a/README.markdown b/README.markdown index a96873c..23246a4 100644 --- a/README.markdown +++ b/README.markdown @@ -13,7 +13,7 @@ Currently supported: * LLVM 22, 21, 20, 19, 18, 17, 16, 15 and 14 from [apt.llvm.org](http://apt.llvm.org/) on Debian/Ubuntu. * LLVM 22, 21, 20, 19, 18, 17, 16, 15 and 14 from Homebrew on macOS. - * LLVM 22, 21, 20, 19, 18, 17, 16, 15 and 14 in an MSYS2 CLANG64 environment on Windows (see the setup below). + * LLVM 22, 21, 20, 19, 18, 17, 16, 15 and 14 in an MSYS2 MINGW64 environment on Windows (see the setup below). * Any of the above versions with a manually built LLVM through the `byollvm` build tag. You need to set up `CFLAGS`/`LDFLAGS` etc yourself in this case. You can select the LLVM version using a build tag, for example `-tags=llvm17` @@ -27,11 +27,11 @@ If you have a supported LLVM installation, you should be able to do a simple `go You can use build tags to select a LLVM version. For example, use `-tags=llvm15` to select LLVM 15. Setting a build tag for a LLVM version that is not supported will be ignored. -### Windows (MSYS2 CLANG64) +### Windows (MSYS2 MINGW64) The Windows bindings expect `pkg-config` metadata named after the selected LLVM major version, such as `llvm-19`. After installing a MinGW-compatible LLVM and -`pkgconf` in a CLANG64 environment, generate that file from `llvm-config`: +`pkgconf` in a MINGW64 environment, generate that file from `llvm-config`: pc_dir="$PWD/.llvm-pkgconfig" mkdir -p "$pc_dir" From e5fb5a763a133a947bef0826ed1c5f7b2e9324d0 Mon Sep 17 00:00:00 2001 From: Li Jie Date: Mon, 24 Aug 2026 13:31:29 +0800 Subject: [PATCH 10/10] ci: fix Windows LLVM matrix toolchain --- .github/workflows/go.yml | 14 ++++++++------ README.markdown | 10 ++++++---- llvm_config_windows_llvm20.go | 10 ---------- 3 files changed, 14 insertions(+), 20 deletions(-) delete mode 100644 llvm_config_windows_llvm20.go diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 19d7c20..cbc734c 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -150,7 +150,9 @@ jobs: pc_dir="$(cygpath -u "$RUNNER_TEMP")/llvm-pkgconfig" mkdir -p "$pc_dir" cflags="$(llvm-config --cflags | tr '\r\n' ' ')" - ldflags="$(llvm-config --ldflags --libs all --system-libs | tr '\r\n' ' ')" + # The release archives can embed their build machine's zstd import + # library path, and their static LLVM libraries require winpthread. + ldflags="$(llvm-config --ldflags --libs all --system-libs | tr '\r\n' ' ' | sed -E 's#[^[:space:]]*/mingw64/lib/libzstd\.dll\.a#-lzstd#g') -lwinpthread" printf '%s\n' \ 'Name: LLVM ${{ matrix.llvm }}' \ 'Description: LLVM ${{ matrix.llvm }} host compiler and linker flags' \ @@ -159,12 +161,12 @@ jobs: "Libs: $ldflags" \ > "$pc_dir/llvm-${{ matrix.llvm }}.pc" - export CC=clang - export CXX=clang++ + export CC=gcc + export CXX=g++ export CGO_ENABLED=1 PKG_CONFIG_PATH="$(cygpath -m "$pc_dir")" export PKG_CONFIG_PATH - clang --version + gcc --version go test -v -tags=llvm${{ matrix.llvm }} - name: Test default LLVM if: matrix.llvm == 19 @@ -173,8 +175,8 @@ jobs: set -euo pipefail llvm_bin="$(cygpath -u "$LLVM_PREFIX")/bin" export PATH="$llvm_bin:$PATH" - export CC=clang - export CXX=clang++ + export CC=gcc + export CXX=g++ export CGO_ENABLED=1 pc_dir="$(cygpath -u "$RUNNER_TEMP")/llvm-pkgconfig" PKG_CONFIG_PATH="$(cygpath -m "$pc_dir")" diff --git a/README.markdown b/README.markdown index 23246a4..3884324 100644 --- a/README.markdown +++ b/README.markdown @@ -30,8 +30,9 @@ You can use build tags to select a LLVM version. For example, use `-tags=llvm15` ### Windows (MSYS2 MINGW64) The Windows bindings expect `pkg-config` metadata named after the selected LLVM -major version, such as `llvm-19`. After installing a MinGW-compatible LLVM and -`pkgconf` in a MINGW64 environment, generate that file from `llvm-config`: +major version, such as `llvm-19`. After installing a MinGW-compatible LLVM, +`mingw-w64-x86_64-gcc`, and `mingw-w64-x86_64-pkgconf` in a MINGW64 +environment, generate that file from `llvm-config`: pc_dir="$PWD/.llvm-pkgconfig" mkdir -p "$pc_dir" @@ -42,7 +43,8 @@ major version, such as `llvm-19`. After installing a MinGW-compatible LLVM and *) echo "unsupported LLVM version: $llvm_version" >&2; exit 1 ;; esac cflags="$(llvm-config --cflags | tr '\r\n' ' ')" - ldflags="$(llvm-config --ldflags --libs all --system-libs | tr '\r\n' ' ')" + # Normalize the release build machine's zstd path and link winpthread. + ldflags="$(llvm-config --ldflags --libs all --system-libs | tr '\r\n' ' ' | sed -E 's#[^[:space:]]*/mingw64/lib/libzstd\.dll\.a#-lzstd#g') -lwinpthread" printf '%s\n' \ "Name: LLVM $llvm_major" \ "Description: LLVM $llvm_major host compiler and linker flags" \ @@ -51,7 +53,7 @@ major version, such as `llvm-19`. After installing a MinGW-compatible LLVM and "Libs: $ldflags" \ > "$pc_dir/llvm-$llvm_major.pc" export PKG_CONFIG_PATH="$(cygpath -m "$pc_dir")" - export CC=clang CXX=clang++ CGO_ENABLED=1 + export CC=gcc CXX=g++ CGO_ENABLED=1 go test -tags="llvm$llvm_major" The Windows CI job in [`.github/workflows/go.yml`](.github/workflows/go.yml) diff --git a/llvm_config_windows_llvm20.go b/llvm_config_windows_llvm20.go deleted file mode 100644 index 15d578a..0000000 --- a/llvm_config_windows_llvm20.go +++ /dev/null @@ -1,10 +0,0 @@ -//go:build !byollvm && windows && llvm20 - -package llvm - -// #cgo CPPFLAGS: -I/usr/include/llvm -I/usr/include/llvm-c -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -// #cgo CXXFLAGS: -std=c++17 -// #cgo LDFLAGS: -Lllvm-20 -lLLVM-20.dll -import "C" - -type run_build_sh int