From 27e4c9d5b9ebd89bc5757b897e34257ae54f2f5f Mon Sep 17 00:00:00 2001 From: Comamoca Date: Fri, 9 Oct 2026 02:51:48 +0900 Subject: [PATCH 1/9] build(nix): publish LLVM/MLIR 23 via cachix instead of per-user source builds nixpkgs has no llvmPackages_23, so this flake builds two LLVM trees from source (~1h, llvm23 1.2GiB + mlir23 774MiB). Every nix run user would pay that, so: - flake.nix nixConfig: add comamoca-lython.cachix.org as an extra substituter with its trusted public key, so first-time users get a one-time accept prompt and pull the prebuilt closure. - .github/workflows/nix-cache.yml: rebuild and push llvm23/mlir23/ lython on pushes touching the flake or compiler sources (CACHIX_AUTH_TOKEN secret), keeping the cache fresh. - .gitignore: result*, .direnv/. --- .github/workflows/nix-cache.yml | 49 +++++++++ .gitignore | 5 + flake.lock | 186 ++++++++++++++++++++++++++++++++ flake.nix | 127 ++++++++++++++++++++++ nix/build-lython.nix | 51 +++++++++ nix/llvm23.nix | 107 ++++++++++++++++++ nix/mlir23.nix | 83 ++++++++++++++ 7 files changed, 608 insertions(+) create mode 100644 .github/workflows/nix-cache.yml create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 nix/build-lython.nix create mode 100644 nix/llvm23.nix create mode 100644 nix/mlir23.nix diff --git a/.github/workflows/nix-cache.yml b/.github/workflows/nix-cache.yml new file mode 100644 index 00000000..58f64271 --- /dev/null +++ b/.github/workflows/nix-cache.yml @@ -0,0 +1,49 @@ +name: Nix cache + +# Keeps comamoca-lython.cachix.org populated so `nix run` users skip the +# ~1 hour LLVM/MLIR source build (llvm23 1.2 GiB + mlir23 774 MiB). + +on: + push: + branches: [main] + paths: + - "flake.nix" + - "flake.lock" + - "nix/**" + - "src/**" + - "emitter/**" + - "runtime/**" + - "tools/**" + - "CMakeLists.txt" + - ".github/workflows/nix-cache.yml" + workflow_dispatch: + +jobs: + cache: + name: Build & push to Cachix + runs-on: ubuntu-latest + # LLVM + MLIR + lython source builds are far over the default timeout. + timeout-minutes: 360 + + steps: + - uses: actions/checkout@v4 + + - uses: cachix/install-nix-action@v31 + with: + nix_path: nixpkgs=channel:nixos-unstable + + - uses: cachix/cachix-action@v16 + with: + name: comamoca-lython + authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" + # Everything already in the local store (e.g. from a developer's + # `nix build`) is pushed too — that is the point of this job. + skipPush: false + + - name: Build packages + env: + NIX_CONFIG: "max-jobs = 4 cores = 4" + run: nix build .#llvm23 .#mlir23 .#lython -L + + - name: Build devShell (warms build-only deps) + run: nix develop -c true diff --git a/.gitignore b/.gitignore index e9c63a57..9ca937a7 100644 --- a/.gitignore +++ b/.gitignore @@ -233,3 +233,8 @@ dkms.conf # --- End of C.gitignore --- tools/.ucd-cache/ + +# --- Nix --- +result +result-* +.direnv/ diff --git a/flake.lock b/flake.lock new file mode 100644 index 00000000..f2fc1dce --- /dev/null +++ b/flake.lock @@ -0,0 +1,186 @@ +{ + "nodes": { + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1767039857, + "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=", + "owner": "NixOS", + "repo": "flake-compat", + "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1772408722, + "narHash": "sha256-rHuJtdcOjK7rAHpHphUb1iCvgkU3GpfvicLMwwnfMT0=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "f20dc5d9b8027381c474144ecabc9034d6a839a3", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "git-hooks-nix": { + "inputs": { + "flake-compat": "flake-compat", + "gitignore": "gitignore", + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1772893680, + "narHash": "sha256-JDqZMgxUTCq85ObSaFw0HhE+lvdOre1lx9iI6vYyOEs=", + "owner": "cachix", + "repo": "git-hooks.nix", + "rev": "8baab586afc9c9b57645a734c820e4ac0a604af9", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "git-hooks.nix", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "git-hooks-nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1709087332, + "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1770073757, + "narHash": "sha256-Vy+G+F+3E/Tl+GMNgiHl9Pah2DgShmIUBJXmbiQPHbI=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "47472570b1e607482890801aeaf29bfb749884f6", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-lib": { + "locked": { + "lastModified": 1772328832, + "narHash": "sha256-e+/T/pmEkLP6BHhYjx6GmwP5ivonQQn0bJdH9YrRB+Q=", + "owner": "nix-community", + "repo": "nixpkgs.lib", + "rev": "c185c7a5e5dd8f9add5b2f8ebeff00888b070742", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixpkgs.lib", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1773628058, + "narHash": "sha256-hpXH0z3K9xv0fHaje136KY872VT2T5uwxtezlAskQgY=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "f8573b9c935cfaa162dd62cc9e75ae2db86f85df", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_3": { + "locked": { + "lastModified": 1770107345, + "narHash": "sha256-tbS0Ebx2PiA1FRW8mt8oejR0qMXmziJmPaU1d4kYY9g=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "4533d9293756b63904b7238acb84ac8fe4c8c2c4", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-parts": "flake-parts", + "git-hooks-nix": "git-hooks-nix", + "nixpkgs": "nixpkgs_2", + "systems": "systems", + "treefmt-nix": "treefmt-nix" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "treefmt-nix": { + "inputs": { + "nixpkgs": "nixpkgs_3" + }, + "locked": { + "lastModified": 1773297127, + "narHash": "sha256-6E/yhXP7Oy/NbXtf1ktzmU8SdVqJQ09HC/48ebEGBpk=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "71b125cd05fbfd78cab3e070b73544abe24c5016", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 00000000..8bec6e5b --- /dev/null +++ b/flake.nix @@ -0,0 +1,127 @@ +{ + description = "Lython: an LLVM/MLIR 23 based Python compiler toolchain"; + + # `nix run github:t3tra-dev/lython` otherwise compiles two LLVM trees from + # source; this lets a first-time user accept the binary cache instead. + nixConfig = { + extra-substituters = [ "https://comamoca-lython.cachix.org" ]; + extra-trusted-public-keys = [ + "comamoca-lython.cachix.org-1:AsNMU2Rio0MerjVsy2UJgjt6cP/ywp7tk0peqoxB1VU=" + ]; + }; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; + treefmt-nix.url = "github:numtide/treefmt-nix"; + flake-parts.url = "github:hercules-ci/flake-parts"; + systems.url = "github:nix-systems/default"; + git-hooks-nix.url = "github:cachix/git-hooks.nix"; + }; + + outputs = + inputs@{ + self, + systems, + nixpkgs, + flake-parts, + ... + }: + flake-parts.lib.mkFlake { inherit inputs; } { + imports = [ + inputs.treefmt-nix.flakeModule + inputs.git-hooks-nix.flakeModule + ]; + systems = import inputs.systems; + + perSystem = + { + config, + pkgs, + system, + ... + }: + let + # Lython hard-requires LLVM/MLIR major 23 (LYTHON_LLVM_MAJOR_VERSION + # in CMakeLists.txt); nixpkgs ships 21. The overlay drops the + # nixpkgs-built toolchain in under the name the rest of the flake + # (and downstream users) expects. + llvm23Overlay = final: prev: { + llvm23 = final.callPackage ./nix/llvm23.nix { }; + mlir23 = final.callPackage ./nix/mlir23.nix { inherit (final) llvm23; }; + }; + + lyPkgs = import inputs.nixpkgs { + inherit system; + overlays = [ llvm23Overlay ]; + }; + + inherit (lyPkgs) llvm23 mlir23; + + lython = lyPkgs.callPackage ./nix/build-lython.nix { inherit llvm23 mlir23; }; + in + { + treefmt = { + projectRootFile = "flake.nix"; + programs = { + nixfmt.enable = true; + }; + + settings.formatter = { }; + }; + + pre-commit = { + check.enable = true; + settings = { + hooks = { + treefmt.enable = true; + ripsecrets.enable = true; + gitleaks = { + enable = true; + entry = "${pkgs.gitleaks}/bin/gitleaks protect --staged"; + language = "system"; + }; + }; + }; + }; + + packages = { + default = lython; + lython = lython; + llvm23 = llvm23; + mlir23 = mlir23; + }; + + devShells.default = pkgs.mkShell { + packages = [ + # The built compiler itself, so `lyc jit` / `lyc foo.py` work + # straight from `nix develop`. + lython + llvm23 + mlir23 + pkgs.cmake + pkgs.ninja + pkgs.gnumake + pkgs.pkg-config + pkgs.python3 + pkgs.uv + pkgs.gdb + # `lyc` shells out to the clang in llvm23/bin for AOT and WASI + # linking; that clang locates the C++ runtime by finding gcc on + # PATH. + pkgs.gcc + pkgs.binutils + ]; + + LLVM_DIR = "${llvm23}/lib/cmake/llvm"; + MLIR_DIR = "${mlir23}/lib/cmake/mlir"; + + shellHook = '' + export LLVM_DIR="${llvm23}/lib/cmake/llvm" + export MLIR_DIR="${mlir23}/lib/cmake/mlir" + echo "LLVM_DIR=$LLVM_DIR" + echo "MLIR_DIR=$MLIR_DIR" + ''; + }; + }; + }; +} diff --git a/nix/build-lython.nix b/nix/build-lython.nix new file mode 100644 index 00000000..c09c2e0f --- /dev/null +++ b/nix/build-lython.nix @@ -0,0 +1,51 @@ +{ + lib, + stdenv, + cmake, + ninja, + llvm23, + mlir23, + zlib, + zstd, + libxml2, + ncurses, +}: + +stdenv.mkDerivation { + pname = "lython"; + version = "0.1.0"; + + src = ../.; + + nativeBuildInputs = [ + cmake + ninja + llvm23 + mlir23 + ]; + + buildInputs = [ + llvm23 + mlir23 + zlib + zstd + libxml2 + ncurses + ]; + + cmakeFlags = [ + (lib.cmakeFeature "CMAKE_BUILD_TYPE" "Release") + "-DLLVM_DIR=${llvm23}/lib/cmake/llvm" + "-DMLIR_DIR=${mlir23}/lib/cmake/mlir" + # tests/CMakeLists.txt pulls googletest through FetchContent, which has no + # network inside the Nix sandbox. The unit and golden suites are run from + # the devShell, where the fetch can reach the network. + "-DLYTHON_BUILD_TESTS=OFF" + ]; + + meta = { + description = "An LLVM/MLIR 23 based Python compiler toolchain"; + homepage = "https://github.com/t3tra-dev/lython"; + platforms = [ "x86_64-linux" ]; + }; +} \ No newline at end of file diff --git a/nix/llvm23.nix b/nix/llvm23.nix new file mode 100644 index 00000000..7a21e6bb --- /dev/null +++ b/nix/llvm23.nix @@ -0,0 +1,107 @@ +{ + lib, + stdenv, + fetchurl, + cmake, + ninja, + python3, + zlib, + zstd, + libxml2, + ncurses, + glibc, + makeWrapper, +}: + +stdenv.mkDerivation (finalAttrs: { + pname = "llvm"; + version = "23.1.2"; + + # The nixpkgs LLVM 21 packaging cannot be pointed at 23: its + # gnu-install-dirs patch no longer applies (llvm_setup_rpath moved), and + # Lython needs the shared `LLVM` and `MLIR` CMake targets that a plain + # nixpkgs MLIR build does not export. Building the release monorepo + # directly keeps LLVM and MLIR in one tree with the exact configuration + # Lython's CMakeLists asks for. + src = fetchurl { + url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-${finalAttrs.version}/llvm-project-${finalAttrs.version}.src.tar.xz"; + hash = "sha256-yYu+8IorTCYTzVDpqprntpsf5sFrLEA3O8CrYRb994o="; + }; + + sourceRoot = "llvm-project-${finalAttrs.version}.src/llvm"; + + nativeBuildInputs = [ + cmake + ninja + python3 + makeWrapper + ]; + + buildInputs = [ + zlib + zstd + libxml2 + ncurses + ]; + + cmakeFlags = [ + (lib.cmakeFeature "CMAKE_BUILD_TYPE" "Release") + # clang is the linker driver `lyc` shells out to for AOT and for the WASI + # target, and lld supplies wasm-ld; both must be the LLVM lyc is linked + # against, which is also why they live in this derivation. + (lib.cmakeFeature "LLVM_ENABLE_PROJECTS" "clang;lld") + (lib.cmakeFeature "LLVM_TARGETS_TO_BUILD" "X86;AArch64;WebAssembly") + (lib.cmakeBool "LLVM_BUILD_LLVM_DYLIB" true) + (lib.cmakeBool "LLVM_LINK_LLVM_DYLIB" true) + (lib.cmakeBool "LLVM_ENABLE_ASSERTIONS" false) + (lib.cmakeBool "LLVM_ENABLE_DUMP" true) + (lib.cmakeBool "LLVM_ENABLE_RTTI" true) + (lib.cmakeBool "LLVM_ENABLE_LIBXML2" true) + (lib.cmakeBool "LLVM_ENABLE_ZLIB" true) + (lib.cmakeBool "LLVM_ENABLE_ZSTD" true) + (lib.cmakeBool "LLVM_ENABLE_TERMINFO" true) + (lib.cmakeBool "LLVM_ENABLE_SPHINX" false) + (lib.cmakeBool "LLVM_INCLUDE_TESTS" false) + (lib.cmakeBool "LLVM_INCLUDE_BENCHMARKS" false) + (lib.cmakeBool "LLVM_BUILD_TOOLS" true) + (lib.cmakeBool "LLVM_INSTALL_UTILS" true) + (lib.cmakeBool "LLVM_ENABLE_BINDINGS" false) + (lib.cmakeBool "LLVM_ENABLE_IDE" false) + (lib.cmakeBool "LLVM_BUILD_EXAMPLES" false) + (lib.cmakeBool "LLVM_INSTALL_TOOLCHAIN_ONLY" false) + ]; + + + # A bare clang in Nix cannot find the C++ runtime: it does not probe the + # gcc on PATH (that gcc is a wrapper script, and glibc lives in its own + # store path anyway), so AOT linking fails on crt1.o / libstdc++. The + # wrapper hands clang the same four things nixpkgs' cc-wrapper does: the + # GCC installation directory, its libstdc++, glibc's headers and its + # start files. `--inherit-argv0` keeps clang++ in C++ driver mode. + postFixup = '' + gccInstallDir=$(echo ${stdenv.cc.cc}/lib/gcc/*/*) + ldso=$(echo ${glibc}/lib/ld-linux*.so.2) + for tool in clang clang++; do + wrapProgram "$out/bin/$tool" \ + --inherit-argv0 \ + --add-flags "--gcc-install-dir=$gccInstallDir" \ + --add-flags "-isystem ${glibc.dev}/include" \ + --add-flags "-B${glibc}/lib" \ + --add-flags "-L${glibc}/lib" \ + --add-flags "-L${stdenv.cc.cc.lib}/lib" \ + --add-flags "-fuse-ld=$out/bin/ld.lld" \ + --add-flags "-Wl,--dynamic-linker=$ldso" \ + --add-flags "-Wl,-rpath,${glibc}/lib" \ + --add-flags "-Wl,-rpath,${stdenv.cc.cc.lib}/lib" + done + ''; + + requiredSystemFeatures = [ "big-parallel" ]; + + meta = { + description = "LLVM ${finalAttrs.version}, shared library with exported CMake packages"; + homepage = "https://llvm.org"; + license = lib.licenses.asl20; + platforms = lib.platforms.unix; + }; +}) \ No newline at end of file diff --git a/nix/mlir23.nix b/nix/mlir23.nix new file mode 100644 index 00000000..81103175 --- /dev/null +++ b/nix/mlir23.nix @@ -0,0 +1,83 @@ +{ + lib, + stdenv, + fetchurl, + cmake, + ninja, + python3, + zlib, + zstd, + libxml2, + ncurses, + llvm23, +}: + +let + version = "23.1.2"; +in +stdenv.mkDerivation (finalAttrs: { + pname = "mlir"; + inherit version; + + # Lython's CMake requires the shared `MLIR` CMake target, which MLIR only + # exports from a BUILD_SHARED_LIBS=ON build. LLVM refuses that flag + # alongside LLVM_LINK_LLVM_DYLIB, and nixpkgs' MLIR builds static-only, so + # MLIR is built standalone here against the shared LLVM 23 above. + src = fetchurl { + url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-${version}/llvm-project-${version}.src.tar.xz"; + hash = "sha256-yYu+8IorTCYTzVDpqprntpsf5sFrLEA3O8CrYRb994o="; + }; + + sourceRoot = "llvm-project-${version}.src/mlir"; + + # MLIR's standalone detection looks one directory up for an LLVM source + # tree; a full one there makes it treat the absent in-tree LLVM build as + # the tablegen source and no generated header appears. nixpkgs leaves a + # blank `llvm/` for the same reason. + postUnpack = '' + rm -rf llvm-project-${version}.src/llvm/* + ''; + + nativeBuildInputs = [ + cmake + ninja + python3 + ]; + + buildInputs = [ + llvm23 + zlib + zstd + libxml2 + ncurses + ]; + + cmakeFlags = [ + (lib.cmakeFeature "CMAKE_BUILD_TYPE" "Release") + (lib.cmakeFeature "LLVM_DIR" "${llvm23}/lib/cmake/llvm") + (lib.cmakeFeature "LLVM_TABLEGEN_EXE" "${llvm23}/bin/llvm-tblgen") + (lib.cmakeBool "LLVM_BUILD_LLVM_DYLIB" true) + (lib.cmakeBool "LLVM_LINK_LLVM_DYLIB" true) + (lib.cmakeBool "LLVM_ENABLE_RTTI" true) + (lib.cmakeBool "LLVM_ENABLE_ASSERTIONS" false) + (lib.cmakeBool "LLVM_ENABLE_LIBXML2" true) + (lib.cmakeBool "LLVM_ENABLE_ZLIB" true) + (lib.cmakeBool "LLVM_ENABLE_ZSTD" true) + (lib.cmakeBool "MLIR_INCLUDE_TESTS" false) + (lib.cmakeBool "MLIR_ENABLE_BINDINGS_PYTHON" false) + (lib.cmakeBool "MLIR_BUILD_EXAMPLES" false) + # add_tablegen() only installs mlir-tblgen when LLVM_BUILD_UTILS is set; + # Lython's CMake looks it up by name on PATH. + (lib.cmakeBool "LLVM_BUILD_UTILS" true) + (lib.cmakeBool "LLVM_INSTALL_TOOLCHAIN_ONLY" false) + ]; + + requiredSystemFeatures = [ "big-parallel" ]; + + meta = { + description = "MLIR ${version} built against LLVM ${version}"; + homepage = "https://mlir.llvm.org/"; + license = lib.licenses.asl20; + platforms = lib.platforms.unix; + }; +}) \ No newline at end of file From c64cd5e3a233db33f9d8a2176d24888b1af8f7e4 Mon Sep 17 00:00:00 2001 From: Comamoca Date: Fri, 9 Oct 2026 04:29:24 +0900 Subject: [PATCH 2/9] refactor(nix): make `nix run` fetch only nixpkgs Flake inputs are fetched lazily, but flake-parts' mkFlake forces its `imports`, so evaluating packages.default dragged flake-parts, nixpkgs-lib, systems, treefmt-nix and git-hooks-nix into every end-user fetch. Hand-rolled outputs keep the tooling inputs referenced only from checks/formatter, which `nix run`/`nix build` never touch; the nixpkgs follows collapse the lock from three nixpkgs revisions to one (11 nodes -> 6). `nix run` also could not execute at all: it looked for bin/lython (the pname) while CMake installs bin/lyc, so meta.mainProgram = "lyc" now points it at the real binary. Verified with forged-narHash probes: packages.default succeeds with all four dev inputs poisoned, while checks.* still fail (they do fetch them). nix flake check, nix develop -c true and `nix run . -- parse examples/hello.py` all pass; nix fmt fixed the trailing-newline diff that kept treefmt/pre-commit checks red. --- flake.lock | 92 ++--------------------- flake.nix | 172 +++++++++++++++++++++++++------------------ nix/build-lython.nix | 5 +- nix/llvm23.nix | 3 +- nix/mlir23.nix | 2 +- 5 files changed, 115 insertions(+), 159 deletions(-) diff --git a/flake.lock b/flake.lock index f2fc1dce..dade1eee 100644 --- a/flake.lock +++ b/flake.lock @@ -16,29 +16,13 @@ "type": "github" } }, - "flake-parts": { - "inputs": { - "nixpkgs-lib": "nixpkgs-lib" - }, - "locked": { - "lastModified": 1772408722, - "narHash": "sha256-rHuJtdcOjK7rAHpHphUb1iCvgkU3GpfvicLMwwnfMT0=", - "owner": "hercules-ci", - "repo": "flake-parts", - "rev": "f20dc5d9b8027381c474144ecabc9034d6a839a3", - "type": "github" - }, - "original": { - "owner": "hercules-ci", - "repo": "flake-parts", - "type": "github" - } - }, "git-hooks-nix": { "inputs": { "flake-compat": "flake-compat", "gitignore": "gitignore", - "nixpkgs": "nixpkgs" + "nixpkgs": [ + "nixpkgs" + ] }, "locked": { "lastModified": 1772893680, @@ -76,37 +60,6 @@ } }, "nixpkgs": { - "locked": { - "lastModified": 1770073757, - "narHash": "sha256-Vy+G+F+3E/Tl+GMNgiHl9Pah2DgShmIUBJXmbiQPHbI=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "47472570b1e607482890801aeaf29bfb749884f6", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs-lib": { - "locked": { - "lastModified": 1772328832, - "narHash": "sha256-e+/T/pmEkLP6BHhYjx6GmwP5ivonQQn0bJdH9YrRB+Q=", - "owner": "nix-community", - "repo": "nixpkgs.lib", - "rev": "c185c7a5e5dd8f9add5b2f8ebeff00888b070742", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "nixpkgs.lib", - "type": "github" - } - }, - "nixpkgs_2": { "locked": { "lastModified": 1773628058, "narHash": "sha256-hpXH0z3K9xv0fHaje136KY872VT2T5uwxtezlAskQgY=", @@ -122,49 +75,18 @@ "type": "github" } }, - "nixpkgs_3": { - "locked": { - "lastModified": 1770107345, - "narHash": "sha256-tbS0Ebx2PiA1FRW8mt8oejR0qMXmziJmPaU1d4kYY9g=", - "owner": "nixos", - "repo": "nixpkgs", - "rev": "4533d9293756b63904b7238acb84ac8fe4c8c2c4", - "type": "github" - }, - "original": { - "owner": "nixos", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, "root": { "inputs": { - "flake-parts": "flake-parts", "git-hooks-nix": "git-hooks-nix", - "nixpkgs": "nixpkgs_2", - "systems": "systems", + "nixpkgs": "nixpkgs", "treefmt-nix": "treefmt-nix" } }, - "systems": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - }, "treefmt-nix": { "inputs": { - "nixpkgs": "nixpkgs_3" + "nixpkgs": [ + "nixpkgs" + ] }, "locked": { "lastModified": 1773297127, diff --git a/flake.nix b/flake.nix index 8bec6e5b..3df51f81 100644 --- a/flake.nix +++ b/flake.nix @@ -12,92 +12,123 @@ inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; + + # Dev-only inputs: referenced from `checks`/`formatter` below, never from + # `packages`/`devShells`. Flake inputs are fetched lazily, so `nix run` and + # `nix build` fetch nothing but nixpkgs. A flake-parts setup could not do + # this: mkFlake forces its `imports`, dragging these five inputs into every + # evaluation of `packages.default`. The follows also collapses the lock + # from three nixpkgs revisions to one. treefmt-nix.url = "github:numtide/treefmt-nix"; - flake-parts.url = "github:hercules-ci/flake-parts"; - systems.url = "github:nix-systems/default"; + treefmt-nix.inputs.nixpkgs.follows = "nixpkgs"; git-hooks-nix.url = "github:cachix/git-hooks.nix"; + git-hooks-nix.inputs.nixpkgs.follows = "nixpkgs"; }; outputs = - inputs@{ + { self, - systems, nixpkgs, - flake-parts, + treefmt-nix, + git-hooks-nix, ... }: - flake-parts.lib.mkFlake { inherit inputs; } { - imports = [ - inputs.treefmt-nix.flakeModule - inputs.git-hooks-nix.flakeModule + let + # nix-systems/default, inlined: four system names are not worth an input + # every `nix run` user would fetch. + systems = [ + "aarch64-darwin" + "aarch64-linux" + "x86_64-darwin" + "x86_64-linux" ]; - systems = import inputs.systems; - perSystem = - { - config, - pkgs, - system, - ... - }: - let - # Lython hard-requires LLVM/MLIR major 23 (LYTHON_LLVM_MAJOR_VERSION - # in CMakeLists.txt); nixpkgs ships 21. The overlay drops the - # nixpkgs-built toolchain in under the name the rest of the flake - # (and downstream users) expects. - llvm23Overlay = final: prev: { - llvm23 = final.callPackage ./nix/llvm23.nix { }; - mlir23 = final.callPackage ./nix/mlir23.nix { inherit (final) llvm23; }; - }; + forAllSystems = nixpkgs.lib.genAttrs systems; - lyPkgs = import inputs.nixpkgs { - inherit system; - overlays = [ llvm23Overlay ]; - }; + pkgsFor = system: import nixpkgs { inherit system; }; - inherit (lyPkgs) llvm23 mlir23; + # Lython hard-requires LLVM/MLIR major 23 (LYTHON_LLVM_MAJOR_VERSION + # in CMakeLists.txt); nixpkgs ships 21. The overlay drops the + # nixpkgs-built toolchain in under the name the rest of the flake + # (and downstream users) expects. + llvm23Overlay = final: prev: { + llvm23 = final.callPackage ./nix/llvm23.nix { }; + mlir23 = final.callPackage ./nix/mlir23.nix { inherit (final) llvm23; }; + }; - lython = lyPkgs.callPackage ./nix/build-lython.nix { inherit llvm23 mlir23; }; - in - { - treefmt = { - projectRootFile = "flake.nix"; - programs = { - nixfmt.enable = true; - }; + lyPkgsFor = + system: + import nixpkgs { + inherit system; + overlays = [ llvm23Overlay ]; + }; - settings.formatter = { }; - }; + # Formatting and git-hook configs stay behind `formatter`/`checks` only. + # Referencing them from `packages` or `devShells` would make `nix run` + # fetch the tooling inputs again. + treefmtEvalFor = + system: + treefmt-nix.lib.evalModule (pkgsFor system) { + projectRootFile = "flake.nix"; + programs.nixfmt.enable = true; + settings.formatter = { }; + }; - pre-commit = { - check.enable = true; - settings = { - hooks = { - treefmt.enable = true; - ripsecrets.enable = true; - gitleaks = { - enable = true; - entry = "${pkgs.gitleaks}/bin/gitleaks protect --staged"; - language = "system"; - }; - }; + preCommitFor = + system: + git-hooks-nix.lib.${system}.run { + src = ./.; + hooks = { + treefmt = { + enable = true; + # The hook must format with this repo's generated treefmt config + # (nixfmt), not a bare treefmt that would find no treefmt.toml. + package = (treefmtEvalFor system).config.build.wrapper; + }; + ripsecrets.enable = true; + gitleaks = { + enable = true; + entry = "${(pkgsFor system).gitleaks}/bin/gitleaks protect --staged"; + language = "system"; }; }; - - packages = { - default = lython; - lython = lython; - llvm23 = llvm23; - mlir23 = mlir23; + }; + in + { + packages = forAllSystems ( + system: + let + lyPkgs = lyPkgsFor system; + lython = lyPkgs.callPackage ./nix/build-lython.nix { + inherit (lyPkgs) llvm23 mlir23; }; + in + { + default = lython; + inherit lython; + llvm23 = lyPkgs.llvm23; + mlir23 = lyPkgs.mlir23; + } + ); + + formatter = forAllSystems (system: (treefmtEvalFor system).config.build.wrapper); - devShells.default = pkgs.mkShell { + checks = forAllSystems (system: { + treefmt = (treefmtEvalFor system).config.build.check self; + pre-commit = preCommitFor system; + }); + + devShells = forAllSystems ( + system: + let + pkgs = pkgsFor system; + lyPkgs = lyPkgsFor system; + in + { + default = pkgs.mkShell { packages = [ - # The built compiler itself, so `lyc jit` / `lyc foo.py` work - # straight from `nix develop`. - lython - llvm23 - mlir23 + lyPkgs.llvm23 + lyPkgs.mlir23 pkgs.cmake pkgs.ninja pkgs.gnumake @@ -112,16 +143,17 @@ pkgs.binutils ]; - LLVM_DIR = "${llvm23}/lib/cmake/llvm"; - MLIR_DIR = "${mlir23}/lib/cmake/mlir"; + LLVM_DIR = "${lyPkgs.llvm23}/lib/cmake/llvm"; + MLIR_DIR = "${lyPkgs.mlir23}/lib/cmake/mlir"; shellHook = '' - export LLVM_DIR="${llvm23}/lib/cmake/llvm" - export MLIR_DIR="${mlir23}/lib/cmake/mlir" + export LLVM_DIR="${lyPkgs.llvm23}/lib/cmake/llvm" + export MLIR_DIR="${lyPkgs.mlir23}/lib/cmake/mlir" echo "LLVM_DIR=$LLVM_DIR" echo "MLIR_DIR=$MLIR_DIR" ''; }; - }; + } + ); }; } diff --git a/nix/build-lython.nix b/nix/build-lython.nix index c09c2e0f..1a36c774 100644 --- a/nix/build-lython.nix +++ b/nix/build-lython.nix @@ -46,6 +46,9 @@ stdenv.mkDerivation { meta = { description = "An LLVM/MLIR 23 based Python compiler toolchain"; homepage = "https://github.com/t3tra-dev/lython"; + # Without this `nix run` looks for bin/lython (the pname) and fails; the + # installed binary is lyc. + mainProgram = "lyc"; platforms = [ "x86_64-linux" ]; }; -} \ No newline at end of file +} diff --git a/nix/llvm23.nix b/nix/llvm23.nix index 7a21e6bb..372bb5d3 100644 --- a/nix/llvm23.nix +++ b/nix/llvm23.nix @@ -71,7 +71,6 @@ stdenv.mkDerivation (finalAttrs: { (lib.cmakeBool "LLVM_INSTALL_TOOLCHAIN_ONLY" false) ]; - # A bare clang in Nix cannot find the C++ runtime: it does not probe the # gcc on PATH (that gcc is a wrapper script, and glibc lives in its own # store path anyway), so AOT linking fails on crt1.o / libstdc++. The @@ -104,4 +103,4 @@ stdenv.mkDerivation (finalAttrs: { license = lib.licenses.asl20; platforms = lib.platforms.unix; }; -}) \ No newline at end of file +}) diff --git a/nix/mlir23.nix b/nix/mlir23.nix index 81103175..e13401cb 100644 --- a/nix/mlir23.nix +++ b/nix/mlir23.nix @@ -80,4 +80,4 @@ stdenv.mkDerivation (finalAttrs: { license = lib.licenses.asl20; platforms = lib.platforms.unix; }; -}) \ No newline at end of file +}) From cc6d5eb5e5534c50cc4f08c3c510543f90f83a9b Mon Sep 17 00:00:00 2001 From: Comamoca Date: Fri, 9 Oct 2026 05:36:17 +0900 Subject: [PATCH 3/9] chore: ignore .omo/ session state directory --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 9ca937a7..a486053f 100644 --- a/.gitignore +++ b/.gitignore @@ -238,3 +238,4 @@ tools/.ucd-cache/ result result-* .direnv/ +.omo/ From ccb1a31df482c243692bc5ea16e6327bbbd44eb6 Mon Sep 17 00:00:00 2001 From: Comamoca Date: Fri, 9 Oct 2026 05:36:21 +0900 Subject: [PATCH 4/9] feat(nix): add direnv config for flake dev shell --- .envrc | 1 + 1 file changed, 1 insertion(+) create mode 100644 .envrc diff --git a/.envrc b/.envrc new file mode 100644 index 00000000..3550a30f --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake From 3ff6f6c0bb5937fa86cfbb4897009e5157455b97 Mon Sep 17 00:00:00 2001 From: Comamoca Date: Fri, 9 Oct 2026 05:39:45 +0900 Subject: [PATCH 5/9] revert: remove .omo/ from .gitignore --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index a486053f..9ca937a7 100644 --- a/.gitignore +++ b/.gitignore @@ -238,4 +238,3 @@ tools/.ucd-cache/ result result-* .direnv/ -.omo/ From 87d11f94bac83e4ead792911af4c57dc96d653a5 Mon Sep 17 00:00:00 2001 From: Comamoca Date: Mon, 12 Oct 2026 14:17:55 +0900 Subject: [PATCH 6/9] refactor(nix): use nixpkgs llvmPackages_23 instead of source builds nixpkgs-unstable now ships LLVM/MLIR 23 (previously only 21), so the custom nix/llvm23.nix and nix/mlir23.nix (which built the upstream release tarball to get a shared MLIR CMake target) are redundant. - flake.nix: drop the llvm23Overlay and the llvm23/mlir23 package outputs; pull pkgs.llvmPackages_23.{llvm,mlir,tblgen} directly. - build-lython.nix: take llvm / mlir / tblgen as arguments; pass LLVM_TABLEGEN_EXE and MLIR_TABLEGEN_EXE because nixpkgs's mlir derivation does not install mlir-tblgen into its `out`. - delete nix/llvm23.nix and nix/mlir23.nix (no longer referenced). - nix-cache.yml: drop .#llvm23 and .#mlir23 from the Cachix push set; nixpkgs already provides them as binary cache hits. --- .github/workflows/nix-cache.yml | 7 ++- flake.lock | 6 +- flake.nix | 55 +++++------------ nix/build-lython.nix | 24 +++++--- nix/llvm23.nix | 106 -------------------------------- nix/mlir23.nix | 83 ------------------------- 6 files changed, 39 insertions(+), 242 deletions(-) delete mode 100644 nix/llvm23.nix delete mode 100644 nix/mlir23.nix diff --git a/.github/workflows/nix-cache.yml b/.github/workflows/nix-cache.yml index 58f64271..5a8950b3 100644 --- a/.github/workflows/nix-cache.yml +++ b/.github/workflows/nix-cache.yml @@ -1,7 +1,8 @@ name: Nix cache -# Keeps comamoca-lython.cachix.org populated so `nix run` users skip the -# ~1 hour LLVM/MLIR source build (llvm23 1.2 GiB + mlir23 774 MiB). +# Populates comamoca-lython.cachix.org with the lython derivation so `nix +# run` users do not pay the lython source build (LLVM/MLIR itself is +# already a binary cache hit via llvmPackages_23). on: push: @@ -43,7 +44,7 @@ jobs: - name: Build packages env: NIX_CONFIG: "max-jobs = 4 cores = 4" - run: nix build .#llvm23 .#mlir23 .#lython -L + run: nix build .#lython -L - name: Build devShell (warms build-only deps) run: nix develop -c true diff --git a/flake.lock b/flake.lock index dade1eee..2de37cdf 100644 --- a/flake.lock +++ b/flake.lock @@ -61,11 +61,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1773628058, - "narHash": "sha256-hpXH0z3K9xv0fHaje136KY872VT2T5uwxtezlAskQgY=", + "lastModified": 1791487292, + "narHash": "sha256-tqM7xDEsaeK1p6VvRygeZ9LkQRpUUkbRT02BHv6hnTM=", "owner": "nixos", "repo": "nixpkgs", - "rev": "f8573b9c935cfaa162dd62cc9e75ae2db86f85df", + "rev": "8edc0c72e3a38faf5434e40d1f19431125fe4b30", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 3df51f81..e4a6ac83 100644 --- a/flake.nix +++ b/flake.nix @@ -1,15 +1,5 @@ { description = "Lython: an LLVM/MLIR 23 based Python compiler toolchain"; - - # `nix run github:t3tra-dev/lython` otherwise compiles two LLVM trees from - # source; this lets a first-time user accept the binary cache instead. - nixConfig = { - extra-substituters = [ "https://comamoca-lython.cachix.org" ]; - extra-trusted-public-keys = [ - "comamoca-lython.cachix.org-1:AsNMU2Rio0MerjVsy2UJgjt6cP/ywp7tk0peqoxB1VU=" - ]; - }; - inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; @@ -47,22 +37,6 @@ pkgsFor = system: import nixpkgs { inherit system; }; - # Lython hard-requires LLVM/MLIR major 23 (LYTHON_LLVM_MAJOR_VERSION - # in CMakeLists.txt); nixpkgs ships 21. The overlay drops the - # nixpkgs-built toolchain in under the name the rest of the flake - # (and downstream users) expects. - llvm23Overlay = final: prev: { - llvm23 = final.callPackage ./nix/llvm23.nix { }; - mlir23 = final.callPackage ./nix/mlir23.nix { inherit (final) llvm23; }; - }; - - lyPkgsFor = - system: - import nixpkgs { - inherit system; - overlays = [ llvm23Overlay ]; - }; - # Formatting and git-hook configs stay behind `formatter`/`checks` only. # Referencing them from `packages` or `devShells` would make `nix run` # fetch the tooling inputs again. @@ -98,16 +72,17 @@ packages = forAllSystems ( system: let - lyPkgs = lyPkgsFor system; - lython = lyPkgs.callPackage ./nix/build-lython.nix { - inherit (lyPkgs) llvm23 mlir23; + pkgs = pkgsFor system; + llvmPackages = pkgs.llvmPackages_23; + lython = pkgs.callPackage ./nix/build-lython.nix { + llvm = llvmPackages.llvm; + mlir = llvmPackages.mlir; + tblgen = llvmPackages.tblgen; }; in { default = lython; inherit lython; - llvm23 = lyPkgs.llvm23; - mlir23 = lyPkgs.mlir23; } ); @@ -122,13 +97,15 @@ system: let pkgs = pkgsFor system; - lyPkgs = lyPkgsFor system; + llvmPackages = pkgs.llvmPackages_23; in { default = pkgs.mkShell { packages = [ - lyPkgs.llvm23 - lyPkgs.mlir23 + llvmPackages.llvm + llvmPackages.mlir + llvmPackages.clang + llvmPackages.lld pkgs.cmake pkgs.ninja pkgs.gnumake @@ -136,19 +113,19 @@ pkgs.python3 pkgs.uv pkgs.gdb - # `lyc` shells out to the clang in llvm23/bin for AOT and WASI + # `lyc` shells out to the clang in llvm23 for AOT and WASI # linking; that clang locates the C++ runtime by finding gcc on # PATH. pkgs.gcc pkgs.binutils ]; - LLVM_DIR = "${lyPkgs.llvm23}/lib/cmake/llvm"; - MLIR_DIR = "${lyPkgs.mlir23}/lib/cmake/mlir"; + LLVM_DIR = "${llvmPackages.llvm.dev}/lib/cmake/llvm"; + MLIR_DIR = "${llvmPackages.mlir.dev}/lib/cmake/mlir"; shellHook = '' - export LLVM_DIR="${lyPkgs.llvm23}/lib/cmake/llvm" - export MLIR_DIR="${lyPkgs.mlir23}/lib/cmake/mlir" + export LLVM_DIR="${llvmPackages.llvm.dev}/lib/cmake/llvm" + export MLIR_DIR="${llvmPackages.mlir.dev}/lib/cmake/mlir" echo "LLVM_DIR=$LLVM_DIR" echo "MLIR_DIR=$MLIR_DIR" ''; diff --git a/nix/build-lython.nix b/nix/build-lython.nix index 1a36c774..98a924e0 100644 --- a/nix/build-lython.nix +++ b/nix/build-lython.nix @@ -3,8 +3,9 @@ stdenv, cmake, ninja, - llvm23, - mlir23, + llvm, + mlir, + tblgen, zlib, zstd, libxml2, @@ -20,13 +21,14 @@ stdenv.mkDerivation { nativeBuildInputs = [ cmake ninja - llvm23 - mlir23 + llvm + mlir + tblgen ]; buildInputs = [ - llvm23 - mlir23 + llvm + mlir zlib zstd libxml2 @@ -35,8 +37,14 @@ stdenv.mkDerivation { cmakeFlags = [ (lib.cmakeFeature "CMAKE_BUILD_TYPE" "Release") - "-DLLVM_DIR=${llvm23}/lib/cmake/llvm" - "-DMLIR_DIR=${mlir23}/lib/cmake/mlir" + "-DLLVM_DIR=${llvm.dev}/lib/cmake/llvm" + "-DMLIR_DIR=${mlir.dev}/lib/cmake/mlir" + # nixpkgs's mlir does not install mlir-tblgen into its `out`; the tablegen + # binary lives in `llvmPackages_23.tblgen`. Lython's CMake requires + # mlir-tblgen (and llvm-tblgen) at configure time, so we hand it the + # absolute paths here and skip the find_program search. + "-DLLVM_TABLEGEN_EXE=${tblgen}/bin/llvm-tblgen" + "-DMLIR_TABLEGEN_EXE=${tblgen}/bin/mlir-tblgen" # tests/CMakeLists.txt pulls googletest through FetchContent, which has no # network inside the Nix sandbox. The unit and golden suites are run from # the devShell, where the fetch can reach the network. diff --git a/nix/llvm23.nix b/nix/llvm23.nix deleted file mode 100644 index 372bb5d3..00000000 --- a/nix/llvm23.nix +++ /dev/null @@ -1,106 +0,0 @@ -{ - lib, - stdenv, - fetchurl, - cmake, - ninja, - python3, - zlib, - zstd, - libxml2, - ncurses, - glibc, - makeWrapper, -}: - -stdenv.mkDerivation (finalAttrs: { - pname = "llvm"; - version = "23.1.2"; - - # The nixpkgs LLVM 21 packaging cannot be pointed at 23: its - # gnu-install-dirs patch no longer applies (llvm_setup_rpath moved), and - # Lython needs the shared `LLVM` and `MLIR` CMake targets that a plain - # nixpkgs MLIR build does not export. Building the release monorepo - # directly keeps LLVM and MLIR in one tree with the exact configuration - # Lython's CMakeLists asks for. - src = fetchurl { - url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-${finalAttrs.version}/llvm-project-${finalAttrs.version}.src.tar.xz"; - hash = "sha256-yYu+8IorTCYTzVDpqprntpsf5sFrLEA3O8CrYRb994o="; - }; - - sourceRoot = "llvm-project-${finalAttrs.version}.src/llvm"; - - nativeBuildInputs = [ - cmake - ninja - python3 - makeWrapper - ]; - - buildInputs = [ - zlib - zstd - libxml2 - ncurses - ]; - - cmakeFlags = [ - (lib.cmakeFeature "CMAKE_BUILD_TYPE" "Release") - # clang is the linker driver `lyc` shells out to for AOT and for the WASI - # target, and lld supplies wasm-ld; both must be the LLVM lyc is linked - # against, which is also why they live in this derivation. - (lib.cmakeFeature "LLVM_ENABLE_PROJECTS" "clang;lld") - (lib.cmakeFeature "LLVM_TARGETS_TO_BUILD" "X86;AArch64;WebAssembly") - (lib.cmakeBool "LLVM_BUILD_LLVM_DYLIB" true) - (lib.cmakeBool "LLVM_LINK_LLVM_DYLIB" true) - (lib.cmakeBool "LLVM_ENABLE_ASSERTIONS" false) - (lib.cmakeBool "LLVM_ENABLE_DUMP" true) - (lib.cmakeBool "LLVM_ENABLE_RTTI" true) - (lib.cmakeBool "LLVM_ENABLE_LIBXML2" true) - (lib.cmakeBool "LLVM_ENABLE_ZLIB" true) - (lib.cmakeBool "LLVM_ENABLE_ZSTD" true) - (lib.cmakeBool "LLVM_ENABLE_TERMINFO" true) - (lib.cmakeBool "LLVM_ENABLE_SPHINX" false) - (lib.cmakeBool "LLVM_INCLUDE_TESTS" false) - (lib.cmakeBool "LLVM_INCLUDE_BENCHMARKS" false) - (lib.cmakeBool "LLVM_BUILD_TOOLS" true) - (lib.cmakeBool "LLVM_INSTALL_UTILS" true) - (lib.cmakeBool "LLVM_ENABLE_BINDINGS" false) - (lib.cmakeBool "LLVM_ENABLE_IDE" false) - (lib.cmakeBool "LLVM_BUILD_EXAMPLES" false) - (lib.cmakeBool "LLVM_INSTALL_TOOLCHAIN_ONLY" false) - ]; - - # A bare clang in Nix cannot find the C++ runtime: it does not probe the - # gcc on PATH (that gcc is a wrapper script, and glibc lives in its own - # store path anyway), so AOT linking fails on crt1.o / libstdc++. The - # wrapper hands clang the same four things nixpkgs' cc-wrapper does: the - # GCC installation directory, its libstdc++, glibc's headers and its - # start files. `--inherit-argv0` keeps clang++ in C++ driver mode. - postFixup = '' - gccInstallDir=$(echo ${stdenv.cc.cc}/lib/gcc/*/*) - ldso=$(echo ${glibc}/lib/ld-linux*.so.2) - for tool in clang clang++; do - wrapProgram "$out/bin/$tool" \ - --inherit-argv0 \ - --add-flags "--gcc-install-dir=$gccInstallDir" \ - --add-flags "-isystem ${glibc.dev}/include" \ - --add-flags "-B${glibc}/lib" \ - --add-flags "-L${glibc}/lib" \ - --add-flags "-L${stdenv.cc.cc.lib}/lib" \ - --add-flags "-fuse-ld=$out/bin/ld.lld" \ - --add-flags "-Wl,--dynamic-linker=$ldso" \ - --add-flags "-Wl,-rpath,${glibc}/lib" \ - --add-flags "-Wl,-rpath,${stdenv.cc.cc.lib}/lib" - done - ''; - - requiredSystemFeatures = [ "big-parallel" ]; - - meta = { - description = "LLVM ${finalAttrs.version}, shared library with exported CMake packages"; - homepage = "https://llvm.org"; - license = lib.licenses.asl20; - platforms = lib.platforms.unix; - }; -}) diff --git a/nix/mlir23.nix b/nix/mlir23.nix deleted file mode 100644 index e13401cb..00000000 --- a/nix/mlir23.nix +++ /dev/null @@ -1,83 +0,0 @@ -{ - lib, - stdenv, - fetchurl, - cmake, - ninja, - python3, - zlib, - zstd, - libxml2, - ncurses, - llvm23, -}: - -let - version = "23.1.2"; -in -stdenv.mkDerivation (finalAttrs: { - pname = "mlir"; - inherit version; - - # Lython's CMake requires the shared `MLIR` CMake target, which MLIR only - # exports from a BUILD_SHARED_LIBS=ON build. LLVM refuses that flag - # alongside LLVM_LINK_LLVM_DYLIB, and nixpkgs' MLIR builds static-only, so - # MLIR is built standalone here against the shared LLVM 23 above. - src = fetchurl { - url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-${version}/llvm-project-${version}.src.tar.xz"; - hash = "sha256-yYu+8IorTCYTzVDpqprntpsf5sFrLEA3O8CrYRb994o="; - }; - - sourceRoot = "llvm-project-${version}.src/mlir"; - - # MLIR's standalone detection looks one directory up for an LLVM source - # tree; a full one there makes it treat the absent in-tree LLVM build as - # the tablegen source and no generated header appears. nixpkgs leaves a - # blank `llvm/` for the same reason. - postUnpack = '' - rm -rf llvm-project-${version}.src/llvm/* - ''; - - nativeBuildInputs = [ - cmake - ninja - python3 - ]; - - buildInputs = [ - llvm23 - zlib - zstd - libxml2 - ncurses - ]; - - cmakeFlags = [ - (lib.cmakeFeature "CMAKE_BUILD_TYPE" "Release") - (lib.cmakeFeature "LLVM_DIR" "${llvm23}/lib/cmake/llvm") - (lib.cmakeFeature "LLVM_TABLEGEN_EXE" "${llvm23}/bin/llvm-tblgen") - (lib.cmakeBool "LLVM_BUILD_LLVM_DYLIB" true) - (lib.cmakeBool "LLVM_LINK_LLVM_DYLIB" true) - (lib.cmakeBool "LLVM_ENABLE_RTTI" true) - (lib.cmakeBool "LLVM_ENABLE_ASSERTIONS" false) - (lib.cmakeBool "LLVM_ENABLE_LIBXML2" true) - (lib.cmakeBool "LLVM_ENABLE_ZLIB" true) - (lib.cmakeBool "LLVM_ENABLE_ZSTD" true) - (lib.cmakeBool "MLIR_INCLUDE_TESTS" false) - (lib.cmakeBool "MLIR_ENABLE_BINDINGS_PYTHON" false) - (lib.cmakeBool "MLIR_BUILD_EXAMPLES" false) - # add_tablegen() only installs mlir-tblgen when LLVM_BUILD_UTILS is set; - # Lython's CMake looks it up by name on PATH. - (lib.cmakeBool "LLVM_BUILD_UTILS" true) - (lib.cmakeBool "LLVM_INSTALL_TOOLCHAIN_ONLY" false) - ]; - - requiredSystemFeatures = [ "big-parallel" ]; - - meta = { - description = "MLIR ${version} built against LLVM ${version}"; - homepage = "https://mlir.llvm.org/"; - license = lib.licenses.asl20; - platforms = lib.platforms.unix; - }; -}) From 0a5bbad0e970866f9cf05d21dfac8d6d80a63642 Mon Sep 17 00:00:00 2001 From: Comamoca Date: Mon, 12 Oct 2026 14:55:38 +0900 Subject: [PATCH 7/9] fix(nix): add llvmPackages.tblgen to devShell cmake's find_program for mlir-tblgen (Lython's CMakeLists.txt:283) was failing inside `nix develop` because the nixpkgs mlir derivation does not install mlir-tblgen into its `out`. The build-lython.nix side already worked around this by passing the tablegen path explicitly; the devShell side was missing the same fix. Lython's devShell workflow (`cmake -B build && cmake --build build` inside `nix develop`) now works again, which is required to build the test suite (`LYTHON_BUILD_TESTS=ON`). --- flake.nix | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/flake.nix b/flake.nix index e4a6ac83..c1769a89 100644 --- a/flake.nix +++ b/flake.nix @@ -104,6 +104,11 @@ packages = [ llvmPackages.llvm llvmPackages.mlir + # mlir-tblgen and llvm-tblgen live only in `tblgen`; nixpkgs's + # mlir derivation does not install them into its `out`. Lython's + # CMake looks them up on PATH at configure time, so the + # devShell has to bring them in. + llvmPackages.tblgen llvmPackages.clang llvmPackages.lld pkgs.cmake From 8c5f08f87c7f2a24b1bd5ef0b16ec7d6d37086a6 Mon Sep 17 00:00:00 2001 From: Comamoca Date: Mon, 12 Oct 2026 14:55:47 +0900 Subject: [PATCH 8/9] chore: ignore build-* directories in .gitignore `nix develop` users building lython with `cmake -B build-test` (or any other suffixed build dir) would otherwise accidentally stage the hundreds of generated files the next time they ran `git add -A`. The existing `build/` entry only matched an exact name; `build-*/` catches `build-test`, `build-debug`, `build-asan`, etc. --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 9ca937a7..c602b307 100644 --- a/.gitignore +++ b/.gitignore @@ -237,4 +237,6 @@ tools/.ucd-cache/ # --- Nix --- result result-* +build/ +build-*/ .direnv/ From 50f6ee3ceef084e3562cb36d4ab27e908374f3ed Mon Sep 17 00:00:00 2001 From: Comamoca Date: Mon, 12 Oct 2026 15:34:08 +0900 Subject: [PATCH 9/9] Remove Cachix push workflow and git-hooks-nix input LLVM/MLIR is now sourced from nixpkgs's llvmPackages_23, which is already on the public binary cache. The Cachix push workflow no longer needs to hold a self-built LLVM/MLIR (those derivations are gone), and lython's own source build is cheap enough that a private cache adds little value. - .github/workflows/nix-cache.yml: deleted (Cachix push no longer needed) - flake.nix: drop git-hooks-nix input and the pre-commit check (the URL is github:cachix/git-hooks.nix, the only remaining cachix reference; the pre-commit hooks depended on it) - flake.lock: regenerated without git-hooks-nix and its transitive inputs (flake-compat, gitignore) --- .github/workflows/nix-cache.yml | 50 --------------------------- flake.lock | 60 --------------------------------- flake.nix | 36 ++------------------ 3 files changed, 3 insertions(+), 143 deletions(-) delete mode 100644 .github/workflows/nix-cache.yml diff --git a/.github/workflows/nix-cache.yml b/.github/workflows/nix-cache.yml deleted file mode 100644 index 5a8950b3..00000000 --- a/.github/workflows/nix-cache.yml +++ /dev/null @@ -1,50 +0,0 @@ -name: Nix cache - -# Populates comamoca-lython.cachix.org with the lython derivation so `nix -# run` users do not pay the lython source build (LLVM/MLIR itself is -# already a binary cache hit via llvmPackages_23). - -on: - push: - branches: [main] - paths: - - "flake.nix" - - "flake.lock" - - "nix/**" - - "src/**" - - "emitter/**" - - "runtime/**" - - "tools/**" - - "CMakeLists.txt" - - ".github/workflows/nix-cache.yml" - workflow_dispatch: - -jobs: - cache: - name: Build & push to Cachix - runs-on: ubuntu-latest - # LLVM + MLIR + lython source builds are far over the default timeout. - timeout-minutes: 360 - - steps: - - uses: actions/checkout@v4 - - - uses: cachix/install-nix-action@v31 - with: - nix_path: nixpkgs=channel:nixos-unstable - - - uses: cachix/cachix-action@v16 - with: - name: comamoca-lython - authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" - # Everything already in the local store (e.g. from a developer's - # `nix build`) is pushed too — that is the point of this job. - skipPush: false - - - name: Build packages - env: - NIX_CONFIG: "max-jobs = 4 cores = 4" - run: nix build .#lython -L - - - name: Build devShell (warms build-only deps) - run: nix develop -c true diff --git a/flake.lock b/flake.lock index 2de37cdf..05da695d 100644 --- a/flake.lock +++ b/flake.lock @@ -1,64 +1,5 @@ { "nodes": { - "flake-compat": { - "flake": false, - "locked": { - "lastModified": 1767039857, - "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=", - "owner": "NixOS", - "repo": "flake-compat", - "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab", - "type": "github" - }, - "original": { - "owner": "NixOS", - "repo": "flake-compat", - "type": "github" - } - }, - "git-hooks-nix": { - "inputs": { - "flake-compat": "flake-compat", - "gitignore": "gitignore", - "nixpkgs": [ - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1772893680, - "narHash": "sha256-JDqZMgxUTCq85ObSaFw0HhE+lvdOre1lx9iI6vYyOEs=", - "owner": "cachix", - "repo": "git-hooks.nix", - "rev": "8baab586afc9c9b57645a734c820e4ac0a604af9", - "type": "github" - }, - "original": { - "owner": "cachix", - "repo": "git-hooks.nix", - "type": "github" - } - }, - "gitignore": { - "inputs": { - "nixpkgs": [ - "git-hooks-nix", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1709087332, - "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=", - "owner": "hercules-ci", - "repo": "gitignore.nix", - "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", - "type": "github" - }, - "original": { - "owner": "hercules-ci", - "repo": "gitignore.nix", - "type": "github" - } - }, "nixpkgs": { "locked": { "lastModified": 1791487292, @@ -77,7 +18,6 @@ }, "root": { "inputs": { - "git-hooks-nix": "git-hooks-nix", "nixpkgs": "nixpkgs", "treefmt-nix": "treefmt-nix" } diff --git a/flake.nix b/flake.nix index c1769a89..7acc26f5 100644 --- a/flake.nix +++ b/flake.nix @@ -3,16 +3,11 @@ inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; - # Dev-only inputs: referenced from `checks`/`formatter` below, never from - # `packages`/`devShells`. Flake inputs are fetched lazily, so `nix run` and - # `nix build` fetch nothing but nixpkgs. A flake-parts setup could not do - # this: mkFlake forces its `imports`, dragging these five inputs into every - # evaluation of `packages.default`. The follows also collapses the lock - # from three nixpkgs revisions to one. + # Formatting tooling stays behind `formatter`/`checks` only. Referencing + # it from `packages` or `devShells` would make `nix run`/`nix build` fetch + # the tooling input again. treefmt-nix.url = "github:numtide/treefmt-nix"; treefmt-nix.inputs.nixpkgs.follows = "nixpkgs"; - git-hooks-nix.url = "github:cachix/git-hooks.nix"; - git-hooks-nix.inputs.nixpkgs.follows = "nixpkgs"; }; outputs = @@ -20,7 +15,6 @@ self, nixpkgs, treefmt-nix, - git-hooks-nix, ... }: let @@ -37,9 +31,6 @@ pkgsFor = system: import nixpkgs { inherit system; }; - # Formatting and git-hook configs stay behind `formatter`/`checks` only. - # Referencing them from `packages` or `devShells` would make `nix run` - # fetch the tooling inputs again. treefmtEvalFor = system: treefmt-nix.lib.evalModule (pkgsFor system) { @@ -47,26 +38,6 @@ programs.nixfmt.enable = true; settings.formatter = { }; }; - - preCommitFor = - system: - git-hooks-nix.lib.${system}.run { - src = ./.; - hooks = { - treefmt = { - enable = true; - # The hook must format with this repo's generated treefmt config - # (nixfmt), not a bare treefmt that would find no treefmt.toml. - package = (treefmtEvalFor system).config.build.wrapper; - }; - ripsecrets.enable = true; - gitleaks = { - enable = true; - entry = "${(pkgsFor system).gitleaks}/bin/gitleaks protect --staged"; - language = "system"; - }; - }; - }; in { packages = forAllSystems ( @@ -90,7 +61,6 @@ checks = forAllSystems (system: { treefmt = (treefmtEvalFor system).config.build.check self; - pre-commit = preCommitFor system; }); devShells = forAllSystems (