diff --git a/crates/cli/src/lib.rs b/crates/cli/src/lib.rs index 1e42baeb5b2..d5c91b912ca 100644 --- a/crates/cli/src/lib.rs +++ b/crates/cli/src/lib.rs @@ -48,6 +48,7 @@ pub const CMD_FORMAT: &str = "format"; pub const CMD_TEST: &str = "test"; pub const CMD_GLUE: &str = "glue"; pub const CMD_GEN_STUB_LIB: &str = "gen-stub-lib"; +pub const CMD_PREPROCESS_HOST: &str = "preprocess-host"; pub const FLAG_DEBUG: &str = "debug"; pub const FLAG_BUNDLE: &str = "bundle"; @@ -345,6 +346,23 @@ pub fn build_app() -> Command { .value_parser(value_parser!(PathBuf)) .required(true) ) + .arg( + Arg::new(FLAG_TARGET) + .long(FLAG_TARGET) + .help("Choose a different target") + .default_value(Into::<&'static str>::into(Target::default())) + .value_parser(build_target_values_parser.clone()) + .required(false), + ) + ) + .subcommand(Command::new(CMD_PREPROCESS_HOST) + .about("Runs the surgical linker preprocessor to generate `.rh` and `.rm` files.") + .arg( + Arg::new(ROC_FILE) + .help("The .roc file for an app using the platform") + .value_parser(value_parser!(PathBuf)) + .required(true) + ) .arg( Arg::new(FLAG_TARGET) .long(FLAG_TARGET) diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 2d679ce917a..8cb445379db 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -4,9 +4,10 @@ use roc_build::link::LinkType; use roc_build::program::{check_file, CodeGenBackend}; use roc_cli::{ build_app, format_files, format_src, test, BuildConfig, FormatMode, CMD_BUILD, CMD_CHECK, - CMD_DEV, CMD_DOCS, CMD_FORMAT, CMD_GEN_STUB_LIB, CMD_GLUE, CMD_REPL, CMD_RUN, CMD_TEST, - CMD_VERSION, DIRECTORY_OR_FILES, FLAG_CHECK, FLAG_DEV, FLAG_LIB, FLAG_NO_LINK, FLAG_OUTPUT, - FLAG_STDIN, FLAG_STDOUT, FLAG_TARGET, FLAG_TIME, GLUE_DIR, GLUE_SPEC, ROC_FILE, + CMD_DEV, CMD_DOCS, CMD_FORMAT, CMD_GEN_STUB_LIB, CMD_GLUE, CMD_PREPROCESS_HOST, CMD_REPL, + CMD_RUN, CMD_TEST, CMD_VERSION, DIRECTORY_OR_FILES, FLAG_CHECK, FLAG_DEV, FLAG_LIB, + FLAG_NO_LINK, FLAG_OUTPUT, FLAG_STDIN, FLAG_STDOUT, FLAG_TARGET, FLAG_TIME, GLUE_DIR, + GLUE_SPEC, ROC_FILE, }; use roc_docs::generate_docs_html; use roc_error_macros::user_error; @@ -14,7 +15,7 @@ use roc_gen_dev::AssemblyBackendMode; use roc_gen_llvm::llvm::build::LlvmBackendMode; use roc_load::{FunctionKind, LoadingProblem, Threading}; use roc_packaging::cache::{self, RocCacheDir}; -use roc_target::Target; +use roc_target::{get_target_triple_str, Target}; use std::fs::{self, FileType}; use std::io::{self, Read, Write}; use std::path::{Path, PathBuf}; @@ -131,7 +132,38 @@ fn main() -> io::Result<()> { RocCacheDir::Persistent(cache::roc_cache_dir().as_path()), &target.to_triple(), function_kind, - ) + ); + Ok(0) + } + Some((CMD_PREPROCESS_HOST, matches)) => { + let input_path = matches.get_one::(ROC_FILE).unwrap(); + let target = matches + .get_one::(FLAG_TARGET) + .and_then(|s| Target::from_str(s).ok()) + .unwrap_or_default(); + + let triple = target.to_triple(); + let function_kind = FunctionKind::LambdaSet; + let (platform_path, stub_lib, stub_dll_symbols) = roc_linker::generate_stub_lib( + &input_path, + RocCacheDir::Persistent(cache::roc_cache_dir().as_path()), + &triple, + function_kind, + ); + + // TODO: pipeline the executable location through here. + // Currently it is essentally hardcoded as platform_path/dynhost. + roc_linker::preprocess_host( + &triple, + &platform_path.with_file_name("main.roc"), + // The target triple string must be derived from the triple to convert from the generic + // `system` target to the exact specific target. + &platform_path + .with_file_name(format!("{}.rh", get_target_triple_str(&triple).unwrap())), + &stub_lib, + &stub_dll_symbols, + ); + Ok(0) } Some((CMD_BUILD, matches)) => { let target = matches diff --git a/crates/linker/src/lib.rs b/crates/linker/src/lib.rs index bec65cbfa24..1f1408bd0bc 100644 --- a/crates/linker/src/lib.rs +++ b/crates/linker/src/lib.rs @@ -90,7 +90,7 @@ pub fn generate_stub_lib( roc_cache_dir: RocCacheDir<'_>, triple: &Triple, function_kind: FunctionKind, -) -> std::io::Result { +) -> (PathBuf, PathBuf, Vec) { // Note: this should theoretically just be able to load the host, I think. // Instead, I am loading an entire app because that was simpler and had example code. // If this was expected to stay around for the the long term, we should change it. @@ -146,10 +146,10 @@ pub fn generate_stub_lib( let stub_dll_symbols = exposed_symbols.stub_dll_symbols(); generate_dynamic_lib(triple, &stub_dll_symbols, &stub_lib); + (platform_path.into(), stub_lib, stub_dll_symbols) } else { unreachable!(); - }; - Ok(0) + } } pub fn generate_stub_lib_from_loaded(