From 5762a8b8a78f336e077f5803b3f2572eb1084ff8 Mon Sep 17 00:00:00 2001 From: ZhouGuangyuan Date: Fri, 28 Aug 2026 17:44:43 +0800 Subject: [PATCH 1/7] cpp/llvm: select LLVM 21 on Windows --- cpp/llvm/config_windows.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cpp/llvm/config_windows.go b/cpp/llvm/config_windows.go index ac90442..21c1fcd 100644 --- a/cpp/llvm/config_windows.go +++ b/cpp/llvm/config_windows.go @@ -23,8 +23,8 @@ const ( // the bridge for the ABI selected by its host clang++, then expose only C // functions to the LLGo target. This avoids leaking that C++ ABI across the // package boundary while retaining the target's native C ABI. - LLGoFiles = "$(pkg-config --cflags llvm-19) -std=c++17 --target=$(llvm-config --host-target): _wrap/demangle_windows.cpp" - // The llvm-19 package preserves LLVM's library order and required Windows + LLGoFiles = "$(pkg-config --cflags llvm-21) -std=c++17 --target=$(llvm-config --host-target): _wrap/demangle_windows.cpp" + // The llvm-21 package preserves LLVM's library order and required Windows // system libraries. - LLGoPackage = "link: $(pkg-config --libs llvm-19)" + LLGoPackage = "link: $(pkg-config --libs llvm-21)" ) From a8f1f8266c99ed9f05484cdb49beb2059225c813 Mon Sep 17 00:00:00 2001 From: ZhouGuangyuan Date: Tue, 1 Sep 2026 13:14:24 +0800 Subject: [PATCH 2/7] cpp/llvm: use selected Windows LLVM metadata --- .github/workflows/go.yml | 17 +++++++++++++++++ cpp/llvm/config_windows.go | 9 +++++---- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index c7d40cd..204da17 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -56,6 +56,23 @@ jobs: with: llvm-version: '19' + - name: Expose selected Windows LLVM metadata alias + if: runner.os == 'Windows' + shell: pwsh + run: | + $ErrorActionPreference = "Stop" + $pcDir = (& pkg-config --variable=pcfiledir llvm-19).Trim() + if ($LASTEXITCODE -ne 0 -or -not $pcDir) { + throw "Unable to locate the selected LLVM pkg-config metadata" + } + $source = Join-Path $pcDir "llvm-19.pc" + $alias = Join-Path $pcDir "llvm.pc" + Copy-Item -LiteralPath $source -Destination $alias -Force + & pkg-config --modversion llvm + if ($LASTEXITCODE -ne 0) { + throw "The selected LLVM pkg-config alias is unavailable" + } + - name: Build LLGo if: runner.os != 'Windows' working-directory: .llgo diff --git a/cpp/llvm/config_windows.go b/cpp/llvm/config_windows.go index 21c1fcd..ec34a85 100644 --- a/cpp/llvm/config_windows.go +++ b/cpp/llvm/config_windows.go @@ -23,8 +23,9 @@ const ( // the bridge for the ABI selected by its host clang++, then expose only C // functions to the LLGo target. This avoids leaking that C++ ABI across the // package boundary while retaining the target's native C ABI. - LLGoFiles = "$(pkg-config --cflags llvm-21) -std=c++17 --target=$(llvm-config --host-target): _wrap/demangle_windows.cpp" - // The llvm-21 package preserves LLVM's library order and required Windows - // system libraries. - LLGoPackage = "link: $(pkg-config --libs llvm-21)" + LLGoFiles = "$(pkg-config --cflags llvm) -std=c++17 --target=$(llvm-config --host-target): _wrap/demangle_windows.cpp" + // The selected LLVM package preserves LLVM's library order and required + // Windows system libraries. LLGo's setup validates the requested version + // before exposing this stable pkg-config alias. + LLGoPackage = "link: $(pkg-config --libs llvm)" ) From 06fc743d39294e19ad1cbfb58f6adee8faeccb1e Mon Sep 17 00:00:00 2001 From: ZhouGuangyuan Date: Tue, 1 Sep 2026 14:53:32 +0800 Subject: [PATCH 3/7] ci: qualify LLVM 22 demangle bridge --- .github/workflows/go.yml | 145 ++++++++++++++++------- cpp/llvm/_wrap/demangle_windows_test.cpp | 74 ++++++++++++ 2 files changed, 174 insertions(+), 45 deletions(-) create mode 100644 cpp/llvm/_wrap/demangle_windows_test.cpp diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 204da17..e94bed4 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -33,14 +33,13 @@ jobs: os: - ubuntu-latest - macos-latest - - windows-2022 steps: - uses: actions/checkout@v4 - name: Set up Go uses: actions/setup-go@v5 with: - go-version: '1.26.7' + go-version: '1.27.0' - name: Check out LLGo uses: actions/checkout@v4 @@ -54,32 +53,20 @@ jobs: - name: Set up LLGo dependencies uses: ./.llgo/.github/actions/setup-deps with: - llvm-version: '19' - - - name: Expose selected Windows LLVM metadata alias - if: runner.os == 'Windows' - shell: pwsh - run: | - $ErrorActionPreference = "Stop" - $pcDir = (& pkg-config --variable=pcfiledir llvm-19).Trim() - if ($LASTEXITCODE -ne 0 -or -not $pcDir) { - throw "Unable to locate the selected LLVM pkg-config metadata" - } - $source = Join-Path $pcDir "llvm-19.pc" - $alias = Join-Path $pcDir "llvm.pc" - Copy-Item -LiteralPath $source -Destination $alias -Force - & pkg-config --modversion llvm - if ($LASTEXITCODE -ne 0) { - throw "The selected LLVM pkg-config alias is unavailable" - } + llvm-version: '22' - name: Build LLGo - if: runner.os != 'Windows' working-directory: .llgo - run: go build -tags=dev -o "$RUNNER_TEMP/llgo" ./cmd/llgo + env: + GOFLAGS: -tags=byollvm + run: | + # Stable LLGo predates the default-version switch, but its source can + # build against system LLVM 22 through the released binding package. + go mod edit -require=github.com/xgo-dev/llvm@v0.9.8 + go mod download github.com/xgo-dev/llvm@v0.9.8 + go build -tags=dev -o "$RUNNER_TEMP/llgo" ./cmd/llgo - name: Test LLGo native bindings - if: runner.os != 'Windows' env: LLGO_BUILD_CACHE: 'off' LLGO_ROOT: ${{ github.workspace }}/.llgo @@ -97,32 +84,100 @@ jobs: run: | "$RUNNER_TEMP/llgo" test -v ./cpp/llvm - - name: Build LLGo on Windows - if: runner.os == 'Windows' - working-directory: .llgo - shell: pwsh - run: go build -tags=dev -o "$env:RUNNER_TEMP\llgo.exe" ./cmd/llgo + windows-llvm-demangle: + name: Windows LLVM 22 demangle bridge + runs-on: windows-2022 + steps: + - uses: actions/checkout@v4 - - name: Test LLGo Windows bindings - if: runner.os == 'Windows' + - name: Cache LLVM 22 development archive + id: llvm-cache + uses: actions/cache/restore@v4 + with: + path: ${{ runner.tool_cache }}\lib-llvm\clang+llvm-22.1.8-x86_64-pc-windows-msvc.tar.xz + key: lib-llvm-22.1.8-windows-msvc-d96c2cc1736f4eb7fa43cb9bbdf56d93551a9ae0a9aadb9c99c3c3b2b712a234-v1 + + - name: Install LLVM 22 development archive shell: pwsh env: - LLGO_BUILD_CACHE: 'off' - LLGO_REQUIRE_MSVC: '1' - LLGO_ROOT: ${{ github.workspace }}/.llgo + LLVM_VERSION: '22.1.8' + LLVM_SHA256: d96c2cc1736f4eb7fa43cb9bbdf56d93551a9ae0a9aadb9c99c3c3b2b712a234 run: | $ErrorActionPreference = "Stop" - $llgo = Join-Path $env:RUNNER_TEMP "llgo.exe" - - & $llgo test -count=1 -v ` - ./c ` - ./c/math/rand ` - ./c/net ` - ./c/os ` - ./c/setjmp ` - ./c/time ` - ./cpp/llvm ` - ./cpp/std + $archiveName = "clang+llvm-$env:LLVM_VERSION-x86_64-pc-windows-msvc.tar.xz" + $archiveDir = Join-Path $env:RUNNER_TOOL_CACHE "lib-llvm" + $archive = Join-Path $archiveDir $archiveName + if ("${{ steps.llvm-cache.outputs.cache-hit }}" -ne "true") { + New-Item -ItemType Directory -Force $archiveDir | Out-Null + $asset = $archiveName.Replace("+", "%2B") + $url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-$env:LLVM_VERSION/$asset" + & curl.exe --fail --location --retry 5 --retry-all-errors --output $archive $url + if ($LASTEXITCODE -ne 0) { + throw "Downloading LLVM failed with exit code $LASTEXITCODE" + } + } + $actual = (Get-FileHash -Algorithm SHA256 $archive).Hash + if (-not $actual.Equals($env:LLVM_SHA256, [StringComparison]::OrdinalIgnoreCase)) { + throw "LLVM archive SHA-256 is $actual, want $env:LLVM_SHA256" + } + + $extractRoot = Join-Path $env:RUNNER_TEMP "lib-llvm-extract" + $sevenZip = Join-Path $env:ProgramFiles "7-Zip\7z.exe" + New-Item -ItemType Directory -Force $extractRoot | Out-Null + & $sevenZip x -y "-o$extractRoot" $archive + if ($LASTEXITCODE -ne 0) { + throw "Decompressing the LLVM archive failed with exit code $LASTEXITCODE" + } + $tar = Get-ChildItem -LiteralPath $extractRoot -Filter "*.tar" | Select-Object -First 1 + & $sevenZip x -y "-o$extractRoot" $tar.FullName + if ($LASTEXITCODE -ne 0) { + throw "Extracting the LLVM archive failed with exit code $LASTEXITCODE" + } + $llvmRoot = Get-ChildItem -LiteralPath $extractRoot -Directory | + Where-Object { Test-Path (Join-Path $_.FullName "bin\llvm-config.exe") } | + Select-Object -First 1 -ExpandProperty FullName + if (-not $llvmRoot) { + throw "The LLVM development archive is incomplete" + } + Add-Content -Encoding utf8 $env:GITHUB_ENV "LLVM_ROOT=$llvmRoot" + + - name: Save LLVM 22 development archive + if: steps.llvm-cache.outputs.cache-hit != 'true' + uses: actions/cache/save@v4 + with: + path: ${{ runner.tool_cache }}\lib-llvm\clang+llvm-22.1.8-x86_64-pc-windows-msvc.tar.xz + key: lib-llvm-22.1.8-windows-msvc-d96c2cc1736f4eb7fa43cb9bbdf56d93551a9ae0a9aadb9c99c3c3b2b712a234-v1 + + - name: Activate MSVC SDK + uses: ilammy/msvc-dev-cmd@v1 + + - name: Compile and run LLVM 22 demangle bridge + shell: pwsh + run: | + $ErrorActionPreference = "Stop" + $llvmConfig = Join-Path $env:LLVM_ROOT "bin\llvm-config.exe" + $version = ((& $llvmConfig --version) -join "").Trim() + if ($LASTEXITCODE -ne 0 -or -not $version.StartsWith("22.")) { + throw "Expected LLVM 22, got '$version'" + } + $clang = Join-Path $env:LLVM_ROOT "bin\clang++.exe" + $include = Join-Path $env:LLVM_ROOT "include" + $demangle = Join-Path $env:LLVM_ROOT "lib\LLVMDemangle.lib" + $test = Join-Path $env:RUNNER_TEMP "demangle_windows_test.exe" + & $clang ` + --target=x86_64-pc-windows-msvc ` + -fuse-ld=lld ` + -fms-runtime-lib=static ` + -std=c++17 ` + "-I$include" ` + cpp/llvm/_wrap/demangle_windows.cpp ` + cpp/llvm/_wrap/demangle_windows_test.cpp ` + $demangle ` + -o $test + if ($LASTEXITCODE -ne 0 -or -not (Test-Path $test)) { + throw "Compiling the LLVM demangle bridge failed with exit code $LASTEXITCODE" + } + & $test if ($LASTEXITCODE -ne 0) { - exit $LASTEXITCODE + throw "The LLVM demangle bridge smoke test failed with exit code $LASTEXITCODE" } diff --git a/cpp/llvm/_wrap/demangle_windows_test.cpp b/cpp/llvm/_wrap/demangle_windows_test.cpp new file mode 100644 index 0000000..f422b4b --- /dev/null +++ b/cpp/llvm/_wrap/demangle_windows_test.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2026 The GoPlus Authors (goplus.org). All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +extern "C" { + +char *llgoLLVMItaniumDemangle(const char *data, size_t size, int parseParams); +char *llgoLLVMMicrosoftDemangle(const char *data, size_t size, size_t *nRead, + int *status, int flags); +char *llgoLLVMRustDemangle(const char *data, size_t size); + +} // extern "C" + +static bool expectEqual(const char *name, char *value, const char *want) { + if (value == nullptr) { + std::cerr << name << " returned null\n"; + return false; + } + const std::string got(value); + std::free(value); + if (got != want) { + std::cerr << name << " returned " << got << ", want " << want << '\n'; + return false; + } + return true; +} + +int main() { + constexpr char itaniumName[] = "_Z3foov"; + bool ok = expectEqual( + "Itanium", + llgoLLVMItaniumDemangle(itaniumName, sizeof(itaniumName) - 1, 1), + "foo()"); + + constexpr char microsoftName[] = "?foo@@YAHH@Z"; + size_t nRead = 0; + int status = -1; + char *microsoft = llgoLLVMMicrosoftDemangle( + microsoftName, sizeof(microsoftName) - 1, &nRead, &status, 0); + if (microsoft == nullptr) { + std::cerr << "Microsoft returned null\n"; + ok = false; + } else { + const std::string got(microsoft); + std::free(microsoft); + if (status != 0 || nRead == 0 || got.find("foo") == std::string::npos) { + std::cerr << "Microsoft returned " << got << ", nRead " << nRead + << ", status " << status << '\n'; + ok = false; + } + } + + constexpr char rustName[] = "_RNvC6_123foo3bar"; + ok = expectEqual("Rust", llgoLLVMRustDemangle(rustName, sizeof(rustName) - 1), + "123foo::bar") && + ok; + return ok ? EXIT_SUCCESS : EXIT_FAILURE; +} From b2be7caaef7e191659230cd0e4b48a9ddd5dd969 Mon Sep 17 00:00:00 2001 From: ZhouGuangyuan Date: Tue, 1 Sep 2026 14:58:03 +0800 Subject: [PATCH 4/7] ci: pass LLVM 22 flags to byollvm --- .github/workflows/go.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index e94bed4..c4641a0 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -62,6 +62,11 @@ jobs: run: | # Stable LLGo predates the default-version switch, but its source can # build against system LLVM 22 through the released binding package. + llvm_version="$(llvm-config --version)" + test "${llvm_version%%.*}" = 22 + export CGO_CPPFLAGS="$(llvm-config --cflags)" + export CGO_CXXFLAGS="$(llvm-config --cxxflags)" + export CGO_LDFLAGS="$(llvm-config --ldflags --libs --system-libs)" go mod edit -require=github.com/xgo-dev/llvm@v0.9.8 go mod download github.com/xgo-dev/llvm@v0.9.8 go build -tags=dev -o "$RUNNER_TEMP/llgo" ./cmd/llgo From bdf7a1381373d3b8fc679c32bfb02da227fd93a6 Mon Sep 17 00:00:00 2001 From: ZhouGuangyuan Date: Tue, 1 Sep 2026 15:05:37 +0800 Subject: [PATCH 5/7] ci: preserve byollvm build tag --- .github/workflows/go.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index c4641a0..295c980 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -57,8 +57,6 @@ jobs: - name: Build LLGo working-directory: .llgo - env: - GOFLAGS: -tags=byollvm run: | # Stable LLGo predates the default-version switch, but its source can # build against system LLVM 22 through the released binding package. @@ -69,7 +67,7 @@ jobs: export CGO_LDFLAGS="$(llvm-config --ldflags --libs --system-libs)" go mod edit -require=github.com/xgo-dev/llvm@v0.9.8 go mod download github.com/xgo-dev/llvm@v0.9.8 - go build -tags=dev -o "$RUNNER_TEMP/llgo" ./cmd/llgo + go build -tags=dev,byollvm -o "$RUNNER_TEMP/llgo" ./cmd/llgo - name: Test LLGo native bindings env: From 1b2357ac6c91a1de236e65a9803068d6a67d841c Mon Sep 17 00:00:00 2001 From: ZhouGuangyuan Date: Tue, 1 Sep 2026 21:59:18 +0800 Subject: [PATCH 6/7] cpp: remove stale LLVM 19 compatibility wording --- cpp/std/_wrap/string.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cpp/std/_wrap/string.cpp b/cpp/std/_wrap/string.cpp index 2187939..1f649ce 100644 --- a/cpp/std/_wrap/string.cpp +++ b/cpp/std/_wrap/string.cpp @@ -1,8 +1,7 @@ #if defined(_WIN32) && defined(__clang__) && __clang_major__ < 20 // The current Visual Studio STL rejects older Clang releases by default. -// LLGo intentionally supports LLVM 19, whose MSVC ABI is sufficient for this -// wrapper; use the STL's documented escape hatch instead of changing the -// compiler or C++ ABI selected by the caller. +// Legacy Clang consumers may still select the STL's documented compatibility +// escape hatch without changing the C++ ABI selected by the caller. #define _ALLOW_COMPILER_AND_STL_VERSION_MISMATCH #endif From 181589449d09e29263c11d696cb47eebb88145fb Mon Sep 17 00:00:00 2001 From: ZhouGuangyuan Date: Thu, 3 Sep 2026 11:08:31 +0800 Subject: [PATCH 7/7] cpp/llvm: select LLVM 22 explicitly on Windows --- cpp/llvm/config_windows.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/cpp/llvm/config_windows.go b/cpp/llvm/config_windows.go index ec34a85..69a171d 100644 --- a/cpp/llvm/config_windows.go +++ b/cpp/llvm/config_windows.go @@ -23,9 +23,8 @@ const ( // the bridge for the ABI selected by its host clang++, then expose only C // functions to the LLGo target. This avoids leaking that C++ ABI across the // package boundary while retaining the target's native C ABI. - LLGoFiles = "$(pkg-config --cflags llvm) -std=c++17 --target=$(llvm-config --host-target): _wrap/demangle_windows.cpp" - // The selected LLVM package preserves LLVM's library order and required - // Windows system libraries. LLGo's setup validates the requested version - // before exposing this stable pkg-config alias. - LLGoPackage = "link: $(pkg-config --libs llvm)" + LLGoFiles = "$(pkg-config --cflags llvm-22) -std=c++17 --target=$(llvm-config --host-target): _wrap/demangle_windows.cpp" + // The explicitly versioned LLVM package preserves LLVM's library order and + // required Windows system libraries. + LLGoPackage = "link: $(pkg-config --libs llvm-22)" )