Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .github/actions/setup-goreleaser/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ runs:
steps:
- name: Set up Go
uses: ./.github/actions/setup-go
- name: Load LLVM payload contract
run: go run ./internal/llvmpayload/cmd/llvmpayload >> "$GITHUB_ENV"
shell: bash
- name: Restore Linux sysroot cache
id: cache-linux-sysroot
uses: actions/cache/restore@v5
Expand All @@ -31,7 +34,7 @@ runs:
uses: actions/cache/restore@v5
with:
path: ${{ inputs.esp-clang-cache-path }}
key: esp-clang-${{ hashFiles('.github/workflows/download_esp_clang.sh') }}
key: esp-clang-${{ hashFiles('.github/workflows/download_esp_clang.sh', 'internal/llvmpayload/**') }}
- name: Download ESP Clang (if cache miss)
if: steps.cache-esp-clang.outputs.cache-hit != 'true'
run: bash .github/workflows/download_esp_clang.sh
Expand All @@ -41,7 +44,7 @@ runs:
uses: actions/cache/save@v5
with:
path: ${{ inputs.esp-clang-cache-path }}
key: esp-clang-${{ hashFiles('.github/workflows/download_esp_clang.sh') }}
key: esp-clang-${{ hashFiles('.github/workflows/download_esp_clang.sh', 'internal/llvmpayload/**') }}
- name: Check file
run: tree .sysroot
shell: bash
63 changes: 56 additions & 7 deletions .github/workflows/download_esp_clang.sh
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
#!/bin/bash
set -e
set -euo pipefail

ESP_CLANG_VERSION="19.1.2_20250905-3"
BASE_URL="https://github.com/goplus/espressif-llvm-project-prebuilt/releases/download/${ESP_CLANG_VERSION}"
payload_env=$(mktemp)
archive_file=""
cleanup() {
rm -f "${payload_env}"
if [[ -n "${archive_file}" ]]; then
rm -f "${archive_file}"
fi
}
trap cleanup EXIT

go run ./internal/llvmpayload/cmd/llvmpayload > "${payload_env}"
# shellcheck disable=SC1090
source "${payload_env}"

get_esp_clang_platform() {
local platform="$1"
Expand Down Expand Up @@ -33,22 +44,56 @@ get_esp_clang_platform() {

get_filename() {
local platform="$1"
local platform_suffix=$(get_esp_clang_platform "${platform}")
local platform_suffix
platform_suffix=$(get_esp_clang_platform "${platform}")
echo "clang-esp-${ESP_CLANG_VERSION}-${platform_suffix}.tar.xz"
}

get_checksum() {
case "$1" in
"darwin-amd64") echo "${ESP_CLANG_SHA256_DARWIN_AMD64}" ;;
"darwin-arm64") echo "${ESP_CLANG_SHA256_DARWIN_ARM64}" ;;
"linux-amd64") echo "${ESP_CLANG_SHA256_LINUX_AMD64}" ;;
"linux-arm64") echo "${ESP_CLANG_SHA256_LINUX_ARM64}" ;;
*) echo "Error: Unsupported checksum platform: $1" >&2; exit 1 ;;
esac
}

verify_checksum() {
local filename="$1"
local expected="$2"
local actual
if command -v sha256sum >/dev/null 2>&1; then
actual=$(sha256sum "${filename}" | awk '{print $1}')
else
actual=$(shasum -a 256 "${filename}" | awk '{print $1}')
fi
if [[ "${actual}" != "${expected}" ]]; then
echo "Error: checksum mismatch for ${filename}: got ${actual}, want ${expected}" >&2
exit 1
fi
}

download_and_extract() {
local platform="$1"
local os="${platform%-*}"
local arch="${platform##*-}"
local filename=$(get_filename "${platform}")
local download_url="${BASE_URL}/${filename}"
local filename
local checksum
filename=$(get_filename "${platform}")
checksum=$(get_checksum "${platform}")
local download_url="${ESP_CLANG_BASE_URL}/${filename}"

echo "Downloading ESP Clang for ${platform}..."
echo " URL: ${download_url}"

archive_file=$(mktemp)
curl -fsSL "${download_url}" -o "${archive_file}"
verify_checksum "${archive_file}" "${checksum}"
mkdir -p ".sysroot/${os}/${arch}/crosscompile/clang"
curl -fsSL "${download_url}" | tar -xJ -C ".sysroot/${os}/${arch}/crosscompile/clang" --strip-components=1
tar -xJf "${archive_file}" -C ".sysroot/${os}/${arch}/crosscompile/clang" --strip-components=1
rm -f "${archive_file}"
archive_file=""

if [[ ! -f ".sysroot/${os}/${arch}/crosscompile/clang/bin/clang++" ]]; then
echo "Error: clang++ not found in ${platform} toolchain"
Expand All @@ -60,6 +105,10 @@ download_and_extract() {

echo "Downloading ESP Clang toolchain version ${ESP_CLANG_VERSION}..."

if [[ -n "${GITHUB_ENV:-}" ]]; then
echo "LLGO_LLVM_MAJOR=${ESP_CLANG_LLVM_MAJOR}" >> "${GITHUB_ENV}"
fi

for platform in "darwin-amd64" "darwin-arm64" "linux-amd64" "linux-arm64"; do
download_and_extract "${platform}"
done
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/release-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ jobs:
docker run \
--rm \
-e GITHUB_TOKEN=${GITHUB_TOKEN} \
-e LLGO_LLVM_MAJOR=${LLGO_LLVM_MAJOR} \
-v /var/run/docker.sock:/var/run/docker.sock \
-v $(pwd):/go/src/llgo \
-w /go/src/llgo \
Expand Down Expand Up @@ -208,6 +209,7 @@ jobs:
docker run \
--rm \
-e GITHUB_TOKEN=${GITHUB_TOKEN} \
-e LLGO_LLVM_MAJOR=${LLGO_LLVM_MAJOR} \
-v /var/run/docker.sock:/var/run/docker.sock \
-v $(pwd):/go/src/llgo \
-w /go/src/llgo \
Expand Down
8 changes: 4 additions & 4 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ builds:
- CC=o64-clang
- CXX=o64-clang++
- CGO_CPPFLAGS=-I{{.Env.SYSROOT_DARWIN_AMD64}}/crosscompile/clang/include -mmacosx-version-min=10.13 -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
- CGO_LDFLAGS=-L{{.Env.SYSROOT_DARWIN_AMD64}}/crosscompile/clang/lib -mmacosx-version-min=10.13 -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM-19 -lz -lm -Wl,-rpath,@executable_path/../crosscompile/clang/lib
- CGO_LDFLAGS=-L{{.Env.SYSROOT_DARWIN_AMD64}}/crosscompile/clang/lib -mmacosx-version-min=10.13 -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM-{{.Env.LLGO_LLVM_MAJOR}} -lz -lm -Wl,-rpath,@executable_path/../crosscompile/clang/lib
targets:
- darwin_amd64
mod_timestamp: "{{.CommitTimestamp}}"
Expand All @@ -43,7 +43,7 @@ builds:
- CC=oa64-clang
- CXX=oa64-clang++
- CGO_CPPFLAGS=-I{{.Env.SYSROOT_DARWIN_ARM64}}/crosscompile/clang/include -mmacosx-version-min=10.13 -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
- CGO_LDFLAGS=-L{{.Env.SYSROOT_DARWIN_ARM64}}/crosscompile/clang/lib -mmacosx-version-min=10.13 -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM-19 -lz -lm -Wl,-rpath,@executable_path/../crosscompile/clang/lib
- CGO_LDFLAGS=-L{{.Env.SYSROOT_DARWIN_ARM64}}/crosscompile/clang/lib -mmacosx-version-min=10.13 -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM-{{.Env.LLGO_LLVM_MAJOR}} -lz -lm -Wl,-rpath,@executable_path/../crosscompile/clang/lib
targets:
- darwin_arm64
mod_timestamp: "{{.CommitTimestamp}}"
Expand All @@ -62,7 +62,7 @@ builds:
- CXX={{.Env.SYSROOT_LINUX_AMD64}}/crosscompile/clang/bin/clang++
- CGO_CPPFLAGS=--target=x86_64-linux-gnu --gcc-toolchain={{.Env.SYSROOT_LINUX_AMD64}}/usr --sysroot={{.Env.SYSROOT_LINUX_AMD64}} -I{{.Env.SYSROOT_LINUX_AMD64}}/crosscompile/clang/include -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
- CGO_CXXFLAGS=-std=c++17 -nostdinc++ -isystem {{.Env.SYSROOT_LINUX_AMD64}}/usr/include/c++/10 -isystem {{.Env.SYSROOT_LINUX_AMD64}}/usr/include/x86_64-linux-gnu/c++/10 -isystem {{.Env.SYSROOT_LINUX_AMD64}}/usr/include/c++/10/backward
- CGO_LDFLAGS=--target=x86_64-linux-gnu --gcc-toolchain={{.Env.SYSROOT_LINUX_AMD64}}/usr --sysroot={{.Env.SYSROOT_LINUX_AMD64}} -L{{.Env.SYSROOT_LINUX_AMD64}}/crosscompile/clang/lib -L{{.Env.SYSROOT_LINUX_AMD64}}/usr/lib/gcc/x86_64-linux-gnu/10 -L{{.Env.SYSROOT_LINUX_AMD64}}/usr/lib/x86_64-linux-gnu -L{{.Env.SYSROOT_LINUX_AMD64}}/lib/x86_64-linux-gnu -lLLVM-19 -lz
- CGO_LDFLAGS=--target=x86_64-linux-gnu --gcc-toolchain={{.Env.SYSROOT_LINUX_AMD64}}/usr --sysroot={{.Env.SYSROOT_LINUX_AMD64}} -L{{.Env.SYSROOT_LINUX_AMD64}}/crosscompile/clang/lib -L{{.Env.SYSROOT_LINUX_AMD64}}/usr/lib/gcc/x86_64-linux-gnu/10 -L{{.Env.SYSROOT_LINUX_AMD64}}/usr/lib/x86_64-linux-gnu -L{{.Env.SYSROOT_LINUX_AMD64}}/lib/x86_64-linux-gnu -lLLVM-{{.Env.LLGO_LLVM_MAJOR}} -lz
- CGO_LDFLAGS_ALLOW=(--target=.*|--gcc-toolchain=.*|--sysroot.*)
targets:
- linux_amd64
Expand All @@ -82,7 +82,7 @@ builds:
- CXX={{.Env.SYSROOT_LINUX_AMD64}}/crosscompile/clang/bin/clang++
- CGO_CPPFLAGS=--target=aarch64-linux-gnu --gcc-toolchain={{.Env.SYSROOT_LINUX_ARM64}}/usr --sysroot={{.Env.SYSROOT_LINUX_ARM64}} -I{{.Env.SYSROOT_LINUX_ARM64}}/crosscompile/clang/include -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
- CGO_CXXFLAGS=-std=c++17 -nostdinc++ -isystem {{.Env.SYSROOT_LINUX_ARM64}}/usr/include/c++/10 -isystem {{.Env.SYSROOT_LINUX_ARM64}}/usr/include/aarch64-linux-gnu/c++/10 -isystem {{.Env.SYSROOT_LINUX_ARM64}}/usr/include/c++/10/backward
- CGO_LDFLAGS=--target=aarch64-linux-gnu --gcc-toolchain={{.Env.SYSROOT_LINUX_ARM64}}/usr --sysroot={{.Env.SYSROOT_LINUX_ARM64}} -L{{.Env.SYSROOT_LINUX_ARM64}}/crosscompile/clang/lib -L{{.Env.SYSROOT_LINUX_ARM64}}/usr/lib/gcc/aarch64-linux-gnu/10 -L{{.Env.SYSROOT_LINUX_ARM64}}/usr/lib/aarch64-linux-gnu -L{{.Env.SYSROOT_LINUX_ARM64}}/lib/aarch64-linux-gnu -lLLVM-19 -lz
- CGO_LDFLAGS=--target=aarch64-linux-gnu --gcc-toolchain={{.Env.SYSROOT_LINUX_ARM64}}/usr --sysroot={{.Env.SYSROOT_LINUX_ARM64}} -L{{.Env.SYSROOT_LINUX_ARM64}}/crosscompile/clang/lib -L{{.Env.SYSROOT_LINUX_ARM64}}/usr/lib/gcc/aarch64-linux-gnu/10 -L{{.Env.SYSROOT_LINUX_ARM64}}/usr/lib/aarch64-linux-gnu -L{{.Env.SYSROOT_LINUX_ARM64}}/lib/aarch64-linux-gnu -lLLVM-{{.Env.LLGO_LLVM_MAJOR}} -lz
- CGO_LDFLAGS_ALLOW=(--target=.*|--gcc-toolchain=.*|--sysroot.*)
targets:
- linux_arm64
Expand Down
2 changes: 1 addition & 1 deletion cl/_testdata/method/in.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func main() {

// CHECK-LABEL: define i64 @"main.(*T).Add"(ptr %0, i64 %1){{.*}} {
// CHECK: [[NIL:%[0-9]+]] = icmp eq ptr %0, null
// CHECK-NEXT: call void @"{{.*}}PanicWrapNilPointer"(i1 [[NIL]], %"{{.*}}String" { ptr @{{[0-9]+}}, i64 44 }, %"{{.*}}String" { ptr @{{[0-9]+}}, i64 3 })
// CHECK-NEXT: call void @"{{.*}}PanicWrapNilPointer"(i1 [[NIL]], %"{{.*}}String" { ptr @{{[0-9]+}}, i64 45 }, %"{{.*}}String" { ptr @{{[0-9]+}}, i64 3 })
// CHECK-NEXT: [[RECEIVER:%[0-9]+]] = load i64, ptr %0
// CHECK-NEXT: [[WRAPPED_SUM:%[0-9]+]] = call i64 @main.T.Add(i64 [[RECEIVER]], i64 %1)
// CHECK-NEXT: ret i64 [[WRAPPED_SUM]]
Expand Down
2 changes: 1 addition & 1 deletion cl/_testrt/struct/in.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func main() {

// CHECK-LABEL: define void @"main.(*Foo).Print"(ptr %0){{.*}} {
// CHECK: [[WRAPPER_NIL:%[0-9]+]] = icmp eq ptr %0, null
// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PanicWrapNilPointer"(i1 [[WRAPPER_NIL]], %"{{.*}}/runtime/internal/runtime.String" { ptr @{{[0-9]+}}, i64 44 }, %"{{.*}}/runtime/internal/runtime.String" { ptr @{{[0-9]+}}, i64 5 })
// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.PanicWrapNilPointer"(i1 [[WRAPPER_NIL]], %"{{.*}}/runtime/internal/runtime.String" { ptr @{{[0-9]+}}, i64 45 }, %"{{.*}}/runtime/internal/runtime.String" { ptr @{{[0-9]+}}, i64 5 })
// CHECK-NEXT: [[WRAPPER_VALUE:%[0-9]+]] = load %main.Foo, ptr %0
// CHECK-NEXT: call void @main.Foo.Print(%main.Foo [[WRAPPER_VALUE]])

Expand Down
20 changes: 20 additions & 0 deletions internal/build/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import (
"github.com/xgo-dev/llgo/internal/typepatch"
"github.com/xgo-dev/llgo/ssa/abi"
xenv "github.com/xgo-dev/llgo/xtool/env"
envllvm "github.com/xgo-dev/llgo/xtool/env/llvm"
gllvm "github.com/xgo-dev/llvm"

llruntime "github.com/xgo-dev/llgo/runtime"
Expand Down Expand Up @@ -411,6 +412,9 @@ func Build(inv Invocation) ([]Package, error) {
if err != nil {
return nil, fmt.Errorf("failed to setup crosscompile: %w", err)
}
if err := validateLLVMToolchain(export); err != nil {
return nil, fmt.Errorf("invalid LLVM toolchain: %w", err)
}
Comment on lines +415 to +417

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] validateLLVMToolchain runs 3 uncached --version subprocesses on every Build

Build now unconditionally calls validateLLVMToolchain, which spawns three subprocesses (llvm-config, clang/export.CC, ld.lld) via exec.Command(tool, "--version"). For a one-shot llgo build this is negligible. But in-process, high-fan-out drivers (the cltest harness, go test suites that call Build/Do once per package) will spawn hundreds x 3 --version processes per run, all producing the same answer since gllvm.Version and the toolchain paths are constant for the process lifetime. Consider memoizing the result per (linkedVersion, toolPath) in ValidateToolchainMajor so repeated Build calls pay the cost once.

applyBuildModeCompileFlags(conf.BuildMode, &export)
// Update GOOS/GOARCH from export if target was used
if conf.Target != "" && export.GOOS != "" {
Expand Down Expand Up @@ -799,6 +803,22 @@ func Build(inv Invocation) ([]Package, error) {
return allPkgs, nil
}

func validateLLVMToolchain(export crosscompile.Export) error {
if export.ClangRoot != "" {
binDir := filepath.Join(export.ClangRoot, "bin")
return envllvm.ValidateToolchainMajor(gllvm.Version,
filepath.Join(binDir, "llvm-config"),
filepath.Join(binDir, "clang"),
filepath.Join(binDir, "ld.lld"),
Comment on lines +806 to +812

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Toolchain validator hardcodes ld.lld/clang (breaks darwin/windows)

validateLLVMToolchain always probes ld.lld, but the linker is platform-specific: darwin toolchains ship ld64.lld and windows uses lld-link (crosscompile.go:290,295). ClangRoot is set to the ESP Clang bundle for darwin and linux hosts, so on macOS filepath.Join(binDir, "ld.lld") does not exist and ValidateToolchainMajor fails with query LLVM tool ... ld.lld ... no such file, aborting the build on exactly the darwin release path this PR cares about.

Also, the ClangRoot branch probes filepath.Join(binDir, "clang"), but the bundle and export.CC only guarantee clang++ (crosscompile.go:217). Prefer validating export.CC and deriving the linker name from the target GOOS (mirroring the crosscompile linker logic) instead of hardcoding ld.lld/clang.

)
}
compiler := filepath.Base(export.CC)
if compiler != "clang" && compiler != "clang++" {
return nil
}
return envllvm.ValidateToolchainMajor(gllvm.Version, "llvm-config", export.CC, "ld.lld")
}

// cHeaderPackages excludes the patched standard runtime implementation. Its
// //export callbacks are linker implementation details and may use internal C
// types that are deliberately not representable in a public generated header.
Expand Down
Loading
Loading