at master 12 kB view raw
1# TODO: 2# - faster build by using lisp with preloaded asdf? 3# - dont include java libs unless abcl? 4# - dont use build-asdf-system to build lispWithPackages? 5# - make the lisp packages overridable? (e.g. buildInputs glibc->musl) 6# - build asdf with nix and use that instead of one shipped with impls 7# (e.g. to fix build with clisp - does anyone use clisp?) 8# - claspPackages ? (gotta package clasp with nix first) 9# - hard one: remove unrelated sources ( of systems not being built) 10# - figure out a less awkward way to patch sources 11# (have to build from src directly for SLIME to work, so can't just patch sources in place) 12 13{ 14 pkgs, 15 lib, 16 stdenv, 17 ... 18}: 19 20let 21 22 inherit (lib) 23 length 24 filter 25 foldl 26 unique 27 id 28 concat 29 concatMap 30 mutuallyExclusive 31 findFirst 32 remove 33 setAttr 34 getAttr 35 hasAttr 36 attrNames 37 attrValues 38 filterAttrs 39 mapAttrs 40 splitString 41 concatStringsSep 42 concatMapStringsSep 43 replaceStrings 44 removeSuffix 45 hasInfix 46 optionalString 47 makeBinPath 48 makeLibraryPath 49 makeSearchPath 50 recurseIntoAttrs 51 ; 52 53 inherit (builtins) 54 head 55 tail 56 elem 57 split 58 storeDir 59 ; 60 61 inherit (pkgs) 62 replaceVars 63 ; 64 65 # Stolen from python-packages.nix 66 # Actually no idea how this works 67 makeOverridableLispPackage = 68 f: origArgs: 69 let 70 ff = f origArgs; 71 overrideWith = 72 newArgs: origArgs // (if pkgs.lib.isFunction newArgs then newArgs origArgs else newArgs); 73 in 74 if builtins.isAttrs ff then 75 ( 76 ff 77 // { 78 overrideLispAttrs = newArgs: makeOverridableLispPackage f (overrideWith newArgs); 79 } 80 ) 81 else if builtins.isFunction ff then 82 { 83 overrideLispAttrs = newArgs: makeOverridableLispPackage f (overrideWith newArgs); 84 __functor = self: ff; 85 } 86 else 87 ff; 88 89 buildAsdf = 90 { 91 asdf, 92 pkg, 93 program, 94 flags, 95 faslExt, 96 }: 97 stdenv.mkDerivation { 98 inherit (asdf) pname version; 99 dontUnpack = true; 100 buildPhase = '' 101 cp -v ${asdf}/lib/common-lisp/asdf/build/asdf.lisp asdf.lisp 102 ${pkg}/bin/${program} ${toString flags} < <(echo '(compile-file "asdf.lisp")') 103 ''; 104 installPhase = '' 105 mkdir -p $out 106 cp -v asdf.${faslExt} $out 107 ''; 108 }; 109 110 # 111 # Wrapper around stdenv.mkDerivation for building ASDF systems. 112 # 113 build-asdf-system = makeOverridableLispPackage ( 114 { 115 pname, 116 version, 117 src ? null, 118 patches ? [ ], 119 120 # Native libraries, will be appended to the library path 121 nativeLibs ? [ ], 122 123 # Java libraries for ABCL, will be appended to the class path 124 javaLibs ? [ ], 125 126 # Lisp dependencies 127 # these should be packages built with `build-asdf-system` 128 # TODO(kasper): use propagatedBuildInputs 129 lispLibs ? [ ], 130 131 # Derivation containing the CL implementation package 132 pkg, 133 134 # Name of the Lisp executable 135 program ? pkg.meta.mainProgram or pkg.pname, 136 137 # General flags to the Lisp executable 138 flags ? [ ], 139 140 # Extension for implementation-dependent FASL files 141 faslExt, 142 143 # ASDF amalgamation file to use 144 # Created in build/asdf.lisp by `make` in ASDF source tree 145 asdf, 146 147 # Some libraries have multiple systems under one project, for 148 # example, cffi has cffi-grovel, cffi-toolchain etc. By 149 # default, only the `pname` system is build. 150 # 151 # .asd's not listed in `systems` are removed in 152 # installPhase. This prevents asdf from referring to uncompiled 153 # systems on run time. 154 # 155 # Also useful when the pname is different than the system name, 156 # such as when using reverse domain naming. 157 systems ? [ pname ], 158 159 # The .asd files that this package provides 160 # TODO(kasper): remove 161 asds ? systems, 162 163 # Other args to mkDerivation 164 ... 165 }@args: 166 167 ( 168 stdenv.mkDerivation ( 169 rec { 170 inherit 171 version 172 nativeLibs 173 javaLibs 174 lispLibs 175 systems 176 asds 177 pkg 178 program 179 flags 180 faslExt 181 ; 182 183 # When src is null, we are building a lispWithPackages and only 184 # want to make use of the dependency environment variables 185 # generated by build-asdf-system 186 dontUnpack = src == null; 187 188 # Portable script to build the systems. 189 # 190 # `lisp` must evaluate this file then exit immediately. For 191 # example, SBCL's --script flag does just that. 192 # 193 # NOTE: 194 # Every other library worked fine with asdf:compile-system in 195 # buildScript. 196 # 197 # cl-syslog, for some reason, signals that CL-SYSLOG::VALID-SD-ID-P 198 # is undefined with compile-system, but works perfectly with 199 # load-system. Strange. 200 201 # TODO(kasper) portable quit 202 asdfFasl = buildAsdf { 203 inherit 204 asdf 205 pkg 206 program 207 flags 208 faslExt 209 ; 210 }; 211 212 buildScript = replaceVars ./builder.lisp { 213 asdf = "${asdfFasl}/asdf.${faslExt}"; 214 }; 215 216 configurePhase = '' 217 runHook preConfigure 218 219 source ${./setup-hook.sh} 220 buildAsdfPath 221 222 runHook postConfigure 223 ''; 224 225 buildPhase = optionalString (src != null) '' 226 runHook preBuild 227 228 export CL_SOURCE_REGISTRY=$CL_SOURCE_REGISTRY:$src// 229 export ASDF_OUTPUT_TRANSLATIONS="$src:$(pwd):${storeDir}:${storeDir}" 230 ${pkg}/bin/${program} ${toString flags} < $buildScript 231 232 runHook postBuild 233 ''; 234 235 # Copy compiled files to store 236 # 237 # Make sure to include '$' in regex to prevent skipping 238 # stuff like 'iolib.asdf.asd' for system 'iolib.asd' 239 # 240 # Same with '/': `local-time.asd` for system `cl-postgres+local-time.asd` 241 installPhase = 242 let 243 mkSystemsRegex = 244 systems: concatMapStringsSep "\\|" (replaceStrings [ "." "+" ] [ "[.]" "[+]" ]) systems; 245 in 246 '' 247 runHook preInstall 248 249 mkdir -pv $out 250 cp -r * $out 251 252 # Remove all .asd files except for those in `systems`. 253 find $out -name "*.asd" \ 254 | grep -v "/\(${mkSystemsRegex systems}\)\.asd$" \ 255 | xargs rm -fv || true 256 257 runHook postInstall 258 ''; 259 260 dontPatchShebangs = true; 261 262 # Not sure if it's needed, but caused problems with SBCL 263 # save-lisp-and-die binaries in the past 264 dontStrip = true; 265 266 } 267 // ( 268 args 269 // ( 270 let 271 isJVM = args.pkg.pname == "abcl"; 272 javaLibs = lib.optionals isJVM args.javaLibs or [ ]; 273 in 274 { 275 pname = "${args.pkg.pname}-${args.pname}"; 276 src = 277 if args ? patches || args ? postPatch then 278 pkgs.applyPatches { 279 inherit (args) src; 280 patches = args.patches or [ ]; 281 postPatch = args.postPatch or ""; 282 } 283 else 284 args.src; 285 patches = [ ]; 286 inherit javaLibs; 287 propagatedBuildInputs = args.propagatedBuildInputs or [ ] ++ lispLibs ++ javaLibs ++ nativeLibs; 288 meta = (args.meta or { }) // { 289 maintainers = args.meta.maintainers or [ ]; 290 teams = args.meta.teams or [ lib.teams.lisp ]; 291 }; 292 } 293 ) 294 ) 295 ) 296 // { 297 # Useful for overriding 298 # Overriding code would prefer to use pname from the attribute set 299 # However, pname is extended with the implementation name 300 # Moreover, it is used in the default list of systems to load 301 # So we pass the original pname 302 pname = args.pname; 303 } 304 ) 305 ); 306 307 # Build the set of lisp packages using `lisp` 308 # These packages are defined manually for one reason or another: 309 # - The library is not in quicklisp 310 # - The library that is in quicklisp is broken 311 # - Special build procedure such as cl-unicode, asdf 312 # 313 # They can use the auto-imported quicklisp packages as dependencies, 314 # but some of those don't work out of the box. 315 # 316 # E.g if a QL package depends on cl-unicode it won't build out of 317 # the box. 318 commonLispPackagesFor = 319 spec: 320 let 321 build-asdf-system' = body: build-asdf-system (body // spec); 322 in 323 pkgs.callPackage ./packages.nix { 324 inherit spec quicklispPackagesFor; 325 build-asdf-system = build-asdf-system'; 326 }; 327 328 # Build the set of packages imported from quicklisp using `lisp` 329 quicklispPackagesFor = 330 spec: 331 let 332 build-asdf-system' = body: build-asdf-system (body // spec); 333 in 334 pkgs.callPackage ./ql.nix { 335 build-asdf-system = build-asdf-system'; 336 }; 337 338 # Creates a lisp wrapper with `packages` installed 339 # 340 # `packages` is a function that takes `clpkgs` - a set of lisp 341 # packages - as argument and returns the list of packages to be 342 # installed 343 # TODO(kasper): assert each package has the same lisp and asdf? 344 lispWithPackages = 345 clpkgs: packages: 346 let 347 first = head (lib.attrValues clpkgs); 348 in 349 (build-asdf-system { 350 inherit (first) 351 pkg 352 program 353 flags 354 faslExt 355 asdf 356 ; 357 # See dontUnpack in build-asdf-system 358 src = null; 359 pname = "with"; 360 version = "packages"; 361 lispLibs = packages clpkgs; 362 systems = [ ]; 363 }).overrideAttrs 364 (o: { 365 nativeBuildInputs = [ pkgs.makeBinaryWrapper ]; 366 installPhase = '' 367 mkdir -pv $out/bin 368 makeWrapper \ 369 ${o.pkg}/bin/${o.program} \ 370 $out/bin/${o.program} \ 371 --add-flags "${toString o.flags}" \ 372 --set ASDF "${o.asdfFasl}/asdf.${o.faslExt}" \ 373 --prefix CL_SOURCE_REGISTRY : "$CL_SOURCE_REGISTRY''${CL_SOURCE_REGISTRY:+:}" \ 374 --prefix ASDF_OUTPUT_TRANSLATIONS : "$(echo $CL_SOURCE_REGISTRY | sed s,//:,::,g):" \ 375 --prefix LD_LIBRARY_PATH : "$LD_LIBRARY_PATH" \ 376 --prefix DYLD_LIBRARY_PATH : "$DYLD_LIBRARY_PATH" \ 377 --prefix CLASSPATH : "$CLASSPATH" \ 378 --prefix GI_TYPELIB_PATH : "$GI_TYPELIB_PATH" \ 379 --prefix PATH : "${makeBinPath (o.propagatedBuildInputs or [ ])}" 380 ''; 381 }); 382 383 wrapLisp = 384 { 385 pkg, 386 faslExt, 387 program ? pkg.meta.mainProgram or pkg.pname, 388 flags ? [ ], 389 asdf ? pkgs.asdf_3_3, 390 packageOverrides ? (self: super: { }), 391 }: 392 let 393 spec = { 394 inherit 395 pkg 396 faslExt 397 program 398 flags 399 asdf 400 ; 401 }; 402 pkgs = (commonLispPackagesFor spec).overrideScope packageOverrides; 403 withPackages = lispWithPackages pkgs; 404 withOverrides = 405 packageOverrides: 406 wrapLisp { 407 inherit 408 pkg 409 faslExt 410 program 411 flags 412 asdf 413 ; 414 inherit packageOverrides; 415 }; 416 buildASDFSystem = args: build-asdf-system (args // spec); 417 in 418 pkg 419 // { 420 inherit 421 pkgs 422 withPackages 423 withOverrides 424 buildASDFSystem 425 ; 426 }; 427 428in 429wrapLisp