Skip to content

Commit 8fa4c94

Browse files
lromorhzeller
authored andcommitted
Package beagleg with nix: flake, cross-compile, multi-binary outputs
flake.nix exposes one runnable flake output per binary, on each target architecture, by taking the Cartesian product of two small lists in the flake itself: binaries = [ machine-control gcode-print-stats gcode2ps ] crossTargets = { armv7 = pkgsCross.armv7l-hf-multiplatform; } So out of the box: nix run .#machine-control, nix run .#gcode2ps, nix build .#gcode-print-stats-armv7, ... Adding a new cross target is a one-line addition to crossTargets. The vendored am335x_pru_package git submodule is followed transparently via inputs.self.submodules = true; in the flake, so the usual nix build .#X works without a ?submodules=1 query. nix/beagleg.nix wraps the project Makefile in a stdenv derivation. It patches the vendored pasm (a K&R-style ppCleanup() prototype recent strict-prototype GCC rejects, and a linuxbuild script that calls bare gcc which is only prefixed under nix-cross), clears ARM_COMPILE_FLAGS on non-ARM hosts, and skips tests when cross-compiling.
1 parent 787da71 commit 8fa4c94

4 files changed

Lines changed: 134 additions & 2 deletions

File tree

Development.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,36 @@ the root of the environment.
4949
nix-shell
5050
```
5151

52+
The shell pulls in the host build deps: gtest, valgrind, clang-tools,
53+
lcov, ghostscript, graphviz.
54+
55+
#### Building with the flake
56+
57+
There is also a `flake.nix` that exposes BeagleG as a nix package and
58+
supports cross-compilation to the BeagleBone target out of the box. The
59+
`am335x_pru_package` git submodule is followed transparently via
60+
`inputs.self.submodules = true;` in the flake.
61+
62+
Each program is its own flake output (and so is its cross-compiled
63+
counterpart suffixed `-armv7`):
64+
65+
```
66+
# run any program directly
67+
nix run .#machine-control -- --help
68+
nix run .#gcode2ps testdata/some.gcode
69+
70+
# build a single binary (result/bin/<name>)
71+
nix build .#gcode-print-stats
72+
73+
# cross-compile a single binary for the BeagleBone (armv7l-hf)
74+
nix build .#machine-control-armv7
75+
76+
# list every flake output (packages, dev shells, ...)
77+
nix flake show
78+
```
79+
80+
The cross-built binaries are ARM EABI5 ELFs ready to scp onto a BBB.
81+
5282
### Coverage
5383
To see if there is code that has not been covered in tests yet, there is
5484
a target `make coverage`, that creates a `src/coverage.html` report with

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ cool is that?).
3535
For detailed system configuration and building the `machine-control` binary, see
3636
[INSTALL.md](./INSTALL.md).
3737

38+
If you use the [nix](https://nixos.org/) package manager, BeagleG ships with
39+
a `flake.nix` that builds the project hermetically and can cross-compile to
40+
the BeagleBone target straight from an x86 dev box — no toolchain to install
41+
by hand, identical builds across machines. See [Development.md](./Development.md#nixos)
42+
for the one-liner.
43+
3844
Before you can use beagleg and get meaningful outputs on the GPIO pins,
3945
two things are required on a fresh Beaglebone installation (we recommend the
4046
IoT image).

flake.nix

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,47 @@
55
inputs.nixpkgs.url = "github:NixOS/nixpkgs/e73de5be04e0eff4190a1432b946d469c794e7b4";
66
inputs.flake-utils.url = "github:numtide/flake-utils";
77

8+
# Follow the am335x_pru_package git submodule transparently, so users
9+
# don't need to add ?submodules=1 to every nix-build invocation.
10+
inputs.self.submodules = true;
11+
812
outputs = { self, nixpkgs, flake-utils }:
9-
flake-utils.lib.eachDefaultSystem (system:
10-
let pkgs = import nixpkgs { inherit system; };
13+
# BeagleG is linux-only; expose the flake on every linux system
14+
# nixpkgs considers reasonable (incl. armv7l-linux for native builds
15+
# on a BeagleBone itself, aarch64-linux for RPi-class boards, etc.).
16+
flake-utils.lib.eachSystem
17+
(nixpkgs.lib.filter (s: nixpkgs.lib.hasSuffix "-linux" s)
18+
nixpkgs.lib.systems.flakeExposed)
19+
(system:
20+
let
21+
pkgs = import nixpkgs { inherit system; };
22+
lib = pkgs.lib;
23+
beagleg = pkgs.callPackage ./nix/beagleg.nix { };
24+
25+
# Cross-compile targets. Add one line per new architecture; the
26+
# suffix becomes the flake-output suffix (e.g. machine-control-armv7).
27+
crossTargets = {
28+
armv7 = pkgs.pkgsCross.armv7l-hf-multiplatform;
29+
};
30+
31+
# Binaries shipped by the package. Each becomes its own flake
32+
# output with mainProgram set, so `nix run .#gcode2ps` picks the
33+
# right entrypoint. All outputs share the same underlying build.
34+
binaries = [ "machine-control" "gcode-print-stats" "gcode2ps" ];
35+
mkRunnable = drv: name: drv.overrideAttrs (_: {
36+
meta = drv.meta // { mainProgram = name; };
37+
});
38+
named = drv: suffix: lib.listToAttrs (map (name: {
39+
name = name + suffix;
40+
value = mkRunnable drv name;
41+
}) binaries);
42+
crossPackages = lib.concatMapAttrs
43+
(suffix: cross: named (cross.callPackage ./nix/beagleg.nix { }) "-${suffix}")
44+
crossTargets;
1145
in {
1246
devShells.default = import ./shell.nix { inherit pkgs; };
47+
packages = { default = beagleg; }
48+
// (named beagleg "")
49+
// crossPackages;
1350
});
1451
}

nix/beagleg.nix

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# BeagleG host package. Builds machine-control and its companion tools
2+
# from the project Makefile. Supports native builds (for tests / dev) and
3+
# cross-compilation to armv7 for BeagleBone deployment via pkgsCross.
4+
{ stdenv, lib, pkg-config, gtest, pkgsBuildBuild }:
5+
stdenv.mkDerivation {
6+
pname = "beagleg";
7+
version = "unstable";
8+
9+
# Pass the project root directly (not lib.cleanSource) so the
10+
# am335x_pru_package submodule is included in the build sandbox.
11+
src = ./..;
12+
13+
# pasm's linuxbuild needs a build-platform C compiler to produce the
14+
# PRU assembler binary that then runs in this sandbox.
15+
nativeBuildInputs = [ pkg-config pkgsBuildBuild.gcc ];
16+
CC_FOR_BUILD = "${pkgsBuildBuild.gcc}/bin/gcc";
17+
buildInputs = [ gtest ];
18+
19+
# Patches for the vendored am335x_pru_package:
20+
# - K&R-style ppCleanup() / definition pair rejected by strict GCC.
21+
# - linuxbuild calls bare `gcc`, which under nix cross-builds is only
22+
# available with the build-platform prefix; use $CC_FOR_BUILD.
23+
postPatch = ''
24+
substituteInPlace am335x_pru_package/pru_sw/utils/pasm_source/pasm.h \
25+
--replace-fail 'void ppCleanup();' 'void ppCleanup(int);'
26+
substituteInPlace am335x_pru_package/pru_sw/utils/pasm_source/pasmpp.c \
27+
--replace-fail 'void ppCleanup()' 'void ppCleanup(int Pass)'
28+
substituteInPlace am335x_pru_package/pru_sw/utils/pasm_source/linuxbuild \
29+
--replace-fail 'gcc -Wall' "''${CC_FOR_BUILD:-gcc} -Wall"
30+
'';
31+
32+
# The Makefile's ARM_COMPILE_FLAGS default targets cortex-a8/armv7-a,
33+
# which is what we want for BBB cross builds. Clear it on any host that
34+
# isn't a 32-bit ARM (nix's stdenv has already set the right CC/CXX).
35+
ARM_COMPILE_FLAGS = lib.optionalString (!stdenv.hostPlatform.isAarch32) "";
36+
37+
enableParallelBuilding = true;
38+
39+
# Tests are gtest-based and run on the build machine; skip when cross-
40+
# compiling because the binaries can't execute on the build host.
41+
doCheck = stdenv.buildPlatform.canExecute stdenv.hostPlatform;
42+
checkTarget = "test";
43+
44+
installPhase = ''
45+
runHook preInstall
46+
mkdir -p $out/bin
47+
install -m 755 machine-control gcode-print-stats $out/bin/
48+
install -m 755 src/gcode2ps $out/bin/
49+
runHook postInstall
50+
'';
51+
52+
meta = with lib; {
53+
description = "Step-motor controller for CNC-like devices using the BeagleBone PRU";
54+
homepage = "https://github.com/hzeller/beagleg";
55+
license = licenses.gpl3Plus;
56+
platforms = platforms.linux;
57+
mainProgram = "machine-control";
58+
};
59+
}

0 commit comments

Comments
 (0)