From d64a0a3e1af71553d43f8d5ea0b3c3eb797b0626 Mon Sep 17 00:00:00 2001 From: Nico Lehmann Date: Wed, 1 Nov 2023 14:43:40 -0700 Subject: [PATCH] Refactor macro infra (#547) --- Cargo.lock | 21 +++--- Cargo.toml | 5 +- book/src/dev/develop.md | 12 +++ book/src/guide/install.md | 4 +- book/src/guide/run.md | 7 -- .../flux-attrs-proc-macros-build/Cargo.toml | 13 ---- .../flux-attrs-proc-macros-build/src/lib.rs | 1 - crates/flux-bin/Cargo.toml | 2 +- crates/flux-bin/src/bin/cargo-flux.rs | 14 ++-- crates/flux-bin/src/bin/rustc-flux.rs | 14 +++- crates/flux-bin/src/utils.rs | 71 +++++++----------- crates/flux-config/src/lib.rs | 5 -- crates/flux-driver/src/bin/main.rs | 4 +- .../flux-macros/src/diagnostics/diagnostic.rs | 1 + .../src/diagnostics/diagnostic_builder.rs | 1 + crates/flux-macros/src/diagnostics/fluent.rs | 2 +- .../src/diagnostics/subdiagnostic.rs | 1 + crates/flux-rs/Cargo.toml | 21 ------ crates/flux-tests/Cargo.toml | 1 + crates/flux-tests/src/lib.rs | 35 +++------ crates/flux-tests/tests/compiletest.rs | 3 + lib/README.md | 14 ++++ {crates => lib}/flux-attrs/Cargo.toml | 3 - lib/flux-attrs/build.rs | 7 ++ {crates => lib}/flux-attrs/src/ast.rs | 4 +- {crates => lib}/flux-attrs/src/lib.rs | 0 lib/flux-rs/Cargo.toml | 14 ++++ lib/flux-rs/build.rs | 7 ++ {crates => lib}/flux-rs/src/lib.rs | 5 +- xtask/Cargo.toml | 1 + xtask/src/main.rs | 73 +++++++++++++++---- 31 files changed, 205 insertions(+), 161 deletions(-) delete mode 100644 crates/flux-attrs-proc-macros-build/Cargo.toml delete mode 100644 crates/flux-attrs-proc-macros-build/src/lib.rs delete mode 100644 crates/flux-rs/Cargo.toml create mode 100644 lib/README.md rename {crates => lib}/flux-attrs/Cargo.toml (89%) create mode 100644 lib/flux-attrs/build.rs rename {crates => lib}/flux-attrs/src/ast.rs (99%) rename {crates => lib}/flux-attrs/src/lib.rs (100%) create mode 100644 lib/flux-rs/Cargo.toml create mode 100644 lib/flux-rs/build.rs rename {crates => lib}/flux-rs/src/lib.rs (82%) diff --git a/Cargo.lock b/Cargo.lock index 93544ad18c..ba30fe2f4d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -461,20 +461,13 @@ dependencies = [ "syn 2.0.37", ] -[[package]] -name = "flux-attrs-proc-macros-build" -version = "0.1.0" -dependencies = [ - "flux-rs", -] - [[package]] name = "flux-bin" version = "0.1.0" dependencies = [ "anyhow", "dirs", - "flux-config", + "home", "rust-toolchain-file", ] @@ -615,7 +608,6 @@ name = "flux-rs" version = "0.1.0" dependencies = [ "flux-attrs", - "proc-macro2", ] [[package]] @@ -631,6 +623,7 @@ name = "flux-tests" version = "0.1.0" dependencies = [ "compiletest_rs", + "flux-bin", "itertools", ] @@ -699,6 +692,15 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" +[[package]] +name = "home" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +dependencies = [ + "windows-sys", +] + [[package]] name = "indexmap" version = "1.9.3" @@ -1826,6 +1828,7 @@ name = "xtask" version = "0.1.0" dependencies = [ "anyhow", + "flux-bin", "flux-tests", "opener", "xflags", diff --git a/Cargo.toml b/Cargo.toml index dda0d97a87..44d4634387 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,6 @@ [workspace] -members = ["crates/*", "xtask"] +default-members = ["crates/*", "xtask"] +members = ["crates/*", "lib/*", "xtask"] resolver = "2" [workspace.package] @@ -7,6 +8,7 @@ edition = "2021" [workspace.dependencies] flux-attrs = { path = "./crates/flux-attrs", version = "0.1.0" } +flux-bin = { path = "./crates/flux-bin", version = "0.1.0" } flux-common = { path = "./crates/flux-common", version = "0.1.0" } flux-config = { path = "./crates/flux-config", version = "0.1.0" } flux-desugar = { path = "./crates/flux-desugar", version = "0.1.0" } @@ -21,6 +23,7 @@ flux-rs = { path = "./crates/flux-rs", version = "0.1.0" } flux-syntax = { path = "./crates/flux-syntax", version = "0.1.0" } flux-tests = { path = "./crates/flux-tests", version = "0.1.0" } +home = "0.5.5" itertools = "0.10.5" [workspace.lints.rust] diff --git a/book/src/dev/develop.md b/book/src/dev/develop.md index 72205603b4..22d74c2edc 100644 --- a/book/src/dev/develop.md +++ b/book/src/dev/develop.md @@ -80,6 +80,18 @@ error[FLUX]: refinement type error You can also pass `-Ztrack-diagnostics=y` to enable it if you are not using `cargo xtask run` +## Running outside the project + +To run Flux in a package outside the flux respo you need to install the binaries globally. You can +do that using `cargo xtask install`. If you are continuously testing new changes it could be annoying +to do it each time. To deal with this, you can set the `FLUX_SYSROOT` environment variable to change the +location where `cargo-flux` and `rustc-flux` load the `flux-driver`. You can set it globally to point +to the `target/debug` directory inside your local copy of the repo. This way you won't have to run +`cargo xtask install` after every change and you can be sure you'll be using the latest local debug +build. Just be aware that the `rustc-flux` and `cargo-flux` binaries are built for a specific toolchain, +and you will get a dynamic linking error if the `flux-driver` was compiled with a different one. This +is to say, you should at least run `cargo xtask install` every time after the toolchain is updated. + ## Profiling Flux Set `FLUX_DUMP_TIMINGS=true` to have flux write timing diagnostics to `./log/timings`. diff --git a/book/src/guide/install.md b/book/src/guide/install.md index 46b38dc095..41b90ba69d 100644 --- a/book/src/guide/install.md +++ b/book/src/guide/install.md @@ -29,4 +29,6 @@ Next, run the following to build and install `flux` binaries cargo xtask install ``` -This will install `flux-driver`, `rustc-flux` and `cargo-flux`. Note that you should not call `flux-driver` directly, but rather use `rustc-flux` and `cargo-flux`. +This will the binaries `rustc-flux` and `cargo-flux` in your cargo home. These two binaries should be used +respectively to run flux on either a single file or on a project using cargo. The installation process will +also copy some files to `$HOME/.flux`. diff --git a/book/src/guide/run.md b/book/src/guide/run.md index 5198001436..e7d7340b82 100644 --- a/book/src/guide/run.md +++ b/book/src/guide/run.md @@ -29,13 +29,6 @@ cargo-flux check in order to get `flux` to check your code. -## Developing locally - -You can set the `FLUX_DRIVER_PATH` environment variable to `./target/debug/flux-driver` if you -want `cargo-flux` and `rustc-flux` to use the version of `flux-driver` that is built -when you run `cargo build`. This is useful if you want to run `cargo build` instead -of `cargo xtask install` every time you make a change. - ## A tiny example The following example declares a function `inc` diff --git a/crates/flux-attrs-proc-macros-build/Cargo.toml b/crates/flux-attrs-proc-macros-build/Cargo.toml deleted file mode 100644 index 64788c6f26..0000000000 --- a/crates/flux-attrs-proc-macros-build/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "flux-attrs-proc-macros-build" -version = "0.1.0" - -edition.workspace = true - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -flux-rs = { workspace = true, features = ["enabled"] } - -[lints] -workspace = true diff --git a/crates/flux-attrs-proc-macros-build/src/lib.rs b/crates/flux-attrs-proc-macros-build/src/lib.rs deleted file mode 100644 index 93a7db8eb9..0000000000 --- a/crates/flux-attrs-proc-macros-build/src/lib.rs +++ /dev/null @@ -1 +0,0 @@ -//! This is a dummy crate to pre-build the `flux-attrs-proc-macros` crate. diff --git a/crates/flux-bin/Cargo.toml b/crates/flux-bin/Cargo.toml index 8e5a3a148c..0688a80fff 100644 --- a/crates/flux-bin/Cargo.toml +++ b/crates/flux-bin/Cargo.toml @@ -19,7 +19,7 @@ test = false [dependencies] anyhow = "1.0.75" dirs = "5.0.1" -flux-config.workspace = true +home.workspace = true rust-toolchain-file = "0.1.1" [lints] diff --git a/crates/flux-bin/src/bin/cargo-flux.rs b/crates/flux-bin/src/bin/cargo-flux.rs index 6fbab70dc9..5b5d5827ad 100644 --- a/crates/flux-bin/src/bin/cargo-flux.rs +++ b/crates/flux-bin/src/bin/cargo-flux.rs @@ -6,7 +6,7 @@ use std::{ use anyhow::Result; use flux_bin::utils::{ - extend_env_var_with_path, get_flux_driver_path, get_ld_library_path, get_rust_toolchain, + get_flux_driver_path, get_rust_toolchain, get_rustc_driver_lib_path, prepend_path_to_env_var, EXIT_ERR, LIB_PATH, }; @@ -24,19 +24,21 @@ fn main() { fn run() -> Result { let flux_driver_path = get_flux_driver_path()?; let rust_toolchain = get_rust_toolchain()?; - let ld_library_path = get_ld_library_path(&rust_toolchain)?; - let extended_lib_path = extend_env_var_with_path(LIB_PATH, ld_library_path)?; + let ld_library_path = get_rustc_driver_lib_path(&rust_toolchain)?; + let extended_lib_path = prepend_path_to_env_var(LIB_PATH, ld_library_path)?; let cargo_target = env::var("CARGO_TARGET_DIR").unwrap_or_else(|_| "target".to_string()); let cargo_target = PathBuf::from_iter([cargo_target, "flux".to_string()]); - let features = ["--features", "flux-rs/enabled"].iter(); - let exit_code = Command::new("cargo") // Skip the invocation of cargo-flux itself .args(env::args().skip(1)) - .args(features) .env(LIB_PATH, extended_lib_path) + // CODESYNC(build-sysroot, 5) When running flux within cargo we want to compile flux libraries + // as the precompiled versions. + .env("FLUX_BUILD_SYSROOT", "1") + // CODESYNC(flux-cargo) Tell the flux-driver it's being called from cargo. + .env("FLUX_CARGO", "1") .env("RUST_TOOLCHAIN", rust_toolchain.clone()) .env("RUSTUP_TOOLCHAIN", rust_toolchain) .env("RUSTC", flux_driver_path) diff --git a/crates/flux-bin/src/bin/rustc-flux.rs b/crates/flux-bin/src/bin/rustc-flux.rs index afe2ff6ff6..7c1aeefc55 100644 --- a/crates/flux-bin/src/bin/rustc-flux.rs +++ b/crates/flux-bin/src/bin/rustc-flux.rs @@ -5,8 +5,8 @@ use std::{ use anyhow::Result; use flux_bin::utils::{ - extend_env_var_with_path, get_flux_driver_path, get_ld_library_path, get_rust_toolchain, - EXIT_ERR, LIB_PATH, + get_flux_driver_path, get_rust_toolchain, get_rustc_driver_lib_path, prepend_path_to_env_var, + sysroot_dir, EXIT_ERR, LIB_PATH, }; fn main() { @@ -23,12 +23,18 @@ fn main() { fn run() -> Result { let flux_driver_path = get_flux_driver_path()?; let rust_toolchain = get_rust_toolchain()?; - let ld_library_path = get_ld_library_path(&rust_toolchain)?; - let extended_lib_path = extend_env_var_with_path(LIB_PATH, ld_library_path)?; + let ld_library_path = get_rustc_driver_lib_path(&rust_toolchain)?; + let extended_lib_path = prepend_path_to_env_var(LIB_PATH, ld_library_path)?; let exit_code = Command::new(flux_driver_path) // Skip the invocation of rustc-flux itself .args(env::args().skip(1)) + .arg("-Zcrate-attr=feature(register_tool,custom_inner_attributes)") + .arg("-Zcrate-attr=register_tool(flux)") + .arg("-L") + .arg(sysroot_dir()) + .arg("--extern") + .arg("flux_rs") .env(LIB_PATH, extended_lib_path) .status()? .code(); diff --git a/crates/flux-bin/src/utils.rs b/crates/flux-bin/src/utils.rs index 0b9d1d70bb..a656eb64b8 100644 --- a/crates/flux-bin/src/utils.rs +++ b/crates/flux-bin/src/utils.rs @@ -1,7 +1,6 @@ use std::{env, ffi::OsString, fs, path::PathBuf}; use anyhow::{anyhow, Result}; -use flux_config as config; #[cfg(target_os = "windows")] pub const LIB_PATH: &str = "PATH"; @@ -12,26 +11,29 @@ pub const LIB_PATH: &str = "DYLD_FALLBACK_LIBRARY_PATH"; pub const EXIT_ERR: i32 = -1; -pub fn get_default_flux_driver_path() -> Result { - let mut default_flux_path = - env::current_exe().map(|path| path.with_file_name("flux-driver"))?; - if cfg!(target_os = "windows") { - default_flux_path.set_extension("exe"); - } - Ok(default_flux_path) +pub const FLUX_SYSROOT: &str = "FLUX_SYSROOT"; + +/// The path of the flux sysroot lib containing precompiled libraries and the flux driver. +pub fn sysroot_dir() -> PathBuf { + env::var(FLUX_SYSROOT).map_or_else(|_| default_sysroot_dir(), PathBuf::from) +} + +/// Return the default sysroot +pub fn default_sysroot_dir() -> PathBuf { + home::home_dir() + .expect("Couldn't find home directory") + .join(".flux") } pub fn get_flux_driver_path() -> Result { - let flux_driver_path = config::driver_path() - .cloned() - .map_or_else(get_default_flux_driver_path, Ok)?; - if !flux_driver_path.is_file() { - return Err(anyhow!( - "flux executable {:?} does not exist or is not a file", - flux_driver_path - )); + let mut path = sysroot_dir().join("flux-driver"); + if cfg!(target_os = "windows") { + path.set_extension("exe"); } - Ok(flux_driver_path) + if !path.is_file() { + return Err(anyhow!("flux executable {:?} does not exist or is not a file", path)); + } + Ok(path) } pub fn get_rust_toolchain() -> Result { @@ -46,9 +48,9 @@ pub fn get_rust_toolchain() -> Result { .map(|channel| channel.name().to_string()) } -pub fn get_ld_library_path(rust_toolchain: &str) -> Result { - let rustup_home_path = get_rustup_home()?; - let toolchains_path = rustup_home_path.join("toolchains"); +/// Path from where to load the rustc-driver library from +pub fn get_rustc_driver_lib_path(rust_toolchain: &str) -> Result { + let toolchains_path = home::rustup_home()?.join("toolchains"); if toolchains_path.is_dir() { let entries = fs::read_dir(toolchains_path)?; for entry in entries { @@ -68,30 +70,13 @@ pub fn get_ld_library_path(rust_toolchain: &str) -> Result { Err(anyhow!("Could not read Rustup toolchains folder")) } -pub fn get_rustup_home() -> Result { - env::var("RUSTUP_HOME").map(PathBuf::from).or_else(|e| { - match e { - env::VarError::NotPresent => { - dirs::home_dir() - .ok_or_else(|| anyhow!("Could not get OS's home dir")) - .map(|home_dir| home_dir.join(".rustup")) - } - _ => Err(anyhow::Error::from(e)), - } - }) -} - /// Prepends the path so that it's the first checked. -pub fn extend_env_var_with_path(var_name: &str, new_path: PathBuf) -> Result { - let mut paths = env::var(var_name) - .map(|paths_str| env::split_paths(&paths_str).collect()) - .or_else(|err| { - match err { - env::VarError::NotPresent => Ok(Vec::new()), - e => Err(e), - } - })?; - // clone the path so we can report it in the error message. +pub fn prepend_path_to_env_var(var_name: &str, new_path: PathBuf) -> Result { + let mut paths = match env::var(var_name) { + Ok(paths) => env::split_paths(&paths).collect(), + Err(env::VarError::NotPresent) => vec![], + Err(e) => Err(e)?, + }; paths.insert(0, new_path); env::join_paths(paths).map_err(anyhow::Error::from) } diff --git a/crates/flux-config/src/lib.rs b/crates/flux-config/src/lib.rs index 1dece5832a..5a085272fd 100644 --- a/crates/flux-config/src/lib.rs +++ b/crates/flux-config/src/lib.rs @@ -53,10 +53,6 @@ pub fn cache_path() -> PathBuf { log_dir().join(&CONFIG.cache_file) } -pub fn driver_path() -> Option<&'static PathBuf> { - CONFIG.driver_path.as_ref() -} - pub fn check_overflow() -> bool { CONFIG.check_overflow } @@ -73,7 +69,6 @@ pub struct CrateConfig { #[derive(Deserialize)] struct Config { - driver_path: Option, log_dir: PathBuf, dump_constraint: bool, dump_checker_trace: bool, diff --git a/crates/flux-driver/src/bin/main.rs b/crates/flux-driver/src/bin/main.rs index 2160eb4049..902559e07f 100644 --- a/crates/flux-driver/src/bin/main.rs +++ b/crates/flux-driver/src/bin/main.rs @@ -12,8 +12,8 @@ mod logger; fn main() -> io::Result<()> { let resolve_logs = logger::install()?; - // Check if we are being called from cargo. - let in_cargo = env::var("CARGO").is_ok(); + // CODESYNC(flux-cargo) Check if we are being called from cargo. + let in_cargo = env::var("FLUX_CARGO").is_ok(); // HACK(nilehmann) // Disable incremental compilation because that makes the borrow checker to not run diff --git a/crates/flux-macros/src/diagnostics/diagnostic.rs b/crates/flux-macros/src/diagnostics/diagnostic.rs index 911d09b2a3..20966ce7f2 100644 --- a/crates/flux-macros/src/diagnostics/diagnostic.rs +++ b/crates/flux-macros/src/diagnostics/diagnostic.rs @@ -1,3 +1,4 @@ +#![allow(clippy::pedantic)] #![deny(unused_must_use)] use std::cell::RefCell; diff --git a/crates/flux-macros/src/diagnostics/diagnostic_builder.rs b/crates/flux-macros/src/diagnostics/diagnostic_builder.rs index ba72998578..5e6b69b523 100644 --- a/crates/flux-macros/src/diagnostics/diagnostic_builder.rs +++ b/crates/flux-macros/src/diagnostics/diagnostic_builder.rs @@ -1,3 +1,4 @@ +#![allow(clippy::pedantic)] #![deny(unused_must_use)] use proc_macro2::{Ident, Span, TokenStream}; diff --git a/crates/flux-macros/src/diagnostics/fluent.rs b/crates/flux-macros/src/diagnostics/fluent.rs index 6e7b753026..c70d15dce2 100644 --- a/crates/flux-macros/src/diagnostics/fluent.rs +++ b/crates/flux-macros/src/diagnostics/fluent.rs @@ -1,4 +1,4 @@ -#![allow(clippy::all)] +#![allow(clippy::all, clippy::pedantic)] use std::{ collections::{HashMap, HashSet}, fs::read_to_string, diff --git a/crates/flux-macros/src/diagnostics/subdiagnostic.rs b/crates/flux-macros/src/diagnostics/subdiagnostic.rs index f45e402816..e28be25770 100644 --- a/crates/flux-macros/src/diagnostics/subdiagnostic.rs +++ b/crates/flux-macros/src/diagnostics/subdiagnostic.rs @@ -1,3 +1,4 @@ +#![allow(clippy::pedantic)] #![deny(unused_must_use)] use proc_macro2::TokenStream; diff --git a/crates/flux-rs/Cargo.toml b/crates/flux-rs/Cargo.toml deleted file mode 100644 index 9a031d8717..0000000000 --- a/crates/flux-rs/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "flux-rs" -version = "0.1.0" - -edition.workspace = true - -[lib] -proc-macro = true - -[dependencies] -flux-attrs.workspace = true -proc-macro2 = { version = "1.0", optional = true } - -[features] -# Design taken from Prusti - we enable the 'flux-attributes-proc-macros/enabled' -# feature when checking with flux which indicates that we should pull in these -# deps. -enabled = ["flux-attrs/enabled"] - -[lints] -workspace = true diff --git a/crates/flux-tests/Cargo.toml b/crates/flux-tests/Cargo.toml index 9e41ba5f95..397dccdd67 100644 --- a/crates/flux-tests/Cargo.toml +++ b/crates/flux-tests/Cargo.toml @@ -9,6 +9,7 @@ doctest = false test = false [dev-dependencies] +flux-bin.workspace = true itertools.workspace = true compiletest_rs = "0.10" diff --git a/crates/flux-tests/src/lib.rs b/crates/flux-tests/src/lib.rs index 97326a448d..d6cbe520b3 100644 --- a/crates/flux-tests/src/lib.rs +++ b/crates/flux-tests/src/lib.rs @@ -1,42 +1,27 @@ +#![feature(register_tool)] use std::path::PathBuf; pub fn find_flux_path() -> PathBuf { - let executable_name = if cfg!(windows) { "flux-driver.exe" } else { "flux-driver" }; + let executable_name = if cfg!(windows) { "rustc-flux.exe" } else { "rustc-flux" }; find_file_in_target_dir(executable_name) } +/// Rustc flags to pass Flux when running tests pub fn rustc_flags() -> Vec { - vec![ - "-Zcrate-attr=feature(register_tool,custom_inner_attributes)".to_string(), - "-Zcrate-attr=register_tool(flux)".to_string(), - "--crate-type=rlib".to_string(), - "--edition=2021".to_string(), - format!("--extern=flux_rs={}", find_flux_rs_lib_path().display()), - ] -} - -fn find_flux_rs_lib_path() -> PathBuf { - let flux_rs_lib = if cfg!(target_os = "linux") { - "libflux_rs.so" - } else if cfg!(target_os = "macos") { - "libflux_rs.dylib" - } else { - todo!("implement for windows") - }; - find_file_in_target_dir(flux_rs_lib) + vec!["--crate-type=rlib".to_string(), "--edition=2021".to_string()] } fn find_file_in_target_dir(file: &str) -> PathBuf { let target_directory = if cfg!(debug_assertions) { "debug" } else { "release" }; - let local_flux_driver_path: PathBuf = ["target", target_directory, file].into_iter().collect(); - if local_flux_driver_path.exists() { - return local_flux_driver_path; + let local_path: PathBuf = ["target", target_directory, file].into_iter().collect(); + if local_path.exists() { + return local_path; } - let workspace_flux_driver_path: PathBuf = ["..", "..", "target", target_directory, file] + let workspace_path: PathBuf = ["..", "..", "target", target_directory, file] .into_iter() .collect(); - if workspace_flux_driver_path.exists() { - return workspace_flux_driver_path; + if workspace_path.exists() { + return workspace_path; } panic!("Could not find {file}"); } diff --git a/crates/flux-tests/tests/compiletest.rs b/crates/flux-tests/tests/compiletest.rs index adcaa6fcfe..1d71e06b58 100644 --- a/crates/flux-tests/tests/compiletest.rs +++ b/crates/flux-tests/tests/compiletest.rs @@ -4,6 +4,7 @@ use std::{env, path::PathBuf}; use compiletest_rs::{common::Mode, Config}; +use flux_bin::utils::FLUX_SYSROOT; use flux_tests::{find_flux_path, rustc_flags}; use itertools::Itertools; @@ -21,6 +22,8 @@ fn test_runner(_: &[&()]) { config.target_rustcflags = Some(rustc_flags().join(" ")); + env::set_var(FLUX_SYSROOT, config.rustc_path.parent().unwrap()); + let path: PathBuf = ["tests", "pos"].iter().collect(); if path.exists() { config.mode = Mode::Ui; diff --git a/lib/README.md b/lib/README.md new file mode 100644 index 0000000000..7fba582cfe --- /dev/null +++ b/lib/README.md @@ -0,0 +1,14 @@ +# lib + +Crates in this directory are meant to be used as dependencies for projects using Flux. They should be +eventually published to [crates.io](https://crates.io). As such, they should not depend on other +crates in the workspace. They could live in a separate repository or be excluded from the workspace, +but we keep them inside to reuse `Cargo.lock` and the lint table. + +## FLUX_BUILD_SYSROOT + +These libraries behave differently depending on whether they are being used during normal compilation +or while flux is analyzing the code. For example, some macros are a no-op during normal compilation. +The different behavior is toggled with a `--cfg flux_sysroot` flag. We control the toggle from cargo +by setting the `FLUX_BUILD_SYSROOT` environment variable. This variable is read from the build scripts +which set the `--cfg flux_sysroot` when present. diff --git a/crates/flux-attrs/Cargo.toml b/lib/flux-attrs/Cargo.toml similarity index 89% rename from crates/flux-attrs/Cargo.toml rename to lib/flux-attrs/Cargo.toml index 20186835cd..ed90763b1b 100644 --- a/crates/flux-attrs/Cargo.toml +++ b/lib/flux-attrs/Cargo.toml @@ -9,8 +9,5 @@ proc-macro2 = "1" quote = "1" syn = { version = "2", features = ["full", "extra-traits"] } -[features] -enabled = [] - [lints] workspace = true diff --git a/lib/flux-attrs/build.rs b/lib/flux-attrs/build.rs new file mode 100644 index 0000000000..93064408de --- /dev/null +++ b/lib/flux-attrs/build.rs @@ -0,0 +1,7 @@ +fn main() { + // CODESYNC(build-sysroot, 5) + println!("cargo:rerun-if-env-changed=FLUX_BUILD_SYSROOT"); + if std::env::var("FLUX_BUILD_SYSROOT").is_ok() { + println!("cargo:rustc-cfg=flux_sysroot"); + } +} diff --git a/crates/flux-attrs/src/ast.rs b/lib/flux-attrs/src/ast.rs similarity index 99% rename from crates/flux-attrs/src/ast.rs rename to lib/flux-attrs/src/ast.rs index aa8b60a219..9c8a2f64bf 100644 --- a/crates/flux-attrs/src/ast.rs +++ b/lib/flux-attrs/src/ast.rs @@ -806,7 +806,7 @@ impl ToTokens for Item { impl ToTokens for ItemFn { fn to_tokens(&self, tokens: &mut TokenStream) { let ItemFn { attrs, vis, sig, block } = self; - #[cfg(feature = "enabled")] + #[cfg(flux_sysroot)] { let flux_sig = ToTokensFlux(sig); quote!(#[flux::sig(#flux_sig)]).to_tokens(tokens); @@ -904,7 +904,7 @@ impl ToTokens for ImplItem { impl ToTokens for ImplItemFn { fn to_tokens(&self, tokens: &mut TokenStream) { let ImplItemFn { attrs, vis, sig, block } = self; - #[cfg(feature = "enabled")] + #[cfg(flux_sysroot)] { let flux_sig = ToTokensFlux(sig); quote!(#[flux::sig(#flux_sig)]).to_tokens(tokens); diff --git a/crates/flux-attrs/src/lib.rs b/lib/flux-attrs/src/lib.rs similarity index 100% rename from crates/flux-attrs/src/lib.rs rename to lib/flux-attrs/src/lib.rs diff --git a/lib/flux-rs/Cargo.toml b/lib/flux-rs/Cargo.toml new file mode 100644 index 0000000000..50e141f791 --- /dev/null +++ b/lib/flux-rs/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "flux-rs" +version = "0.1.0" + +edition.workspace = true + +[lib] +proc-macro = true + +[dependencies] +flux-attrs = { path = "../flux-attrs", version = "0.1.0" } + +[lints] +workspace = true diff --git a/lib/flux-rs/build.rs b/lib/flux-rs/build.rs new file mode 100644 index 0000000000..93064408de --- /dev/null +++ b/lib/flux-rs/build.rs @@ -0,0 +1,7 @@ +fn main() { + // CODESYNC(build-sysroot, 5) + println!("cargo:rerun-if-env-changed=FLUX_BUILD_SYSROOT"); + if std::env::var("FLUX_BUILD_SYSROOT").is_ok() { + println!("cargo:rustc-cfg=flux_sysroot"); + } +} diff --git a/crates/flux-rs/src/lib.rs b/lib/flux-rs/src/lib.rs similarity index 82% rename from crates/flux-rs/src/lib.rs rename to lib/flux-rs/src/lib.rs index 6d3ea1d959..9b980b0127 100644 --- a/crates/flux-rs/src/lib.rs +++ b/lib/flux-rs/src/lib.rs @@ -1,14 +1,13 @@ // When running without flux, all macros are pass-through -#![cfg_attr(not(feature = "enabled"), no_std)] use proc_macro::TokenStream; -#[cfg(not(feature = "enabled"))] +#[cfg(not(flux_sysroot))] #[proc_macro_attribute] pub fn extern_spec(_attrs: TokenStream, _tokens: TokenStream) -> TokenStream { TokenStream::new() } -#[cfg(feature = "enabled")] +#[cfg(flux_sysroot)] #[proc_macro_attribute] pub fn extern_spec(attrs: TokenStream, tokens: TokenStream) -> TokenStream { flux_attrs::extern_spec(attrs.into(), tokens.into()).into() diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index bb3b6d19e0..ad6a0654b0 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -7,6 +7,7 @@ version = "0.1.0" [dependencies] anyhow = "1.0.75" +flux-bin.workspace = true flux-tests.workspace = true opener = "0.6.1" xflags = "0.3.1" diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 87c50bc0b9..b4d2727e86 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -4,7 +4,7 @@ use std::{ path::{Path, PathBuf}, }; -use flux_tests::{find_flux_path, rustc_flags}; +use flux_bin::utils::{default_sysroot_dir, FLUX_SYSROOT}; use xshell::{cmd, Shell}; xflags::xflags! { @@ -22,11 +22,15 @@ xflags::xflags! { /// Extra options to pass to the flux binary, e.g. `cargo xtask run file.rs -- -Zdump-mir=y` repeated opts: OsString } - /// Install flux binaries to ~/.cargo/bin + /// Install flux binaries to ~/.cargo/bin and precompiled libraries and driver to ~/.flux cmd install { /// Build the flux-driver binary in debug mode (with the 'dev' profile) instead of release mode optional --debug } + /// Uninstall flux binaries and libraries + cmd uninstall { } + /// Generate precompiled libraries + cmd build-sysroot { } /// Build the documentation cmd doc { optional -o,--open @@ -39,7 +43,6 @@ fn main() -> anyhow::Result<()> { Ok(cmd) => cmd, Err(err) => { if err.is_help() { - println!("{err}"); std::process::exit(0); } else { eprintln!("error: {err}\n"); @@ -54,13 +57,16 @@ fn main() -> anyhow::Result<()> { match cmd.subcommand { XtaskCmd::Test(args) => test(sh, args), XtaskCmd::Run(args) => run(sh, args), - XtaskCmd::Install(args) => install(sh, args), + XtaskCmd::Install(args) => install(&sh, &args), XtaskCmd::Doc(args) => doc(sh, args), + XtaskCmd::BuildSysroot(_) => build_sysroot(&sh), + XtaskCmd::Uninstall(_) => uninstall(&sh), } } fn test(sh: Shell, args: Test) -> anyhow::Result<()> { let Test { filter } = args; + build_sysroot(&sh)?; cmd!(sh, "cargo build").run()?; if let Some(filter) = filter { @@ -73,24 +79,48 @@ fn test(sh: Shell, args: Test) -> anyhow::Result<()> { fn run(sh: Shell, args: Run) -> anyhow::Result<()> { let Run { input, opts } = args; + build_sysroot(&sh)?; cmd!(sh, "cargo build").run()?; - let flux_path = find_flux_path(); - let mut rustc_flags = rustc_flags(); + let flux_path = flux_tests::find_flux_path(); + let _env = sh.push_env(FLUX_SYSROOT, flux_path.parent().unwrap()); + let mut rustc_flags = flux_tests::rustc_flags(); rustc_flags.extend(["-Ztrack-diagnostics=y".to_string()]); cmd!(sh, "{flux_path} {rustc_flags...} {opts...} {input}").run()?; Ok(()) } -fn install(sh: Shell, args: Install) -> anyhow::Result<()> { - let Install { debug } = args; - let mut opts = vec!["--force"]; - if debug { - opts.push("--debug"); - } - cmd!(sh, "cargo install --path crates/flux-driver {opts...}").run()?; +fn install(sh: &Shell, args: &Install) -> anyhow::Result<()> { cmd!(sh, "cargo install --path crates/flux-bin --force").run()?; + install_driver(sh, args)?; + install_libs(sh, args)?; + + Ok(()) +} + +fn install_driver(sh: &Shell, args: &Install) -> anyhow::Result<()> { + let profile = args.profile(); + let out_dir = default_sysroot_dir(); + cmd!(sh, "cargo build -Zunstable-options --bin flux-driver {profile} --out-dir {out_dir}") + .run()?; + Ok(()) +} + +fn install_libs(sh: &Shell, args: &Install) -> anyhow::Result<()> { + // CODESYNC(build-sysroot, 5) + let _env = sh.push_env("FLUX_BUILD_SYSROOT", "1"); + + let profile = args.profile(); + let out_dir = default_sysroot_dir(); + cmd!(sh, "cargo build -Zunstable-options {profile} -p flux-rs --out-dir {out_dir}").run()?; + Ok(()) +} + +fn uninstall(sh: &Shell) -> anyhow::Result<()> { + cmd!(sh, "cargo uninstall -p flux-bin").run()?; + println!("$ rm -rf ~/.flux"); + std::fs::remove_dir_all(default_sysroot_dir())?; Ok(()) } @@ -112,3 +142,20 @@ fn project_root() -> PathBuf { .unwrap() .to_path_buf() } + +fn build_sysroot(sh: &Shell) -> anyhow::Result<()> { + // CODESYNC(build-sysroot, 5) + let _env = sh.push_env("FLUX_BUILD_SYSROOT", "1"); + cmd!(sh, "cargo build -p flux-rs").run()?; + Ok(()) +} + +impl Install { + fn profile(&self) -> &'static str { + if self.debug { + "--debug" + } else { + "--release" + } + } +}