diff --git a/Cargo.lock b/Cargo.lock index 7bb567e093..56b1715a13 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3380,6 +3380,7 @@ dependencies = [ "roc_target", "roc_types", "roc_unify", + "roc_utils", "serde_json", "target-lexicon", "tempfile", @@ -3397,6 +3398,7 @@ dependencies = [ "roc_module", "roc_region", "roc_target", + "roc_utils", "tempfile", ] diff --git a/crates/cli/src/build.rs b/crates/cli/src/build.rs index a113f6f0ce..326e5bf9e6 100644 --- a/crates/cli/src/build.rs +++ b/crates/cli/src/build.rs @@ -307,8 +307,11 @@ pub fn build_file<'a>( host_input_path.as_path().to_str().unwrap(), app_o_file.to_str().unwrap(), ]; + + let str_host_obj_path = bitcode::get_builtins_host_obj_path(); + if matches!(opt_level, OptLevel::Development) { - inputs.push(bitcode::BUILTINS_HOST_OBJ_PATH); + inputs.push(&str_host_obj_path); } let (mut child, _) = // TODO use lld diff --git a/crates/compiler/build/Cargo.toml b/crates/compiler/build/Cargo.toml index 17ff3d5609..e7bfad68f2 100644 --- a/crates/compiler/build/Cargo.toml +++ b/crates/compiler/build/Cargo.toml @@ -26,6 +26,7 @@ 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 } +roc_utils = { path = "../../utils" } bumpalo = { version = "3.8.0", features = ["collections"] } libloading = "0.7.1" tempfile = "3.2.0" diff --git a/crates/compiler/build/src/link.rs b/crates/compiler/build/src/link.rs index a610abe32c..eee35d5c21 100644 --- a/crates/compiler/build/src/link.rs +++ b/crates/compiler/build/src/link.rs @@ -3,6 +3,7 @@ use libloading::{Error, Library}; use roc_builtins::bitcode; use roc_error_macros::internal_error; use roc_mono::ir::OptLevel; +use roc_utils::get_lib_path; use std::collections::HashMap; use std::env; use std::io; @@ -66,12 +67,13 @@ pub fn link( fn find_zig_str_path() -> PathBuf { // First try using the lib path relative to the executable location. - let exe_relative_str_path = std::env::current_exe() - .ok() - .and_then(|path| Some(path.parent()?.join("lib").join("str.zig"))); - if let Some(exe_relative_str_path) = exe_relative_str_path { - if std::path::Path::exists(&exe_relative_str_path) { - return exe_relative_str_path; + let lib_path_opt = get_lib_path(); + + if let Some(lib_path) = lib_path_opt { + let zig_str_path = lib_path.join("str.zig"); + + if std::path::Path::exists(&zig_str_path) { + return zig_str_path; } } @@ -87,7 +89,7 @@ fn find_zig_str_path() -> PathBuf { return zig_str_path; } - panic!("cannot find `str.zig`. Launch me from either the root of the roc repo or one level down(roc/examples, roc/cli...)") + panic!("cannot find `str.zig`. Check the source code in find_zig_str_path() to show all the paths I tried.") } fn find_wasi_libc_path() -> PathBuf { @@ -123,7 +125,7 @@ pub fn build_zig_host_native( "build-exe", "-fPIE", shared_lib_path.to_str().unwrap(), - bitcode::BUILTINS_HOST_OBJ_PATH, + &bitcode::get_builtins_host_obj_path(), ]); } else { command.args(&["build-obj", "-fPIC"]); @@ -340,7 +342,7 @@ pub fn build_c_host_native( if let Some(shared_lib_path) = shared_lib_path { command.args(&[ shared_lib_path.to_str().unwrap(), - bitcode::BUILTINS_HOST_OBJ_PATH, + &bitcode::get_builtins_host_obj_path(), "-fPIE", "-pie", "-lm", @@ -1172,7 +1174,7 @@ pub fn preprocess_host_wasm32(host_input_path: &Path, preprocessed_host_path: &P let mut command = Command::new(&zig_executable()); let args = &[ "wasm-ld", - bitcode::BUILTINS_WASM32_OBJ_PATH, + &bitcode::get_builtins_wasm32_obj_path(), host_input, WASI_LIBC_PATH, WASI_COMPILER_RT_PATH, // builtins need __multi3, __udivti3, __fixdfti diff --git a/crates/compiler/builtins/Cargo.toml b/crates/compiler/builtins/Cargo.toml index 6d3033797a..5da5a79551 100644 --- a/crates/compiler/builtins/Cargo.toml +++ b/crates/compiler/builtins/Cargo.toml @@ -10,6 +10,7 @@ roc_collections = { path = "../collections" } roc_region = { path = "../region" } roc_module = { path = "../module" } roc_target = { path = "../roc_target" } +roc_utils = { path = "../../utils" } lazy_static = "1.4.0" [build-dependencies] diff --git a/crates/compiler/builtins/build.rs b/crates/compiler/builtins/build.rs index 67f4581667..965696eeb6 100644 --- a/crates/compiler/builtins/build.rs +++ b/crates/compiler/builtins/build.rs @@ -4,6 +4,7 @@ use std::ffi::OsStr; use std::fs; use std::io; use std::path::Path; +use std::path::PathBuf; use std::process::Command; use std::str; @@ -53,19 +54,9 @@ fn main() { #[cfg(not(windows))] const BUILTINS_HOST_FILE: &str = "builtins-host.o"; - generate_object_file( - &bitcode_path, - "BUILTINS_HOST_O", - "object", - BUILTINS_HOST_FILE, - ); + generate_object_file(&bitcode_path, "object", BUILTINS_HOST_FILE); - generate_object_file( - &bitcode_path, - "BUILTINS_WASM32_O", - "wasm32-object", - "builtins-wasm32.o", - ); + generate_object_file(&bitcode_path, "wasm32-object", "builtins-wasm32.o"); copy_zig_builtins_to_target_dir(&bitcode_path); @@ -84,21 +75,10 @@ fn main() { .expect("Failed to delete temp dir zig_cache_dir."); } -fn generate_object_file( - bitcode_path: &Path, - env_var_name: &str, - zig_object: &str, - object_file_name: &str, -) { - let out_dir = env::var_os("OUT_DIR").unwrap(); - - let dest_obj_path = Path::new(&out_dir).join(object_file_name); +fn generate_object_file(bitcode_path: &Path, zig_object: &str, object_file_name: &str) { + let dest_obj_path = get_lib_dir().join(object_file_name); let dest_obj = dest_obj_path.to_str().expect("Invalid dest object path"); - // set the variable (e.g. BUILTINS_HOST_O) that is later used in - // `compiler/builtins/src/bitcode.rs` to load the object file - println!("cargo:rustc-env={}={}", env_var_name, dest_obj); - let src_obj_path = bitcode_path.join(object_file_name); let src_obj = src_obj_path.to_str().expect("Invalid src object path"); @@ -146,20 +126,29 @@ fn generate_bc_file(bitcode_path: &Path, zig_object: &str, file_name: &str) { ); } -fn copy_zig_builtins_to_target_dir(bitcode_path: &Path) { - // To enable roc to find the zig biultins, we want them to be moved to a folder next to the roc executable. - // So if /roc is the executable. The zig files will be in /lib/*.zig - +pub fn get_lib_dir() -> PathBuf { // Currently we have the OUT_DIR variable which points to `/target/debug/build/roc_builtins-*/out/`. // So we just need to shed a 3 of the outer layers to get `/target/debug/` and then add `lib`. let out_dir = env::var_os("OUT_DIR").unwrap(); - let target_profile_dir = Path::new(&out_dir) + + let lib_path = Path::new(&out_dir) .parent() .and_then(|path| path.parent()) .and_then(|path| path.parent()) .unwrap() .join("lib"); + // create dir of it does not exist + fs::create_dir_all(lib_path.clone()).expect("Failed to make lib dir."); + + lib_path +} + +fn copy_zig_builtins_to_target_dir(bitcode_path: &Path) { + // To enable roc to find the zig biultins, we want them to be moved to a folder next to the roc executable. + // So if /roc is the executable. The zig files will be in /lib/*.zig + let target_profile_dir = get_lib_dir(); + let zig_src_dir = bitcode_path.join("src"); std::fs::create_dir_all(&target_profile_dir).unwrap_or_else(|err| { diff --git a/crates/compiler/builtins/src/bitcode.rs b/crates/compiler/builtins/src/bitcode.rs index 612960cd80..b19946ea02 100644 --- a/crates/compiler/builtins/src/bitcode.rs +++ b/crates/compiler/builtins/src/bitcode.rs @@ -1,16 +1,29 @@ use roc_module::symbol::Symbol; use roc_target::TargetInfo; +use roc_utils::get_lib_path; use std::ops::Index; -pub const BUILTINS_HOST_OBJ_PATH: &str = env!( - "BUILTINS_HOST_O", - "Env var BUILTINS_HOST_O not found. Is there a problem with the build script?" -); +pub fn get_builtins_host_obj_path() -> String { + let builtins_host_path = get_lib_path() + .expect("Failed to find lib dir.") + .join("builtins-host.o"); -pub const BUILTINS_WASM32_OBJ_PATH: &str = env!( - "BUILTINS_WASM32_O", - "Env var BUILTINS_WASM32_O not found. Is there a problem with the build script?" -); + builtins_host_path + .into_os_string() + .into_string() + .expect("Failed to convert builtins_host_path to str") +} + +pub fn get_builtins_wasm32_obj_path() -> String { + let builtins_wasm32_path = get_lib_path() + .expect("Failed to find lib dir.") + .join("builtins-wasm32.o"); + + builtins_wasm32_path + .into_os_string() + .into_string() + .expect("Failed to convert builtins_wasm32_path to str") +} #[derive(Debug, Default, Copy, Clone)] pub struct IntrinsicName { diff --git a/crates/compiler/test_gen/build.rs b/crates/compiler/test_gen/build.rs index ae3e1856f2..66879ab115 100644 --- a/crates/compiler/test_gen/build.rs +++ b/crates/compiler/test_gen/build.rs @@ -95,7 +95,7 @@ fn build_wasm_test_host() { run_zig(&[ "wasm-ld", - bitcode::BUILTINS_WASM32_OBJ_PATH, + &bitcode::get_builtins_wasm32_obj_path(), platform_path.to_str().unwrap(), WASI_COMPILER_RT_PATH, WASI_LIBC_PATH, diff --git a/crates/repl_wasm/build.rs b/crates/repl_wasm/build.rs index 93af44fe29..93f869ef43 100644 --- a/crates/repl_wasm/build.rs +++ b/crates/repl_wasm/build.rs @@ -26,7 +26,7 @@ fn main() { let output = Command::new(&zig_executable()) .args([ "wasm-ld", - bitcode::BUILTINS_WASM32_OBJ_PATH, + &bitcode::get_builtins_wasm32_obj_path(), platform_obj.to_str().unwrap(), WASI_COMPILER_RT_PATH, WASI_LIBC_PATH, diff --git a/crates/utils/src/lib.rs b/crates/utils/src/lib.rs index 8ebfae2069..cdc5d3fb0e 100644 --- a/crates/utils/src/lib.rs +++ b/crates/utils/src/lib.rs @@ -1,5 +1,5 @@ use snafu::OptionExt; -use std::{collections::HashMap, slice::SliceIndex}; +use std::{collections::HashMap, path::PathBuf, slice::SliceIndex}; use util_error::{IndexOfFailedSnafu, KeyNotFoundSnafu, OutOfBoundsSnafu, UtilResult}; pub mod util_error; @@ -93,3 +93,30 @@ pub fn first_last_index_of( .fail() } } + +// get the path of the lib folder +// runtime dependencies like zig files, builtin_host.o are put in the lib folder +pub fn get_lib_path() -> Option { + let exe_relative_str_path_opt = std::env::current_exe().ok(); + + if let Some(exe_relative_str_path) = exe_relative_str_path_opt { + let mut curr_parent_opt = exe_relative_str_path.parent(); + + // this differs for regular build and nix releases, so we check in multiple spots. + for _ in 0..3 { + if let Some(curr_parent) = curr_parent_opt { + let lib_path = curr_parent.join("lib"); + + if std::path::Path::exists(&lib_path) { + return Some(lib_path); + } else { + curr_parent_opt = curr_parent.parent(); + } + } else { + break; + } + } + } + + None +} diff --git a/default.nix b/default.nix index 0e5f2cc3b6..7470237f92 100644 --- a/default.nix +++ b/default.nix @@ -16,26 +16,10 @@ rustPlatform.buildRustPackage { src = pkgs.nix-gitignore.gitignoreSource [] ./.; - cargoSha256 = "sha256-ey1zHqiFhGNgjQLC6ATEH6i7RcuXJGcijGMcv9amn0w="; + cargoSha256 = "sha256-ZT3lH2P0OnK8XwI89csINXIK+/AhhKVmXDqNGYMy/vk="; LLVM_SYS_130_PREFIX = "${llvmPkgs.llvm.dev}"; - # for cli bindgen "No such file or directory" - preBuild = '' - # From: https://github.com/NixOS/nixpkgs/blob/1fab95f5190d087e66a3502481e34e15d62090aa/pkgs/applications/networking/browsers/firefox/common.nix#L247-L253 - # Set C flags for Rust's bindgen program. Unlike ordinary C - # compilation, bindgen does not invoke $CC directly. Instead it - # uses LLVM's libclang. To make sure all necessary flags are - # included we need to look in a few places. - export BINDGEN_EXTRA_CLANG_ARGS="$(< ${pkgs.stdenv.cc}/nix-support/libc-crt1-cflags) \ - $(< ${pkgs.stdenv.cc}/nix-support/libc-cflags) \ - $(< ${pkgs.stdenv.cc}/nix-support/cc-cflags) \ - $(< ${pkgs.stdenv.cc}/nix-support/libcxx-cxxflags) \ - ${pkgs.lib.optionalString pkgs.stdenv.cc.isClang "-idirafter ${pkgs.stdenv.cc.cc}/lib/clang/${pkgs.lib.getVersion pkgs.stdenv.cc.cc}/include"} \ - ${pkgs.lib.optionalString pkgs.stdenv.cc.isGNU "-isystem ${pkgs.stdenv.cc.cc}/include/c++/${pkgs.lib.getVersion pkgs.stdenv.cc.cc} -isystem ${pkgs.stdenv.cc.cc}/include/c++/${pkgs.lib.getVersion pkgs.stdenv.cc.cc}/${pkgs.stdenv.hostPlatform.config}"} - " - ''; - # required for zig XDG_CACHE_HOME = "xdg_cache"; # prevents zig AccessDenied error github.com/ziglang/zig/issues/6810 # nix does not store libs in /usr/lib or /lib @@ -68,6 +52,7 @@ rustPlatform.buildRustPackage { ncurses zlib cargo + makeWrapper # necessary for postBuild wrapProgram ] ++ lib.optionals pkgs.stdenv.isLinux [ alsa-lib @@ -92,4 +77,12 @@ rustPlatform.buildRustPackage { Security ]); + # mkdir -p $out/lib + + # cp: to copy str.zig,list.zig... + # wrapProgram pkgs.stdenv.cc: to make ld available for compiler/build/src/link.rs + postInstall = '' + cp -r target/x86_64-unknown-linux-gnu/release/lib/. $out/lib + wrapProgram $out/bin/roc --prefix PATH : ${pkgs.lib.makeBinPath [ pkgs.stdenv.cc ]} + ''; }