diff --git a/.github/actions/setup-deps/action.yml b/.github/actions/setup-deps/action.yml index 7a0669c8..b0bdb4bc 100644 --- a/.github/actions/setup-deps/action.yml +++ b/.github/actions/setup-deps/action.yml @@ -5,6 +5,10 @@ inputs: description: "LLVM version to install" required: true default: "19" + install-llvm: + description: "Whether to install LLVM" + required: false + default: "true" runs: using: "composite" @@ -14,9 +18,17 @@ runs: shell: bash run: | brew update - brew install llvm@${{inputs.llvm-version}} lld@${{inputs.llvm-version}} bdw-gc openssl libffi libuv - brew link --overwrite llvm@${{inputs.llvm-version}} lld@${{inputs.llvm-version}} libffi - echo "$(brew --prefix llvm@${{inputs.llvm-version}})/bin" >> $GITHUB_PATH + + # Install LLVM if requested + if [[ "${{ inputs.install-llvm }}" == "true" ]]; then + brew install llvm@${{inputs.llvm-version}} lld@${{inputs.llvm-version}} + brew link --overwrite llvm@${{inputs.llvm-version}} lld@${{inputs.llvm-version}} + echo "$(brew --prefix llvm@${{inputs.llvm-version}})/bin" >> $GITHUB_PATH + fi + + # Install common dependencies + brew install bdw-gc openssl libffi libuv + brew link --overwrite libffi # Install optional deps for demos. # @@ -31,11 +43,19 @@ runs: if: runner.os == 'Linux' shell: bash run: | - echo "deb http://apt.llvm.org/$(lsb_release -cs)/ llvm-toolchain-$(lsb_release -cs)-${{inputs.llvm-version}} main" | sudo tee /etc/apt/sources.list.d/llvm.list - wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - - sudo apt-get update - sudo apt-get install -y llvm-${{inputs.llvm-version}}-dev clang-${{inputs.llvm-version}} libclang-${{inputs.llvm-version}}-dev lld-${{inputs.llvm-version}} libunwind-${{inputs.llvm-version}}-dev libc++-${{inputs.llvm-version}}-dev pkg-config libgc-dev libssl-dev zlib1g-dev libffi-dev libcjson-dev libuv1-dev - echo "PATH=/usr/lib/llvm-${{inputs.llvm-version}}/bin:$PATH" >> $GITHUB_ENV + # Install LLVM if requested + if [[ "${{ inputs.install-llvm }}" == "true" ]]; then + echo "deb http://apt.llvm.org/$(lsb_release -cs)/ llvm-toolchain-$(lsb_release -cs)-${{inputs.llvm-version}} main" | sudo tee /etc/apt/sources.list.d/llvm.list + wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - + sudo apt-get update + sudo apt-get install -y llvm-${{inputs.llvm-version}}-dev clang-${{inputs.llvm-version}} libclang-${{inputs.llvm-version}}-dev lld-${{inputs.llvm-version}} libunwind-${{inputs.llvm-version}}-dev libc++-${{inputs.llvm-version}}-dev + echo "PATH=/usr/lib/llvm-${{inputs.llvm-version}}/bin:$PATH" >> $GITHUB_ENV + else + sudo apt-get update + fi + + # Install common dependencies + sudo apt-get install -y pkg-config libgc-dev libssl-dev zlib1g-dev libffi-dev libcjson-dev libuv1-dev # Install optional deps for demos. # diff --git a/.github/actions/setup-goreleaser/action.yml b/.github/actions/setup-goreleaser/action.yml index d4ef8665..644388db 100644 --- a/.github/actions/setup-goreleaser/action.yml +++ b/.github/actions/setup-goreleaser/action.yml @@ -35,3 +35,6 @@ runs: - name: Check file run: tree .sysroot shell: bash + - name: Get Esp clang + run: bash .github/workflows/download_esp_clang.sh + shell: bash diff --git a/.github/actions/test-helloworld/action.yml b/.github/actions/test-helloworld/action.yml index 9ce49ef9..9020e788 100644 --- a/.github/actions/test-helloworld/action.yml +++ b/.github/actions/test-helloworld/action.yml @@ -38,7 +38,7 @@ runs: Hello, LLGo! Hello, LLGo! Hello LLGo by cpp/std.Str" - OUTPUT=$(llgo run . 2>&1) + OUTPUT=$(llgo run . 2>&1 | tee /dev/stderr) if echo "$OUTPUT" | grep -qF "$EXPECTED"; then echo "Basic test passed" else @@ -50,4 +50,14 @@ runs: exit 1 fi - #TODO(zzy): Test embed targets, need dispatch target dir + cd ../.. + mkdir -p _test/emb && cd _test/emb + cat > main.go << 'EOL' + package main + + func main() { + } + EOL + llgo build -v -target esp32-coreboard-v2 -o demo.out . + test -f demo.out.elf && echo "ESP32 cross-compilation test passed: demo.out.elf generated" + exit $? diff --git a/.github/workflows/download_esp_clang.sh b/.github/workflows/download_esp_clang.sh new file mode 100755 index 00000000..5ea6a764 --- /dev/null +++ b/.github/workflows/download_esp_clang.sh @@ -0,0 +1,67 @@ +#!/bin/bash +set -e + +ESP_CLANG_VERSION="19.1.2_20250905-3" +BASE_URL="https://github.com/goplus/espressif-llvm-project-prebuilt/releases/download/${ESP_CLANG_VERSION}" + +get_esp_clang_platform() { + local platform="$1" + local os="${platform%-*}" + local arch="${platform##*-}" + + case "${os}" in + "darwin") + case "${arch}" in + "amd64") echo "x86_64-apple-darwin" ;; + "arm64") echo "aarch64-apple-darwin" ;; + *) echo "Error: Unsupported darwin architecture: ${arch}" >&2; exit 1 ;; + esac + ;; + "linux") + case "${arch}" in + "amd64") echo "x86_64-linux-gnu" ;; + "arm64") echo "aarch64-linux-gnu" ;; + *) echo "Error: Unsupported linux architecture: ${arch}" >&2; exit 1 ;; + esac + ;; + *) + echo "Error: Unsupported OS: ${os}" >&2 + exit 1 + ;; + esac +} + +get_filename() { + local platform="$1" + local platform_suffix=$(get_esp_clang_platform "${platform}") + echo "clang-esp-${ESP_CLANG_VERSION}-${platform_suffix}.tar.xz" +} + +download_and_extract() { + local platform="$1" + local os="${platform%-*}" + local arch="${platform##*-}" + local filename=$(get_filename "${platform}") + local download_url="${BASE_URL}/${filename}" + + echo "Downloading ESP Clang for ${platform}..." + echo " URL: ${download_url}" + + mkdir -p ".sysroot/${os}/${arch}/crosscompile/clang" + curl -fsSL "${download_url}" | tar -xJ -C ".sysroot/${os}/${arch}/crosscompile/clang" --strip-components=1 + + if [[ ! -f ".sysroot/${os}/${arch}/crosscompile/clang/bin/clang++" ]]; then + echo "Error: clang++ not found in ${platform} toolchain" + exit 1 + fi + + echo "${platform} ESP Clang ready in .sysroot/${os}/${arch}/crosscompile/clang" +} + +echo "Downloading ESP Clang toolchain version ${ESP_CLANG_VERSION}..." + +for platform in "darwin-amd64" "darwin-arm64" "linux-amd64" "linux-arm64"; do + download_and_extract "${platform}" +done + +echo "ESP Clang toolchain completed successfully!" diff --git a/.github/workflows/release-build.yml b/.github/workflows/release-build.yml index fef8f053..15c64c53 100644 --- a/.github/workflows/release-build.yml +++ b/.github/workflows/release-build.yml @@ -27,7 +27,6 @@ jobs: LINUX_KEY="linux-sysroot-${{ hashFiles('.github/workflows/populate_linux_sysroot.sh', '.github/workflows/release-build.yml') }}-v1.0.0" echo "darwin-key=$DARWIN_KEY" >> $GITHUB_OUTPUT echo "linux-key=$LINUX_KEY" >> $GITHUB_OUTPUT - populate-darwin-sysroot: runs-on: macos-latest timeout-minutes: 30 @@ -107,7 +106,7 @@ jobs: -v $(pwd):/go/src/llgo \ -w /go/src/llgo \ ghcr.io/goreleaser/goreleaser-cross:v1.22 \ - release --skip=publish,nfpm,snapcraft --snapshot --clean + release --verbose --skip=publish,nfpm,snapcraft --snapshot --clean - name: Upload Darwin AMD64 Artifacts uses: actions/upload-artifact@v4 @@ -179,6 +178,8 @@ jobs: - uses: actions/checkout@v5 - name: Install dependencies uses: ./.github/actions/setup-deps + with: + install-llvm: false - name: Set up Go uses: actions/setup-go@v6 with: @@ -205,7 +206,8 @@ jobs: mod-version: ${{ matrix.go-mod-version }} release: - needs: [setup, build, test-artifacts] + needs: + [setup, test-artifacts, populate-darwin-sysroot, populate-linux-sysroot] runs-on: ubuntu-latest if: startsWith(github.ref, 'refs/tags/') steps: @@ -231,4 +233,4 @@ jobs: -v $(pwd):/go/src/llgo \ -w /go/src/llgo \ ghcr.io/goreleaser/goreleaser-cross:v1.22 \ - release --clean --skip nfpm,snapcraft + release --clean --verbose --skip nfpm,snapcraft diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 4a42dbe3..bbd0104c 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -23,12 +23,11 @@ builds: ldflags: - -X github.com/goplus/llgo/internal/env.buildVersion=v{{.Version}} - -X github.com/goplus/llgo/internal/env.buildTime={{.Date}} - - -X github.com/goplus/llgo/xtool/env/llvm.ldLLVMConfigBin=/usr/local/opt/llvm@19/bin/llvm-config env: - CC=o64-clang - CXX=o64-clang++ - - CGO_CPPFLAGS=-I{{.Env.SYSROOT_DARWIN_AMD64}}/usr/local/opt/llvm@19/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}}/usr/local/opt/llvm@19/lib -mmacosx-version-min=10.13 -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM-19 -lz -lm + - 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 targets: - darwin_amd64 mod_timestamp: "{{.CommitTimestamp}}" @@ -40,12 +39,11 @@ builds: ldflags: - -X github.com/goplus/llgo/internal/env.buildVersion=v{{.Version}} - -X github.com/goplus/llgo/internal/env.buildTime={{.Date}} - - -X github.com/goplus/llgo/xtool/env/llvm.ldLLVMConfigBin=/opt/homebrew/opt/llvm@19/bin/llvm-config env: - CC=oa64-clang - CXX=oa64-clang++ - - CGO_CPPFLAGS=-I{{.Env.SYSROOT_DARWIN_ARM64}}/opt/homebrew/opt/llvm@19/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}}/opt/homebrew/opt/llvm@19/lib -mmacosx-version-min=10.13 -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM-19 -lz -lm + - 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 targets: - darwin_arm64 mod_timestamp: "{{.CommitTimestamp}}" @@ -57,12 +55,13 @@ builds: ldflags: - -X github.com/goplus/llgo/internal/env.buildVersion=v{{.Version}} - -X github.com/goplus/llgo/internal/env.buildTime={{.Date}} - - -X github.com/goplus/llgo/xtool/env/llvm.ldLLVMConfigBin=/usr/lib/llvm-19/bin/llvm-config + - '-extldflags=-Wl,-rpath,$ORIGIN/../crosscompile/clang/lib' env: - CC=x86_64-linux-gnu-gcc - CXX=x86_64-linux-gnu-g++ - - CGO_CPPFLAGS=--sysroot={{.Env.SYSROOT_LINUX_AMD64}} -I{{.Env.SYSROOT_LINUX_AMD64}}/usr/include/llvm-19 -I{{.Env.SYSROOT_LINUX_AMD64}}/usr/include/llvm-c-19 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS - - CGO_LDFLAGS=--sysroot={{.Env.SYSROOT_LINUX_AMD64}} -L{{.Env.SYSROOT_LINUX_AMD64}}/usr/lib/llvm-19/lib -lLLVM-19 + - CGO_CPPFLAGS=--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_LDFLAGS=--sysroot={{.Env.SYSROOT_LINUX_AMD64}} -L{{.Env.SYSROOT_LINUX_AMD64}}/crosscompile/clang/lib -lLLVM-19 + - CGO_LDFLAGS_ALLOW=--sysroot.* targets: - linux_amd64 mod_timestamp: "{{.CommitTimestamp}}" @@ -74,12 +73,13 @@ builds: ldflags: - -X github.com/goplus/llgo/internal/env.buildVersion=v{{.Version}} - -X github.com/goplus/llgo/internal/env.buildTime={{.Date}} - - -X github.com/goplus/llgo/xtool/env/llvm.ldLLVMConfigBin=/usr/lib/llvm-19/bin/llvm-config + - '-extldflags=-Wl,-rpath,$ORIGIN/../crosscompile/clang/lib' env: - CC=aarch64-linux-gnu-gcc - CXX=aarch64-linux-gnu-g++ - - CGO_CPPFLAGS=--sysroot={{.Env.SYSROOT_LINUX_ARM64}} -I{{.Env.SYSROOT_LINUX_ARM64}}/usr/include/llvm-19 -I{{.Env.SYSROOT_LINUX_ARM64}}/usr/include/llvm-c-19 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS - - CGO_LDFLAGS=--sysroot={{.Env.SYSROOT_LINUX_ARM64}} -L{{.Env.SYSROOT_LINUX_ARM64}}/usr/lib/llvm-19/lib -lLLVM-19 + - CGO_CPPFLAGS=--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_LDFLAGS=--sysroot={{.Env.SYSROOT_LINUX_ARM64}} -L{{.Env.SYSROOT_LINUX_ARM64}}/crosscompile/clang/lib -lLLVM-19 + - CGO_LDFLAGS_ALLOW=--sysroot.* targets: - linux_arm64 mod_timestamp: "{{.CommitTimestamp}}" @@ -93,7 +93,11 @@ archives: - LICENSE - README.md - runtime - + - targets + - src: ".sysroot/{{.Os}}/{{.Arch}}/crosscompile/clang" + dst: crosscompile/clang + info: + mode: 0755 checksum: name_template: "{{.ProjectName}}{{.Version}}.checksums.txt" diff --git a/internal/crosscompile/crosscompile.go b/internal/crosscompile/crosscompile.go index 8c0bf788..5b31aea8 100644 --- a/internal/crosscompile/crosscompile.go +++ b/internal/crosscompile/crosscompile.go @@ -15,6 +15,7 @@ import ( "github.com/goplus/llgo/internal/flash" "github.com/goplus/llgo/internal/targets" "github.com/goplus/llgo/internal/xtool/llvm" + envllvm "github.com/goplus/llgo/xtool/env/llvm" ) type Export struct { @@ -108,7 +109,7 @@ func getESPClangRoot(forceEspClang bool) (clangRoot string, err error) { llgoRoot := env.LLGoROOT() // First check if clang exists in LLGoROOT - espClangRoot := filepath.Join(llgoRoot, "crosscompile", "clang") + espClangRoot := filepath.Join(llgoRoot, envllvm.CrosscompileClangPath) if _, err = os.Stat(espClangRoot); err == nil { clangRoot = espClangRoot return diff --git a/xtool/env/llvm/llvm.go b/xtool/env/llvm/llvm.go index a34757c9..56771908 100644 --- a/xtool/env/llvm/llvm.go +++ b/xtool/env/llvm/llvm.go @@ -22,6 +22,7 @@ import ( "path/filepath" "strings" + "github.com/goplus/llgo/internal/env" "github.com/goplus/llgo/xtool/clang" "github.com/goplus/llgo/xtool/llvm/install_name_tool" "github.com/goplus/llgo/xtool/llvm/llvmlink" @@ -30,6 +31,13 @@ import ( // ----------------------------------------------------------------------------- +const ( + // CrosscompileClangPath is the relative path from LLGO_ROOT to the clang installation + CrosscompileClangPath = "crosscompile/clang" +) + +// ----------------------------------------------------------------------------- + // defaultLLVMConfigBin returns the default path to the llvm-config binary. It // checks the LLVM_CONFIG environment variable first, then searches in PATH. If // not found, it returns [ldLLVMConfigBin] as a last resort. @@ -42,6 +50,13 @@ func defaultLLVMConfigBin() string { if bin != "" { return bin } + + llgoRoot := env.LLGoROOT() + // Check LLGO_ROOT/crosscompile/clang for llvm-config + crossLLVMConfigBin := filepath.Join(llgoRoot, CrosscompileClangPath, "bin", "llvm-config") + if _, err := os.Stat(crossLLVMConfigBin); err == nil { + return crossLLVMConfigBin + } return ldLLVMConfigBin }