diff --git a/Cargo.lock b/Cargo.lock index 3ed416d82..855a21ac3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -39,6 +39,10 @@ dependencies = [ "rowan", ] +[[package]] +name = "lixutil-rs" +version = "0.0.0" + [[package]] name = "once_cell" version = "1.19.0" diff --git a/Cargo.toml b/Cargo.toml index 0fbb1db51..1dcabac33 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] resolver = "2" -members = ["lix/lix-doc"] +members = ["lix/lix-doc", "lix/libutil"] [workspace.package] edition = "2021" diff --git a/lix/libutil/Cargo.toml b/lix/libutil/Cargo.toml new file mode 100644 index 000000000..aa1fa2055 --- /dev/null +++ b/lix/libutil/Cargo.toml @@ -0,0 +1,13 @@ +# Note: this is not really intended to actually do anything with Cargo, it +# exists to make Cargo manage dependencies in a workspace across lix-doc and +# liblixrust +# +# It is highly likely it will not actually pass build, especially as the build +# system gets more anti-Cargo. + +[package] +name = "lixutil-rs" +edition.workspace = true + +[lib] +path = "lib.rs" diff --git a/lix/libutil/cbindgen.toml b/lix/libutil/cbindgen.toml new file mode 100644 index 000000000..465196338 --- /dev/null +++ b/lix/libutil/cbindgen.toml @@ -0,0 +1,2 @@ +language = "C++" +namespace = "nix" diff --git a/lix/libutil/lib.rs b/lix/libutil/lib.rs new file mode 100644 index 000000000..eb281a07c --- /dev/null +++ b/lix/libutil/lib.rs @@ -0,0 +1,14 @@ +#[repr(C)] +pub struct TestMultiplyArgs { + pub a: u64, + pub b: u64, +} + +#[no_mangle] +pub extern "C" fn test_multiply(args: TestMultiplyArgs) -> u64 { + args.a * args.b +} + +pub mod exports { + pub use super::test_multiply; +} diff --git a/lix/libutil/meson.build b/lix/libutil/meson.build index cedab1952..bbd766689 100644 --- a/lix/libutil/meson.build +++ b/lix/libutil/meson.build @@ -344,6 +344,10 @@ dependencies = [ nlohmann_json, openssl, libatomic, + + # NOTE: this is secretly rust-monocrate in a trenchcoat. + # See that directory's README for more details. + liblixutil_rs, ] libutil_temp = library( @@ -422,6 +426,8 @@ liblixutil = declare_dependency( libarchive, nlohmann_json, libatomic, + # This is secretly rust-monocrate + the generated header. + liblixutil_rs, ], link_with : libutil ) diff --git a/lix/meson.build b/lix/meson.build index 207fcb1a7..33a06bfb9 100644 --- a/lix/meson.build +++ b/lix/meson.build @@ -25,8 +25,54 @@ install_headers(config_h, subdir : 'lix') # Subcomponents: these link into artifacts themselves, and have interdependencies. subdir('lix-doc') +# We manage libutil's Rust components here, because subdir(rust-monocrate) +# needs libutil's Rust components, and subdir(libutil) needs rust-monocrate. +# FIXME?: Should libutil-rs just be in a separate directory from libutil, then? +libutil_rs_sources = files( + 'libutil/lib.rs', +) +libutil_rs = static_library( + 'lixutil_rs', + sources : libutil_rs_sources, + rust_args : [ + # Will be empty if we're linking statically. + rust_dynamic_args, + # Will no-op if we're linking statically. + '-C', f'link-arg=-Wl,@soname_arg@,liblixutil_rs.@dylib_suffix@', + ], +) +libutil_rs_gen_h = custom_target( + 'libutil-rs.gen.hh', + input : [ + files('libutil/cbindgen.toml'), + libutil_rs_sources, + ], + output : ['libutil-rs.gen.hh'], + command : [ + cbindgen, + '--config', + '@INPUT0@', + '--output', + '@OUTPUT0@', + '--', + '@INPUT1@', + ], +) +# For rust-monocrate. +liblixutil_rs_internal = declare_dependency( + link_with : libutil_rs, +) + subdir('rust-monocrate') +# NOW we can create the dependency object anything that actually wants to use liblixutil_rs, +# because liblixutil_rs is secretly rust-monocrate in a trenchcoat. +# `library('lixutil')` and `executable('liblixutil-tests')` depend on this. +liblixutil_rs = declare_dependency( + link_with : rust_monocrate, + sources : [libutil_rs_gen_h], +) + # liblix_doc is actually rust-monocrate in a trenchcoat. liblix_doc = declare_dependency( link_with : rust_monocrate, diff --git a/lix/rust-monocrate/Cargo.toml b/lix/rust-monocrate/Cargo.toml index 53c2f5745..d00817067 100644 --- a/lix/rust-monocrate/Cargo.toml +++ b/lix/rust-monocrate/Cargo.toml @@ -6,3 +6,4 @@ edition.workspace = true [lib] crate-type = ["staticlib"] lix-doc = { path = "../lix-doc" } +lixutil_rs = { path = "../libutil_rs" } diff --git a/lix/rust-monocrate/meson.build b/lix/rust-monocrate/meson.build index 71a94726c..d65c8cf25 100644 --- a/lix/rust-monocrate/meson.build +++ b/lix/rust-monocrate/meson.build @@ -10,6 +10,7 @@ rust_monocrate = static_library( sources : rust_monocrate_sources, dependencies : [ liblix_doc_internal, + liblixutil_rs_internal, rnix, rowan, ], diff --git a/lix/rust-monocrate/src/lib.rs b/lix/rust-monocrate/src/lib.rs index 480f7504c..89d2de0e7 100644 --- a/lix/rust-monocrate/src/lib.rs +++ b/lix/rust-monocrate/src/lib.rs @@ -10,3 +10,4 @@ //! //! It re-exports all the symbols that should be exported to C++. pub use lix_doc::*; +pub use lixutil_rs::*; diff --git a/tests/unit/libutil/rust.cc b/tests/unit/libutil/rust.cc new file mode 100644 index 000000000..7e828c4fe --- /dev/null +++ b/tests/unit/libutil/rust.cc @@ -0,0 +1,15 @@ +#include "lix/libutil-rs.gen.hh" +#include + +namespace nix { + TEST(rustSupport, testMultiplyArgs) { + TestMultiplyArgs const args{ + .a = 20, + .b = 5, + }; + + uint64_t const product = test_multiply(args); + + ASSERT_EQ(product, 20 * 5); + } +} diff --git a/tests/unit/meson.build b/tests/unit/meson.build index 017e2fe19..960512708 100644 --- a/tests/unit/meson.build +++ b/tests/unit/meson.build @@ -69,6 +69,7 @@ libutil_tests_sources = files( 'libutil/paths-setting.cc', 'libutil/pool.cc', 'libutil/references.cc', + 'libutil/rust.cc', 'libutil/serialise.cc', 'libutil/suggestions.cc', 'libutil/tarfile.cc',