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
This commit is contained in:
John Ericson 2025-12-06 15:44:20 -05:00
parent 485070ffa9
commit dbb00333b1
51 changed files with 571 additions and 104 deletions

69
Cargo.lock generated
View file

@ -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",

View file

@ -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",

View file

@ -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.<name>.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
];

52
nci.nix
View file

@ -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;
};
}

View file

@ -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"

View file

@ -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.

View file

@ -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!");
}

View file

@ -0,0 +1,2 @@
#define GC_THREADS
#include <gc/gc.h>

View file

@ -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"));

View file

@ -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"

View file

@ -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.

View file

@ -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<String> {
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!");
}

View file

@ -0,0 +1,2 @@
#include <nix_api_expr.h>
#include <nix_api_value.h>

View file

@ -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"));

View file

@ -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"

View file

@ -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<ThreadRegistrationGuard> {
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,

View file

@ -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("<rust nix-expr application error message contained null byte>")
.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());
},
}
}

View file

@ -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.

View file

@ -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`].
///

View file

@ -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"

View file

@ -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.

View file

@ -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<String> {
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!");
}

View file

@ -0,0 +1 @@
#include <nix_api_fetchers.h>

View file

@ -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"));

View file

@ -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"

View file

@ -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 {

View file

@ -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"

View file

@ -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.

View file

@ -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<String> {
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!");
}

View file

@ -0,0 +1,3 @@
#define GC_THREADS
#include <gc/gc.h>
#include <nix_api_flake.h>

View file

@ -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"));

View file

@ -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"

View file

@ -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 {

View file

@ -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"

View file

@ -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.

View file

@ -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<String> {
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!");
}

View file

@ -0,0 +1 @@
#include <nix_api_store.h>

View file

@ -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"));

View file

@ -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"

View file

@ -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

View file

@ -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<raw::StorePath>,

View file

@ -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,
) {

View file

@ -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"

View file

@ -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.

View file

@ -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<String> {
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()

View file

@ -1,7 +0,0 @@
#include <nix_api_util.h>
#include <nix_api_store.h>
#define GC_THREADS
#include <gc/gc.h>
#include <nix_api_expr.h>
#include <nix_api_value.h>
#include <nix_api_flake.h>

View file

@ -0,0 +1 @@
#include <nix_api_util.h>

View file

@ -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]

View file

@ -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);
}

View file

@ -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;

View file

@ -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)?;