Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DO NOT MERGE] nix-based build system! #84

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
# Add extra packages we might need
# Currently this contains spike
deps.overlay_pkgs
(final: prev: {
inherit (lowrisc-nix.packages.${system}) lowrisc-toolchain-gcc-rv32imcb;
})
];
};

Expand All @@ -45,6 +48,14 @@
];
};
in {
legacyPackages.sw = let
rules = import ./rules {inherit pkgs;};
common = pkgs.callPackage sw/c/common {inherit rules;};
demo = pkgs.callPackage sw/c/demo {inherit rules common;};
in {
inherit common demo;
};

devShells.default = pkgs.mkShellNoCC {
name = "labenv";
buildInputs = with pkgs; [
Expand Down
175 changes: 175 additions & 0 deletions rules/cc.nix
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very cool! Are there any other projects using nix itself as the build system?

Original file line number Diff line number Diff line change
@@ -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;
}
3 changes: 3 additions & 0 deletions rules/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{pkgs}: {
cc = pkgs.callPackage ./cc.nix {};
}
64 changes: 64 additions & 0 deletions sw/c/common/default.nix
Original file line number Diff line number Diff line change
@@ -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
11 changes: 11 additions & 0 deletions sw/c/demo/default.nix
Original file line number Diff line number Diff line change
@@ -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];
};
}