diff --git a/BUILDING_FROM_SOURCE.md b/BUILDING_FROM_SOURCE.md index 688188c2f5..fef2f2a147 100644 --- a/BUILDING_FROM_SOURCE.md +++ b/BUILDING_FROM_SOURCE.md @@ -16,6 +16,8 @@ To run the test suite (via `cargo test`), you additionally need to install: * [`valgrind`](https://www.valgrind.org/) (needs special treatment to [install on macOS](https://stackoverflow.com/a/61359781) Alternatively, you can use `cargo test --no-fail-fast` or `cargo test -p specific_tests` to skip over the valgrind failures & tests. +For debugging LLVM IR, we use [DebugIR](https://github.com/vaivaswatha/debugir). This dependency is only required to build with the `--debug` flag, and for normal developtment you should be fine without it. + ### libunwind & libc++-dev MacOS systems should already have `libunwind`, but other systems will need to install it (On Ubuntu, this can be donw with `sudo apt-get install libunwind-dev`). diff --git a/cli/src/build.rs b/cli/src/build.rs index c4e2dc02ed..386b4324d5 100644 --- a/cli/src/build.rs +++ b/cli/src/build.rs @@ -24,6 +24,7 @@ pub fn build_file( src_dir: PathBuf, roc_file_path: PathBuf, opt_level: OptLevel, + emit_debug_info: bool, link_type: LinkType, ) -> Result { let compilation_start = SystemTime::now(); @@ -95,6 +96,7 @@ pub fn build_file( Triple::host(), &app_o_file, opt_level, + emit_debug_info, ); println!("\nSuccess! 🎉\n\n\t➡ {}\n", app_o_file.display()); diff --git a/cli/src/lib.rs b/cli/src/lib.rs index e21605045e..fee018e1ba 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -14,6 +14,7 @@ use target_lexicon::Triple; pub mod build; pub mod repl; +pub static FLAG_DEBUG: &str = "debug"; pub static FLAG_OPTIMIZE: &str = "optimize"; pub static FLAG_ROC_FILE: &str = "ROC_FILE"; pub static DIRECTORY_OR_FILES: &str = "DIRECTORY_OR_FILES"; @@ -34,6 +35,12 @@ pub fn build_app<'a>() -> App<'a> { .help("Optimize the compiled program to run faster. (Optimization takes time to complete.)") .required(false), ) + .arg( + Arg::with_name(FLAG_DEBUG) + .long(FLAG_DEBUG) + .help("Store LLVM debug information in the generated program") + .required(false), + ) ) .subcommand(App::new("run") .about("Build and run a program") @@ -48,6 +55,12 @@ pub fn build_app<'a>() -> App<'a> { .help("Optimize the compiled program to run faster. (Optimization takes time to complete.)") .required(false), ) + .arg( + Arg::with_name(FLAG_DEBUG) + .long(FLAG_DEBUG) + .help("Store LLVM debug information in the generated program") + .required(false), + ) ) .subcommand(App::new("repl") .about("Launch the interactive Read Eval Print Loop (REPL)") @@ -70,6 +83,8 @@ pub fn build(target: &Triple, matches: &ArgMatches, run_after_build: bool) -> io } else { OptLevel::Normal }; + let emit_debug_info = matches.is_present(FLAG_DEBUG); + let path = Path::new(filename).canonicalize().unwrap(); let src_dir = path.parent().unwrap().canonicalize().unwrap(); @@ -92,8 +107,15 @@ pub fn build(target: &Triple, matches: &ArgMatches, run_after_build: bool) -> io } }); - let binary_path = build::build_file(target, src_dir, path, opt_level, LinkType::Executable) - .expect("TODO gracefully handle build_file failing"); + let binary_path = build::build_file( + target, + src_dir, + path, + opt_level, + emit_debug_info, + LinkType::Executable, + ) + .expect("TODO gracefully handle build_file failing"); if run_after_build { // Run the compiled app diff --git a/compiler/build/src/program.rs b/compiler/build/src/program.rs index f053d7d2e2..48d8b01197 100644 --- a/compiler/build/src/program.rs +++ b/compiler/build/src/program.rs @@ -20,6 +20,7 @@ pub fn gen_from_mono_module( target: Triple, app_o_file: &Path, opt_level: OptLevel, + emit_debug_info: bool, ) { use roc_reporting::report::{ can_problem, mono_problem, type_problem, RocDocAllocator, DEFAULT_PALETTE, @@ -161,7 +162,9 @@ pub fn gen_from_mono_module( // annotate the LLVM IR output with debug info // so errors are reported with the line number of the LLVM source - if true { + if emit_debug_info { + module.strip_debug_info(); + let mut app_ll_file = std::path::PathBuf::from(app_o_file); app_ll_file.set_extension("ll"); @@ -217,19 +220,18 @@ pub fn gen_from_mono_module( ]) .output() .unwrap(); + } else { + // Emit the .o file - return; + let reloc = RelocMode::Default; + let model = CodeModel::Default; + let target_machine = + target::target_machine(&target, opt_level.into(), reloc, model).unwrap(); + + target_machine + .write_to_file(&env.module, FileType::Object, &app_o_file) + .expect("Writing .o file failed"); } - - // Emit the .o file - - let reloc = RelocMode::Default; - let model = CodeModel::Default; - let target_machine = target::target_machine(&target, opt_level.into(), reloc, model).unwrap(); - - target_machine - .write_to_file(&env.module, FileType::Object, &app_o_file) - .expect("Writing .o file failed"); } pub struct FunctionIterator<'ctx> { diff --git a/examples/effect/Main.roc b/examples/effect/Main.roc index 2e37d4be5b..2bbefaca8d 100644 --- a/examples/effect/Main.roc +++ b/examples/effect/Main.roc @@ -1,11 +1,18 @@ -app "effect-example" imports [ Effect, RBTree ] provides [ main ] to "./platform" +app "effect-example" imports [ Effect ] provides [ main ] to "./platform" + main : Effect.Effect {} as Fx main = - if RBTree.isEmpty (RBTree.insert 1 2 Empty) then - Effect.putLine "Yay" - |> Effect.after (\{} -> Effect.getLine) - |> Effect.after (\line -> Effect.putLine line) - else - Effect.putLine "Nay" + when if 1 == 1 then True 3 else False 3.14 is + True 3 -> Effect.putLine "Yay" + _ -> Effect.putLine "Yay" +# main : Effect.Effect {} as Fx +# main = +# if RBTree.isEmpty (RBTree.insert 1 2 Empty) then +# Effect.putLine "Yay" +# |> Effect.after (\{} -> Effect.getLine) +# |> Effect.after (\line -> Effect.putLine line) +# else +# Effect.putLine "Nay" +# diff --git a/examples/effect/platform/src/lib.rs b/examples/effect/platform/src/lib.rs index ba517b18c8..216595ca4c 100644 --- a/examples/effect/platform/src/lib.rs +++ b/examples/effect/platform/src/lib.rs @@ -95,7 +95,12 @@ pub fn rust_main() -> isize { let closure_data_ptr = buffer.offset(16); - call_the_closure(function_pointer as *const u8, closure_data_ptr as *const u8) + let result = + call_the_closure(function_pointer as *const u8, closure_data_ptr as *const u8); + + std::alloc::dealloc(buffer, layout); + + result } Err(msg) => { std::alloc::dealloc(buffer, layout);