From dbb00333b1acd74900e5ae94b2220db4ff2a9eb9 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Sat, 6 Dec 2025 15:44:20 -0500 Subject: [PATCH 1/2] Split monolithic raw crates into sys crates Creating a crate for bwd-gc highlights the fact that it would be nice to fix 2! The file blocklist is a lost less unmaintainable then the more fine-grained one we had before. Fix #9 --- Cargo.lock | 69 ++++++++++++++++--- Cargo.toml | 5 ++ flake.nix | 41 +++++------ nci.nix | 52 +++++++++++++- nix-bindings-bdwgc-sys/Cargo.toml | 15 ++++ nix-bindings-bdwgc-sys/README.md | 4 ++ nix-bindings-bdwgc-sys/build.rs | 27 ++++++++ nix-bindings-bdwgc-sys/include/bdwgc.h | 2 + nix-bindings-bdwgc-sys/src/lib.rs | 7 ++ nix-bindings-expr-sys/Cargo.toml | 17 +++++ nix-bindings-expr-sys/README.md | 5 ++ nix-bindings-expr-sys/build.rs | 42 +++++++++++ nix-bindings-expr-sys/include/nix-c-expr.h | 2 + nix-bindings-expr-sys/src/lib.rs | 10 +++ nix-bindings-expr/Cargo.toml | 11 +-- nix-bindings-expr/src/eval_state.rs | 20 +++--- nix-bindings-expr/src/primop.rs | 7 +- nix-bindings-expr/src/value.rs | 2 +- nix-bindings-expr/src/value/__private.rs | 2 +- nix-bindings-fetchers-sys/Cargo.toml | 16 +++++ nix-bindings-fetchers-sys/README.md | 5 ++ nix-bindings-fetchers-sys/build.rs | 40 +++++++++++ .../include/nix-c-fetchers.h | 1 + nix-bindings-fetchers-sys/src/lib.rs | 9 +++ nix-bindings-fetchers/Cargo.toml | 8 +-- nix-bindings-fetchers/src/lib.rs | 2 +- nix-bindings-flake-sys/Cargo.toml | 20 ++++++ nix-bindings-flake-sys/README.md | 5 ++ nix-bindings-flake-sys/build.rs | 56 +++++++++++++++ nix-bindings-flake-sys/include/nix-c-flake.h | 3 + nix-bindings-flake-sys/src/lib.rs | 11 +++ nix-bindings-flake/Cargo.toml | 12 ++-- nix-bindings-flake/src/lib.rs | 2 +- nix-bindings-store-sys/Cargo.toml | 16 +++++ nix-bindings-store-sys/README.md | 5 ++ nix-bindings-store-sys/build.rs | 40 +++++++++++ nix-bindings-store-sys/include/nix-c-store.h | 1 + nix-bindings-store-sys/src/lib.rs | 9 +++ nix-bindings-store/Cargo.toml | 9 +-- nix-bindings-store/src/derivation.rs | 2 +- nix-bindings-store/src/path.rs | 2 +- nix-bindings-store/src/store.rs | 5 +- nix-bindings-util-sys/Cargo.toml | 4 +- nix-bindings-util-sys/README.md | 11 +-- nix-bindings-util-sys/build.rs | 16 ++--- nix-bindings-util-sys/include/nix-c-raw.h | 7 -- nix-bindings-util-sys/include/nix-c-util.h | 1 + nix-bindings-util/Cargo.toml | 6 +- nix-bindings-util/src/context.rs | 2 +- nix-bindings-util/src/lib.rs | 3 + nix-bindings-util/src/settings.rs | 6 +- 51 files changed, 571 insertions(+), 104 deletions(-) create mode 100644 nix-bindings-bdwgc-sys/Cargo.toml create mode 100644 nix-bindings-bdwgc-sys/README.md create mode 100644 nix-bindings-bdwgc-sys/build.rs create mode 100644 nix-bindings-bdwgc-sys/include/bdwgc.h create mode 100644 nix-bindings-bdwgc-sys/src/lib.rs create mode 100644 nix-bindings-expr-sys/Cargo.toml create mode 100644 nix-bindings-expr-sys/README.md create mode 100644 nix-bindings-expr-sys/build.rs create mode 100644 nix-bindings-expr-sys/include/nix-c-expr.h create mode 100644 nix-bindings-expr-sys/src/lib.rs create mode 100644 nix-bindings-fetchers-sys/Cargo.toml create mode 100644 nix-bindings-fetchers-sys/README.md create mode 100644 nix-bindings-fetchers-sys/build.rs create mode 100644 nix-bindings-fetchers-sys/include/nix-c-fetchers.h create mode 100644 nix-bindings-fetchers-sys/src/lib.rs create mode 100644 nix-bindings-flake-sys/Cargo.toml create mode 100644 nix-bindings-flake-sys/README.md create mode 100644 nix-bindings-flake-sys/build.rs create mode 100644 nix-bindings-flake-sys/include/nix-c-flake.h create mode 100644 nix-bindings-flake-sys/src/lib.rs create mode 100644 nix-bindings-store-sys/Cargo.toml create mode 100644 nix-bindings-store-sys/README.md create mode 100644 nix-bindings-store-sys/build.rs create mode 100644 nix-bindings-store-sys/include/nix-c-store.h create mode 100644 nix-bindings-store-sys/src/lib.rs delete mode 100644 nix-bindings-util-sys/include/nix-c-raw.h create mode 100644 nix-bindings-util-sys/include/nix-c-util.h diff --git a/Cargo.lock b/Cargo.lock index 146ff70..5eb39f0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -208,36 +208,66 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" +[[package]] +name = "nix-bindings-bdwgc-sys" +version = "0.2.0" +dependencies = [ + "bindgen", + "pkg-config", +] + [[package]] name = "nix-bindings-expr" -version = "0.1.1" +version = "0.2.0" dependencies = [ "anyhow", "cstr", "ctor", "lazy_static", + "nix-bindings-bdwgc-sys", + "nix-bindings-expr-sys", "nix-bindings-store", + "nix-bindings-store-sys", "nix-bindings-util", "nix-bindings-util-sys", "tempfile", ] +[[package]] +name = "nix-bindings-expr-sys" +version = "0.2.0" +dependencies = [ + "bindgen", + "nix-bindings-store-sys", + "nix-bindings-util-sys", + "pkg-config", +] + [[package]] name = "nix-bindings-fetchers" -version = "0.1.1" +version = "0.2.0" dependencies = [ "anyhow", "cstr", "ctor", + "nix-bindings-fetchers-sys", "nix-bindings-store", "nix-bindings-util", - "nix-bindings-util-sys", "tempfile", ] +[[package]] +name = "nix-bindings-fetchers-sys" +version = "0.2.0" +dependencies = [ + "bindgen", + "nix-bindings-util-sys", + "pkg-config", +] + [[package]] name = "nix-bindings-flake" -version = "0.1.1" +version = "0.2.0" dependencies = [ "anyhow", "cstr", @@ -245,28 +275,51 @@ dependencies = [ "lazy_static", "nix-bindings-expr", "nix-bindings-fetchers", + "nix-bindings-flake-sys", "nix-bindings-store", "nix-bindings-util", - "nix-bindings-util-sys", "tempfile", ] +[[package]] +name = "nix-bindings-flake-sys" +version = "0.2.0" +dependencies = [ + "bindgen", + "nix-bindings-bdwgc-sys", + "nix-bindings-expr-sys", + "nix-bindings-fetchers-sys", + "nix-bindings-store-sys", + "nix-bindings-util-sys", + "pkg-config", +] + [[package]] name = "nix-bindings-store" -version = "0.1.1" +version = "0.2.0" dependencies = [ "anyhow", "ctor", "lazy_static", + "nix-bindings-store-sys", "nix-bindings-util", "nix-bindings-util-sys", "pkg-config", "tempfile", ] +[[package]] +name = "nix-bindings-store-sys" +version = "0.2.0" +dependencies = [ + "bindgen", + "nix-bindings-util-sys", + "pkg-config", +] + [[package]] name = "nix-bindings-util" -version = "0.1.1" +version = "0.2.0" dependencies = [ "anyhow", "ctor", @@ -275,7 +328,7 @@ dependencies = [ [[package]] name = "nix-bindings-util-sys" -version = "0.1.1" +version = "0.2.0" dependencies = [ "bindgen", "pkg-config", diff --git a/Cargo.toml b/Cargo.toml index 7cfd424..67da147 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,11 @@ [workspace] members = [ + "nix-bindings-bdwgc-sys", "nix-bindings-util-sys", + "nix-bindings-store-sys", + "nix-bindings-expr-sys", + "nix-bindings-fetchers-sys", + "nix-bindings-flake-sys", "nix-bindings-expr", "nix-bindings-fetchers", "nix-bindings-flake", diff --git a/flake.nix b/flake.nix index f9896ad..ddd12be 100644 --- a/flake.nix +++ b/flake.nix @@ -29,10 +29,7 @@ { _file = ./flake.nix; options.perSystem = flake-parts-lib.mkPerSystemOption ( - { config, pkgs, ... }: - let - cfg = config.nix-bindings-rust; - in + { pkgs, ... }: { options.nix-bindings-rust = { nixPackage = lib.mkOption { @@ -49,10 +46,25 @@ A module to load into your nix-cargo-integration [`perSystem.nci.projects..depsDrvConfig`](https://flake.parts/options/nix-cargo-integration.html#opt-perSystem.nci.projects._name_.depsDrvConfig) or similar such options. + This provides common build configuration (pkg-config, libclang, etc.) but you must + add the specific Nix C libraries your crates need to `buildInputs`: + - `nix-bindings-util-sys` needs `nix-util-c` + - `nix-bindings-store-sys` needs `nix-store-c` + - `nix-bindings-expr-sys` needs `nix-expr-c` + - `nix-bindings-fetchers-sys` needs `nix-fetchers-c` (Nix >= 2.29) + - `nix-bindings-flake-sys` needs `nix-flake-c` + - `nix-bindings-bdwgc-sys` needs `boehmgc` + Example: ```nix - perSystem = perSystem@{ config, ... }: { - nci.projects."my_project".depsDrvConfig = perSystem.config.nix-bindings-rust.nciBuildConfig; + perSystem = perSystem@{ config, pkgs, ... }: { + nci.projects."my_project".depsDrvConfig = { + imports = [ perSystem.config.nix-bindings-rust.nciBuildConfig ]; + mkDerivation.buildInputs = [ + perSystem.config.nix-bindings-rust.nixPackage.libs.nix-store-c + # ... add other libs as needed + ]; + }; } ``` ''; @@ -64,22 +76,7 @@ buildInputs = [ # stdbool.h pkgs.stdenv.cc - ] - ++ ( - if cfg.nixPackage ? libs then - let - l = cfg.nixPackage.libs; - in - [ - l.nix-expr-c - l.nix-store-c - l.nix-util-c - l.nix-fetchers-c or null # Nix >= 2.29 - l.nix-flake-c - ] - else - [ cfg.nixPackage ] - ); + ]; nativeBuildInputs = [ pkgs.pkg-config ]; diff --git a/nci.nix b/nci.nix index cc864b0..9a468b6 100644 --- a/nci.nix +++ b/nci.nix @@ -2,8 +2,24 @@ perSystem = { config, + pkgs, ... }: + let + cfg = config.nix-bindings-rust; + nixLibs = + if cfg.nixPackage ? libs then + cfg.nixPackage.libs + else + # Fallback for older Nix versions without split libs + { + nix-util-c = cfg.nixPackage; + nix-store-c = cfg.nixPackage; + nix-expr-c = cfg.nixPackage; + nix-fetchers-c = cfg.nixPackage; + nix-flake-c = cfg.nixPackage; + }; + in { # https://flake.parts/options/nix-cargo-integration nci.projects.nix-bindings = { @@ -42,12 +58,46 @@ echo "experimental-features = ca-derivations flakes" > "$NIX_CONF_DIR/nix.conf" # Init ahead of time, because concurrent initialization is flaky - ${config.nix-bindings-rust.nixPackage}/bin/nix-store --init + ${cfg.nixPackage}/bin/nix-store --init echo "Store initialized." ''; }; }; }; + + # Per-crate configuration: only provide the specific Nix libs each crate needs + # FIXME should use propagatedBuildInputs + nci.crates.nix-bindings-bdwgc-sys.drvConfig.mkDerivation.buildInputs = [ + pkgs.boehmgc + ]; + nci.crates.nix-bindings-util-sys.drvConfig.mkDerivation.buildInputs = [ + nixLibs.nix-util-c + ]; + nci.crates.nix-bindings-util.drvConfig.mkDerivation.buildInputs = + config.nci.crates.nix-bindings-util-sys.drvConfig.mkDerivation.buildInputs; + nci.crates.nix-bindings-store-sys.drvConfig.mkDerivation.buildInputs = + config.nci.crates.nix-bindings-util-sys.drvConfig.mkDerivation.buildInputs + ++ [ nixLibs.nix-store-c ]; + nci.crates.nix-bindings-store.drvConfig.mkDerivation.buildInputs = + config.nci.crates.nix-bindings-store-sys.drvConfig.mkDerivation.buildInputs; + nci.crates.nix-bindings-expr-sys.drvConfig.mkDerivation.buildInputs = + config.nci.crates.nix-bindings-store-sys.drvConfig.mkDerivation.buildInputs + ++ [ + nixLibs.nix-expr-c + pkgs.boehmgc + ]; + nci.crates.nix-bindings-expr.drvConfig.mkDerivation.buildInputs = + config.nci.crates.nix-bindings-expr-sys.drvConfig.mkDerivation.buildInputs; + nci.crates.nix-bindings-fetchers-sys.drvConfig.mkDerivation.buildInputs = + config.nci.crates.nix-bindings-expr-sys.drvConfig.mkDerivation.buildInputs + ++ [ nixLibs.nix-fetchers-c ]; + nci.crates.nix-bindings-fetchers.drvConfig.mkDerivation.buildInputs = + config.nci.crates.nix-bindings-fetchers-sys.drvConfig.mkDerivation.buildInputs; + nci.crates.nix-bindings-flake-sys.drvConfig.mkDerivation.buildInputs = + config.nci.crates.nix-bindings-fetchers-sys.drvConfig.mkDerivation.buildInputs + ++ [ nixLibs.nix-flake-c ]; + nci.crates.nix-bindings-flake.drvConfig.mkDerivation.buildInputs = + config.nci.crates.nix-bindings-flake-sys.drvConfig.mkDerivation.buildInputs; }; } diff --git a/nix-bindings-bdwgc-sys/Cargo.toml b/nix-bindings-bdwgc-sys/Cargo.toml new file mode 100644 index 0000000..bf75ca7 --- /dev/null +++ b/nix-bindings-bdwgc-sys/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "nix-bindings-bdwgc-sys" +version = "0.2.0" +edition = "2021" +build = "build.rs" +license = "LGPL-2.1" + +[lib] +path = "src/lib.rs" + +[dependencies] + +[build-dependencies] +bindgen = "0.69" +pkg-config = "0.3" diff --git a/nix-bindings-bdwgc-sys/README.md b/nix-bindings-bdwgc-sys/README.md new file mode 100644 index 0000000..3723e90 --- /dev/null +++ b/nix-bindings-bdwgc-sys/README.md @@ -0,0 +1,4 @@ +# nix-bindings-bdwgc-sys + +This crate contains generated bindings for the Boehm-Demers-Weiser garbage collector (`bdw-gc`). +**You should not have to use this crate directly,** and so you should probably not add it to your dependencies. diff --git a/nix-bindings-bdwgc-sys/build.rs b/nix-bindings-bdwgc-sys/build.rs new file mode 100644 index 0000000..aed2a8c --- /dev/null +++ b/nix-bindings-bdwgc-sys/build.rs @@ -0,0 +1,27 @@ +use std::env; +use std::path::PathBuf; + +fn main() { + println!("cargo:rerun-if-changed=include/bdwgc.h"); + + let mut args = Vec::new(); + for path in pkg_config::probe_library("bdw-gc") + .unwrap() + .include_paths + .iter() + { + args.push(format!("-I{}", path.to_str().unwrap())); + } + + let bindings = bindgen::Builder::default() + .header("include/bdwgc.h") + .clang_args(args) + .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) + .generate() + .expect("Unable to generate bindings"); + + let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + bindings + .write_to_file(out_path.join("bindings.rs")) + .expect("Couldn't write bindings!"); +} diff --git a/nix-bindings-bdwgc-sys/include/bdwgc.h b/nix-bindings-bdwgc-sys/include/bdwgc.h new file mode 100644 index 0000000..2a70434 --- /dev/null +++ b/nix-bindings-bdwgc-sys/include/bdwgc.h @@ -0,0 +1,2 @@ +#define GC_THREADS +#include diff --git a/nix-bindings-bdwgc-sys/src/lib.rs b/nix-bindings-bdwgc-sys/src/lib.rs new file mode 100644 index 0000000..0cf64d2 --- /dev/null +++ b/nix-bindings-bdwgc-sys/src/lib.rs @@ -0,0 +1,7 @@ +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(dead_code)] +#![allow(clippy::all)] + +include!(concat!(env!("OUT_DIR"), "/bindings.rs")); diff --git a/nix-bindings-expr-sys/Cargo.toml b/nix-bindings-expr-sys/Cargo.toml new file mode 100644 index 0000000..39518fc --- /dev/null +++ b/nix-bindings-expr-sys/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "nix-bindings-expr-sys" +version = "0.2.0" +edition = "2021" +build = "build.rs" +license = "LGPL-2.1" + +[lib] +path = "src/lib.rs" + +[dependencies] +nix-bindings-util-sys = { path = "../nix-bindings-util-sys", version = "0.2.0" } +nix-bindings-store-sys = { path = "../nix-bindings-store-sys", version = "0.2.0" } + +[build-dependencies] +bindgen = "0.69" +pkg-config = "0.3" diff --git a/nix-bindings-expr-sys/README.md b/nix-bindings-expr-sys/README.md new file mode 100644 index 0000000..ccdcc26 --- /dev/null +++ b/nix-bindings-expr-sys/README.md @@ -0,0 +1,5 @@ +# nix-bindings-expr-sys + +This crate contains generated bindings for the Nix C API (`nix-expr-c`). +**You should not have to use this crate directly,** and so you should probably not add it to your dependencies. +Instead, use the `nix-bindings-expr` crate, which _should_ be sufficient. diff --git a/nix-bindings-expr-sys/build.rs b/nix-bindings-expr-sys/build.rs new file mode 100644 index 0000000..6e0eed2 --- /dev/null +++ b/nix-bindings-expr-sys/build.rs @@ -0,0 +1,42 @@ +use std::path::PathBuf; + +#[derive(Debug)] +struct StripNixPrefix; + +impl bindgen::callbacks::ParseCallbacks for StripNixPrefix { + fn item_name(&self, name: &str) -> Option { + name.strip_prefix("nix_").map(String::from) + } +} + +fn main() { + println!("cargo:rerun-if-changed=include/nix-c-expr.h"); + println!("cargo:rustc-link-lib=nixexprc"); + + let mut args = Vec::new(); + for path in pkg_config::probe_library("nix-expr-c") + .unwrap() + .include_paths + .iter() + { + args.push(format!("-I{}", path.to_str().unwrap())); + } + + let out_path = PathBuf::from(std::env::var("OUT_DIR").unwrap()); + + let bindings = bindgen::Builder::default() + .header("include/nix-c-expr.h") + .clang_args(args) + .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) + .parse_callbacks(Box::new(StripNixPrefix)) + // Blocklist symbols from nix-bindings-util-sys + .blocklist_file(".*nix_api_util\\.h") + // Blocklist symbols from nix-bindings-store-sys + .blocklist_file(".*nix_api_store\\.h") + .generate() + .expect("Unable to generate bindings"); + + bindings + .write_to_file(out_path.join("bindings.rs")) + .expect("Couldn't write bindings!"); +} diff --git a/nix-bindings-expr-sys/include/nix-c-expr.h b/nix-bindings-expr-sys/include/nix-c-expr.h new file mode 100644 index 0000000..c2649a4 --- /dev/null +++ b/nix-bindings-expr-sys/include/nix-c-expr.h @@ -0,0 +1,2 @@ +#include +#include diff --git a/nix-bindings-expr-sys/src/lib.rs b/nix-bindings-expr-sys/src/lib.rs new file mode 100644 index 0000000..afd13d3 --- /dev/null +++ b/nix-bindings-expr-sys/src/lib.rs @@ -0,0 +1,10 @@ +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(dead_code)] +#![allow(clippy::all)] + +use nix_bindings_store_sys::*; +use nix_bindings_util_sys::*; + +include!(concat!(env!("OUT_DIR"), "/bindings.rs")); diff --git a/nix-bindings-expr/Cargo.toml b/nix-bindings-expr/Cargo.toml index 4daee1c..a231e3c 100644 --- a/nix-bindings-expr/Cargo.toml +++ b/nix-bindings-expr/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nix-bindings-expr" -version = "0.1.1" +version = "0.2.0" edition = "2021" license = "LGPL-2.1" description = "Rust bindings to Nix expression evaluator" @@ -11,9 +11,12 @@ path = "src/lib.rs" [dependencies] anyhow = "1.0" -nix-bindings-store = { path = "../nix-bindings-store", version = "0.1.1" } -nix-bindings-util = { path = "../nix-bindings-util", version = "0.1.1" } -nix-bindings-util-sys = { path = "../nix-bindings-util-sys", version = "0.1.1" } +nix-bindings-store = { path = "../nix-bindings-store", version = "0.2.0" } +nix-bindings-util = { path = "../nix-bindings-util", version = "0.2.0" } +nix-bindings-bdwgc-sys = { path = "../nix-bindings-bdwgc-sys", version = "0.2.0" } +nix-bindings-util-sys = { path = "../nix-bindings-util-sys", version = "0.2.0" } +nix-bindings-store-sys = { path = "../nix-bindings-store-sys", version = "0.2.0" } +nix-bindings-expr-sys = { path = "../nix-bindings-expr-sys", version = "0.2.0" } lazy_static = "1.4" ctor = "0.2" tempfile = "3.10" diff --git a/nix-bindings-expr/src/eval_state.rs b/nix-bindings-expr/src/eval_state.rs index 44b6945..b34de83 100644 --- a/nix-bindings-expr/src/eval_state.rs +++ b/nix-bindings-expr/src/eval_state.rs @@ -134,14 +134,16 @@ use anyhow::Context as _; use anyhow::{bail, Result}; use cstr::cstr; use lazy_static::lazy_static; +use nix_bindings_bdwgc_sys as gc; +use nix_bindings_expr_sys as raw; use nix_bindings_store::path::StorePath; use nix_bindings_store::store::{Store, StoreWeak}; +use nix_bindings_store_sys as raw_store; use nix_bindings_util::context::Context; use nix_bindings_util::string_return::{ callback_get_result_string, callback_get_result_string_data, }; use nix_bindings_util::{check_call, check_call_opt_key, result_string_init}; -use nix_bindings_util_sys as raw; use std::ffi::{c_char, CString}; use std::iter::FromIterator; use std::os::raw::c_uint; @@ -151,7 +153,7 @@ use std::sync::{Arc, Weak}; lazy_static! { static ref INIT: Result<()> = { unsafe { - raw::GC_allow_register_threads(); + gc::GC_allow_register_threads(); check_call!(raw::libexpr_init(&mut Context::new()))?; Ok(()) } @@ -887,7 +889,7 @@ impl EvalState { let mut paths = Vec::with_capacity(n as usize); for i in 0..n { let path = raw::realised_string_get_store_path(rs, i); - let path = NonNull::new(path as *mut raw::StorePath).ok_or_else(|| { + let path = NonNull::new(path as *mut raw_store::StorePath).ok_or_else(|| { anyhow::format_err!( "nix_realised_string_get_store_path returned a null pointer" ) @@ -1153,7 +1155,7 @@ impl Drop for ThreadRegistrationGuard { fn drop(&mut self) { if self.must_unregister { unsafe { - raw::GC_unregister_my_thread(); + gc::GC_unregister_my_thread(); } } } @@ -1161,14 +1163,14 @@ impl Drop for ThreadRegistrationGuard { fn gc_register_my_thread_do_it() -> Result<()> { unsafe { - let mut sb: raw::GC_stack_base = raw::GC_stack_base { + let mut sb: gc::GC_stack_base = gc::GC_stack_base { mem_base: null_mut(), }; - let r = raw::GC_get_stack_base(&mut sb); - if r as u32 != raw::GC_SUCCESS { + let r = gc::GC_get_stack_base(&mut sb); + if r as u32 != gc::GC_SUCCESS { Err(anyhow::format_err!("GC_get_stack_base failed: {}", r))?; } - raw::GC_register_my_thread(&sb); + gc::GC_register_my_thread(&sb); Ok(()) } } @@ -1179,7 +1181,7 @@ fn gc_register_my_thread_do_it() -> Result<()> { pub fn gc_register_my_thread() -> Result { init()?; unsafe { - let already_done = raw::GC_thread_is_registered(); + let already_done = gc::GC_thread_is_registered(); if already_done != 0 { return Ok(ThreadRegistrationGuard { must_unregister: false, diff --git a/nix-bindings-expr/src/primop.rs b/nix-bindings-expr/src/primop.rs index 7996605..02410fc 100644 --- a/nix-bindings-expr/src/primop.rs +++ b/nix-bindings-expr/src/primop.rs @@ -1,8 +1,9 @@ use crate::eval_state::{EvalState, EvalStateWeak}; use crate::value::Value; use anyhow::Result; +use nix_bindings_expr_sys as raw; use nix_bindings_util::check_call; -use nix_bindings_util_sys as raw; +use nix_bindings_util_sys as raw_util; use std::ffi::{c_int, c_void, CStr, CString}; use std::mem::ManuallyDrop; use std::ptr::{null, null_mut}; @@ -84,7 +85,7 @@ struct PrimOpContext { unsafe extern "C" fn function_adapter( user_data: *mut ::std::os::raw::c_void, - context_out: *mut raw::c_context, + context_out: *mut raw_util::c_context, _state: *mut raw::EvalState, args: *mut *mut raw::Value, ret: *mut raw::Value, @@ -111,7 +112,7 @@ unsafe extern "C" fn function_adapter( CString::new("") .unwrap() }); - raw::set_err_msg(context_out, raw::err_NIX_ERR_UNKNOWN, cstr.as_ptr()); + raw_util::set_err_msg(context_out, raw_util::err_NIX_ERR_UNKNOWN, cstr.as_ptr()); }, } } diff --git a/nix-bindings-expr/src/value.rs b/nix-bindings-expr/src/value.rs index 1d7f866..e75c4df 100644 --- a/nix-bindings-expr/src/value.rs +++ b/nix-bindings-expr/src/value.rs @@ -1,7 +1,7 @@ pub mod __private; +use nix_bindings_expr_sys as raw; use nix_bindings_util::{check_call, context::Context}; -use nix_bindings_util_sys as raw; use std::ptr::{null_mut, NonNull}; // TODO: test: cloning a thunk does not duplicate the evaluation. diff --git a/nix-bindings-expr/src/value/__private.rs b/nix-bindings-expr/src/value/__private.rs index 4d59514..770a217 100644 --- a/nix-bindings-expr/src/value/__private.rs +++ b/nix-bindings-expr/src/value/__private.rs @@ -1,6 +1,6 @@ //! Functions that are relevant for other bindings modules, but normally not end users. use super::Value; -use nix_bindings_util_sys as raw; +use nix_bindings_expr_sys as raw; /// Take ownership of a new [`Value`]. /// diff --git a/nix-bindings-fetchers-sys/Cargo.toml b/nix-bindings-fetchers-sys/Cargo.toml new file mode 100644 index 0000000..6101928 --- /dev/null +++ b/nix-bindings-fetchers-sys/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "nix-bindings-fetchers-sys" +version = "0.2.0" +edition = "2021" +build = "build.rs" +license = "LGPL-2.1" + +[lib] +path = "src/lib.rs" + +[dependencies] +nix-bindings-util-sys = { path = "../nix-bindings-util-sys", version = "0.2.0" } + +[build-dependencies] +bindgen = "0.69" +pkg-config = "0.3" diff --git a/nix-bindings-fetchers-sys/README.md b/nix-bindings-fetchers-sys/README.md new file mode 100644 index 0000000..b403eac --- /dev/null +++ b/nix-bindings-fetchers-sys/README.md @@ -0,0 +1,5 @@ +# nix-bindings-fetchers-sys + +This crate contains generated bindings for the Nix C API (`nix-fetchers-c`). +**You should not have to use this crate directly,** and so you should probably not add it to your dependencies. +Instead, use the `nix-bindings-fetchers` crate, which _should_ be sufficient. diff --git a/nix-bindings-fetchers-sys/build.rs b/nix-bindings-fetchers-sys/build.rs new file mode 100644 index 0000000..34f6640 --- /dev/null +++ b/nix-bindings-fetchers-sys/build.rs @@ -0,0 +1,40 @@ +use std::path::PathBuf; + +#[derive(Debug)] +struct StripNixPrefix; + +impl bindgen::callbacks::ParseCallbacks for StripNixPrefix { + fn item_name(&self, name: &str) -> Option { + name.strip_prefix("nix_").map(String::from) + } +} + +fn main() { + println!("cargo:rerun-if-changed=include/nix-c-fetchers.h"); + println!("cargo:rustc-link-lib=nixfetchersc"); + + let mut args = Vec::new(); + for path in pkg_config::probe_library("nix-fetchers-c") + .unwrap() + .include_paths + .iter() + { + args.push(format!("-I{}", path.to_str().unwrap())); + } + + let out_path = PathBuf::from(std::env::var("OUT_DIR").unwrap()); + + let bindings = bindgen::Builder::default() + .header("include/nix-c-fetchers.h") + .clang_args(args) + .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) + .parse_callbacks(Box::new(StripNixPrefix)) + // Blocklist symbols from nix-bindings-util-sys + .blocklist_file(".*nix_api_util\\.h") + .generate() + .expect("Unable to generate bindings"); + + bindings + .write_to_file(out_path.join("bindings.rs")) + .expect("Couldn't write bindings!"); +} diff --git a/nix-bindings-fetchers-sys/include/nix-c-fetchers.h b/nix-bindings-fetchers-sys/include/nix-c-fetchers.h new file mode 100644 index 0000000..2f4c542 --- /dev/null +++ b/nix-bindings-fetchers-sys/include/nix-c-fetchers.h @@ -0,0 +1 @@ +#include diff --git a/nix-bindings-fetchers-sys/src/lib.rs b/nix-bindings-fetchers-sys/src/lib.rs new file mode 100644 index 0000000..4c5c9fe --- /dev/null +++ b/nix-bindings-fetchers-sys/src/lib.rs @@ -0,0 +1,9 @@ +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(dead_code)] +#![allow(clippy::all)] + +use nix_bindings_util_sys::*; + +include!(concat!(env!("OUT_DIR"), "/bindings.rs")); diff --git a/nix-bindings-fetchers/Cargo.toml b/nix-bindings-fetchers/Cargo.toml index e816590..cf216a0 100644 --- a/nix-bindings-fetchers/Cargo.toml +++ b/nix-bindings-fetchers/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nix-bindings-fetchers" -version = "0.1.1" +version = "0.2.0" edition = "2021" license = "LGPL-2.1" description = "Rust bindings to Nix fetchers" @@ -11,9 +11,9 @@ path = "src/lib.rs" [dependencies] anyhow = "1.0" -nix-bindings-store = { path = "../nix-bindings-store", version = "0.1.1" } -nix-bindings-util = { path = "../nix-bindings-util", version = "0.1.1" } -nix-bindings-util-sys = { path = "../nix-bindings-util-sys", version = "0.1.1" } +nix-bindings-store = { path = "../nix-bindings-store", version = "0.2.0" } +nix-bindings-util = { path = "../nix-bindings-util", version = "0.2.0" } +nix-bindings-fetchers-sys = { path = "../nix-bindings-fetchers-sys", version = "0.2.0" } ctor = "0.2" tempfile = "3.10" cstr = "0.2" diff --git a/nix-bindings-fetchers/src/lib.rs b/nix-bindings-fetchers/src/lib.rs index 2ea0b84..0b7b6cc 100644 --- a/nix-bindings-fetchers/src/lib.rs +++ b/nix-bindings-fetchers/src/lib.rs @@ -1,6 +1,6 @@ use anyhow::{Context as _, Result}; +use nix_bindings_fetchers_sys as raw; use nix_bindings_util::context::{self, Context}; -use nix_bindings_util_sys as raw; use std::ptr::NonNull; pub struct FetchersSettings { diff --git a/nix-bindings-flake-sys/Cargo.toml b/nix-bindings-flake-sys/Cargo.toml new file mode 100644 index 0000000..e53bbe4 --- /dev/null +++ b/nix-bindings-flake-sys/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "nix-bindings-flake-sys" +version = "0.2.0" +edition = "2021" +build = "build.rs" +license = "LGPL-2.1" + +[lib] +path = "src/lib.rs" + +[dependencies] +nix-bindings-util-sys = { path = "../nix-bindings-util-sys", version = "0.2.0" } +nix-bindings-store-sys = { path = "../nix-bindings-store-sys", version = "0.2.0" } +nix-bindings-expr-sys = { path = "../nix-bindings-expr-sys", version = "0.2.0" } +nix-bindings-fetchers-sys = { path = "../nix-bindings-fetchers-sys", version = "0.2.0" } +nix-bindings-bdwgc-sys = { path = "../nix-bindings-bdwgc-sys", version = "0.2.0" } + +[build-dependencies] +bindgen = "0.69" +pkg-config = "0.3" diff --git a/nix-bindings-flake-sys/README.md b/nix-bindings-flake-sys/README.md new file mode 100644 index 0000000..10a9d96 --- /dev/null +++ b/nix-bindings-flake-sys/README.md @@ -0,0 +1,5 @@ +# nix-bindings-flake-sys + +This crate contains generated bindings for the Nix C API (`nix-flake-c`). +**You should not have to use this crate directly,** and so you should probably not add it to your dependencies. +Instead, use the `nix-bindings-flake` crate, which _should_ be sufficient. diff --git a/nix-bindings-flake-sys/build.rs b/nix-bindings-flake-sys/build.rs new file mode 100644 index 0000000..1fb3233 --- /dev/null +++ b/nix-bindings-flake-sys/build.rs @@ -0,0 +1,56 @@ +use std::path::PathBuf; + +#[derive(Debug)] +struct StripNixPrefix; + +impl bindgen::callbacks::ParseCallbacks for StripNixPrefix { + fn item_name(&self, name: &str) -> Option { + name.strip_prefix("nix_").map(String::from) + } +} + +fn main() { + println!("cargo:rerun-if-changed=include/nix-c-flake.h"); + println!("cargo:rustc-link-lib=nixflakec"); + + let mut args = Vec::new(); + for path in pkg_config::probe_library("nix-flake-c") + .unwrap() + .include_paths + .iter() + { + args.push(format!("-I{}", path.to_str().unwrap())); + } + for path in pkg_config::probe_library("bdw-gc") + .unwrap() + .include_paths + .iter() + { + args.push(format!("-I{}", path.to_str().unwrap())); + } + + let out_path = PathBuf::from(std::env::var("OUT_DIR").unwrap()); + + let bindings = bindgen::Builder::default() + .header("include/nix-c-flake.h") + .clang_args(args) + .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) + .parse_callbacks(Box::new(StripNixPrefix)) + // Blocklist symbols from nix-bindings-util-sys + .blocklist_file(".*nix_api_util\\.h") + // Blocklist symbols from nix-bindings-store-sys + .blocklist_file(".*nix_api_store\\.h") + // Blocklist symbols from nix-bindings-expr-sys + .blocklist_file(".*nix_api_expr\\.h") + .blocklist_file(".*nix_api_value\\.h") + // Blocklist symbols from nix-bindings-fetchers-sys + .blocklist_file(".*nix_api_fetchers\\.h") + // Blocklist symbols from nix-bindings-bdwgc-sys + .blocklist_file(".*/gc\\.h") + .generate() + .expect("Unable to generate bindings"); + + bindings + .write_to_file(out_path.join("bindings.rs")) + .expect("Couldn't write bindings!"); +} diff --git a/nix-bindings-flake-sys/include/nix-c-flake.h b/nix-bindings-flake-sys/include/nix-c-flake.h new file mode 100644 index 0000000..89a45f1 --- /dev/null +++ b/nix-bindings-flake-sys/include/nix-c-flake.h @@ -0,0 +1,3 @@ +#define GC_THREADS +#include +#include diff --git a/nix-bindings-flake-sys/src/lib.rs b/nix-bindings-flake-sys/src/lib.rs new file mode 100644 index 0000000..1bcac64 --- /dev/null +++ b/nix-bindings-flake-sys/src/lib.rs @@ -0,0 +1,11 @@ +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(dead_code)] +#![allow(clippy::all)] + +use nix_bindings_expr_sys::*; +use nix_bindings_fetchers_sys::*; +use nix_bindings_util_sys::*; + +include!(concat!(env!("OUT_DIR"), "/bindings.rs")); diff --git a/nix-bindings-flake/Cargo.toml b/nix-bindings-flake/Cargo.toml index 7a76906..78e8460 100644 --- a/nix-bindings-flake/Cargo.toml +++ b/nix-bindings-flake/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nix-bindings-flake" -version = "0.1.1" +version = "0.2.0" edition = "2021" license = "LGPL-2.1" description = "Rust bindings to Nix flakes" @@ -11,11 +11,11 @@ path = "src/lib.rs" [dependencies] anyhow = "1.0" -nix-bindings-expr = { path = "../nix-bindings-expr", version = "0.1.1" } -nix-bindings-fetchers = { path = "../nix-bindings-fetchers", version = "0.1.1" } -nix-bindings-store = { path = "../nix-bindings-store", version = "0.1.1" } -nix-bindings-util = { path = "../nix-bindings-util", version = "0.1.1" } -nix-bindings-util-sys = { path = "../nix-bindings-util-sys", version = "0.1.1" } +nix-bindings-expr = { path = "../nix-bindings-expr", version = "0.2.0" } +nix-bindings-fetchers = { path = "../nix-bindings-fetchers", version = "0.2.0" } +nix-bindings-store = { path = "../nix-bindings-store", version = "0.2.0" } +nix-bindings-util = { path = "../nix-bindings-util", version = "0.2.0" } +nix-bindings-flake-sys = { path = "../nix-bindings-flake-sys", version = "0.2.0" } lazy_static = "1.4" ctor = "0.2" tempfile = "3.10" diff --git a/nix-bindings-flake/src/lib.rs b/nix-bindings-flake/src/lib.rs index 5da43dc..cb8e850 100644 --- a/nix-bindings-flake/src/lib.rs +++ b/nix-bindings-flake/src/lib.rs @@ -3,12 +3,12 @@ use std::{ffi::CString, os::raw::c_char, ptr::NonNull}; use anyhow::{Context as _, Result}; use nix_bindings_expr::eval_state::EvalState; use nix_bindings_fetchers::FetchersSettings; +use nix_bindings_flake_sys as raw; use nix_bindings_util::{ context::{self, Context}, result_string_init, string_return::{callback_get_result_string, callback_get_result_string_data}, }; -use nix_bindings_util_sys as raw; /// Store settings for the flakes feature. pub struct FlakeSettings { diff --git a/nix-bindings-store-sys/Cargo.toml b/nix-bindings-store-sys/Cargo.toml new file mode 100644 index 0000000..c098860 --- /dev/null +++ b/nix-bindings-store-sys/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "nix-bindings-store-sys" +version = "0.2.0" +edition = "2021" +build = "build.rs" +license = "LGPL-2.1" + +[lib] +path = "src/lib.rs" + +[dependencies] +nix-bindings-util-sys = { path = "../nix-bindings-util-sys", version = "0.2.0" } + +[build-dependencies] +bindgen = "0.69" +pkg-config = "0.3" diff --git a/nix-bindings-store-sys/README.md b/nix-bindings-store-sys/README.md new file mode 100644 index 0000000..73138ee --- /dev/null +++ b/nix-bindings-store-sys/README.md @@ -0,0 +1,5 @@ +# nix-bindings-store-sys + +This crate contains generated bindings for the Nix C API (`nix-store-c`). +**You should not have to use this crate directly,** and so you should probably not add it to your dependencies. +Instead, use the `nix-bindings-store` crate, which _should_ be sufficient. diff --git a/nix-bindings-store-sys/build.rs b/nix-bindings-store-sys/build.rs new file mode 100644 index 0000000..bafdfae --- /dev/null +++ b/nix-bindings-store-sys/build.rs @@ -0,0 +1,40 @@ +use std::path::PathBuf; + +#[derive(Debug)] +struct StripNixPrefix; + +impl bindgen::callbacks::ParseCallbacks for StripNixPrefix { + fn item_name(&self, name: &str) -> Option { + name.strip_prefix("nix_").map(String::from) + } +} + +fn main() { + println!("cargo:rerun-if-changed=include/nix-c-store.h"); + println!("cargo:rustc-link-lib=nixstorec"); + + let mut args = Vec::new(); + for path in pkg_config::probe_library("nix-store-c") + .unwrap() + .include_paths + .iter() + { + args.push(format!("-I{}", path.to_str().unwrap())); + } + + let out_path = PathBuf::from(std::env::var("OUT_DIR").unwrap()); + + let bindings = bindgen::Builder::default() + .header("include/nix-c-store.h") + .clang_args(args) + .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) + .parse_callbacks(Box::new(StripNixPrefix)) + // Blocklist symbols from nix-bindings-util-sys + .blocklist_file(".*nix_api_util\\.h") + .generate() + .expect("Unable to generate bindings"); + + bindings + .write_to_file(out_path.join("bindings.rs")) + .expect("Couldn't write bindings!"); +} diff --git a/nix-bindings-store-sys/include/nix-c-store.h b/nix-bindings-store-sys/include/nix-c-store.h new file mode 100644 index 0000000..2c04d1d --- /dev/null +++ b/nix-bindings-store-sys/include/nix-c-store.h @@ -0,0 +1 @@ +#include diff --git a/nix-bindings-store-sys/src/lib.rs b/nix-bindings-store-sys/src/lib.rs new file mode 100644 index 0000000..4c5c9fe --- /dev/null +++ b/nix-bindings-store-sys/src/lib.rs @@ -0,0 +1,9 @@ +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(dead_code)] +#![allow(clippy::all)] + +use nix_bindings_util_sys::*; + +include!(concat!(env!("OUT_DIR"), "/bindings.rs")); diff --git a/nix-bindings-store/Cargo.toml b/nix-bindings-store/Cargo.toml index 2754072..e0ed8a0 100644 --- a/nix-bindings-store/Cargo.toml +++ b/nix-bindings-store/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nix-bindings-store" -version = "0.1.1" +version = "0.2.0" edition = "2021" build = "build.rs" license = "LGPL-2.1" @@ -12,8 +12,9 @@ path = "src/lib.rs" [dependencies] anyhow = "1.0" -nix-bindings-util = { path = "../nix-bindings-util", version = "0.1.1" } -nix-bindings-util-sys = { path = "../nix-bindings-util-sys", version = "0.1.1" } +nix-bindings-util = { path = "../nix-bindings-util", version = "0.2.0" } +nix-bindings-util-sys = { path = "../nix-bindings-util-sys", version = "0.2.0" } +nix-bindings-store-sys = { path = "../nix-bindings-store-sys", version = "0.2.0" } lazy_static = "1.4" [dev-dependencies] @@ -23,7 +24,7 @@ tempfile = "3.10" [build-dependencies] pkg-config = "0.3" # Needed for version parsing in build.rs -nix-bindings-util = { path = "../nix-bindings-util", version = "0.1.1" } +nix-bindings-util = { path = "../nix-bindings-util", version = "0.2.0" } [lints.rust] warnings = "deny" diff --git a/nix-bindings-store/src/derivation.rs b/nix-bindings-store/src/derivation.rs index f036dce..a1ee1c6 100644 --- a/nix-bindings-store/src/derivation.rs +++ b/nix-bindings-store/src/derivation.rs @@ -1,6 +1,6 @@ #![cfg(nix_at_least = "2.33.0pre")] -use nix_bindings_util_sys as raw; +use nix_bindings_store_sys as raw; use std::ptr::NonNull; /// A Nix derivation diff --git a/nix-bindings-store/src/path.rs b/nix-bindings-store/src/path.rs index ca694f2..51469af 100644 --- a/nix-bindings-store/src/path.rs +++ b/nix-bindings-store/src/path.rs @@ -1,11 +1,11 @@ use std::ptr::NonNull; use anyhow::Result; +use nix_bindings_store_sys as raw; use nix_bindings_util::{ result_string_init, string_return::{callback_get_result_string, callback_get_result_string_data}, }; -use nix_bindings_util_sys as raw; pub struct StorePath { raw: NonNull, diff --git a/nix-bindings-store/src/store.rs b/nix-bindings-store/src/store.rs index 61b60b6..d884c69 100644 --- a/nix-bindings-store/src/store.rs +++ b/nix-bindings-store/src/store.rs @@ -1,11 +1,12 @@ use anyhow::{bail, Error, Result}; use lazy_static::lazy_static; +use nix_bindings_store_sys as raw; use nix_bindings_util::context::Context; use nix_bindings_util::string_return::{ callback_get_result_string, callback_get_result_string_data, }; use nix_bindings_util::{check_call, result_string_init}; -use nix_bindings_util_sys as raw; +use nix_bindings_util_sys as raw_util; #[cfg(nix_at_least = "2.33.0pre")] use std::collections::BTreeMap; use std::collections::HashMap; @@ -73,7 +74,7 @@ lazy_static! { #[cfg(nix_at_least = "2.33.0pre")] unsafe extern "C" fn callback_get_result_store_path_set( - _context: *mut raw::c_context, + _context: *mut raw_util::c_context, user_data: *mut std::os::raw::c_void, store_path: *const raw::StorePath, ) { diff --git a/nix-bindings-util-sys/Cargo.toml b/nix-bindings-util-sys/Cargo.toml index f450317..e37bf1a 100644 --- a/nix-bindings-util-sys/Cargo.toml +++ b/nix-bindings-util-sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nix-bindings-util-sys" -version = "0.1.1" +version = "0.2.0" edition = "2021" build = "build.rs" license = "LGPL-2.1" @@ -10,6 +10,8 @@ repository = "https://github.com/nixops4/nix-bindings-rust" [lib] path = "src/lib.rs" +[dependencies] + [build-dependencies] bindgen = "0.69" pkg-config = "0.3" diff --git a/nix-bindings-util-sys/README.md b/nix-bindings-util-sys/README.md index b74d9a1..82debbf 100644 --- a/nix-bindings-util-sys/README.md +++ b/nix-bindings-util-sys/README.md @@ -1,12 +1,5 @@ # nix-bindings-util-sys -This crate contains generated bindings for the Nix C API. +This crate contains generated bindings for the Nix C API (`nix-util-c`). **You should not have to use this crate directly,** and so you should probably not add it to your dependencies. -Instead, use the `nix-bindings-util`, `nix-bindings-store` and `nix-bindings-expr` crates, which _should_ be sufficient. - -## Design - -Rust bindgen currently does not allow "layered" libraries to be split into separate crates. -For example, the expr crate would have all-new types that are distinct and incompatible with the store crate. - -Ideally bindgen will support reusing already generated modules, and we could move the code generation into the appropriate crates, so that the system dependencies of each crate become accurate. +Instead, use the `nix-bindings-util` crate, which _should_ be sufficient. diff --git a/nix-bindings-util-sys/build.rs b/nix-bindings-util-sys/build.rs index 5dbdbc7..2851ee2 100644 --- a/nix-bindings-util-sys/build.rs +++ b/nix-bindings-util-sys/build.rs @@ -11,12 +11,12 @@ impl bindgen::callbacks::ParseCallbacks for StripNixPrefix { fn main() { // Tell cargo to invalidate the built crate whenever the wrapper changes - println!("cargo:rerun-if-changed=include/nix-c-raw.h"); - println!("cargo:rustc-link-lib=nixflake"); + println!("cargo:rerun-if-changed=include/nix-c-util.h"); + println!("cargo:rustc-link-lib=nixutil"); // https://rust-lang.github.io/rust-bindgen/library-usage.html let bindings = bindgen::Builder::default() - .header("include/nix-c-raw.h") + .header("include/nix-c-util.h") // Find the includes .clang_args(c_headers()) // Tell cargo to invalidate the built crate whenever any of the @@ -38,15 +38,7 @@ fn main() { fn c_headers() -> Vec { let mut args = Vec::new(); // args.push("-isystem".to_string()); - for path in pkg_config::probe_library("nix-flake-c") - .unwrap() - .include_paths - .iter() - { - args.push(format!("-I{}", path.to_str().unwrap())); - } - - for path in pkg_config::probe_library("bdw-gc") + for path in pkg_config::probe_library("nix-util-c") .unwrap() .include_paths .iter() diff --git a/nix-bindings-util-sys/include/nix-c-raw.h b/nix-bindings-util-sys/include/nix-c-raw.h deleted file mode 100644 index 88e252f..0000000 --- a/nix-bindings-util-sys/include/nix-c-raw.h +++ /dev/null @@ -1,7 +0,0 @@ -#include -#include -#define GC_THREADS -#include -#include -#include -#include diff --git a/nix-bindings-util-sys/include/nix-c-util.h b/nix-bindings-util-sys/include/nix-c-util.h new file mode 100644 index 0000000..7fd0bc6 --- /dev/null +++ b/nix-bindings-util-sys/include/nix-c-util.h @@ -0,0 +1 @@ +#include diff --git a/nix-bindings-util/Cargo.toml b/nix-bindings-util/Cargo.toml index fcf1aba..6c0d9db 100644 --- a/nix-bindings-util/Cargo.toml +++ b/nix-bindings-util/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nix-bindings-util" -version = "0.1.1" +version = "0.2.0" edition = "2021" license = "LGPL-2.1" description = "Rust bindings to Nix utility library" @@ -11,7 +11,9 @@ path = "src/lib.rs" [dependencies] anyhow = "1.0" -nix-bindings-util-sys = { path = "../nix-bindings-util-sys", version = "0.1.1" } +nix-bindings-util-sys = { path = "../nix-bindings-util-sys", version = "0.2.0" } + +[dev-dependencies] ctor = "0.2" [lints.rust] diff --git a/nix-bindings-util/src/context.rs b/nix-bindings-util/src/context.rs index af82b27..dbb333e 100644 --- a/nix-bindings-util/src/context.rs +++ b/nix-bindings-util/src/context.rs @@ -113,7 +113,7 @@ macro_rules! check_call_opt_key { { let ctx : &mut $crate::context::Context = $ctx; let ret = $($f)::*(ctx.ptr(), $($arg,)*); - if unsafe { raw::err_code(ctx.ptr()) == raw::err_NIX_ERR_KEY } { + if unsafe { $crate::raw_sys::err_code(ctx.ptr()) == $crate::raw_sys::err_NIX_ERR_KEY } { ctx.clear(); return Ok(None); } diff --git a/nix-bindings-util/src/lib.rs b/nix-bindings-util/src/lib.rs index c74208c..f626d96 100644 --- a/nix-bindings-util/src/lib.rs +++ b/nix-bindings-util/src/lib.rs @@ -3,3 +3,6 @@ pub mod settings; #[macro_use] pub mod string_return; pub mod nix_version; + +// Re-export for use in macros +pub use nix_bindings_util_sys as raw_sys; diff --git a/nix-bindings-util/src/settings.rs b/nix-bindings-util/src/settings.rs index 72af247..8c213aa 100644 --- a/nix-bindings-util/src/settings.rs +++ b/nix-bindings-util/src/settings.rs @@ -74,20 +74,20 @@ mod tests { fn setup() { let mut ctx = context::Context::new(); unsafe { - check_call!(raw::libstore_init(&mut ctx)).unwrap(); + check_call!(nix_bindings_util_sys::libutil_init(&mut ctx)).unwrap(); } } #[test] fn set_get() { // Something that shouldn't matter if it's a different value temporarily - let key = "user-agent-suffix"; + let key = "json-log-path"; // Save the old value, in case it's important. Probably not. // If this doesn't work, pick a different setting to test with let old_value = get(key).unwrap(); - let new_value = "just a string that we're storing into some option for testing purposes"; + let new_value = "/just/a/path/that/we/are/storing/into/some/option/for/testing/purposes"; let res_e = (|| { set(key, new_value)?; From 6110414520617d2ea279ee5b44b726aba4699a04 Mon Sep 17 00:00:00 2001 From: Robert Hensing Date: Tue, 13 Jan 2026 15:25:57 +0100 Subject: [PATCH 2/2] Add automatic C library input propagation workaround Automatically adds Nix C library build inputs based on which nix-bindings crates are dependencies, working around missing native input propagation in nix-cargo-integration. The workaround inspects the dreamLock to detect: - If the crate being built is a nix-bindings crate (adds its own inputs) - Direct dependencies on nix-bindings crates (adds their inputs) The mapping is recursive via lazyAttrsOf, so depending on nix-bindings-flake automatically brings in transitive C library dependencies. Downstream consumers can extend the mapping for their own multi-crate workspaces where crate A depends on crate B which depends on nix-bindings. --- flake.nix | 25 +++--- input-propagation-workaround.nix | 143 +++++++++++++++++++++++++++++++ nci.nix | 54 +----------- 3 files changed, 156 insertions(+), 66 deletions(-) create mode 100644 input-propagation-workaround.nix diff --git a/flake.nix b/flake.nix index ddd12be..a8295dd 100644 --- a/flake.nix +++ b/flake.nix @@ -28,6 +28,7 @@ }: { _file = ./flake.nix; + imports = [ ./input-propagation-workaround.nix ]; options.perSystem = flake-parts-lib.mkPerSystemOption ( { pkgs, ... }: { @@ -46,24 +47,20 @@ A module to load into your nix-cargo-integration [`perSystem.nci.projects..depsDrvConfig`](https://flake.parts/options/nix-cargo-integration.html#opt-perSystem.nci.projects._name_.depsDrvConfig) or similar such options. - This provides common build configuration (pkg-config, libclang, etc.) but you must - add the specific Nix C libraries your crates need to `buildInputs`: - - `nix-bindings-util-sys` needs `nix-util-c` - - `nix-bindings-store-sys` needs `nix-store-c` - - `nix-bindings-expr-sys` needs `nix-expr-c` - - `nix-bindings-fetchers-sys` needs `nix-fetchers-c` (Nix >= 2.29) - - `nix-bindings-flake-sys` needs `nix-flake-c` - - `nix-bindings-bdwgc-sys` needs `boehmgc` + This provides common build configuration (pkg-config, libclang, etc.) and + automatically adds Nix C library build inputs based on which nix-bindings + crates are *direct* dependencies of your crate. + + To disable automatic build input detection: + ```nix + nix-bindings-rust.inputPropagationWorkaround.enable = false; + ``` Example: ```nix - perSystem = perSystem@{ config, pkgs, ... }: { - nci.projects."my_project".depsDrvConfig = { + perSystem = perSystem@{ config, ... }: { + nci.projects."my_project".drvConfig = { imports = [ perSystem.config.nix-bindings-rust.nciBuildConfig ]; - mkDerivation.buildInputs = [ - perSystem.config.nix-bindings-rust.nixPackage.libs.nix-store-c - # ... add other libs as needed - ]; }; } ``` diff --git a/input-propagation-workaround.nix b/input-propagation-workaround.nix new file mode 100644 index 0000000..c3ac92f --- /dev/null +++ b/input-propagation-workaround.nix @@ -0,0 +1,143 @@ +# Workaround for missing native input propagation in nix-cargo-integration +# +# Automatically adds Nix C library build inputs based on which nix-bindings +# crates are direct dependencies of the crate being built. The mapping is +# recursive, so depending on nix-bindings-flake will also bring in the +# transitive C library dependencies (nix-fetchers-c, nix-expr-c, etc.). +# +# Note: For multi-crate workspaces, if your crate A depends on your crate B +# which depends on nix-bindings, you'll need to add an A -> B mapping to +# `crateInputMapping` so that A also gets B's nix-bindings inputs. +{ + perSystem = + { + lib, + config, + pkgs, + ... + }: + let + cfg = config.nix-bindings-rust.inputPropagationWorkaround; + nixPackage = config.nix-bindings-rust.nixPackage; + + nixLibs = + if nixPackage ? libs then + nixPackage.libs + else + # Fallback for older Nix versions without split libs + { + nix-util-c = nixPackage; + nix-store-c = nixPackage; + nix-expr-c = nixPackage; + nix-fetchers-c = nixPackage; + nix-flake-c = nixPackage; + }; + + # A module for nciBuildConfig that sets buildInputs based on nix-bindings dependencies. + # Uses options inspection to detect drvConfig vs depsDrvConfig context. + workaroundModule = + { + lib, + config, + options, + ... + }: + let + # rust-cargo-lock exists in drvConfig but not depsDrvConfig + isDrvConfig = options ? rust-cargo-lock; + + dreamLock = config.rust-cargo-lock.dreamLock; + depsList = dreamLock.dependencies.${config.name}.${config.version} or [ ]; + + # Convert list of deps to attrset keyed by name for efficient lookup + deps = builtins.listToAttrs ( + map (dep: { + name = dep.name; + value = dep; + }) depsList + ); + + # Inputs for the crate itself if it's in the mapping + selfInputs = cfg.crateInputMapping.${config.name} or [ ]; + + # Inputs for direct dependencies that have mappings + depInputs = lib.concatLists (lib.attrValues (lib.intersectAttrs deps cfg.crateInputMapping)); + + allInputs = selfInputs ++ depInputs; + in + { + config = lib.optionalAttrs isDrvConfig { + mkDerivation.buildInputs = allInputs; + rust-crane.depsDrv.mkDerivation.buildInputs = allInputs; + }; + }; + in + { + options.nix-bindings-rust.inputPropagationWorkaround = { + enable = lib.mkOption { + type = lib.types.bool; + default = true; + description = '' + Whether to automatically add Nix C library build inputs based on + which nix-bindings crates are direct dependencies. + + Set to `false` to disable automatic detection and specify buildInputs manually. + ''; + }; + + crateInputMapping = lib.mkOption { + type = lib.types.lazyAttrsOf (lib.types.listOf lib.types.package); + description = '' + Mapping from crate names to build inputs. Entries can reference + other entries for transitive dependencies. + + The input propagation workaround can see direct dependencies, so + if you have `my-crate -> nix-bindings`, that works out of the box. + If you have `my-other-crate -> my-crate -> nix-bindings`, then you + need to specify `my-other-crate -> my-crate` as follows: + + ```nix + nix-bindings-rust.inputPropagationWorkaround.crateInputMapping."my-other-crate" = + config.nix-bindings-rust.inputPropagationWorkaround.crateInputMapping."my-crate"; + ``` + ''; + default = { }; + }; + }; + + config = lib.mkIf cfg.enable { + nix-bindings-rust.inputPropagationWorkaround.crateInputMapping = { + # -sys crates with their transitive dependencies + "nix-bindings-bdwgc-sys" = [ pkgs.boehmgc ]; + "nix-bindings-util-sys" = [ nixLibs.nix-util-c.dev ]; + "nix-bindings-store-sys" = [ + nixLibs.nix-store-c.dev + ] + ++ cfg.crateInputMapping."nix-bindings-util-sys"; + "nix-bindings-expr-sys" = [ + nixLibs.nix-expr-c.dev + ] + ++ cfg.crateInputMapping."nix-bindings-store-sys" + ++ cfg.crateInputMapping."nix-bindings-bdwgc-sys"; + "nix-bindings-fetchers-sys" = [ + nixLibs.nix-fetchers-c.dev + ] + ++ cfg.crateInputMapping."nix-bindings-expr-sys"; + "nix-bindings-flake-sys" = [ + nixLibs.nix-flake-c.dev + ] + ++ cfg.crateInputMapping."nix-bindings-fetchers-sys" + ++ cfg.crateInputMapping."nix-bindings-bdwgc-sys"; + # High-level crates reference their -sys counterparts + "nix-bindings-bdwgc" = cfg.crateInputMapping."nix-bindings-bdwgc-sys"; + "nix-bindings-util" = cfg.crateInputMapping."nix-bindings-util-sys"; + "nix-bindings-store" = cfg.crateInputMapping."nix-bindings-store-sys"; + "nix-bindings-expr" = cfg.crateInputMapping."nix-bindings-expr-sys"; + "nix-bindings-fetchers" = cfg.crateInputMapping."nix-bindings-fetchers-sys"; + "nix-bindings-flake" = cfg.crateInputMapping."nix-bindings-flake-sys"; + }; + + nix-bindings-rust.nciBuildConfig.imports = [ workaroundModule ]; + }; + }; +} diff --git a/nci.nix b/nci.nix index 9a468b6..62c523e 100644 --- a/nci.nix +++ b/nci.nix @@ -1,24 +1,8 @@ { perSystem = - { - config, - pkgs, - ... - }: + { config, ... }: let cfg = config.nix-bindings-rust; - nixLibs = - if cfg.nixPackage ? libs then - cfg.nixPackage.libs - else - # Fallback for older Nix versions without split libs - { - nix-util-c = cfg.nixPackage; - nix-store-c = cfg.nixPackage; - nix-expr-c = cfg.nixPackage; - nix-fetchers-c = cfg.nixPackage; - nix-flake-c = cfg.nixPackage; - }; in { # https://flake.parts/options/nix-cargo-integration @@ -31,7 +15,7 @@ drvConfig = { imports = [ # Downstream projects import this into depsDrvConfig instead - config.nix-bindings-rust.nciBuildConfig + cfg.nciBuildConfig ]; # Extra settings for running the tests mkDerivation = { @@ -65,39 +49,5 @@ }; }; }; - - # Per-crate configuration: only provide the specific Nix libs each crate needs - # FIXME should use propagatedBuildInputs - nci.crates.nix-bindings-bdwgc-sys.drvConfig.mkDerivation.buildInputs = [ - pkgs.boehmgc - ]; - nci.crates.nix-bindings-util-sys.drvConfig.mkDerivation.buildInputs = [ - nixLibs.nix-util-c - ]; - nci.crates.nix-bindings-util.drvConfig.mkDerivation.buildInputs = - config.nci.crates.nix-bindings-util-sys.drvConfig.mkDerivation.buildInputs; - nci.crates.nix-bindings-store-sys.drvConfig.mkDerivation.buildInputs = - config.nci.crates.nix-bindings-util-sys.drvConfig.mkDerivation.buildInputs - ++ [ nixLibs.nix-store-c ]; - nci.crates.nix-bindings-store.drvConfig.mkDerivation.buildInputs = - config.nci.crates.nix-bindings-store-sys.drvConfig.mkDerivation.buildInputs; - nci.crates.nix-bindings-expr-sys.drvConfig.mkDerivation.buildInputs = - config.nci.crates.nix-bindings-store-sys.drvConfig.mkDerivation.buildInputs - ++ [ - nixLibs.nix-expr-c - pkgs.boehmgc - ]; - nci.crates.nix-bindings-expr.drvConfig.mkDerivation.buildInputs = - config.nci.crates.nix-bindings-expr-sys.drvConfig.mkDerivation.buildInputs; - nci.crates.nix-bindings-fetchers-sys.drvConfig.mkDerivation.buildInputs = - config.nci.crates.nix-bindings-expr-sys.drvConfig.mkDerivation.buildInputs - ++ [ nixLibs.nix-fetchers-c ]; - nci.crates.nix-bindings-fetchers.drvConfig.mkDerivation.buildInputs = - config.nci.crates.nix-bindings-fetchers-sys.drvConfig.mkDerivation.buildInputs; - nci.crates.nix-bindings-flake-sys.drvConfig.mkDerivation.buildInputs = - config.nci.crates.nix-bindings-fetchers-sys.drvConfig.mkDerivation.buildInputs - ++ [ nixLibs.nix-flake-c ]; - nci.crates.nix-bindings-flake.drvConfig.mkDerivation.buildInputs = - config.nci.crates.nix-bindings-flake-sys.drvConfig.mkDerivation.buildInputs; }; }