{ lib , stdenv , callPackage , runCommand , writeText , pub2nix , dartHooks , makeWrapper , dart , nodejs , darwin , jq , yq }: { src , sourceRoot ? "source" , packageRoot ? (lib.removePrefix "/" (lib.removePrefix "source" sourceRoot)) , gitHashes ? { } , sdkSourceBuilders ? { } , customSourceBuilders ? { } , sdkSetupScript ? "" , extraPackageConfigSetup ? "" # Output type to produce. Can be any kind supported by dart # https://dart.dev/tools/dart-compile#types-of-output # If using jit, you might want to pass some arguments to `dartJitFlags` , dartOutputType ? "exe" , dartCompileCommand ? "dart compile" , dartCompileFlags ? [ ] # These come at the end of the command, useful to pass flags to the jit run , dartJitFlags ? [ ] # Attrset of entry point files to build and install. # Where key is the final binary path and value is the source file path # e.g. { "bin/foo" = "bin/main.dart"; } # Set to null to read executables from pubspec.yaml , dartEntryPoints ? null # Used when wrapping aot, jit, kernel, and js builds. # Set to null to disable wrapping. , dartRuntimeCommand ? if dartOutputType == "aot-snapshot" then "${dart}/bin/dartaotruntime" else if (dartOutputType == "jit-snapshot" || dartOutputType == "kernel") then "${dart}/bin/dart" else if dartOutputType == "js" then "${nodejs}/bin/node" else null , runtimeDependencies ? [ ] , extraWrapProgramArgs ? "" , autoPubspecLock ? null , pubspecLock ? if autoPubspecLock == null then throw "The pubspecLock argument is required. If import-from-derivation is allowed (it isn't in Nixpkgs), you can set autoPubspecLock to the path to a pubspec.lock instead." else assert lib.assertMsg (builtins.pathExists autoPubspecLock) "The pubspec.lock file could not be found!"; lib.importJSON (runCommand "${lib.getName args}-pubspec-lock-json" { nativeBuildInputs = [ yq ]; } ''yq . '${autoPubspecLock}' > "$out"'') , ... }@args: let generators = callPackage ./generators.nix { inherit dart; } { buildDrvArgs = args; }; pubspecLockFile = builtins.toJSON pubspecLock; pubspecLockData = pub2nix.readPubspecLock { inherit src packageRoot pubspecLock gitHashes sdkSourceBuilders customSourceBuilders; }; packageConfig = generators.linkPackageConfig { packageConfig = pub2nix.generatePackageConfig { pname = if args.pname != null then "${args.pname}-${args.version}" else null; dependencies = # Ideally, we'd only include the main dependencies and their transitive # dependencies. # # The pubspec.lock file does not contain information about where # transitive dependencies come from, though, and it would be weird to # include the transitive dependencies of dev and override dependencies # without including the dev and override dependencies themselves. builtins.concatLists (builtins.attrValues pubspecLockData.dependencies); inherit (pubspecLockData) dependencySources; }; extraSetupCommands = extraPackageConfigSetup; }; inherit (dartHooks.override { inherit dart; }) dartConfigHook dartBuildHook dartInstallHook dartFixupHook; baseDerivation = stdenv.mkDerivation (finalAttrs: (builtins.removeAttrs args [ "gitHashes" "sdkSourceBuilders" "pubspecLock" "customSourceBuilders" ]) // { inherit pubspecLockFile packageConfig sdkSetupScript dartCompileCommand dartOutputType dartRuntimeCommand dartCompileFlags dartJitFlags; outputs = args.outputs or [ ] ++ [ "out" "pubcache" ]; dartEntryPoints = if (dartEntryPoints != null) then writeText "entrypoints.json" (builtins.toJSON dartEntryPoints) else null; runtimeDependencies = map lib.getLib runtimeDependencies; nativeBuildInputs = (args.nativeBuildInputs or [ ]) ++ [ dart dartConfigHook dartBuildHook dartInstallHook dartFixupHook makeWrapper jq ] ++ lib.optionals stdenv.isDarwin [ darwin.sigtool ] ++ # Ensure that we inherit the propagated build inputs from the dependencies. builtins.attrValues pubspecLockData.dependencySources; preConfigure = args.preConfigure or "" + '' ln -sf "$pubspecLockFilePath" pubspec.lock ''; # When stripping, it seems some ELF information is lost and the dart VM cli # runs instead of the expected program. Don't strip if it's an exe output. dontStrip = args.dontStrip or (dartOutputType == "exe"); passAsFile = [ "pubspecLockFile" ]; passthru = { pubspecLock = pubspecLockData; } // (args.passthru or { }); meta = (args.meta or { }) // { platforms = args.meta.platforms or dart.meta.platforms; }; }); in assert !(builtins.isString dartOutputType && dartOutputType != "") -> throw "dartOutputType must be a non-empty string"; baseDerivation