From 241adb343a4e7468b14dabec4869de735133c080 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Thu, 21 Dec 2023 21:09:59 +0000 Subject: [PATCH] [DO NOT MERGE] nix-based build system! --- flake.lock | 46 ++--------- flake.nix | 11 ++- rules/cc.nix | 175 ++++++++++++++++++++++++++++++++++++++++ rules/default.nix | 3 + sw/c/common/default.nix | 64 +++++++++++++++ sw/c/demo/default.nix | 11 +++ 6 files changed, 271 insertions(+), 39 deletions(-) create mode 100644 rules/cc.nix create mode 100644 rules/default.nix create mode 100644 sw/c/common/default.nix create mode 100644 sw/c/demo/default.nix diff --git a/flake.lock b/flake.lock index 99b33d00..14a262b1 100644 --- a/flake.lock +++ b/flake.lock @@ -35,42 +35,27 @@ "type": "github" } }, - "flake-utils_2": { - "inputs": { - "systems": "systems_2" - }, - "locked": { - "lastModified": 1701680307, - "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "4022d587cbbfd70fe950c1e2083a02621806a725", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, "lowrisc-nix": { "inputs": { - "flake-utils": "flake-utils_2", + "flake-utils": [ + "flake-utils" + ], "nixpkgs": [ "nixpkgs" ], "poetry2nix": "poetry2nix" }, "locked": { - "lastModified": 1703264099, - "narHash": "sha256-sgSNitlXAMblPTsV8uCguIn1LD0zeANRHv2BjZx5THo=", + "lastModified": 1703159561, + "narHash": "sha256-EFLITT8uzdCRsaW0FL+fgDLgQzJlyemJUOkjtnOKlfM=", "owner": "lowRISC", "repo": "lowrisc-nix", - "rev": "81a1467706e01077ee60cba8448594a7ea672b35", + "rev": "f12db37b69b4fc531c047636b2a1e7882bea7de4", "type": "github" }, "original": { "owner": "lowRISC", + "ref": "pull/4/merge", "repo": "lowrisc-nix", "type": "github" } @@ -124,7 +109,7 @@ "lowrisc-nix", "nixpkgs" ], - "systems": "systems_3", + "systems": "systems_2", "treefmt-nix": "treefmt-nix" }, "locked": { @@ -165,21 +150,6 @@ } }, "systems_2": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - }, - "systems_3": { "locked": { "lastModified": 1681028828, "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", diff --git a/flake.nix b/flake.nix index aaefab95..0eecb9a8 100644 --- a/flake.nix +++ b/flake.nix @@ -5,8 +5,9 @@ nixpkgs.url = "github:nixos/nixpkgs/nixos-23.11"; flake-utils.url = "github:numtide/flake-utils"; lowrisc-nix = { - url = "github:lowRISC/lowrisc-nix"; + url = "github:lowRISC/lowrisc-nix/pull/4/merge"; inputs.nixpkgs.follows = "nixpkgs"; + inputs.flake-utils.follows = "flake-utils"; }; deps = { url = "path:./dependencies"; @@ -62,7 +63,15 @@ zlib # vivado ]); + + rules = import ./rules {inherit pkgs;}; in { + legacyPackages.sw = let + common = pkgs.callPackage sw/c/common {inherit rules;}; + demo = pkgs.callPackage sw/c/demo {inherit rules common;}; + in { + inherit common demo; + }; devShells.default = pkgs.mkShell { name = "labenv"; buildInputs = project_deps; diff --git a/rules/cc.nix b/rules/cc.nix new file mode 100644 index 00000000..b5c55756 --- /dev/null +++ b/rules/cc.nix @@ -0,0 +1,175 @@ +{ + pkgs, + lib, + stdenv, + toolchain ? { + cc = "/no-toolchain-defined"; + cflags = []; + ld = "/no-toolchain-defined"; + ldflags = []; + asm = "/no-toolchain-defined"; + asmflags = []; + }, +}: let + include = { + src, + deps ? [], + }: + pkgs.runCommandLocal (builtins.baseNameOf src) {} '' + mkdir -p $out/include + + ARGS=() + for dep in $deps; do + if [ -d $dep/include ]; then + ln -s $src/include/* $out/include/ + fi + done + + ln -s ${src} $out/include/${builtins.baseNameOf src} + ''; + + # If a raw file path is specified, turn that into a header derivation. + autowrap_header = f: + if !(builtins.isPath f) + then f + else if lib.hasSuffix ".h" f + then include {src = f;} + else throw "unknown file type: ${f}"; + + # Turn all raw file paths into derivations. + # Files will be grouped so that source files can depend on header files. + autowrap_deps = deps: let + src = builtins.filter (f: builtins.isPath f && !(lib.hasSuffix ".h" f)) deps; + other = builtins.filter (f: !(builtins.isPath f) || lib.hasSuffix ".h" f) deps; + wrapped = map autowrap_header other; + src_drv = + map ( + f: + if lib.hasSuffix ".S" f + then + asm { + src = f; + deps = wrapped; + } + else if lib.hasSuffix ".c" f + then + object { + src = f; + deps = wrapped; + } + else throw "unknown file type: ${f}" + ) + src; + in + src_drv ++ wrapped; + + asm = { + src, + deps ? [], + extra-asmflags ? [], + asmflags ? toolchain.asmflags ++ extra-asmflags, + }: + stdenv.mkDerivation { + name = (lib.removeSuffix ".S" (builtins.baseNameOf src)) + ".o"; + inherit src asmflags; + inherit (toolchain) asm; + deps = autowrap_deps deps; + dontUnpack = true; + buildPhase = '' + ARGS=() + for dep in $deps; do + if [ -d $dep/include ]; then + ARGS+=(-I$dep/include) + fi + done + + mkdir -p $out/obj + $asm $asmflags -c -o $out/obj/$name $src ''${ARGS[@]} + ''; + }; + + object = { + src, + deps ? [], + extra-cflags ? [], + cflags ? toolchain.cflags ++ extra-cflags, + }: + stdenv.mkDerivation { + name = (lib.removeSuffix ".c" (builtins.baseNameOf src)) + ".o"; + inherit src cflags; + inherit (toolchain) cc; + deps = autowrap_deps deps; + dontUnpack = true; + buildPhase = '' + ARGS=() + for dep in $deps; do + if [ -d $dep/include ]; then + ARGS+=(-I$dep/include) + fi + done + + mkdir -p $out/obj + $cc $cflags -c -o $out/obj/$name $src ''${ARGS[@]} + ''; + }; + + static = { + name, + deps, + }: + stdenv.mkDerivation { + inherit name; + srcs = autowrap_deps deps; + dontUnpack = true; + buildPhase = '' + ARGS=() + for src in $srcs; do + if [ -d $src/obj ]; then + ARGS+=($src/obj/*) + fi + if [ -d $src/include ]; then + mkdir -p $out/include + ln -s $src/include/* $out/include/ + fi + done + + mkdir -p $out/lib + ar rcs $out/lib/$name ''${ARGS[@]} + ''; + }; + + binary = { + name, + deps ? [], + extra-ldflags ? [], + ldflags ? toolchain.ldflags ++ extra-ldflags, + }: + stdenv.mkDerivation { + inherit name ldflags; + inherit (toolchain) ld; + srcs = autowrap_deps deps; + dontUnpack = true; + buildPhase = '' + ARGS=() + for src in $srcs; do + if [ -d $src/obj ]; then + ARGS+=($src/obj/*) + fi + if [ -d $src/lib ]; then + ARGS+=($src/lib/*) + fi + done + + mkdir -p $out/bin + $ld $ldflags -o $out/bin/$name ''${ARGS[@]} + ''; + }; + + set = deps: + pkgs.symlinkJoin { + name = ""; + paths = autowrap_deps deps; + }; +in { + inherit asm include object static binary set; +} diff --git a/rules/default.nix b/rules/default.nix new file mode 100644 index 00000000..48982fe1 --- /dev/null +++ b/rules/default.nix @@ -0,0 +1,3 @@ +{pkgs}: { + cc = pkgs.callPackage ./cc.nix {}; +} diff --git a/sw/c/common/default.nix b/sw/c/common/default.nix new file mode 100644 index 00000000..75548ac2 --- /dev/null +++ b/sw/c/common/default.nix @@ -0,0 +1,64 @@ +{ + rules, + pkgs, + lowrisc-toolchain-gcc-rv32imcb, +}: let + toolchain = rec { + cc = "${lowrisc-toolchain-gcc-rv32imcb}/bin/riscv32-unknown-elf-gcc"; + cflags = ["-march=rv32imc" "-mabi=ilp32" "-mcmodel=medany" "-Wall" "-fvisibility=hidden" "-ffreestanding"]; + ld = cc; + ldflags = ["-nostartfiles" "-T" "${../../common/link.ld}"]; + asm = cc; + asmflags = ["-march=rv32imc"]; + }; + + rules_cc = rules.cc.override { + inherit toolchain; + }; + + passthru = with rules_cc; rec { + inherit toolchain rules_cc; + + crt0 = asm { + src = ./crt0.S; + deps = [./demo_system_regs.h]; + }; + + gpio = object { + src = ./gpio.c; + deps = [./gpio.h ./uart.h ./dev_access.h ./demo_system.h ./demo_system_regs.h]; + extra-cflags = ["-O3"]; + }; + + uart = object { + src = ./uart.c; + deps = [./gpio.h ./uart.h ./dev_access.h ./demo_system.h ./demo_system_regs.h]; + }; + + pwm = object { + src = ./pwm.c; + deps = [./gpio.h ./uart.h ./pwm.h ./dev_access.h ./demo_system.h ./demo_system_regs.h]; + }; + + spi = object { + src = ./spi.c; + deps = [./gpio.h ./uart.h ./spi.h ./dev_access.h ./demo_system.h ./demo_system_regs.h]; + }; + + timer = object { + src = ./timer.c; + deps = [./gpio.h ./uart.h ./timer.h ./dev_access.h ./demo_system.h ./demo_system_regs.h]; + }; + + demo_system = object { + src = ./demo_system.c; + deps = [./gpio.h ./uart.h ./dev_access.h ./demo_system.h ./demo_system_regs.h]; + }; + + common = static { + name = "common.a"; + deps = [crt0 gpio uart pwm spi timer ./demo_system.c] ++ [./gpio.h ./uart.h ./timer.h ./spi.h ./pwm.h ./dev_access.h ./demo_system.h ./demo_system_regs.h]; + }; + }; +in + passthru.common // passthru diff --git a/sw/c/demo/default.nix b/sw/c/demo/default.nix new file mode 100644 index 00000000..1d8a2158 --- /dev/null +++ b/sw/c/demo/default.nix @@ -0,0 +1,11 @@ +{ + rules, + common, + lowrisc-toolchain-gcc-rv32imcb, +}: +with common.rules_cc; { + hello_world = binary { + name = "hello_world"; + deps = [hello_world/main.c common]; + }; +}