• 0 Posts
  • 15 Comments
Joined 7 months ago
cake
Cake day: March 28th, 2026

help-circle







  • 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 $(c)=$(OUT)/lib$(c).rlib)
    extpm   = $(foreach c,$(1),--extern $(c)=$(OUT)/lib$(c).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.



  • yes, but to manually build packages against libraries yourself would be a nightmare of tooling without cargo.

    It’s no different than every base-devel and similar package requiring cmake because sure, you could manually run the c/c++ compilers and linkers yourself against every single file, passing in the flags yourself, but that would take an obscene amount of time to manually build and run every compiler command yourself

    https://wiki.debian.org/Rust

    Debian builds it’s own local cargo registry by default. If your distro provides “pinned versions” like I said, you won’t need rustup, but you’ll still need cargo to do anything beyond a tiny project with no imports, unless you plan on writing async/http/encryption libraries all yourself.