diff --git a/Cargo.lock b/Cargo.lock index d2436dc095..27c0e7bf0f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3370,6 +3370,7 @@ dependencies = [ "roc_can", "roc_collections", "roc_constrain", + "roc_error_macros", "roc_gen_dev", "roc_gen_llvm", "roc_gen_wasm", diff --git a/cli/src/build.rs b/cli/src/build.rs index a32c5c1e23..ab3d7d0c42 100644 --- a/cli/src/build.rs +++ b/cli/src/build.rs @@ -246,6 +246,11 @@ pub fn build_file<'a>( todo!("gracefully handle failing to surgically link"); })?; BuildOutcome::NoProblems + } else if matches!(link_type, LinkType::None) { + // Just copy the object file to the output folder. + binary_path.set_extension(app_extension); + std::fs::copy(app_o_file, &binary_path).unwrap(); + BuildOutcome::NoProblems } else { let mut inputs = vec![ host_input_path.as_path().to_str().unwrap(), diff --git a/cli/src/lib.rs b/cli/src/lib.rs index 54620dbfc8..7d82ed074c 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -34,6 +34,7 @@ pub const FLAG_DEV: &str = "dev"; pub const FLAG_OPTIMIZE: &str = "optimize"; pub const FLAG_OPT_SIZE: &str = "opt-size"; pub const FLAG_LIB: &str = "lib"; +pub const FLAG_NO_LINK: &str = "no-link"; pub const FLAG_TARGET: &str = "target"; pub const FLAG_TIME: &str = "time"; pub const FLAG_LINK: &str = "roc-linker"; @@ -88,6 +89,12 @@ pub fn build_app<'a>() -> App<'a> { .about("Build a C library instead of an executable.") .required(false), ) + .arg( + Arg::new(FLAG_NO_LINK) + .long(FLAG_NO_LINK) + .about("Does not link. Instead just outputs the `.o` file") + .required(false), + ) .arg( Arg::new(FLAG_DEBUG) .long(FLAG_DEBUG) @@ -291,10 +298,14 @@ pub fn build(matches: &ArgMatches, config: BuildConfig) -> io::Result { let emit_debug_info = matches.is_present(FLAG_DEBUG); let emit_timings = matches.is_present(FLAG_TIME); - let link_type = if matches.is_present(FLAG_LIB) { - LinkType::Dylib - } else { - LinkType::Executable + let link_type = match ( + matches.is_present(FLAG_LIB), + matches.is_present(FLAG_NO_LINK), + ) { + (true, false) => LinkType::Dylib, + (true, true) => user_error!("build can only be one of `--lib` or `--no-link`"), + (false, true) => LinkType::None, + (false, false) => LinkType::Executable, }; let surgically_link = matches.is_present(FLAG_LINK); let precompiled = matches.is_present(FLAG_PRECOMPILED); diff --git a/compiler/build/Cargo.toml b/compiler/build/Cargo.toml index 54872936b4..323a820d46 100644 --- a/compiler/build/Cargo.toml +++ b/compiler/build/Cargo.toml @@ -24,6 +24,7 @@ roc_gen_llvm = { path = "../gen_llvm", optional = true } roc_gen_wasm = { path = "../gen_wasm", optional = true } roc_gen_dev = { path = "../gen_dev", default-features = false } roc_reporting = { path = "../../reporting" } +roc_error_macros = { path = "../../error_macros" } roc_std = { path = "../../roc_std", default-features = false } bumpalo = { version = "3.8.0", features = ["collections"] } libloading = "0.7.1" diff --git a/compiler/build/src/link.rs b/compiler/build/src/link.rs index 6b76c37b7a..a7e32d0328 100644 --- a/compiler/build/src/link.rs +++ b/compiler/build/src/link.rs @@ -2,6 +2,7 @@ use crate::target::{arch_str, target_zig_str}; #[cfg(feature = "llvm")] use libloading::{Error, Library}; use roc_builtins::bitcode; +use roc_error_macros::internal_error; // #[cfg(feature = "llvm")] use roc_mono::ir::OptLevel; use std::collections::HashMap; @@ -20,10 +21,10 @@ fn zig_executable() -> String { #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum LinkType { - // These numbers correspond to the --lib flag; if it's present - // (e.g. is_present returns `1 as bool`), this will be 1 as well. + // These numbers correspond to the --lib and --no-link flags Executable = 0, Dylib = 1, + None = 2, } /// input_paths can include the host as well as the app. e.g. &["host.o", "roc_app.o"] @@ -835,6 +836,7 @@ fn link_linux( output_path, ) } + LinkType::None => internal_error!("link_linux should not be called with link type of none"), }; let env_path = env::var("PATH").unwrap_or_else(|_| "".to_string()); @@ -904,6 +906,7 @@ fn link_macos( ("-dylib", output_path) } + LinkType::None => internal_error!("link_macos should not be called with link type of none"), }; let arch = match target.architecture {