Unverified Commit b465d339 authored by Maciej Krüger's avatar Maciej Krüger Committed by GitHub
Browse files

Merge pull request #231483 from hacker1024/feature/flutter-on-dart

buildFlutterApplication: Wrap buildDartApplication
parents 96107a2d 98a7a5ed
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -12,6 +12,8 @@ If you are packaging a Flutter desktop application, use [`buildFlutterApplicatio

If the upstream source is missing a `pubspec.lock` file, you'll have to vendor one and specify it using `pubspecLockFile`. If it is needed, one will be generated for you and printed when attempting to build the derivation.

The `depsListFile` must always be provided when packaging in Nixpkgs. It will be generated and printed if the derivation is attempted to be built without one. Alternatively, `autoDepsList` may be set to `true` only when outside of Nixpkgs, as it relies on import-from-derivation.

The `dart` commands run can be overridden through `pubGetScript` and `dartCompileCommand`, you can also add flags using `dartCompileFlags` or `dartJitFlags`.

Dart supports multiple [outputs types](https://dart.dev/tools/dart-compile#types-of-output), you can choose between them using `dartOutputType` (defaults to `exe`). If you want to override the binaries path or the source path they come from, you can use `dartEntryPoints`. Outputs that require a runtime will automatically be wrapped with the relevant runtime (`dartaotruntime` for `aot-snapshot`, `dart run` for `jit-snapshot` and `kernel`, `node` for `js`), this can be overridden through `dartRuntimeCommand`.
@@ -31,6 +33,7 @@ buildDartApplication rec {
  };

  pubspecLockFile = ./pubspec.lock;
  depsListFile = ./deps.json;
  vendorHash = "sha256-Atm7zfnDambN/BmmUf4BG0yUz/y6xWzf0reDw3Ad41s=";
}
```
@@ -39,9 +42,7 @@ buildDartApplication rec {

The function `buildFlutterApplication` builds Flutter applications.

The deps.json file must always be provided when packaging in Nixpkgs. It will be generated and printed if the derivation is attempted to be built without one. Alternatively, `autoDepsList` may be set to `true` when outside of Nixpkgs, as it relies on import-from-derivation.

A `pubspec.lock` file must be available. See the [Dart documentation](#ssec-dart-applications) for more details.
See the [Dart documentation](#ssec-dart-applications) for more details on required files and arguments.

```nix
{  flutter, fetchFromGitHub }:
+80 −31
Original line number Diff line number Diff line
{ lib, stdenv, fetchDartDeps, runCommand, writeText, dartHooks, makeWrapper, dart, cacert, nodejs, darwin }:
{ lib, stdenv, callPackage, fetchDartDeps, runCommand, writeText, dartHooks, makeWrapper, dart, cacert, nodejs, darwin, jq }:

{ pubGetScript ? "dart pub get"
{ sdkSetupScript ? ""
, pubGetScript ? "dart pub get"

  # Output type to produce. Can be any kind supported by dart
  # https://dart.dev/tools/dart-compile#types-of-output
@@ -18,12 +19,16 @@
, 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"
, 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 ? ""
, customPackageOverrides ? { }
, autoDepsList ? false
, depsListFile ? null
, pubspecLockFile ? null
, vendorHash ? ""
, ...
@@ -38,32 +43,48 @@ let
    '';
  }) {
    buildDrvArgs = args;
    inherit pubGetScript vendorHash pubspecLockFile;
    inherit sdkSetupScript pubGetScript vendorHash pubspecLockFile;
  };
  inherit (dartHooks.override { inherit dart; }) dartConfigHook dartBuildHook dartInstallHook;
in
assert !(builtins.isString dartOutputType && dartOutputType != "") ->
  throw "dartOutputType must be a non-empty string";
stdenv.mkDerivation (args // {
  inherit pubGetScript dartCompileCommand dartOutputType dartRuntimeCommand
    dartCompileFlags dartJitFlags;
  inherit (dartHooks.override { inherit dart; }) dartConfigHook dartBuildHook dartInstallHook dartFixupHook;

  baseDerivation = stdenv.mkDerivation (finalAttrs: args // {
    inherit sdkSetupScript pubGetScript dartCompileCommand dartOutputType
      dartRuntimeCommand dartCompileFlags dartJitFlags runtimeDependencies;

    dartEntryPoints =
      if (dartEntryPoints != null)
      then writeText "entrypoints.json" (builtins.toJSON dartEntryPoints)
      else null;

    runtimeDependencyLibraryPath = lib.makeLibraryPath finalAttrs.runtimeDependencies;

    nativeBuildInputs = (args.nativeBuildInputs or [ ]) ++ [
      dart
      dartDeps
      dartConfigHook
      dartBuildHook
      dartInstallHook
      dartFixupHook
      makeWrapper
      jq
    ] ++ lib.optionals stdenv.isDarwin [
      darwin.sigtool
    ];

    preUnpack = ''
      ${lib.optionalString (!autoDepsList) ''
        if ! { [ '${lib.boolToString (depsListFile != null)}' = 'true' ] ${lib.optionalString (depsListFile != null) "&& cmp -s <(jq -Sc . '${depsListFile}') <(jq -Sc . '${finalAttrs.passthru.dartDeps.depsListFile}')"}; }; then
          echo 1>&2 -e '\nThe dependency list file was either not given or differs from the expected result.' \
                      '\nPlease choose one of the following solutions:' \
                      '\n - Duplicate the following file and pass it to the depsListFile argument.' \
                      '\n   ${finalAttrs.passthru.dartDeps.depsListFile}' \
                      '\n - Set autoDepsList to true (not supported by Hydra or permitted in Nixpkgs)'.
          exit 1
        fi
      ''}
      ${args.preUnpack or ""}
    '';

    # 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");
@@ -71,4 +92,32 @@ stdenv.mkDerivation (args // {
    passthru = { inherit dartDeps; } // (args.passthru or { });

    meta = (args.meta or { }) // { platforms = args.meta.platforms or dart.meta.platforms; };
  });

  packageOverrideRepository = (callPackage ../../../development/compilers/dart/package-overrides { }) // customPackageOverrides;
  productPackages = builtins.filter (package: package.kind != "dev")
    (if autoDepsList
    then lib.importJSON dartDeps.depsListFile
    else
      if depsListFile == null
      then [ ]
      else lib.importJSON depsListFile);
in
assert !(builtins.isString dartOutputType && dartOutputType != "") ->
throw "dartOutputType must be a non-empty string";
builtins.foldl'
  (prev: package:
  if packageOverrideRepository ? ${package.name}
  then
    prev.overrideAttrs
      (packageOverrideRepository.${package.name} {
        inherit (package)
          name
          version
          kind
          source
          dependencies;
      })
  else prev)
  baseDerivation
  productPackages
+3 −0
Original line number Diff line number Diff line
@@ -3,6 +3,9 @@
dartConfigHook() {
    echo "Executing dartConfigHook"

    echo "Setting up SDK"
    eval "$sdkSetupScript"

    echo "Installing dependencies"
    eval doPubGet "$pubGetScript" --offline

+32 −0
Original line number Diff line number Diff line
# shellcheck shell=bash

dartFixupHook() {
    echo "Executing dartFixupHook"

    declare -a wrapProgramArgs

    # Add runtime library dependencies to the LD_LIBRARY_PATH.
    # For some reason, the RUNPATH of the executable is not used to load dynamic libraries in dart:ffi with DynamicLibrary.open().
    #
    # This could alternatively be fixed with patchelf --add-needed, but this would cause all the libraries to be opened immediately,
    # which is not what application authors expect.
    echo "$runtimeDependencyLibraryPath"
    if [[ ! -z "$runtimeDependencyLibraryPath" ]]; then
        wrapProgramArgs+=(--suffix LD_LIBRARY_PATH : \"$runtimeDependencyLibraryPath\")
    fi

    if [[ ! -z "$extraWrapProgramArgs" ]]; then
        wrapProgramArgs+=("$extraWrapProgramArgs")
    fi

    if [ ${#wrapProgramArgs[@]} -ne 0 ]; then
        for f in "$out"/bin/*; do
            echo "Wrapping $f..."
            eval "wrapProgram \"$f\" ${wrapProgramArgs[@]}"
        done
    fi

    echo "Finished dartFixupHook"
}

postFixupHooks+=(dartFixupHook)
+3 −0
Original line number Diff line number Diff line
@@ -12,4 +12,7 @@
  dartInstallHook = makeSetupHook {
    name = "dart-install-hook";
  } ./dart-install-hook.sh;
  dartFixupHook = makeSetupHook {
    name = "dart-fixup-hook";
  } ./dart-fixup-hook.sh;
}
Loading