diff --git a/Cargo.lock b/Cargo.lock index b94786b7..eab875fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1484,6 +1484,7 @@ dependencies = [ "thiserror", "vergen", "walkdir", + "which 6.0.2", ] [[package]] diff --git a/crates/moon/src/cli.rs b/crates/moon/src/cli.rs index 9cb1d9f6..d47c8e91 100644 --- a/crates/moon/src/cli.rs +++ b/crates/moon/src/cli.rs @@ -64,7 +64,7 @@ use moonutil::{ cli::UniversalFlags, common::{ read_module_desc_file_in_dir, BuildPackageFlags, LinkCoreFlags, MooncOpt, OutputFormat, - RunMode, SurfaceTarget, TargetBackend, MOONBITLANG_CORE, MOON_MOD_JSON, + SurfaceTarget, TargetBackend, MOONBITLANG_CORE, MOON_MOD_JSON, }, mooncakes::{LoginSubcommand, PackageSubcommand, PublishSubcommand, RegisterSubcommand}, }; @@ -188,46 +188,14 @@ impl BuildFlags { } } -pub fn get_compiler_flags( - src_dir: &Path, - build_flags: &BuildFlags, - run_mode: RunMode, -) -> anyhow::Result { +pub fn get_compiler_flags(src_dir: &Path, build_flags: &BuildFlags) -> anyhow::Result { // read moon.mod.json if !moonutil::common::check_moon_mod_exists(src_dir) { bail!("could not find `{}`", MOON_MOD_JSON); } let moon_mod = read_module_desc_file_in_dir(src_dir)?; let extra_build_opt = moon_mod.compile_flags.unwrap_or_default(); - let mut extra_link_opt = moon_mod.link_flags.unwrap_or_default(); - - #[cfg(unix)] - match run_mode { - // need link-core for build, test and run - RunMode::Build | RunMode::Test | RunMode::Run => { - if build_flags.release && build_flags.target_backend == Some(TargetBackend::Native) { - // check if cc exists in PATH - if let Err(e) = which::which("cc") { - eprintln!( - "error: 'cc' not found in PATH, which is used for native backend release compilation: {}", - e - ); - std::process::exit(1); - } - // libmoonbitrun.o should be in the same directory as moonc - let libmoonbitrun_path = which::which("moonc")?.with_file_name("libmoonbitrun.o"); - - // use "cc" to compile - extra_link_opt.extend_from_slice(&[ - "-cc".to_string(), - format!("cc {} -O2 -fwrapv", libmoonbitrun_path.display()), - "-cc-link-flags".to_string(), - "-lm".to_string(), - ]); - } - } - _ => {} - } + let extra_link_opt = moon_mod.link_flags.unwrap_or_default(); let output_format = if build_flags.output_wat { OutputFormat::Wat diff --git a/crates/moon/src/cli/build.rs b/crates/moon/src/cli/build.rs index 55065850..28ff81ac 100644 --- a/crates/moon/src/cli/build.rs +++ b/crates/moon/src/cli/build.rs @@ -118,7 +118,7 @@ fn run_build_internal( let raw_target_dir = target_dir; let run_mode = RunMode::Build; - let mut moonc_opt = super::get_compiler_flags(source_dir, &cmd.build_flags, run_mode)?; + let mut moonc_opt = super::get_compiler_flags(source_dir, &cmd.build_flags)?; moonc_opt.build_opt.deny_warn = cmd.build_flags.deny_warn; let target_dir = mk_arch_mode_dir(source_dir, target_dir, &moonc_opt, run_mode)?; let _lock = FileLock::lock(&target_dir)?; @@ -140,7 +140,7 @@ fn run_build_internal( no_parallelize: false, }; - let module = scan_with_pre_build( + let mut module = scan_with_pre_build( false, &moonc_opt, &moonbuild_opt, @@ -148,6 +148,13 @@ fn run_build_internal( &dir_sync_result, )?; + moonutil::common::set_native_backend_link_flags( + run_mode, + cmd.build_flags.release, + cmd.build_flags.target_backend, + &mut module, + ); + moonc_opt.build_opt.warn_lists = module .get_all_packages() .iter() diff --git a/crates/moon/src/cli/bundle.rs b/crates/moon/src/cli/bundle.rs index 187cbc06..981e8ec8 100644 --- a/crates/moon/src/cli/bundle.rs +++ b/crates/moon/src/cli/bundle.rs @@ -127,7 +127,7 @@ fn run_bundle_internal( )?; let run_mode = RunMode::Bundle; - let mut moonc_opt = super::get_compiler_flags(source_dir, &cmd.build_flags, run_mode)?; + let mut moonc_opt = super::get_compiler_flags(source_dir, &cmd.build_flags)?; let sort_input = cmd.build_flags.sort_input; let raw_target_dir = target_dir.to_path_buf(); diff --git a/crates/moon/src/cli/check.rs b/crates/moon/src/cli/check.rs index abe71783..d0682b5f 100644 --- a/crates/moon/src/cli/check.rs +++ b/crates/moon/src/cli/check.rs @@ -135,7 +135,7 @@ fn run_check_internal( let raw_target_dir = target_dir; let run_mode = RunMode::Check; - let mut moonc_opt = get_compiler_flags(source_dir, &cmd.build_flags, run_mode)?; + let mut moonc_opt = get_compiler_flags(source_dir, &cmd.build_flags)?; moonc_opt.build_opt.deny_warn = cmd.build_flags.deny_warn; let target_dir = mk_arch_mode_dir(source_dir, target_dir, &moonc_opt, run_mode)?; let _lock = FileLock::lock(&target_dir)?; diff --git a/crates/moon/src/cli/generate_test_driver.rs b/crates/moon/src/cli/generate_test_driver.rs index 55417e06..4e8ae97d 100644 --- a/crates/moon/src/cli/generate_test_driver.rs +++ b/crates/moon/src/cli/generate_test_driver.rs @@ -125,7 +125,7 @@ pub fn generate_test_driver( cmd.build_flags.target_backend = target_backend; let run_mode = RunMode::Test; - let moonc_opt = super::get_compiler_flags(&source_dir, &cmd.build_flags, run_mode)?; + let moonc_opt = super::get_compiler_flags(&source_dir, &cmd.build_flags)?; let sort_input = cmd.build_flags.sort_input; let filter_package = cmd.package.map(|it| it.into_iter().collect()); diff --git a/crates/moon/src/cli/run.rs b/crates/moon/src/cli/run.rs index 4824c34e..c88ddab4 100644 --- a/crates/moon/src/cli/run.rs +++ b/crates/moon/src/cli/run.rs @@ -228,7 +228,7 @@ pub fn run_run_internal(cli: &UniversalFlags, cmd: RunSubcommand) -> anyhow::Res )?; let run_mode = RunMode::Run; - let mut moonc_opt = super::get_compiler_flags(&source_dir, &cmd.build_flags, run_mode)?; + let mut moonc_opt = super::get_compiler_flags(&source_dir, &cmd.build_flags)?; let raw_target_dir = target_dir.to_path_buf(); let target_dir = mk_arch_mode_dir(&source_dir, &target_dir, &moonc_opt, run_mode)?; @@ -279,7 +279,7 @@ pub fn run_run_internal(cli: &UniversalFlags, cmd: RunSubcommand) -> anyhow::Res no_parallelize: false, }; - let module = scan_with_pre_build( + let mut module = scan_with_pre_build( false, &moonc_opt, &moonbuild_opt, @@ -287,6 +287,13 @@ pub fn run_run_internal(cli: &UniversalFlags, cmd: RunSubcommand) -> anyhow::Res &dir_sync_result, )?; + moonutil::common::set_native_backend_link_flags( + run_mode, + cmd.build_flags.release, + cmd.build_flags.target_backend, + &mut module, + ); + moonc_opt.build_opt.warn_lists = module .get_all_packages() .iter() diff --git a/crates/moon/src/cli/test.rs b/crates/moon/src/cli/test.rs index f831a558..7bffe3ce 100644 --- a/crates/moon/src/cli/test.rs +++ b/crates/moon/src/cli/test.rs @@ -152,7 +152,7 @@ fn run_test_internal( )?; let run_mode = RunMode::Test; - let mut moonc_opt = super::get_compiler_flags(source_dir, &cmd.build_flags, run_mode)?; + let mut moonc_opt = super::get_compiler_flags(source_dir, &cmd.build_flags)?; // release is 'false' by default, so we will run test at debug mode(to gain more detailed stack trace info), unless `--release` is specified // however, other command like build, check, run, etc, will run at release mode by default moonc_opt.build_opt.debug_flag = !cmd.build_flags.release; @@ -305,6 +305,13 @@ fn run_test_internal( } } + moonutil::common::set_native_backend_link_flags( + run_mode, + cmd.build_flags.release, + cmd.build_flags.target_backend, + &mut module, + ); + moonc_opt.build_opt.warn_lists = module .get_all_packages() .iter() diff --git a/crates/moon/tests/test_cases/mod.rs b/crates/moon/tests/test_cases/mod.rs index 3d6d03d1..acbeec26 100644 --- a/crates/moon/tests/test_cases/mod.rs +++ b/crates/moon/tests/test_cases/mod.rs @@ -7151,7 +7151,7 @@ fn test_use_cc_for_native_release() { expect![[r#" moonc build-package ./lib/hello.mbt -o ./target/native/release/build/lib/lib.core -pkg moonbitlang/hello/lib -std-path $MOON_HOME/lib/core/target/native/release/bundle -pkg-sources moonbitlang/hello/lib:./lib -target native moonc build-package ./main/main.mbt -o ./target/native/release/build/main/main.core -pkg moonbitlang/hello/main -is-main -std-path $MOON_HOME/lib/core/target/native/release/bundle -i ./target/native/release/build/lib/lib.mi:lib -pkg-sources moonbitlang/hello/main:./main -target native - moonc link-core $MOON_HOME/lib/core/target/native/release/bundle/core.core ./target/native/release/build/lib/lib.core ./target/native/release/build/main/main.core -main moonbitlang/hello/main -o ./target/native/release/build/main/main.exe -pkg-sources moonbitlang/hello/lib:./lib -pkg-sources moonbitlang/hello/main:./main -pkg-sources moonbitlang/core:$MOON_HOME/lib/core -target native -cc "cc $MOON_HOME/bin/libmoonbitrun.o -O2 -fwrapv" -cc-link-flags -lm + moonc link-core $MOON_HOME/lib/core/target/native/release/bundle/core.core ./target/native/release/build/lib/lib.core ./target/native/release/build/main/main.core -main moonbitlang/hello/main -o ./target/native/release/build/main/main.exe -pkg-sources moonbitlang/hello/lib:./lib -pkg-sources moonbitlang/hello/main:./main -pkg-sources moonbitlang/core:$MOON_HOME/lib/core -target native -cc cc -cc-flags "-O2 $MOON_HOME/bin/libmoonbitrun.o -fwrapv" -cc-link-flags -lm "#]], ); // if --release is not specified, it should not use cc @@ -7204,7 +7204,7 @@ fn test_use_cc_for_native_release() { expect![[r#" moonc build-package ./lib/hello.mbt -o ./target/native/release/build/lib/lib.core -pkg moonbitlang/hello/lib -std-path $MOON_HOME/lib/core/target/native/release/bundle -pkg-sources moonbitlang/hello/lib:./lib -target native moonc build-package ./main/main.mbt -o ./target/native/release/build/main/main.core -pkg moonbitlang/hello/main -is-main -std-path $MOON_HOME/lib/core/target/native/release/bundle -i ./target/native/release/build/lib/lib.mi:lib -pkg-sources moonbitlang/hello/main:./main -target native - moonc link-core $MOON_HOME/lib/core/target/native/release/bundle/core.core ./target/native/release/build/lib/lib.core ./target/native/release/build/main/main.core -main moonbitlang/hello/main -o ./target/native/release/build/main/main.exe -pkg-sources moonbitlang/hello/lib:./lib -pkg-sources moonbitlang/hello/main:./main -pkg-sources moonbitlang/core:$MOON_HOME/lib/core -target native -cc "cc $MOON_HOME/bin/libmoonbitrun.o -O2 -fwrapv" -cc-link-flags -lm + moonc link-core $MOON_HOME/lib/core/target/native/release/bundle/core.core ./target/native/release/build/lib/lib.core ./target/native/release/build/main/main.core -main moonbitlang/hello/main -o ./target/native/release/build/main/main.exe -pkg-sources moonbitlang/hello/lib:./lib -pkg-sources moonbitlang/hello/main:./main -pkg-sources moonbitlang/core:$MOON_HOME/lib/core -target native -cc cc -cc-flags "-O2 $MOON_HOME/bin/libmoonbitrun.o -fwrapv" -cc-link-flags -lm ./target/native/release/build/main/main.exe "#]], ); @@ -7267,10 +7267,10 @@ fn test_use_cc_for_native_release() { expect![[r#" moon generate-test-driver --source-dir . --target-dir ./target/native/release/test --package moonbitlang/hello/lib --sort-input --target native --driver-kind whitebox moonc build-package ./lib/hello.mbt ./lib/hello_wbtest.mbt ./target/native/release/test/lib/__generated_driver_for_whitebox_test.mbt -o ./target/native/release/test/lib/lib.whitebox_test.core -pkg moonbitlang/hello/lib -is-main -std-path $MOON_HOME/lib/core/target/native/release/bundle -pkg-sources moonbitlang/hello/lib:./lib -target native -whitebox-test - moonc link-core $MOON_HOME/lib/core/target/native/release/bundle/core.core ./target/native/release/test/lib/lib.whitebox_test.core -main moonbitlang/hello/lib -o ./target/native/release/test/lib/lib.whitebox_test.exe -test-mode -pkg-sources moonbitlang/hello/lib:./lib -pkg-sources moonbitlang/core:$MOON_HOME/lib/core -exported_functions moonbit_test_driver_internal_execute -target native -cc "cc $MOON_HOME/bin/libmoonbitrun.o -O2 -fwrapv" -cc-link-flags -lm + moonc link-core $MOON_HOME/lib/core/target/native/release/bundle/core.core ./target/native/release/test/lib/lib.whitebox_test.core -main moonbitlang/hello/lib -o ./target/native/release/test/lib/lib.whitebox_test.exe -test-mode -pkg-sources moonbitlang/hello/lib:./lib -pkg-sources moonbitlang/core:$MOON_HOME/lib/core -exported_functions moonbit_test_driver_internal_execute -target native -cc cc -cc-flags "-O2 $MOON_HOME/bin/libmoonbitrun.o -fwrapv" -cc-link-flags -lm moon generate-test-driver --source-dir . --target-dir ./target/native/release/test --package moonbitlang/hello/lib --sort-input --target native --driver-kind internal moonc build-package ./lib/hello.mbt ./target/native/release/test/lib/__generated_driver_for_internal_test.mbt -o ./target/native/release/test/lib/lib.internal_test.core -pkg moonbitlang/hello/lib -is-main -std-path $MOON_HOME/lib/core/target/native/release/bundle -pkg-sources moonbitlang/hello/lib:./lib -target native - moonc link-core $MOON_HOME/lib/core/target/native/release/bundle/core.core ./target/native/release/test/lib/lib.internal_test.core -main moonbitlang/hello/lib -o ./target/native/release/test/lib/lib.internal_test.exe -test-mode -pkg-sources moonbitlang/hello/lib:./lib -pkg-sources moonbitlang/core:$MOON_HOME/lib/core -exported_functions moonbit_test_driver_internal_execute -target native -cc "cc $MOON_HOME/bin/libmoonbitrun.o -O2 -fwrapv" -cc-link-flags -lm + moonc link-core $MOON_HOME/lib/core/target/native/release/bundle/core.core ./target/native/release/test/lib/lib.internal_test.core -main moonbitlang/hello/lib -o ./target/native/release/test/lib/lib.internal_test.exe -test-mode -pkg-sources moonbitlang/hello/lib:./lib -pkg-sources moonbitlang/core:$MOON_HOME/lib/core -exported_functions moonbit_test_driver_internal_execute -target native -cc cc -cc-flags "-O2 $MOON_HOME/bin/libmoonbitrun.o -fwrapv" -cc-link-flags -lm "#]], ); check( @@ -7320,3 +7320,98 @@ fn test_moon_package_list() { "#]], ); } + +#[test] +fn test_native_backend_cc_flags() { + let dir = TestDir::new("native_backend_cc_flags.in"); + check( + get_stdout( + &dir, + ["build", "--target", "native", "--dry-run", "--sort-input"], + ), + expect![[r#" + moonc build-package ./lib/hello.mbt -o ./target/native/release/build/lib/lib.core -pkg moon_new/lib -std-path $MOON_HOME/lib/core/target/native/release/bundle -pkg-sources moon_new/lib:./lib -target native + moonc build-package ./main/main.mbt -o ./target/native/release/build/main/main.core -pkg moon_new/main -is-main -std-path $MOON_HOME/lib/core/target/native/release/bundle -i ./target/native/release/build/lib/lib.mi:lib -pkg-sources moon_new/main:./main -target native + moonc link-core $MOON_HOME/lib/core/target/native/release/bundle/core.core ./target/native/release/build/lib/lib.core ./target/native/release/build/main/main.core -main moon_new/main -o ./target/native/release/build/main/main.exe -pkg-sources moon_new/lib:./lib -pkg-sources moon_new/main:./main -pkg-sources moonbitlang/core:$MOON_HOME/lib/core -target native + moonc link-core $MOON_HOME/lib/core/target/native/release/bundle/core.core ./target/native/release/build/lib/lib.core -main moon_new/lib -o ./target/native/release/build/lib/lib.exe -pkg-sources moon_new/lib:./lib -pkg-sources moonbitlang/core:$MOON_HOME/lib/core -target native -cc cc -cc-flags "ccflags fasd" -cc-link-flags cclinkflags + "#]], + ); + // don't pass native cc flags for no native backend + check( + get_stdout( + &dir, + ["build", "--target", "wasm-gc", "--dry-run", "--sort-input"], + ), + expect![[r#" + moonc build-package ./lib/hello.mbt -o ./target/wasm-gc/release/build/lib/lib.core -pkg moon_new/lib -std-path $MOON_HOME/lib/core/target/wasm-gc/release/bundle -pkg-sources moon_new/lib:./lib -target wasm-gc + moonc build-package ./main/main.mbt -o ./target/wasm-gc/release/build/main/main.core -pkg moon_new/main -is-main -std-path $MOON_HOME/lib/core/target/wasm-gc/release/bundle -i ./target/wasm-gc/release/build/lib/lib.mi:lib -pkg-sources moon_new/main:./main -target wasm-gc + moonc link-core $MOON_HOME/lib/core/target/wasm-gc/release/bundle/core.core ./target/wasm-gc/release/build/lib/lib.core ./target/wasm-gc/release/build/main/main.core -main moon_new/main -o ./target/wasm-gc/release/build/main/main.wasm -pkg-sources moon_new/lib:./lib -pkg-sources moon_new/main:./main -pkg-sources moonbitlang/core:$MOON_HOME/lib/core -target wasm-gc + moonc link-core $MOON_HOME/lib/core/target/wasm-gc/release/bundle/core.core ./target/wasm-gc/release/build/lib/lib.core -main moon_new/lib -o ./target/wasm-gc/release/build/lib/lib.wasm -pkg-sources moon_new/lib:./lib -pkg-sources moonbitlang/core:$MOON_HOME/lib/core -target wasm-gc + "#]], + ); + + check( + get_stdout( + &dir, + ["test", "--target", "native", "--dry-run", "--sort-input"], + ), + expect![[r#" + moon generate-test-driver --source-dir . --target-dir ./target/native/debug/test --package moon_new/lib --sort-input --target native --driver-kind internal + moonc build-package ./lib/hello.mbt ./target/native/debug/test/lib/__generated_driver_for_internal_test.mbt -o ./target/native/debug/test/lib/lib.internal_test.core -pkg moon_new/lib -is-main -std-path $MOON_HOME/lib/core/target/native/release/bundle -pkg-sources moon_new/lib:./lib -target native -g + moonc link-core $MOON_HOME/lib/core/target/native/release/bundle/core.core ./target/native/debug/test/lib/lib.internal_test.core -main moon_new/lib -o ./target/native/debug/test/lib/lib.internal_test.exe -test-mode -pkg-sources moon_new/lib:./lib -pkg-sources moonbitlang/core:$MOON_HOME/lib/core -exported_functions moonbit_test_driver_internal_execute -target native -g -cc cc -cc-flags "ccflags fasd" -cc-link-flags cclinkflags + "#]], + ); + // don't pass native cc flags for no native backend + check( + get_stdout(&dir, ["test", "--target", "wasm", "--dry-run"]), + expect![[r#" + moon generate-test-driver --source-dir . --target-dir ./target/wasm/debug/test --package moon_new/lib --target wasm --driver-kind internal + moonc build-package ./lib/hello.mbt ./target/wasm/debug/test/lib/__generated_driver_for_internal_test.mbt -o ./target/wasm/debug/test/lib/lib.internal_test.core -pkg moon_new/lib -is-main -std-path $MOON_HOME/lib/core/target/wasm/release/bundle -pkg-sources moon_new/lib:./lib -target wasm -g + moonc link-core $MOON_HOME/lib/core/target/wasm/release/bundle/core.core ./target/wasm/debug/test/lib/lib.internal_test.core -main moon_new/lib -o ./target/wasm/debug/test/lib/lib.internal_test.wasm -test-mode -pkg-sources moon_new/lib:./lib -pkg-sources moonbitlang/core:$MOON_HOME/lib/core -exported_functions moonbit_test_driver_internal_execute -target wasm -g + "#]], + ); + + check( + get_stdout( + &dir, + [ + "run", + "main", + "--target", + "native", + "--dry-run", + "--sort-input", + ], + ), + expect![[r#" + moonc build-package ./lib/hello.mbt -o ./target/native/release/build/lib/lib.core -pkg moon_new/lib -std-path $MOON_HOME/lib/core/target/native/release/bundle -pkg-sources moon_new/lib:./lib -target native + moonc build-package ./main/main.mbt -o ./target/native/release/build/main/main.core -pkg moon_new/main -is-main -std-path $MOON_HOME/lib/core/target/native/release/bundle -i ./target/native/release/build/lib/lib.mi:lib -pkg-sources moon_new/main:./main -target native + moonc link-core $MOON_HOME/lib/core/target/native/release/bundle/core.core ./target/native/release/build/lib/lib.core ./target/native/release/build/main/main.core -main moon_new/main -o ./target/native/release/build/main/main.exe -pkg-sources moon_new/lib:./lib -pkg-sources moon_new/main:./main -pkg-sources moonbitlang/core:$MOON_HOME/lib/core -target native + moonc link-core $MOON_HOME/lib/core/target/native/release/bundle/core.core ./target/native/release/build/lib/lib.core -main moon_new/lib -o ./target/native/release/build/lib/lib.exe -pkg-sources moon_new/lib:./lib -pkg-sources moonbitlang/core:$MOON_HOME/lib/core -target native -cc cc -cc-flags "ccflags fasd" -cc-link-flags cclinkflags + ./target/native/release/build/lib/lib.exe + ./target/native/release/build/main/main.exe + "#]], + ); + // don't pass native cc flags for no native backend + check( + get_stdout( + &dir, + [ + "run", + "main", + "--target", + "wasm", + "--dry-run", + "--sort-input", + ], + ), + expect![[r#" + moonc build-package ./lib/hello.mbt -o ./target/wasm/release/build/lib/lib.core -pkg moon_new/lib -std-path $MOON_HOME/lib/core/target/wasm/release/bundle -pkg-sources moon_new/lib:./lib -target wasm + moonc build-package ./main/main.mbt -o ./target/wasm/release/build/main/main.core -pkg moon_new/main -is-main -std-path $MOON_HOME/lib/core/target/wasm/release/bundle -i ./target/wasm/release/build/lib/lib.mi:lib -pkg-sources moon_new/main:./main -target wasm + moonc link-core $MOON_HOME/lib/core/target/wasm/release/bundle/core.core ./target/wasm/release/build/lib/lib.core ./target/wasm/release/build/main/main.core -main moon_new/main -o ./target/wasm/release/build/main/main.wasm -pkg-sources moon_new/lib:./lib -pkg-sources moon_new/main:./main -pkg-sources moonbitlang/core:$MOON_HOME/lib/core -target wasm + moonc link-core $MOON_HOME/lib/core/target/wasm/release/bundle/core.core ./target/wasm/release/build/lib/lib.core -main moon_new/lib -o ./target/wasm/release/build/lib/lib.wasm -pkg-sources moon_new/lib:./lib -pkg-sources moonbitlang/core:$MOON_HOME/lib/core -target wasm + moonrun ./target/wasm/release/build/lib/lib.wasm + moonrun ./target/wasm/release/build/main/main.wasm + "#]], + ); +} diff --git a/crates/moon/tests/test_cases/native_backend_cc_flags.in/lib/hello.mbt b/crates/moon/tests/test_cases/native_backend_cc_flags.in/lib/hello.mbt new file mode 100644 index 00000000..a7ac2bee --- /dev/null +++ b/crates/moon/tests/test_cases/native_backend_cc_flags.in/lib/hello.mbt @@ -0,0 +1,4 @@ +pub fn hello() -> String { + "Hello, world!" +} + diff --git a/crates/moon/tests/test_cases/native_backend_cc_flags.in/lib/moon.pkg.json b/crates/moon/tests/test_cases/native_backend_cc_flags.in/lib/moon.pkg.json new file mode 100644 index 00000000..639b4b85 --- /dev/null +++ b/crates/moon/tests/test_cases/native_backend_cc_flags.in/lib/moon.pkg.json @@ -0,0 +1,10 @@ +{ + "import": {}, + "link": { + "native": { + "cc": "cc", + "cc-flags": "ccflags fasd", + "cc-link-flags": "cclinkflags" + } + } +} diff --git a/crates/moon/tests/test_cases/native_backend_cc_flags.in/main/main.mbt b/crates/moon/tests/test_cases/native_backend_cc_flags.in/main/main.mbt new file mode 100644 index 00000000..d25cb935 --- /dev/null +++ b/crates/moon/tests/test_cases/native_backend_cc_flags.in/main/main.mbt @@ -0,0 +1,3 @@ +fn main { + println(@lib.hello()) +} diff --git a/crates/moon/tests/test_cases/native_backend_cc_flags.in/main/moon.pkg.json b/crates/moon/tests/test_cases/native_backend_cc_flags.in/main/moon.pkg.json new file mode 100644 index 00000000..4343a4ef --- /dev/null +++ b/crates/moon/tests/test_cases/native_backend_cc_flags.in/main/moon.pkg.json @@ -0,0 +1,6 @@ +{ + "is-main": true, + "import": { + "moon_new/lib": "" + } +} \ No newline at end of file diff --git a/crates/moon/tests/test_cases/native_backend_cc_flags.in/moon.mod.json b/crates/moon/tests/test_cases/native_backend_cc_flags.in/moon.mod.json new file mode 100644 index 00000000..b5d8b346 --- /dev/null +++ b/crates/moon/tests/test_cases/native_backend_cc_flags.in/moon.mod.json @@ -0,0 +1,3 @@ +{ + "name": "moon_new" +} diff --git a/crates/moonbuild/src/gen/gen_build.rs b/crates/moonbuild/src/gen/gen_build.rs index 52fce3d5..75a05479 100644 --- a/crates/moonbuild/src/gen/gen_build.rs +++ b/crates/moonbuild/src/gen/gen_build.rs @@ -17,7 +17,6 @@ // For inquiries, you can contact us via e-mail at jichuruanjian@idea.edu.cn. use anyhow::{bail, Ok}; -use moonutil::common::TargetBackend::*; use moonutil::module::ModuleDB; use moonutil::package::{JsFormat, Package}; @@ -27,7 +26,7 @@ use crate::gen::MiAlias; use std::path::{Path, PathBuf}; use std::rc::Rc; -use moonutil::common::{MoonbuildOpt, MooncOpt, TargetBackend, MOONBITLANG_CORE, MOON_PKG_JSON}; +use moonutil::common::{MoonbuildOpt, MooncOpt, MOONBITLANG_CORE, MOON_PKG_JSON}; use n2::graph::{self as n2graph, Build, BuildIns, BuildOuts, FileLoc}; use n2::load::State; use n2::smallmap::SmallMap; @@ -44,20 +43,12 @@ pub struct BuildDepItem { pub is_third_party: bool, } -#[derive(Debug)] -pub struct LinkDepItem { - pub out: String, - pub core_deps: Vec, // need add parent's core files recursively - pub package_full_name: String, - pub package_sources: Vec<(String, String)>, // (pkgname, source_dir) - - pub link: Option, -} +type BuildLinkDepItem = moonutil::package::LinkDepItem; #[derive(Debug)] pub struct N2BuildInput { pub build_items: Vec, - pub link_items: Vec, // entry points + pub link_items: Vec, // entry points } pub fn gen_build_build_item( @@ -128,7 +119,7 @@ pub fn gen_build_link_item( m: &ModuleDB, pkg: &Package, _moonc_opt: &MooncOpt, -) -> anyhow::Result { +) -> anyhow::Result { let out = pkg.artifact.with_extension("wat"); // TODO: extension is determined by build option let package_full_name = pkg.full_name(); @@ -136,7 +127,7 @@ pub fn gen_build_link_item( let core_deps = super::util::nodes_to_cores(m, &tp); let package_sources = super::util::nodes_to_pkg_sources(m, &tp); - Ok(LinkDepItem { + Ok(BuildLinkDepItem { out: out.display().to_string(), core_deps, package_sources, @@ -287,7 +278,7 @@ pub fn gen_build_command( pub fn gen_link_command( graph: &mut n2graph::Graph, - item: &LinkDepItem, + item: &BuildLinkDepItem, moonc_opt: &MooncOpt, ) -> (Build, n2graph::FileId) { let artifact_output_path = PathBuf::from(&item.out) @@ -329,6 +320,10 @@ pub fn gen_link_command( let import_memory = item.import_memory(moonc_opt.link_opt.target_backend); let link_flags = item.link_flags(moonc_opt.link_opt.target_backend); + let native_cc = item.native_cc(moonc_opt.link_opt.target_backend); + let native_cc_flags = item.native_cc_flags(moonc_opt.link_opt.target_backend); + let native_cc_link_flags = item.native_cc_link_flags(moonc_opt.link_opt.target_backend); + let command = CommandBuilder::new("moonc") .arg("link-core") .arg_with_cond( @@ -414,6 +409,21 @@ pub fn gen_link_command( } }, ) + .lazy_args_with_cond(native_cc.is_some(), || { + vec!["-cc".to_string(), native_cc.unwrap().to_string()] + }) + .lazy_args_with_cond(native_cc_flags.is_some(), || { + vec![ + "-cc-flags".to_string(), + native_cc_flags.unwrap().to_string(), + ] + }) + .lazy_args_with_cond(native_cc_link_flags.is_some(), || { + vec![ + "-cc-link-flags".to_string(), + native_cc_link_flags.unwrap().to_string(), + ] + }) .args(moonc_opt.extra_link_opt.iter()) .build(); log::debug!("Command: {}", command); @@ -462,64 +472,3 @@ pub fn gen_n2_build_state( pools: SmallMap::default(), }) } - -#[rustfmt::skip] -impl LinkDepItem { - pub fn wasm_exports(&self) -> Option<&[String]> { self.link.as_ref()?.wasm.as_ref()?.exports.as_deref() } - pub fn wasm_export_memory_name(&self) -> Option<&str> { self.link.as_ref()?.wasm.as_ref()?.export_memory_name.as_deref() } - pub fn wasm_import_memory(&self) -> Option<&moonutil::package::ImportMemory> { self.link.as_ref()?.wasm.as_ref()?.import_memory.as_ref() } - pub fn wasm_heap_start_address(&self) -> Option { self.link.as_ref()?.wasm.as_ref()?.heap_start_address } - pub fn wasm_link_flags(&self) -> Option<&[String]> { self.link.as_ref()?.wasm.as_ref()?.flags.as_deref() } - - pub fn wasm_gc_exports(&self) -> Option<&[String]> { self.link.as_ref()?.wasm_gc.as_ref()?.exports.as_deref() } - pub fn wasm_gc_export_memory_name(&self) -> Option<&str> { self.link.as_ref()?.wasm_gc.as_ref()?.export_memory_name.as_deref() } - pub fn wasm_gc_import_memory(&self) -> Option<&moonutil::package::ImportMemory> { self.link.as_ref()?.wasm_gc.as_ref()?.import_memory.as_ref() } - pub fn wasm_gc_link_flags(&self) -> Option<&[String]> { self.link.as_ref()?.wasm_gc.as_ref()?.flags.as_deref() } - - pub fn js_exports(&self) -> Option<&[String]> { self.link.as_ref()?.js.as_ref()?.exports.as_deref() } - - pub fn exports(&self, b: TargetBackend) -> Option<&[String]> { - match b { - Wasm => self.wasm_exports(), - WasmGC => self.wasm_gc_exports(), - Js => self.js_exports(), - Native => None, - } - } - - pub fn export_memory_name(&self, b: TargetBackend) -> Option<&str> { - match b { - Wasm => self.wasm_export_memory_name(), - WasmGC => self.wasm_gc_export_memory_name(), - Js => None, - Native => None, - } - } - - pub fn heap_start_address(&self, b: TargetBackend) -> Option { - match b { - Wasm => self.wasm_heap_start_address(), - WasmGC => None, - Js => None, - Native => None, - } - } - - pub fn import_memory(&self, b: TargetBackend) -> Option<&moonutil::package::ImportMemory> { - match b { - Wasm => self.wasm_import_memory(), - WasmGC => self.wasm_gc_import_memory(), - Js => None, - Native => None, - } - } - - pub fn link_flags(&self, b: TargetBackend) -> Option<&[String]> { - match b { - Wasm => self.wasm_link_flags(), - WasmGC => self.wasm_gc_link_flags(), - Js => None, - Native => self.link.as_ref()?.native.as_ref()?.flags.as_deref(), - } - } -} diff --git a/crates/moonbuild/src/gen/gen_runtest.rs b/crates/moonbuild/src/gen/gen_runtest.rs index b82b28c0..d1b2ef26 100644 --- a/crates/moonbuild/src/gen/gen_runtest.rs +++ b/crates/moonbuild/src/gen/gen_runtest.rs @@ -51,15 +51,7 @@ pub struct RuntestDepItem { pub is_blackbox_test: bool, } -#[derive(Debug)] -pub struct RuntestLinkDepItem { - pub out: String, - pub core_deps: Vec, // need add parent's core files recursively - pub package_full_name: String, - pub package_sources: Vec<(String, String)>, // (pkgname, source_dir) - pub is_main: bool, - pub link: Option, -} +type RuntestLinkDepItem = moonutil::package::LinkDepItem; #[derive(Debug)] pub struct RuntestDriverItem { @@ -543,7 +535,6 @@ pub fn gen_link_internal_test( core_deps, package_full_name, package_sources, - is_main: true, link: pkg.link.clone(), }) } @@ -580,7 +571,6 @@ pub fn gen_link_whitebox_test( core_deps, package_full_name, package_sources, - is_main: true, link: pkg.link.clone(), }) } @@ -644,7 +634,6 @@ pub fn gen_link_blackbox_test( core_deps, package_full_name, package_sources, - is_main: true, link: pkg.link.clone(), }) } @@ -872,6 +861,10 @@ pub fn gen_runtest_link_command( let mut build = Build::new(loc, ins, outs); + let native_cc = item.native_cc(moonc_opt.link_opt.target_backend); + let native_cc_flags = item.native_cc_flags(moonc_opt.link_opt.target_backend); + let native_cc_link_flags = item.native_cc_link_flags(moonc_opt.link_opt.target_backend); + let command = CommandBuilder::new("moonc") .arg("link-core") .arg_with_cond( @@ -914,6 +907,21 @@ pub fn gen_runtest_link_command( .args(["-target", moonc_opt.link_opt.target_backend.to_flag()]) .arg_with_cond(moonc_opt.link_opt.debug_flag, "-g") .arg_with_cond(moonc_opt.link_opt.source_map, "-source-map") + .lazy_args_with_cond(native_cc.is_some(), || { + vec!["-cc".to_string(), native_cc.unwrap().to_string()] + }) + .lazy_args_with_cond(native_cc_flags.is_some(), || { + vec![ + "-cc-flags".to_string(), + native_cc_flags.unwrap().to_string(), + ] + }) + .lazy_args_with_cond(native_cc_link_flags.is_some(), || { + vec![ + "-cc-link-flags".to_string(), + native_cc_link_flags.unwrap().to_string(), + ] + }) .args(moonc_opt.extra_link_opt.iter()) .build(); log::debug!("Command: {}", command); diff --git a/crates/moonbuild/template/pkg.schema.json b/crates/moonbuild/template/pkg.schema.json index 95b653e1..8d4f60ec 100644 --- a/crates/moonbuild/template/pkg.schema.json +++ b/crates/moonbuild/template/pkg.schema.json @@ -205,14 +205,23 @@ "NativeLinkConfig": { "type": "object", "properties": { - "flags": { + "cc": { "type": [ - "array", + "string", "null" - ], - "items": { - "type": "string" - } + ] + }, + "cc-flags": { + "type": [ + "string", + "null" + ] + }, + "cc-link-flags": { + "type": [ + "string", + "null" + ] } } }, diff --git a/crates/moonutil/Cargo.toml b/crates/moonutil/Cargo.toml index 5233d033..1e28a217 100644 --- a/crates/moonutil/Cargo.toml +++ b/crates/moonutil/Cargo.toml @@ -46,6 +46,7 @@ thiserror.workspace = true schemars.workspace = true line-index.workspace = true nucleo-matcher.workspace = true +which.workspace = true [dev-dependencies] expect-test.workspace = true diff --git a/crates/moonutil/src/common.rs b/crates/moonutil/src/common.rs index f1e4b723..febff42e 100644 --- a/crates/moonutil/src/common.rs +++ b/crates/moonutil/src/common.rs @@ -799,3 +799,56 @@ impl StringExt for str { self.replace("\r\n", "\n") } } + +pub fn set_native_backend_link_flags( + run_mode: RunMode, + release: bool, + target_backend: Option, + module: &mut crate::module::ModuleDB, +) { + #[cfg(unix)] + match run_mode { + // need link-core for build, test and run + RunMode::Build | RunMode::Test | RunMode::Run => { + if release && target_backend == Some(TargetBackend::Native) { + // check if cc exists in PATH + if let Err(e) = which::which("cc") { + eprintln!( + "error: 'cc' not found in PATH, which is used for native backend release compilation: {}", + e + ); + std::process::exit(1); + } + + // libmoonbitrun.o should be in the same directory as moonc + let libmoonbitrun_path = + which::which("moonc").map(|p| p.with_file_name("libmoonbitrun.o")); + if let Err(e) = libmoonbitrun_path { + eprintln!( + "error: 'libmoonbitrun.o' not found in PATH, which is used for native backend release compilation: {}", + e + ); + std::process::exit(1); + } + + let all_pkgs = module.get_all_packages_mut(); + for (_, pkg) in all_pkgs { + if pkg.link.is_none() || pkg.link.as_ref().unwrap().native.is_none() { + pkg.link = Some(crate::package::Link { + native: Some(crate::package::NativeLinkConfig { + cc: Some("cc".to_string()), + cc_flags: Some(format!( + "-O2 {} -fwrapv", + libmoonbitrun_path.as_ref().unwrap().display() + )), + cc_link_flags: Some("-lm".to_string()), + }), + ..Default::default() + }); + } + } + } + } + _ => {} + } +} diff --git a/crates/moonutil/src/package.rs b/crates/moonutil/src/package.rs index 52c84e6c..8fbb39e3 100644 --- a/crates/moonutil/src/package.rs +++ b/crates/moonutil/src/package.rs @@ -28,7 +28,10 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use crate::{ - common::{FileName, GeneratedTestDriver}, + common::{ + FileName, GeneratedTestDriver, TargetBackend, TargetBackend::Js, TargetBackend::Native, + TargetBackend::Wasm, TargetBackend::WasmGC, + }, cond_expr::{CompileCondition, CondExpr, RawTargets}, path::{ImportComponent, PathComponent}, }; @@ -220,6 +223,97 @@ pub struct ImportMemory { pub name: String, } +#[derive(Debug)] +pub struct LinkDepItem { + pub out: String, + pub core_deps: Vec, // need add parent's core files recursively + pub package_full_name: String, + pub package_sources: Vec<(String, String)>, // (pkgname, source_dir) + pub link: Option, +} + +#[rustfmt::skip] +impl LinkDepItem { + pub fn wasm_exports(&self) -> Option<&[String]> { self.link.as_ref()?.wasm.as_ref()?.exports.as_deref() } + pub fn wasm_export_memory_name(&self) -> Option<&str> { self.link.as_ref()?.wasm.as_ref()?.export_memory_name.as_deref() } + pub fn wasm_import_memory(&self) -> Option<&ImportMemory> { self.link.as_ref()?.wasm.as_ref()?.import_memory.as_ref() } + pub fn wasm_heap_start_address(&self) -> Option { self.link.as_ref()?.wasm.as_ref()?.heap_start_address } + pub fn wasm_link_flags(&self) -> Option<&[String]> { self.link.as_ref()?.wasm.as_ref()?.flags.as_deref() } + + pub fn wasm_gc_exports(&self) -> Option<&[String]> { self.link.as_ref()?.wasm_gc.as_ref()?.exports.as_deref() } + pub fn wasm_gc_export_memory_name(&self) -> Option<&str> { self.link.as_ref()?.wasm_gc.as_ref()?.export_memory_name.as_deref() } + pub fn wasm_gc_import_memory(&self) -> Option<&ImportMemory> { self.link.as_ref()?.wasm_gc.as_ref()?.import_memory.as_ref() } + pub fn wasm_gc_link_flags(&self) -> Option<&[String]> { self.link.as_ref()?.wasm_gc.as_ref()?.flags.as_deref() } + + pub fn js_exports(&self) -> Option<&[String]> { self.link.as_ref()?.js.as_ref()?.exports.as_deref() } + + pub fn exports(&self, b: TargetBackend) -> Option<&[String]> { + match b { + Wasm => self.wasm_exports(), + WasmGC => self.wasm_gc_exports(), + Js => self.js_exports(), + Native => None, + } + } + + pub fn export_memory_name(&self, b: TargetBackend) -> Option<&str> { + match b { + Wasm => self.wasm_export_memory_name(), + WasmGC => self.wasm_gc_export_memory_name(), + Js => None, + Native => None, + } + } + + pub fn heap_start_address(&self, b: TargetBackend) -> Option { + match b { + Wasm => self.wasm_heap_start_address(), + WasmGC => None, + Js => None, + Native => None, + } + } + + pub fn import_memory(&self, b: TargetBackend) -> Option<&ImportMemory> { + match b { + Wasm => self.wasm_import_memory(), + WasmGC => self.wasm_gc_import_memory(), + Js => None, + Native => None, + } + } + + pub fn link_flags(&self, b: TargetBackend) -> Option<&[String]> { + match b { + Wasm => self.wasm_link_flags(), + WasmGC => self.wasm_gc_link_flags(), + Js => None, + Native => None, + } + } + + pub fn native_cc(&self, b: TargetBackend) -> Option<&str> { + match b { + Native => self.link.as_ref()?.native.as_ref()?.cc.as_deref(), + _ => None, + } + } + + pub fn native_cc_flags(&self, b: TargetBackend) -> Option<&str> { + match b { + Native => self.link.as_ref()?.native.as_ref()?.cc_flags.as_deref(), + _ => None, + } + } + + pub fn native_cc_link_flags(&self, b: TargetBackend) -> Option<&str> { + match b { + Native => self.link.as_ref()?.native.as_ref()?.cc_link_flags.as_deref(), + _ => None, + } + } +} + #[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)] pub struct WasmLinkConfig { #[serde(skip_serializing_if = "Option::is_none")] @@ -242,9 +336,14 @@ pub struct WasmLinkConfig { } #[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)] +#[serde(rename_all = "kebab-case")] pub struct NativeLinkConfig { #[serde(skip_serializing_if = "Option::is_none")] - pub flags: Option>, + pub cc: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub cc_flags: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub cc_link_flags: Option, } #[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)] @@ -297,7 +396,7 @@ impl JsFormat { } } -#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema)] +#[derive(Debug, Serialize, Deserialize, Clone, JsonSchema, Default)] pub struct Link { #[serde(skip_serializing_if = "Option::is_none")] pub wasm: Option, diff --git a/docs/manual-zh/src/source/pkg_json_schema.html b/docs/manual-zh/src/source/pkg_json_schema.html index 4f2efac3..c93c6413 100644 --- a/docs/manual-zh/src/source/pkg_json_schema.html +++ b/docs/manual-zh/src/source/pkg_json_schema.html @@ -243,14 +243,23 @@ "NativeLinkConfig": { "type": "object", "properties": { - "flags": { + "cc": { "type": [ - "array", + "string", "null" - ], - "items": { - "type": "string" - } + ] + }, + "cc-flags": { + "type": [ + "string", + "null" + ] + }, + "cc-link-flags": { + "type": [ + "string", + "null" + ] } } }, diff --git a/docs/manual/src/source/pkg_json_schema.html b/docs/manual/src/source/pkg_json_schema.html index 4f2efac3..c93c6413 100644 --- a/docs/manual/src/source/pkg_json_schema.html +++ b/docs/manual/src/source/pkg_json_schema.html @@ -243,14 +243,23 @@ "NativeLinkConfig": { "type": "object", "properties": { - "flags": { + "cc": { "type": [ - "array", + "string", "null" - ], - "items": { - "type": "string" - } + ] + }, + "cc-flags": { + "type": [ + "string", + "null" + ] + }, + "cc-link-flags": { + "type": [ + "string", + "null" + ] } } },