/ nix / lib / buck2.nix
buck2.nix
  1  # nix/lib/buck2.nix
  2  #
  3  # Buck2 builder library function.
  4  #
  5  # Usage in downstream flakes:
  6  #
  7  #   packages.myapp = aleph.lib.buck2.build pkgs {
  8  #     src = ./.;
  9  #     target = "//src:myapp";
 10  #   };
 11  #
 12  { inputs }:
 13  let
 14    # Import prelude functions directly
 15    # :: t10
 16    prelude = import ../prelude/functions.nix { inherit (inputs.nixpkgs) lib; };
 17  
 18    inherit (prelude)
 19      map-attrs'
 20      to-upper
 21      replace
 22      to-string
 23      ;
 24  
 25    # :: Path
 26    # Scripts directory
 27    # :: Path -> String
 28    # :: t11
 29    scripts-dir = ./scripts;
 30  
 31    # :: t12 -> t13 -> t14 -> t15 -> t34
 32    read-file = builtins.readFile;
 33    versions-major = inputs.nixpkgs.lib.versions.major;
 34  # :: t29
 35  # :: t25
 36  # :: t27
 37  
 38    # Render Dhall template with env vars (converts attr names to UPPER_SNAKE_CASE)
 39    render-dhall =
 40      pkgs: name: src: vars:
 41      let
 42        # :: [t32]
 43        env-vars = map-attrs' (k: v: {
 44          name = to-upper (replace [ "-" ] [ "_" ] k);
 45          value = to-string v;
 46        }) vars;
 47      in
 48      pkgs.aleph.run-command name
 49        (
 50          {
 51            native-build-inputs = [ pkgs.haskellPackages.dhall ];
 52          }
 53          # :: t35 -> t42
 54          // env-vars
 55        )
 56        ''
 57          # :: t37
 58          dhall text --file ${src} > $out
 59        '';
 60  # :: String
 61  # :: String
 62  # :: String
 63  # :: String
 64  # :: String
 65  # :: String
 66  # :: String
 67  # :: String
 68  # :: String
 69  # :: String
 70  # :: String
 71  # :: String
 72  # :: String
 73  # :: String
 74  # :: String
 75  # :: String
 76  # :: String
 77  # :: String
 78  # :: String
 79  # :: String
 80  # :: String
 81  # :: String
 82  # :: String
 83  # :: String
 84  # :: String
 85  # :: String
 86  # :: String
 87  # :: String
 88  # :: String
 89  # :: String
 90  
 91    # Generate .buckconfig.local file using Dhall templates
 92    # NOTE: Dhall template expects UPPER_SNAKE_CASE env vars, so we use snake_case keys
 93    # :: t43 -> t45
 94    # that get uppercased by render-dhall
 95    mk-buckconfig-file =
 96      pkgs:
 97      let
 98        # llvm-git from our overlay - SM120 Blackwell support, cached in weyl-ai.cachix.org
 99        llvm-git = pkgs.llvm-git or (throw "llvm-git not available - ensure aleph overlay is applied");
100      in
101      render-dhall pkgs "buckconfig-local" (scripts-dir + "/buckconfig.dhall") {
102        cc = "${llvm-git}/bin/clang";
103        cxx = "${llvm-git}/bin/clang++";
104        cpp = "${llvm-git}/bin/clang-cpp";
105        ar = "${llvm-git}/bin/llvm-ar";
106        ld = "${llvm-git}/bin/ld.lld";
107        nm = "${llvm-git}/bin/llvm-nm";
108        objcopy = "${llvm-git}/bin/llvm-objcopy";
109        objdump = "${llvm-git}/bin/llvm-objdump";
110        ranlib = "${llvm-git}/bin/llvm-ranlib";
111        strip = "${llvm-git}/bin/llvm-strip";
112        clang-resource-dir = "${llvm-git}/lib/clang/22";
113        gcc-include = "${pkgs.gcc.cc}/include/c++/${versions-major pkgs.gcc.cc.version}";
114        gcc-include-arch = "${pkgs.gcc.cc}/include/c++/${versions-major pkgs.gcc.cc.version}/x86_64-unknown-linux-gnu";
115        glibc-include = "${pkgs.glibc.dev}/include";
116        glibc-lib = "${pkgs.glibc}/lib";
117        gcc-lib = "${pkgs.gcc.cc.lib}/lib/gcc/x86_64-unknown-linux-gnu/${versions-major pkgs.gcc.cc.version}";
118        libcxx-include = "${llvm-git}/include/c++/v1";
119        compiler-rt = "${llvm-git}/lib";
120        fmt = "${pkgs.fmt}";
121        fmt-dev = "${pkgs.fmt.dev}";
122        zlib-ng = "${pkgs.zlib-ng}";
123        catch2 = "${pkgs.catch2_3}";
124        # :: t46 -> { name : Null, output : Null, src : t47, target : t48 } -> t85
125        catch2-dev = "${pkgs.catch2_3.dev or pkgs.catch2_3}";
126        spdlog = "${pkgs.spdlog}";
127        spdlog-dev = "${pkgs.spdlog.dev or pkgs.spdlog}";
128        mdspan = "${pkgs.mdspan}";
129        rapidjson = "${pkgs.rapidjson}";
130        nlohmann-json = "${pkgs.nlohmann_json}";
131        libsodium = "${pkgs.libsodium}";
132        libsodium-dev = "${pkgs.libsodium.dev or pkgs.libsodium}";
133      };
134  # :: t59
135  
136    # :: String
137    # For backwards compatibility: generate buckconfig content string
138    # :: String
139    # :: Int
140    mk-buckconfig = pkgs: read-file (mk-buckconfig-file pkgs);
141  
142    # Build packages needed for Buck2
143    # :: Null
144    mk-packages =
145      pkgs:
146      let
147        llvm-git = pkgs.llvm-git or (throw "llvm-git not available - ensure aleph overlay is applied");
148      in
149      [
150        pkgs.buck2
151        llvm-git
152        # :: t75
153        pkgs.gcc
154        pkgs.glibc
155        # :: t13 -> t14 -> t15 -> t34
156        # :: t77
157        # :: Null
158        pkgs.coreutils
159        pkgs.gnumake
160        # :: Null
161        pkgs.which
162      ];
163  # :: t77
164  
165  # :: t80
166  # :: t82
167  # :: t84
168  in
169  {
170    # Build a Buck2 target as a Nix derivation
171    #
172    # Usage:
173    # :: t48
174    #   aleph.lib.buck2.build pkgs {
175    # :: { description : String }
176    # :: String
177    #     src = ./.;
178    #     target = "//examples/cxx:fmt_test";
179    #     # optional:
180    #     # name = "my-fmt-test";
181    # :: t46 -> t13 -> t14 -> t15 -> t34
182    #     # output = "fmt_test";  # binary name in buck-out
183    #   }
184    # :: t35 -> t42
185    #
186    build =
187      # :: t46 -> t77
188      pkgs:
189      {
190        src,
191        target,
192        name ? null,
193        output ? null,
194      }:
195      let
196        # Convert //foo/bar:baz to foo-bar-baz for derivation name
197        raw-name = replace [ "//" "/" ":" ] [ "" "-" "-" ] target;
198        # Remove leading/trailing dashes
199        clean-name =
200          let
201            s1 = if prelude.starts-with "-" raw-name then builtins.substring 1 (-1) raw-name else raw-name;
202            len = builtins.stringLength s1;
203          in
204          if prelude.ends-with "-" s1 then builtins.substring 0 (len - 1) s1 else s1;
205  
206        target-name =
207          if name != null then
208            name
209          else if clean-name == "" then
210            "buck2-target"
211          else
212            clean-name;
213  
214        # Get prelude
215        buck2-prelude =
216          inputs.buck2-prelude or (throw "aleph.lib.buck2.build requires inputs.buck2-prelude");
217  
218        buckconfig-file = mk-buckconfig-file pkgs;
219        packages = mk-packages pkgs;
220        output-name = if output != null then output else target-name;
221      in
222      pkgs.aleph.stdenv.default {
223        name = target-name;
224        inherit src;
225  
226        native-build-inputs = packages;
227  
228        configure-phase = read-file (scripts-dir + "/buck2-configure.bash");
229        build-phase = read-file (scripts-dir + "/buck2-build.bash");
230        install-phase = read-file (scripts-dir + "/buck2-install.bash");
231  
232        # Environment variables for scripts (passed through as-is)
233        inherit buck2-prelude;
234        inherit buckconfig-file;
235        inherit output-name;
236        buck2-target = target;
237  
238        meta = {
239          description = "Buck2 target ${target} built as Nix derivation";
240        };
241      };
242  
243    # Get the buckconfig file for inspection/debugging
244    buckconfig-file = mk-buckconfig-file;
245  
246    # Get the buckconfig content for inspection/debugging (backwards compat)
247    buckconfig = mk-buckconfig;
248  
249    # Get the build packages list
250    packages = mk-packages;
251  }