From 23180714b94d6b7a1793e27785403d5527f9c94c Mon Sep 17 00:00:00 2001 From: Fu Lin Date: Tue, 26 Dec 2023 22:07:16 +0800 Subject: [PATCH 1/4] build: support downloading deps automatically `go build` won't download deps automatically, it need `go mod tidy`. Signed-off-by: Fu Lin --- src/lib.rs | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 64b7a0a..3140c75 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -155,12 +155,61 @@ impl Build { /// /// Panics if any error occurs during compilation. pub fn build(&self, output: &str) { + if let Err(err) = self.try_tidy() { + eprintln!("\n\nerror occurred: {}\n", err); + process::exit(1); + } if let Err(err) = self.try_build(output) { eprintln!("\n\nerror occurred: {}\n", err); process::exit(1); } } + /// Downloads the dependency + pub fn try_tidy(&self) -> Result<(), Error> { + let mut cmd = process::Command::new("go"); + + cmd.arg("mod").arg("tidy"); + if let Some(change_dir) = &self.change_dir { + cmd.args([&"-C".into(), change_dir]); + } + + let tidy_output = match cmd.output() { + Ok(tidy_output) => tidy_output, + Err(err) => { + return Err(Error::new( + ErrorKind::ToolExecError, + &format!("failed to execute go command: {}", err), + )); + } + }; + + if tidy_output.status.success() { + return Ok(()); + } + + let mut message = format!( + "failed to tidy Go library ({}). Tidy output:", + tidy_output.status + ); + + let mut push_output = |stream_name, bytes| { + let string = String::from_utf8_lossy(bytes); + let string = string.trim(); + + if string.is_empty() { + return; + } + + write!(&mut message, "\n=== {stream_name}:\n{string}").unwrap(); + }; + + push_output("stdout", &tidy_output.stdout); + push_output("stderr", &tidy_output.stderr); + + Err(Error::new(ErrorKind::ToolExecError, &message)) + } + /// Builds the Go package, generating the file `output`. pub fn try_build(&self, output: &str) -> Result<(), Error> { // Use the provided values for GOARCH and GOOS, otherwise fetch the From fa5dbc240073d0ac21f6127132f37572aa87fb57 Mon Sep 17 00:00:00 2001 From: Fu Lin Date: Tue, 26 Dec 2023 23:40:00 +0800 Subject: [PATCH 2/4] fix(windows): fixup cgo C compiler not found When rust-std-x86_64-pc-windows-msvc is used, compiling go will reports error: error occurred: ToolExecError: failed to build Go library (exit code: 1). Build output: === stderr: # runtime/cgo cgo: C compiler "C:\\Program" not found: exec: "C:\\Program": file does not exist The reason is that golang uses MSVC (cl.exe) instead of gcc but golang don't support MSVC. At the same time, golang can't be built as static. Here use cfg to control compilier selection, and add doc. Signed-off-by: Fu Lin --- README.md | 13 +++++++++++++ src/lib.rs | 24 ++++++++++++++++++------ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 87722fb..1235d3d 100644 --- a/README.md +++ b/README.md @@ -18,9 +18,22 @@ cgo = "*" The following example will statically compile the Go package and instruct cargo to link the resulting library (`libexample`). +Not Windows: + +```rust +fn main() { + cgo::Build::new() + .package("pkg/example/main.go") + .build("example"); +} +``` + +Windows: + ```rust fn main() { cgo::Build::new() + .build_mode(cgo::BuildMode::CShared) .package("pkg/example/main.go") .build("example"); } diff --git a/src/lib.rs b/src/lib.rs index 3140c75..14bd200 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -330,6 +330,7 @@ impl Build { /// /// Refer to the [Go docs](https://pkg.go.dev/cmd/go#hdr-Build_modes) /// for more information. +/// Notice: Windows support `CShared` only #[derive(Clone, Debug, Default)] pub enum BuildMode { /// Build the listed main package, plus all packages it imports, @@ -420,15 +421,26 @@ impl std::fmt::Display for Error { } fn get_cc() -> PathBuf { - cc::Build::new().get_compiler().path().to_path_buf() + #[cfg(not( target_os = "windows" ))] + return cc::Build::new().get_compiler().path().to_path_buf(); + #[cfg( target_os = "windows" )] + return cc::Build::new().target("x86_64-pc-windows-gnu").get_compiler().path().to_path_buf(); } fn get_cxx() -> PathBuf { - cc::Build::new() - .cpp(true) - .get_compiler() - .path() - .to_path_buf() + #[cfg(not( target_os = "windows" ))] + return cc::Build::new() + .cpp(true) + .get_compiler() + .path() + .to_path_buf(); + #[cfg( target_os = "windows" )] + return cc::Build::new() + .cpp(true) + .target("x86_64-pc-windows-gnu") + .get_compiler() + .path() + .to_path_buf(); } fn goarch_from_env() -> Result { From 33a214522fd4f5aa032233268c95c9bc0a7b4d2b Mon Sep 17 00:00:00 2001 From: Fu Lin Date: Thu, 28 Dec 2023 14:42:27 +0800 Subject: [PATCH 3/4] fix(windows): fixup lib format Original `cfg!(windows)` don't work, and MinGW toolchain .a for static link, .dll for dynamic link. Otherwise it reports error: /usr/bin/x86_64-w64-mingw32-ld: cannot find -lxxx: No such file or directory Signed-off-by: Fu Lin --- src/lib.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 14bd200..ba907d4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -303,25 +303,32 @@ impl Build { } fn format_lib_name(&self, output: &str) -> PathBuf { + let target_os = goos_from_env().unwrap(); let mut lib = String::with_capacity(output.len() + 7); lib.push_str("lib"); lib.push_str(output); lib.push_str(match self.build_mode { + // It's odd here. neither `if cfg!(windows)` nor + // `#[cfg( target_os = "windows" )]` works here. BuildMode::CArchive => { - if cfg!(windows) { + // Only msvc toolchain will use `.lib` suffix. + // mingw toolchain will use `.a`. + let target_env = get_env_var("CARGO_CFG_TARGET_ENV").unwrap(); + if target_os.eq("windows") && target_env.eq("msvc") { ".lib" } else { ".a" } } BuildMode::CShared => { - if cfg!(windows) { + if target_os.eq("windows") { ".dll" } else { ".so" } } }); + lib.into() } } From 2e9c90154dc8de0658505725899140cf83d1ec9d Mon Sep 17 00:00:00 2001 From: Fu Lin Date: Tue, 26 Dec 2023 23:50:21 +0800 Subject: [PATCH 4/4] version: bump Signed-off-by: Fu Lin --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ab33892..6ddfdea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cgo" -version = "0.3.0" +version = "0.3.1" edition = "2021" authors = ["Ryan Fowler"] description = "A library for build scripts to compile custom Go code"