Skip to content

Commit 9ff8543

Browse files
authored
🪅 Rewrite most of the toolchain logic (#3)
- Implement an unneccessarily overtuned C++ toolchain using Rust-based uutils and the mold linker which speeds up linking by up to 95%. - Fix hermeticity issues with system library linking. This makes the remote execution workflow pass. - Bundle tinfo and ncurses from Ubuntu 24.04 instead of the Nix variant. This makes the version symbol warnings go away. - The above also makes the `mojo` command work. That is, we now support the Mojo REPL. - Change the wrapping logic of the nix package. This lets us remove most of the Bazel passthrough variables and simplifies the Bazel toolchain.
1 parent e57adb9 commit 9ff8543

File tree

19 files changed

+283
-174
lines changed

19 files changed

+283
-174
lines changed

‎.github/styles/config/vocabularies/rules_mojo/accept.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,6 @@ Bazel
22
[Ee]xecution
33
[Tt]oolchain
44
LLVM
5+
uutils
6+
patchelf
7+
coreutils

‎.github/workflows/local-remote-execution.yaml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
strategy:
1515
fail-fast: false
1616
matrix:
17-
os: [ubuntu-24.04]
17+
os: [large-ubuntu-22.04]
1818
name: ${{ matrix.os }}
1919
runs-on: ${{ matrix.os }}
2020
timeout-minutes: 45
@@ -52,4 +52,8 @@ jobs:
5252
- name: Run Mojo tests against the cluster
5353
run: |
5454
nix develop --impure --command \
55-
bash -c "lre-bazel test --jobs=4 @mojo//... --verbose_failures"
55+
bash -c "lre-bazel test \
56+
--jobs=$(nproc) \
57+
--keep_going \
58+
--verbose_failures \
59+
@mojo//..."

‎.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,7 @@ Pulumi.dev.yaml
3030

3131
# Ignore the generated kustomization from NativeLink.
3232
/kustomization.yaml
33+
34+
# These files might get created while playing around in the repository.
35+
hello
36+
mypackage.mojopkg

‎README.md

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
# `rules_mojo` 🔥
22

3-
Hermetic, reproducible Bazel/Nix rules for Mojo 🔥.
3+
Hermetic, reproducible Bazel/Nix rules for Mojo 🔥
44

55
Brings Mojo to all Linux distributions.
66

7+
```bash
8+
nix run github:TraceMachina/rules_mojo#mojo
9+
```
10+
711
✨ **Features**:
812

913
- Mojo wrapped in [Nix](https://nixos.org/). No implicit `apt` installations, no
@@ -17,6 +21,12 @@ Brings Mojo to all Linux distributions.
1721
which lets you execute builds in arbitrarily scalable Kubernetes clusters.
1822
Whether you want to run a build on 1000 cores or just share your build cache
1923
among friends, the NativeLink+LRE infrastructure supports it.
24+
- A bundled Clang/LLVM C++ toolchain with the [mold](https://github.com/rui314/mold)
25+
linker and [uutils](https://github.com/uutils/coreutils), the Rust rewrite of
26+
coreutils. This toolchain links Mojo executables up to two orders of magnitude
27+
faster than a standard C++ toolchain.
28+
- Pretty compiler crash stack traces, powered by the `llvm-symbolizer` built
29+
from upstream LLVM sources.
2030

2131
🔮 **Coming soon™**:
2232

@@ -31,14 +41,25 @@ Brings Mojo to all Linux distributions.
3141
Also, the LRE framework is still actively under development (in fact,
3242
`rules_mojo` acts as a validation case for LRE), so expect larger scale
3343
refactors.
34-
- At the moment there is no way to chose the Mojo version. `rules_mojo` uses
44+
- At the moment there is no way to choose the Mojo version. `rules_mojo` uses
3545
a pinned `nightly` toolchain that happened to not crash because stable
3646
crashed.
47+
- The toolchain links all executables to dynamic libraries from `nixpkgs`.
48+
This brings potential performance improvements from recent `glibc` and
49+
`libstdc++` versions, but makes the executables incompatible with systems that
50+
don't have these libraries present. You can attempt to rewrite the `RPATH`s
51+
with [patchelf](https://github.com/NixOS/patchelf), but you might run into
52+
`glibc` version incompatibility issues on non-bleeding-edge systems.
53+
- The dynamic loader `ld-linux-x86_64.so.2` isn't set to the Nix variant.
54+
This lets you run `rules_mojo`-built executables outside of the nix
55+
environment. However, on older systems the version mismatch between the
56+
dynamic loader and the nix-based `glibc` might lead to issues. When in doubt,
57+
use `ldd <path/to/executable>` to double-check the dynamic dependency
58+
resolution.
3759

3860
🦋 **Known bugs**:
3961

4062
- While you can build tests remotely, you need to run them locally.
41-
- The Mojo REPL doesn't work yet due to an `ncurses` linker symbol mismatch.
4263
- All mojo invocations print `crashdb` warnings because it's unclear how to
4364
configure the `crashdb` output location to point outside of the nix store.
4465

@@ -68,13 +89,34 @@ direnv allow
6889
> If you don't want to use `direnv` you can use `nix develop` manually which is
6990
> the command that `direnv` would automatically call for you.
7091
71-
The Mojo standard library is convenience test target for `rules_mojo`. To run
72-
all tests:
92+
Inside the Nix environment you'll have access to the `mojo` command:
93+
94+
```bash
95+
# The mojo REPL.
96+
mojo
97+
98+
# Build a mojo executable.
99+
mojo build examples/hello.mojo
100+
101+
# Build a mojo package.
102+
mojo package examples/mypackage
103+
104+
# Invoke the nix-packaged `mojo` executable
105+
# outside of the `rules_mojo` repository:
106+
nix run github:TraceMachina/rules_mojo#mojo
107+
```
108+
109+
To test the `mojo_toolchain` with Bazel, run the Mojo standard library test
110+
suite:
73111

74112
```bash
75113
bazel test @mojo//...
76114
```
77115

116+
> [!TIP]
117+
> Check out [`thirdparty/mojo.BUILD.bazel`](./thirdparty/mojo.BUILD.bazel) for
118+
> the build file of this target.
119+
78120
To run the example in the `examples` directory:
79121

80122
```bash
@@ -148,5 +190,5 @@ nix flake init -t github:TraceMachina/rules_mojo
148190

149191
Licensed under the Apache 2.0 License with LLVM exceptions.
150192

151-
This repository wraps the Mojo SDK which is under a proprietary license, bundled
152-
with the Mojo SDK and also available in the `licenses` directory.
193+
This repository wraps the Modular Mojo SDK which is under a proprietary license,
194+
bundled with the SDK and also available in the `licenses` directory.

‎examples/BUILD.bazel

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ mojo_binary(
1717
)
1818

1919
mojo_test(
20-
name = "hello_world_test",
20+
name = "hello_test",
2121
srcs = ["hello.mojo"],
22+
deps = [":mypackage"],
2223
)

‎examples/hello.mojo

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from mypackage.mymodule import MyPair
22

3+
34
fn main():
45
var mine = MyPair(2, 4)
56
mine.dump()

‎flake.nix

Lines changed: 23 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -81,59 +81,38 @@
8181
, ...
8282
}:
8383
let
84+
tinfo6-bin = pkgs.callPackage ./tinfo6-bin.nix { };
85+
86+
ncurses6-bin = pkgs.callPackage ./ncurses6-bin.nix { };
87+
8488
native-cli = inputs.nativelink.packages.${system}.native-cli;
8589

86-
lre-mojo-cluster = import ./local-remote-execution/lre-mojo-cluster.nix {
90+
lre-mojo-cluster = pkgs.callPackage ./local-remote-execution/lre-mojo-cluster.nix {
8791
inherit native-cli;
88-
inherit (pkgs)
89-
curl
90-
git
91-
kubectl
92-
kustomize
93-
nix
94-
writeShellScriptBin;
9592
};
9693

9794
lre-cc = nativelink.packages.${system}.lre-cc;
9895
inherit (nix2container.packages.${system}.nix2container) buildImage;
9996

100-
mojo-sdk = import ./mojo-sdk.nix {
101-
inherit (pkgs)
102-
autoPatchelfHook
103-
fetchurl
104-
glibc
105-
icu
106-
libedit
107-
libgcc
108-
libxml2
109-
ncurses
110-
stdenv
111-
zlib
112-
zstd;
97+
mojo = pkgs.callPackage ./mojo.nix {
98+
inherit (pkgs.lib) makeBinPath makeLibraryPath;
99+
inherit (pkgs.llvmPackages_18) clang;
100+
ncurses = ncurses6-bin;
101+
tinfo = tinfo6-bin;
113102
};
114103

115-
lre-mojo = import ./local-remote-execution/lre-mojo.nix {
116-
inherit (pkgs)
117-
gcc
118-
lib
119-
ncurses
120-
python312
121-
zlib;
122-
inherit buildImage lre-cc mojo-sdk;
104+
lre-mojo = pkgs.callPackage ./local-remote-execution/lre-mojo.nix {
105+
# ncurses = ncurses6-bin;
106+
# tinfo = ncurses6-bin;
107+
mojoEnv = self.lib.defaultMojoEnv {
108+
inherit pkgs mojo;
109+
};
110+
inherit buildImage lre-cc;
123111
};
124112

125-
lre-kill-the-mojo = import ./local-remote-execution/lre-kill-the-mojo.nix {
126-
inherit (pkgs) docker findutils kind writeShellScriptBin;
127-
};
113+
lre-kill-the-mojo = pkgs.callPackage ./local-remote-execution/lre-kill-the-mojo.nix { };
128114

129-
createWorker = import ./local-remote-execution/create-worker.nix {
130-
inherit (pkgs)
131-
bash
132-
buildEnv
133-
coreutils
134-
lib
135-
runCommand
136-
runtimeShell;
115+
createWorker = pkgs.callPackage ./local-remote-execution/create-worker.nix {
137116
inherit buildImage self;
138117
nativelink = nativelink.packages.${system}.nativelink-debug;
139118
};
@@ -143,11 +122,7 @@
143122
exec ${pkgs.bazelisk}/bin/bazelisk "$@"
144123
'';
145124

146-
lre-bazel = import ./lre-bazel.nix {
147-
inherit bazel;
148-
inherit (pkgs) kubectl writeShellScriptBin;
149-
};
150-
125+
lre-bazel = pkgs.callPackage ./lre-bazel.nix { inherit bazel; };
151126
in
152127
{
153128
_module.args.pkgs = import self.inputs.nixpkgs {
@@ -172,21 +147,20 @@
172147
LL_LDFLAGS = "-L${openssl.out}/lib";
173148
};
174149
rules_mojo.settings.mojoEnv = self.lib.defaultMojoEnv {
175-
inherit pkgs mojo-sdk;
150+
inherit pkgs mojo;
176151
};
177152
packages = {
178-
inherit lre-mojo lre-cc mojo-sdk lre-mojo-cluster lre-kill-the-mojo bazel lre-bazel;
153+
inherit lre-mojo lre-cc mojo lre-mojo-cluster lre-kill-the-mojo bazel lre-bazel;
179154
nativelink-worker-lre-mojo = createWorker lre-mojo;
180155
};
181156
devShells.default = pkgs.mkShell {
182157
nativeBuildInputs = [
183-
mojo-sdk
158+
mojo
184159
lre-mojo-cluster
185160
lre-kill-the-mojo
186161
bazel
187162
lre-bazel
188163
pkgs.kubectl
189-
pkgs.zlib
190164
pkgs.python312
191165
pkgs.tektoncd-cli
192166
pkgs.kind

‎local-remote-execution/lre-mojo.nix

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,11 @@
11
{ buildImage
2-
, gcc
3-
, lib
42
, lre-cc
5-
, mojo-sdk
6-
, ncurses
7-
, python312
8-
, zlib
3+
, mojoEnv
94
, ...
105
}:
116

127
let
13-
# This environment is shared between toolchain autogen images and the final
14-
# toolchain image.
15-
Env = [
16-
# Add all tooling here so that the generated toolchains use `/nix/store/*`
17-
# paths instead of `/bin` or `/usr/bin`. This way we're guaranteed to use
18-
# binary identical toolchains during local and remote execution.
19-
("PATH="
20-
+ (lib.strings.concatStringsSep ":" [
21-
"${gcc}/bin"
22-
"${mojo-sdk}/bin"
23-
]))
24-
"MODULAR_HOME=${mojo-sdk}"
25-
"MOJO_COMPILER=${mojo-sdk}/bin/mojo"
26-
"MOJO_CC_PATH=${gcc}/bin:${mojo-sdk}/bin"
27-
"MOJO_LIBRARY_PATH=${zlib}/lib:${ncurses}/lib"
28-
"MOJO_PYTHON_LIBRARY=${python312}/lib"
29-
];
8+
Env = mojoEnv;
309
in
3110
buildImage {
3211
name = "lre-mojo";

‎modules/defaultMojoEnv.nix

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
{ pkgs, mojo-sdk, ... }:
1+
{ pkgs, mojo, ... }:
22

33
[
4-
"MODULAR_HOME=${mojo-sdk}"
5-
"MOJO_COMPILER=${mojo-sdk}/bin/mojo"
6-
"MOJO_CC_PATH=${pkgs.gcc}/bin:${mojo-sdk}/bin"
7-
"MOJO_LIBRARY_PATH=${pkgs.zlib}/lib:${pkgs.ncurses}/lib"
4+
"MODULAR_HOME=${mojo}"
5+
"MOJO_COMPILER=${mojo}/bin/mojo"
6+
"MOJO_CC_PATH=${pkgs.lib.makeBinPath mojo.passthru.mojoBinPath}"
7+
"LD_LIBRARY_PATH=${pkgs.lib.makeLibraryPath mojo.passthru.mojoLibraryPath}"
88

9-
# TODO(aaronmondal): This needs to be set during runtime. Let's just add it to
10-
# a mojo wrapper script.
9+
# TODO(aaronmondal): This needs to be set during runtime.
1110
# "MOJO_PYTHON_LIBRARY=${pkgs.python312}/lib/libpython3.12.so.1.0"
1211
]

‎modules/rules_mojo.nix

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,14 @@ in
3232
3333
```nix
3434
mojoEnv = [
35-
"MOJO_COMPILER=''${mojo-sdk}/bin/mojo"
35+
"MOJO_COMPILER=''${mojo}/bin/mojo"
3636
]
3737
```
3838
3939
results in the following line in `.bazelrc.ll`:
4040
4141
```bash
42-
build --@rules_mojo//mojo:MOJO_COMPILER=''${mojo-sdk}/bin/mojo
42+
build --@rules_mojo//mojo:MOJO_COMPILER=''${mojo}/bin/mojo
4343
```
4444
4545
Supported values are:

0 commit comments

Comments
 (0)