diff --git a/crates/cli/src/build.rs b/crates/cli/src/build.rs index 6dba4a6f38..b09bf3b0f5 100644 --- a/crates/cli/src/build.rs +++ b/crates/cli/src/build.rs @@ -4,7 +4,7 @@ use roc_build::{ legacy_host_filename, link, preprocess_host_wasm32, preprocessed_host_filename, rebuild_host, LinkType, LinkingStrategy, }, - program::{self, CodeGenOptions}, + program::{self, CodeGenBackend, CodeGenOptions}, }; use roc_builtins::bitcode; use roc_load::{ @@ -18,7 +18,10 @@ use roc_reporting::{ report::{RenderTarget, DEFAULT_PALETTE}, }; use roc_target::TargetInfo; -use std::time::{Duration, Instant}; +use std::{ + path::Path, + time::{Duration, Instant}, +}; use std::{path::PathBuf, thread::JoinHandle}; use target_lexicon::Triple; @@ -130,7 +133,7 @@ pub fn build_file<'a>( } #[allow(clippy::too_many_arguments)] -fn build_loaded_file<'a>( +pub fn build_loaded_file<'a>( arena: &'a Bump, target: &Triple, app_module_path: PathBuf, @@ -570,3 +573,56 @@ pub fn check_file<'a>( compilation_end, )) } + +pub fn build_str_test<'a>( + arena: &'a Bump, + app_module_path: &Path, + app_module_source: &'a str, + assume_prebuild: bool, +) -> Result, BuildFileError<'a>> { + let triple = target_lexicon::Triple::host(); + + let code_gen_options = CodeGenOptions { + backend: CodeGenBackend::Llvm, + opt_level: OptLevel::Normal, + emit_debug_info: false, + }; + + let emit_timings = false; + let link_type = LinkType::Executable; + let linking_strategy = LinkingStrategy::Surgical; + let wasm_dev_stack_bytes = None; + + let roc_cache_dir = roc_packaging::cache::RocCacheDir::Disallowed; + let build_ordering = BuildOrdering::AlwaysBuild; + let threading = Threading::AtMost(2); + + let load_config = standard_load_config(&triple, build_ordering, threading); + + let compilation_start = std::time::Instant::now(); + + // Step 1: compile the app and generate the .o file + let loaded = roc_load::load_and_monomorphize_from_str( + arena, + PathBuf::from("valgrind_test.roc"), + app_module_source, + app_module_path.to_path_buf(), + roc_cache_dir, + load_config, + ) + .map_err(|e| BuildFileError::from_mono_error(e, compilation_start))?; + + build_loaded_file( + arena, + &triple, + app_module_path.to_path_buf(), + code_gen_options, + emit_timings, + link_type, + linking_strategy, + assume_prebuild, + wasm_dev_stack_bytes, + loaded, + compilation_start, + ) +} diff --git a/crates/valgrind/Cargo.toml b/crates/valgrind/Cargo.toml index c9440c23a7..bae1ee46b8 100644 --- a/crates/valgrind/Cargo.toml +++ b/crates/valgrind/Cargo.toml @@ -27,3 +27,5 @@ roc_reporting = { path = "../reporting" } roc_packaging = { path = "../packaging" } bumpalo.workspace = true target-lexicon.workspace = true +tempfile.workspace = true +indoc.workspace = true diff --git a/crates/valgrind/build.rs b/crates/valgrind/build.rs index c99e8eaa72..c9fd05a8a3 100644 --- a/crates/valgrind/build.rs +++ b/crates/valgrind/build.rs @@ -1,50 +1,33 @@ -use std::path::PathBuf; - -use roc_build::{ - link::{LinkType, LinkingStrategy}, - program::{CodeGenBackend, CodeGenOptions}, -}; -use roc_cli::build::BuildOrdering; -use roc_load::Threading; -use roc_mono::ir::OptLevel; - fn main() { - // goal: build the platform, so tests can use `precompiled-platform=true` - // idea: just compile one of the tests; that'll re-build the platform for us - let app_module_path = "tests/str_concat_1.roc"; + let temp_dir = tempfile::tempdir().unwrap(); + let app_module_path = temp_dir.path().join("app.roc"); - let arena = bumpalo::Bump::new(); - let triple = target_lexicon::Triple::host(); + let pf = std::env::current_dir() + .unwrap() + .join("zig-platform/main.roc"); - let code_gen_options = CodeGenOptions { - backend: CodeGenBackend::Llvm, - opt_level: OptLevel::Normal, - emit_debug_info: false, - }; + let app_module_source: String = format!( + indoc::indoc!( + r#" + app "test" + packages {{ pf: "{}" }} + imports [] + provides [main] to pf - let emit_timings = false; - let link_type = LinkType::Executable; - let linking_strategy = LinkingStrategy::Surgical; - let prebuilt_requested = false; - let wasm_dev_stack_bytes = None; - - let roc_cache_dir = roc_packaging::cache::RocCacheDir::Disallowed; - let build_ordering = BuildOrdering::AlwaysBuild; - - let res_binary_path = roc_cli::build::build_file( - &arena, - &triple, - PathBuf::from(app_module_path), - code_gen_options, - emit_timings, - link_type, - linking_strategy, - prebuilt_requested, - Threading::AtMost(2), - wasm_dev_stack_bytes, - roc_cache_dir, - build_ordering, + main = "hello world" + "# + ), + pf.to_str().unwrap() ); - assert!(res_binary_path.is_ok()); + let arena = bumpalo::Bump::new(); + let assume_prebuilt = false; + let res_binary_path = roc_cli::build::build_str_test( + &arena, + &app_module_path, + &app_module_source, + assume_prebuilt, + ); + + res_binary_path.unwrap(); } diff --git a/crates/valgrind/src/lib.rs b/crates/valgrind/src/lib.rs index fd8a7b6a0b..0ba617a96b 100644 --- a/crates/valgrind/src/lib.rs +++ b/crates/valgrind/src/lib.rs @@ -1,53 +1,46 @@ #![cfg(test)] -use std::{ - ffi::OsStr, - path::{Path, PathBuf}, -}; +use indoc::indoc; use cli_utils::helpers::{extract_valgrind_errors, ValgrindError, ValgrindErrorXWhat}; -use roc_build::{ - link::{LinkType, LinkingStrategy}, - program::{CodeGenBackend, CodeGenOptions}, -}; -use roc_cli::build::{BuildOrdering, BuiltFile}; -use roc_load::Threading; -use roc_mono::ir::OptLevel; +use roc_cli::build::BuiltFile; -fn run_example(app_module_path: impl AsRef) { - let app_module_path = app_module_path.as_ref(); +fn valgrind_test(source: &str) { + let pf = std::env::current_dir() + .unwrap() + .join("zig-platform/main.roc"); + + assert!(pf.exists(), "{:?}", &pf); + + let mut app_module_source = format!( + indoc::indoc!( + r#" + app "test" + packages {{ pf: "{}" }} + imports [] + provides [main] to pf + + main = + "# + ), + pf.to_str().unwrap() + ); + + for line in source.lines() { + app_module_source.push_str(" "); + app_module_source.push_str(line); + } + + let temp_dir = tempfile::tempdir().unwrap(); + let app_module_path = temp_dir.path().join("app.roc"); let arena = bumpalo::Bump::new(); - let triple = target_lexicon::Triple::host(); - - let code_gen_options = CodeGenOptions { - backend: CodeGenBackend::Llvm, - opt_level: OptLevel::Normal, - emit_debug_info: false, - }; - - let emit_timings = false; - let link_type = LinkType::Executable; - let linking_strategy = LinkingStrategy::Surgical; - let prebuilt_requested = true; - let wasm_dev_stack_bytes = None; - - let roc_cache_dir = roc_packaging::cache::RocCacheDir::Disallowed; - let build_ordering = BuildOrdering::AlwaysBuild; - - let res_binary_path = roc_cli::build::build_file( + let assume_prebuilt = true; + let res_binary_path = roc_cli::build::build_str_test( &arena, - &triple, - PathBuf::from(app_module_path), - code_gen_options, - emit_timings, - link_type, - linking_strategy, - prebuilt_requested, - Threading::AtMost(2), - wasm_dev_stack_bytes, - roc_cache_dir, - build_ordering, + &app_module_path, + &app_module_source, + assume_prebuilt, ); match res_binary_path { @@ -106,70 +99,36 @@ fn run_example(app_module_path: impl AsRef) { } Err(e) => panic!("{:?}", e), } -} -#[test] -fn run_valgrind_tests() { - for dir_entry in std::fs::read_dir("tests").unwrap() { - let path = dir_entry.unwrap().path(); - - if path.extension() != Some(OsStr::new("roc")) { - continue; - } - - println!("test file: {:?}\n", &path); - - run_example(path); - } -} - -macro_rules! valgrind_test { - ($source:expr) => { - let temp_dir = tempfile::tempdir().unwrap(); - let app_roc = temp_dir.path().join("app.roc"); - - let mut file = std::fs::OpenOptions::new() - .create(true) - .write(true) - .open(&app_roc) - .unwrap(); - - use std::io::Write; - - let pf = std::env::current_dir() - .unwrap() - .join("zig-platform/main.roc"); - - assert!(pf.exists(), "{:?}", &pf); - - write!( - &mut file, - indoc::indoc!( - r#" - app "test" - packages {{ pf: "{}" }} - imports [] - provides [main] to pf - - main = - "# - ), - pf.to_str().unwrap() - ) - .unwrap(); - - for line in $source.lines() { - write!(&mut file, " {}", line).unwrap(); - } - - run_example(app_roc); - - drop(file); - drop(temp_dir) - }; + drop(temp_dir) } #[test] fn list_concat_consumes_first_argument() { - valgrind_test!("List.concat (List.withCapacity 1024) [1,2,3] |> List.len |> Num.toStr"); + valgrind_test("List.concat (List.withCapacity 1024) [1,2,3] |> List.len |> Num.toStr"); +} + +#[test] +fn str_capacity_concat() { + valgrind_test(r#"Str.withCapacity 42 |> Str.concat "foobar""#); +} + +#[test] +fn append_scalar() { + valgrind_test(indoc!( + r#" + Str.appendScalar "abcd" 'A' + |> Result.withDefault "" + "# + )); +} + +#[test] +fn split_not_present() { + valgrind_test(indoc!( + r#" + Str.split (Str.concat "a string that is stored on the heap" "!") "\n" + |> Str.joinWith "" + "# + )); } diff --git a/crates/valgrind/tests/rocLovesZig b/crates/valgrind/tests/rocLovesZig deleted file mode 100755 index e57e7f151b..0000000000 Binary files a/crates/valgrind/tests/rocLovesZig and /dev/null differ diff --git a/crates/valgrind/tests/str_concat_1.roc b/crates/valgrind/tests/str_concat_1.roc deleted file mode 100644 index 5424e2bdfb..0000000000 --- a/crates/valgrind/tests/str_concat_1.roc +++ /dev/null @@ -1,8 +0,0 @@ -app "test" - packages { pf: "../zig-platform/main.roc" } - imports [] - provides [main] to pf - -main = - Str.withCapacity 42 - |> Str.concat "foobar" diff --git a/crates/valgrind/zig-platform/dynhost b/crates/valgrind/zig-platform/dynhost index 9b44a8cc63..f99a4ceef2 100755 Binary files a/crates/valgrind/zig-platform/dynhost and b/crates/valgrind/zig-platform/dynhost differ