Merge pull request #27 from nixops4/split-raw

Split monolithic raw crates into sys crates
This commit is contained in:
Robert Hensing 2026-01-13 15:46:37 +01:00 committed by GitHub
commit 95a8d49693
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
52 changed files with 665 additions and 108 deletions

69
Cargo.lock generated
View file

@ -208,37 +208,67 @@ 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",
"pkg-config",
"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",
@ -246,28 +276,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",
@ -276,7 +329,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

@ -28,11 +28,9 @@
}:
{
_file = ./flake.nix;
imports = [ ./input-propagation-workaround.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 +47,21 @@
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.) 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, ... }: {
nci.projects."my_project".depsDrvConfig = perSystem.config.nix-bindings-rust.nciBuildConfig;
nci.projects."my_project".drvConfig = {
imports = [ perSystem.config.nix-bindings-rust.nciBuildConfig ];
};
}
```
'';
@ -64,22 +73,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
];

View file

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

12
nci.nix
View file

@ -1,9 +1,9 @@
{
perSystem =
{
config,
...
}:
{ config, ... }:
let
cfg = config.nix-bindings-rust;
in
{
# https://flake.parts/options/nix-cargo-integration
nci.projects.nix-bindings = {
@ -15,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 = {
@ -42,7 +42,7 @@
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."
'';

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"
build = "build.rs"
license = "LGPL-2.1"
@ -12,9 +12,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(())
}
@ -914,7 +916,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"
)
@ -1180,7 +1182,7 @@ impl Drop for ThreadRegistrationGuard {
fn drop(&mut self) {
if self.must_unregister {
unsafe {
raw::GC_unregister_my_thread();
gc::GC_unregister_my_thread();
}
}
}
@ -1188,14 +1190,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(())
}
}
@ -1206,7 +1208,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)?;