diff --git a/.github/workflows/build-cli-release.reusable.yaml b/.github/workflows/build-cli-release.reusable.yaml index 9b30ea3f9b..6eac46b0df 100644 --- a/.github/workflows/build-cli-release.reusable.yaml +++ b/.github/workflows/build-cli-release.reusable.yaml @@ -12,7 +12,9 @@ on: type: boolean default: true required: false - + push: + branches: + - protoc-fix env: MACOSX_DEPLOYMENT_TARGET: "10.13" @@ -69,18 +71,47 @@ jobs: # shell: bash # run: | # ci/ubuntu-install-packages - + - uses: dtolnay/rust-toolchain@stable with: toolchain: stable target: ${{ matrix._.target }} - + - uses: Swatinem/rust-cache@v2 + with: + workspaces: engine + prefix-key: "v5-rust-${{ matrix._.target }}" - uses: actions/setup-go@v5 with: go-version: '1.21' - - name: Install protoc-gen-go - run: go install github.com/golang/protobuf/protoc-gen-go@latest + - name: Install protoc-gen-go into .cargo/bin + shell: bash + run: | + # The cross-compile environment sanitizes the PATH, so we install the plugin + # directly into a directory that is guaranteed to be in the PATH for cargo. + # We also create a symlink from the go/bin to the cargo/bin for consistency. + mkdir -p .cargo/bin + go install github.com/golang/protobuf/protoc-gen-go@latest + cp "$HOME/go/bin/protoc-gen-go" ".cargo/bin/" + echo "Installed protoc-gen-go into .cargo/bin:" + ls -la .cargo/bin + + - name: Test protoc-gen-go availability + id: protoc_gen_go_setup + shell: bash + run: | + echo "Current PATH: $PATH" + echo "Go bin directory contents:" + ls -la $HOME/go/bin/ + echo "Which protoc-gen-go:" + PROTOC_GEN_GO_PATH=$(which protoc-gen-go) + echo "Found protoc-gen-go at: $PROTOC_GEN_GO_PATH" + echo "protoc_gen_go_path=$PROTOC_GEN_GO_PATH" >> $GITHUB_OUTPUT + echo "Testing protoc can find protoc-gen-go plugin..." + # Test that protoc can find the go plugin (this will show an error about missing .proto file, but that's expected) + protoc --go_out=/tmp --help | grep -q "go_out" && echo "✅ protoc recognizes --go_out flag" || echo "❌ protoc does not recognize --go_out flag" + + - name: Use Cross if: contains(matrix._.os, 'ubuntu') @@ -106,11 +137,7 @@ jobs: echo "target flag is: ${{ env.TARGET_FLAGS }}" echo "target dir is: ${{ env.TARGET_DIR }}" - - uses: Swatinem/rust-cache@v2 - with: - workspaces: engine - prefix-key: "v5-rust-${{ matrix._.target }}" - + # Build the CLI - Always use static-ssl features - name: Build CLI Binary # This single step now handles all builds @@ -121,7 +148,24 @@ jobs: working-directory: engine - name: Build CFFI Library - run: > + shell: bash + run: | + # Set the correct protoc-gen-go path based on whether we're using cross (Linux) or native build + if [[ "${{ env.CARGO }}" == "cross" ]]; then + # For cross builds (Linux), protoc-gen-go will be installed in the container at /usr/local/bin + export PROTOC_GEN_GO_PATH="/usr/local/bin/protoc-gen-go" + else + # For native builds (macOS), use the host path + export PROTOC_GEN_GO_PATH="${{ steps.protoc_gen_go_setup.outputs.protoc_gen_go_path }}" + fi + echo "Using PROTOC_GEN_GO_PATH: $PROTOC_GEN_GO_PATH" + + # We must use PROTOC_GEN_GO_PATH to explicitly tell the build script + # where to find the plugin, as the cross-compile environment is isolated. + export GOPATH=$HOME/go + export GOBIN=$GOPATH/bin + export PATH=$PATH:$GOROOT:$GOPATH:$GOBIN + ${{ env.CARGO }} build --release -p baml_cffi ${{ env.TARGET_FLAGS }} working-directory: engine # Skip this step on Windows runners diff --git a/engine/Cross.toml b/engine/Cross.toml new file mode 100644 index 0000000000..e636c1b55b --- /dev/null +++ b/engine/Cross.toml @@ -0,0 +1,44 @@ +# Cross.toml - Configuration for cross-compilation + +# Install Go and protoc-gen-go for Linux targets +[target.x86_64-unknown-linux-gnu] +pre-build = [ + "apt-get update", + "apt-get install -y wget", + "wget -q https://go.dev/dl/go1.21.13.linux-amd64.tar.gz", + "tar -xzf go1.21.13.linux-amd64.tar.gz -C /usr/local", + "export PATH=$PATH:/usr/local/go/bin", + "/usr/local/go/bin/go install github.com/golang/protobuf/protoc-gen-go@latest", + "cp /root/go/bin/protoc-gen-go /usr/local/bin/", +] + +[target.x86_64-unknown-linux-musl] +pre-build = [ + "if command -v apk >/dev/null 2>&1; then apk update && apk add wget; elif command -v apt-get >/dev/null 2>&1; then apt-get update && apt-get install -y wget; elif command -v yum >/dev/null 2>&1; then yum install -y wget; fi", + "wget -q https://go.dev/dl/go1.21.13.linux-amd64.tar.gz", + "tar -xzf go1.21.13.linux-amd64.tar.gz -C /usr/local", + "export PATH=$PATH:/usr/local/go/bin", + "/usr/local/go/bin/go install github.com/golang/protobuf/protoc-gen-go@latest", + "cp /root/go/bin/protoc-gen-go /usr/local/bin/", +] + +[target.aarch64-unknown-linux-gnu] +pre-build = [ + "apt-get update", + "apt-get install -y wget", + "wget -q https://go.dev/dl/go1.21.13.linux-amd64.tar.gz", + "tar -xzf go1.21.13.linux-amd64.tar.gz -C /usr/local", + "export PATH=$PATH:/usr/local/go/bin", + "/usr/local/go/bin/go install github.com/golang/protobuf/protoc-gen-go@latest", + "cp /root/go/bin/protoc-gen-go /usr/local/bin/", +] + +[target.aarch64-unknown-linux-musl] +pre-build = [ + "if command -v apk >/dev/null 2>&1; then apk update && apk add wget; elif command -v apt-get >/dev/null 2>&1; then apt-get update && apt-get install -y wget; elif command -v yum >/dev/null 2>&1; then yum install -y wget; fi", + "wget -q https://go.dev/dl/go1.21.13.linux-amd64.tar.gz", + "tar -xzf go1.21.13.linux-amd64.tar.gz -C /usr/local", + "export PATH=$PATH:/usr/local/go/bin", + "/usr/local/go/bin/go install github.com/golang/protobuf/protoc-gen-go@latest", + "cp /root/go/bin/protoc-gen-go /usr/local/bin/", +] diff --git a/engine/language_client_cffi/build.rs b/engine/language_client_cffi/build.rs index 51fe2a25a1..05bccfb8d5 100644 --- a/engine/language_client_cffi/build.rs +++ b/engine/language_client_cffi/build.rs @@ -323,6 +323,13 @@ mod protoc_lang_out { } fn main() -> std::io::Result<()> { + #[cfg(target_os = "windows")] + println!("cargo:rustc-link-lib=dylib=ntdll"); + + // The last component of the target triple + let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap(); + let is_windows = target_os == "windows"; + // Re-run build.rs if these files change. println!("cargo:rerun-if-changed=types/cffi.fbs"); println!("cargo:rerun-if-changed=types/cffi.proto"); @@ -348,10 +355,18 @@ fn main() -> std::io::Result<()> { // ..Default::default() // }; - protoc_lang_out::ProtocLangOut::new() + let mut protoc = protoc_lang_out::ProtocLangOut::new(); + protoc .lang(lang) .input("types/cffi.proto") - .out_dir(lang_dir) + .out_dir(lang_dir); + + // Allow overriding the protoc-gen-go plugin path + if let Ok(path) = std::env::var("PROTOC_GEN_GO_PATH") { + protoc.plugin(&path); + } + + protoc .run() .unwrap_or_else(|_| panic!("Failed to generate {lang} bindings")); }