EEE

The systemd project has officially introduced support for developing programs in Rust, following the merger of a pull request submitted by Linux kernel developer Christian Brauner. The change, merged into the project’s main branch, establishes a new development option for systemd while keeping its existing C-based architecture intact.

And before anyone assumes systemd is preparing a complete rewrite in Rust, that’s not the case. The maintainers agreed on a deliberately limited approach: Rust may be used only for new, standalone components that other parts of systemd do not depend on. Existing C code will remain untouched.

Another important decision concerns the build process. Rather than introducing Cargo, Rust’s standard package manager and build tool, systemd continues to use Meson for all builds. This keeps Rust development integrated into the project’s existing build infrastructure.

The implementation also places strict limits on dependencies. Rust programs use the no_std approach, meaning they do not rely on Rust’s standard library or external third-party crates. Instead, they interact with systemd’s existing C libraries through generated bindings.

For memory management, systemd provides its own Rust implementations of common container types, with allocation failures handled explicitly rather than causing the program to abort. The new infrastructure also includes wrappers for logging, command-line argument handling, event processing, and error management, allowing Rust utilities to behave consistently with their C counterparts.

Rust support is optional and automatically detected during configuration. Developers wishing to enable it need Rust 1.85 or later, bindgen 0.71.1 or later, and Meson 1.4 or later. Systems without the required toolchain can continue building systemd without Rust support.

Interestingly, initial tests show that a stripped Rust command-line utility occupies about 32 KB, compared to 20 KB for its C equivalent built with link-time optimization. This gives an early indication of the additional overhead, though the comparison involves only a small test program.

The first planned real-world application of this infrastructure is systemd-keyring-setup, a new utility intended to help manage certificates in Linux kernel keyrings. Its implementation is being developed separately, alongside additional Rust wrappers for systemd’s shared libraries.

For Linux distributions, the change introduces packaging considerations. Builds that enable all available features will need the appropriate Rust compiler and bindgen dependencies or must disable Rust support to avoid build failures.

Whether Rust becomes widely used within systemd will depend on future development, but the necessary groundwork is now in place.

    • urushitan 漆たん@kakera.kintsugi.moe
      link
      fedilink
      arrow-up
      1
      arrow-down
      2
      ·
      edit-2
      hace 10 horas

      ok a makefile is basically a script runner like this. the c/c++ compiler doesn’t touch the makefile, that’s a separate tool

      edit : main.o kbd.o command.o display.o \
             insert.o search.o files.o utils.o
              cc -o edit main.o kbd.o command.o display.o \
                         insert.o search.o files.o utils.o
      
      main.o : main.c defs.h
              cc -c main.c
      kbd.o : kbd.c defs.h command.h
              cc -c kbd.c
      command.o : command.c defs.h command.h
              cc -c command.c
      display.o : display.c defs.h buffer.h
              cc -c display.c
      insert.o : insert.c defs.h buffer.h
              cc -c insert.c
      search.o : search.c defs.h buffer.h
              cc -c search.c
      files.o : files.c defs.h buffer.h command.h
              cc -c files.c
      utils.o : utils.c defs.h
              cc -c utils.c
      clean :
              rm edit main.o kbd.o command.o display.o \
                 insert.o search.o files.o utils.o
      

      for a rust program, you might have a cargo.toml like

      [package]
      name = "jsontool"
      version = "0.1.0"
      edition = "2021"
      
      [dependencies]
      anyhow = "1"
      clap = { version = "4", features = ["derive"] }
      serde = { version = "1", features = ["derive"] }
      serde_json = "1"
      
      [profile.release]
      lto = true```
      
      and .cargo/config.toml like (for the local distro config, no internet packages)
      
      

      [source.crates-io] replace-with = “distro”

      [source.distro] directory = “/usr/share/cargo/registry” # or: registry = “sparse+https://crates.internal.example/index/”

      [net] offline = true

      
      If you wanted that same functionality from a makefile for rust it would be something like
      
      

      Makefile: build jsontool with plain rustc, no cargo.

      RUSTC ?= rustc REG := /usr/share/cargo/registry OUT := $(abspath build) HOST := $(shell $(RUSTC) -vV | sed -n ‘s/^host: //p’) FLAGS := -C opt-level=3 --cap-lints=allow -L dependency=$(OUT) --out-dir $(OUT) ext = $(foreach c,$(1),–extern $©=$(OUT)/lib$©.rlib) extpm = $(foreach c,$(1),–extern $©=$(OUT)/lib$©.so)

      Pinned by hand. Cargo.lock does this for you; here, a distro upgrade

      renames these directories and the build breaks.

      UNICODE_IDENT := $(REG)/unicode-ident-1.0.13 PROC_MACRO2 := $(REG)/proc-macro2-1.0.89 QUOTE := $(REG)/quote-1.0.37 SYN := $(REG)/syn-2.0.85 SERDE_DERIVE := $(REG)/serde_derive-1.0.213

      … ~20 more …

      ---- 1. Plain library crate ----

      Edition, crate name (hyphens -> underscores), and features all come from

      reading each crate’s Cargo.toml yourself.

      $(OUT)/libunicode_ident.rlib: $(RUSTC) --edition=2018 --crate-type=lib --crate-name unicode_ident
      $(FLAGS) $(UNICODE_IDENT)/src/lib.rs

      ---- 2. Crate with a build.rs: compile it, run it with the env vars cargo

      would set, then scrape its stdout for cfg flags ----

      $(OUT)/proc_macro2.cfg: mkdir -p $(OUT)/bs-pm2 $(RUSTC) --edition=2021 --crate-type=bin $(PROC_MACRO2)/build.rs
      -o $(OUT)/bs-pm2/build-script cd $(PROC_MACRO2) && env OUT_DIR=$(OUT)/bs-pm2 RUSTC=$(RUSTC)
      TARGET=$(HOST) HOST=$(HOST) PROFILE=release OPT_LEVEL=3
      CARGO_MANIFEST_DIR=$(PROC_MACRO2) CARGO_PKG_VERSION=1.0.89
      CARGO_FEATURE_DEFAULT=1 CARGO_FEATURE_PROC_MACRO=1
      CARGO_CFG_TARGET_OS=linux CARGO_CFG_TARGET_ARCH=x86_64
      $(OUT)/bs-pm2/build-script
      | sed -n ‘s/^cargo::?rustc-cfg=(.*)/–cfg=\1/p’ > $@

      $(OUT)/libproc_macro2.rlib: $(OUT)/proc_macro2.cfg $(OUT)/libunicode_ident.rlib $(RUSTC) --edition=2021 --crate-type=lib --crate-name proc_macro2 $(FLAGS)
      –cfg ‘feature=“default”’ --cfg ‘feature=“proc-macro”’
      $$(cat $<) $(call ext,unicode_ident) $(PROC_MACRO2)/src/lib.rs

      ---- 3. Proc-macro crate: different crate type, must be built for the

      HOST (matters when cross-compiling), linked as a .so ----

      syn’s feature list must be the UNION of what serde_derive AND clap_derive

      need. Cargo computes this (feature unification); here you work it out by hand.

      $(OUT)/libserde_derive.so: $(OUT)/libproc_macro2.rlib $(OUT)/libquote.rlib $(OUT)/libsyn.rlib $(RUSTC) --edition=2015 --crate-type=proc-macro --crate-name serde_derive
      $(FLAGS) --cfg ‘feature=“default”’
      $(call ext,proc_macro2 quote syn) $(SERDE_DERIVE)/src/lib.rs

      … ~20 more rules like the above (serde, serde_json, anyhow, and

      clap_* each have their own quirks, and several have build.rs) …

      ---- Finally, your program ----

      clap’s derive expands to env!(“CARGO_PKG_VERSION”), so you fake cargo’s env.

      Source files are listed by hand (or you wire up --emit=dep-info .d files).

      build/jsontool: src/main.rs src/cli.rs src/convert.rs $(ALL_DEPS) CARGO_PKG_NAME=jsontool CARGO_PKG_VERSION=0.1.0
      $(RUSTC) --edition=2021 --crate-type=bin --crate-name jsontool $(FLAGS)
      $(call ext,anyhow clap serde serde_json) src/main.rs

      Still to write: test (rustc --test + every --extern again), doc-tests

      (rustdoc --test), debug vs release flags, clean, install…

      
      So are you proposing GNU style makefiles for rust then? You say not another tool, just use the compiler. Either you type those commands yourself, you type them into a make style build script, or cargo or **another tool** automates them.
      • thingsiplay@lemmy.ml
        link
        fedilink
        arrow-up
        2
        ·
        hace 10 horas

        No, I am not talking about the same functionality and without using cargo. I am talking about using rustc to compile individual Rust programs.

        $ ls -1
        hello.rs
        main.rs
        

        main.rs:

        mod hello;
        
        fn main() {
            hello::print_hello();
        }
        

        hello.rs:

        pub fn print_hello() {
            println!("Hello World!");
        }
        
        $ rustc --target helloworld main.rs
        $ ./helloworld
        Hello World!
        

        No Cargo, no toml, no registry.

        • Ferk@lemmy.ml
          link
          fedilink
          arrow-up
          1
          ·
          hace 1 minuto

          Nobody is gonna manually compile each .rs file one by one and link it… for anything else than a 1 file simple project you’d want to use another tool (like make or cargo), to automate that.

          • thingsiplay@lemmy.ml
            link
            fedilink
            arrow-up
            1
            ·
            hace 8 horas

            That’s the entire point you intelligence beast. I’m telling you the entire time “without cargo” and “include rustc and standard libraries only”. I think I told you 10 times.