diff options
author | Maciej Krüger <mkg20001@gmail.com> | 2023-10-21 23:42:02 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-10-21 23:42:02 +0200 |
commit | b465d339b38c883448a9b810159ec0cf82ba88ae (patch) | |
tree | bb96a3fe0c669bdebf59bd188ed75f443a4c6e61 /pkgs/build-support | |
parent | 96107a2d2a2f351a75defdd95bf0a0a52e9910f6 (diff) | |
parent | 98a7a5edd36d91b906558536f73239e709b36feb (diff) |
Merge pull request #231483 from hacker1024/feature/flutter-on-dart
buildFlutterApplication: Wrap buildDartApplication
Diffstat (limited to 'pkgs/build-support')
6 files changed, 181 insertions, 178 deletions
diff --git a/pkgs/build-support/dart/build-dart-application/default.nix b/pkgs/build-support/dart/build-dart-application/default.nix index be1fd72776711..76328e5645f6b 100644 --- a/pkgs/build-support/dart/build-dart-application/default.nix +++ b/pkgs/build-support/dart/build-dart-application/default.nix @@ -1,6 +1,7 @@ -{ 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" - else if (dartOutputType == "jit-snapshot" || dartOutputType == "kernel") then "${dart}/bin/dart" - else if dartOutputType == "js" then "${nodejs}/bin/node" - else null +, 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,37 +43,81 @@ 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; - nativeBuildInputs = (args.nativeBuildInputs or [ ]) ++ [ - dart - dartDeps - dartConfigHook - dartBuildHook - dartInstallHook - makeWrapper - ] ++ lib.optionals stdenv.isDarwin [ - darwin.sigtool - ]; + runtimeDependencyLibraryPath = lib.makeLibraryPath finalAttrs.runtimeDependencies; - # 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"); + 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 ""} + ''; - passthru = { inherit dartDeps; } // (args.passthru 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"); - meta = (args.meta or { }) // { platforms = args.meta.platforms or dart.meta.platforms; }; -}) + 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 diff --git a/pkgs/build-support/dart/build-dart-application/hooks/dart-config-hook.sh b/pkgs/build-support/dart/build-dart-application/hooks/dart-config-hook.sh index 3e901995237d9..f22d7d2ce64d4 100644 --- a/pkgs/build-support/dart/build-dart-application/hooks/dart-config-hook.sh +++ b/pkgs/build-support/dart/build-dart-application/hooks/dart-config-hook.sh @@ -3,6 +3,9 @@ dartConfigHook() { echo "Executing dartConfigHook" + echo "Setting up SDK" + eval "$sdkSetupScript" + echo "Installing dependencies" eval doPubGet "$pubGetScript" --offline diff --git a/pkgs/build-support/dart/build-dart-application/hooks/dart-fixup-hook.sh b/pkgs/build-support/dart/build-dart-application/hooks/dart-fixup-hook.sh new file mode 100644 index 0000000000000..c5a9bedd0665a --- /dev/null +++ b/pkgs/build-support/dart/build-dart-application/hooks/dart-fixup-hook.sh @@ -0,0 +1,32 @@ +# 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) diff --git a/pkgs/build-support/dart/build-dart-application/hooks/default.nix b/pkgs/build-support/dart/build-dart-application/hooks/default.nix index 463061c54a8dd..134989426d96b 100644 --- a/pkgs/build-support/dart/build-dart-application/hooks/default.nix +++ b/pkgs/build-support/dart/build-dart-application/hooks/default.nix @@ -12,4 +12,7 @@ dartInstallHook = makeSetupHook { name = "dart-install-hook"; } ./dart-install-hook.sh; + dartFixupHook = makeSetupHook { + name = "dart-fixup-hook"; + } ./dart-fixup-hook.sh; } diff --git a/pkgs/build-support/dart/fetch-dart-deps/default.nix b/pkgs/build-support/dart/fetch-dart-deps/default.nix index e523b60797eb1..51052cae18f48 100644 --- a/pkgs/build-support/dart/fetch-dart-deps/default.nix +++ b/pkgs/build-support/dart/fetch-dart-deps/default.nix @@ -169,6 +169,8 @@ let dart pub deps --json | jq .packages > $out runHook postBuild ''; + + dontInstall = true; } // (removeAttrs buildDrvInheritArgs [ "name" "pname" ])); # As of Dart 3.0.0, Pub checks the revision of cached Git-sourced packages. diff --git a/pkgs/build-support/flutter/default.nix b/pkgs/build-support/flutter/default.nix index a0ed1211ed812..3e136211655b8 100644 --- a/pkgs/build-support/flutter/default.nix +++ b/pkgs/build-support/flutter/default.nix @@ -1,34 +1,28 @@ { lib , callPackage -, stdenvNoCC , runCommand , makeWrapper , wrapGAppsHook -, llvmPackages_13 +, fetchDartDeps +, buildDartApplication , cacert , glib , flutter -, jq }: # absolutely no mac support for now { pubGetScript ? "flutter pub get" , flutterBuildFlags ? [ ] -, runtimeDependencies ? [ ] -, customPackageOverrides ? { } -, autoDepsList ? false -, depsListFile ? null -, vendorHash ? "" -, pubspecLockFile ? null -, nativeBuildInputs ? [ ] -, preUnpack ? "" -, postFixup ? "" , extraWrapProgramArgs ? "" , ... }@args: -let - flutterSetupScript = '' + +(buildDartApplication.override { + dart = flutter; + fetchDartDeps = fetchDartDeps.override { dart = flutter; }; +}) (args // { + sdkSetupScript = '' # Pub needs SSL certificates. Dart normally looks in a hardcoded path. # https://github.com/dart-lang/sdk/blob/3.1.0/runtime/bin/security_context_linux.cc#L48 # @@ -54,136 +48,56 @@ let flutter config --enable-linux-desktop >/dev/null ''; - deps = callPackage ../dart/fetch-dart-deps { dart = flutter; } { - sdkSetupScript = flutterSetupScript; - inherit pubGetScript vendorHash pubspecLockFile; - buildDrvArgs = args; - }; - - baseDerivation = llvmPackages_13.stdenv.mkDerivation (finalAttrs: args // { - inherit flutterBuildFlags runtimeDependencies; - - outputs = [ "out" "debug" ]; - - nativeBuildInputs = [ - makeWrapper - deps - flutter - jq - glib - wrapGAppsHook - ] ++ nativeBuildInputs; - - dontWrapGApps = true; - - preUnpack = '' - ${lib.optionalString (!autoDepsList) '' - if ! { [ '${lib.boolToString (depsListFile != null)}' = 'true' ] ${lib.optionalString (depsListFile != null) "&& cmp -s <(jq -Sc . '${depsListFile}') <(jq -Sc . '${finalAttrs.passthru.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.depsListFile}' \ - '\n - Set autoDepsList to true (not supported by Hydra or permitted in Nixpkgs)'. - exit 1 - fi - ''} - - ${preUnpack} - ''; - - configurePhase = '' - runHook preConfigure - - ${flutterSetupScript} - - runHook postConfigure - ''; - - buildPhase = '' - runHook preBuild - - mkdir -p build/flutter_assets/fonts - - doPubGet flutter pub get --offline -v - flutter build linux -v --release --split-debug-info="$debug" ${builtins.concatStringsSep " " (map (flag: "\"${flag}\"") finalAttrs.flutterBuildFlags)} - - runHook postBuild - ''; - - installPhase = '' - runHook preInstall - - built=build/linux/*/release/bundle - - mkdir -p $out/bin - mv $built $out/app - - for f in $(find $out/app -iname "*.desktop" -type f); do - install -D $f $out/share/applications/$(basename $f) - done - - for f in $(find $out/app -maxdepth 1 -type f); do - ln -s $f $out/bin/$(basename $f) - done - - # make *.so executable - find $out/app -iname "*.so" -type f -exec chmod +x {} + - - # remove stuff like /build/source/packages/ubuntu_desktop_installer/linux/flutter/ephemeral - for f in $(find $out/app -executable -type f); do - if patchelf --print-rpath "$f" | grep /build; then # this ignores static libs (e,g. libapp.so) also - echo "strip RPath of $f" - newrp=$(patchelf --print-rpath $f | sed -r "s|/build.*ephemeral:||g" | sed -r "s|/build.*profile:||g") - patchelf --set-rpath "$newrp" "$f" - fi - done - - runHook postInstall - ''; - - postFixup = '' - # 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. - for f in "$out"/bin/*; do - wrapProgram "$f" \ - --suffix LD_LIBRARY_PATH : '${lib.makeLibraryPath finalAttrs.runtimeDependencies}' \ - ''${gappsWrapperArgs[@]} \ - ${extraWrapProgramArgs} - done - - ${postFixup} - ''; - - passthru = (args.passthru or {}) // { - inherit (deps) depsListFile; - }; - }); - - packageOverrideRepository = (callPackage ../../development/compilers/flutter/package-overrides { }) // customPackageOverrides; - productPackages = builtins.filter (package: package.kind != "dev") - (if autoDepsList - then lib.importJSON deps.depsListFile - else - if depsListFile == null - then [ ] - else lib.importJSON depsListFile); -in -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 + nativeBuildInputs = (args.nativeBuildInputs or [ ]) ++ [ wrapGAppsHook ]; + buildInputs = (args.buildInputs or [ ]) ++ [ glib ]; + + dontDartBuild = true; + buildPhase = args.buildPhase or '' + runHook preBuild + + mkdir -p build/flutter_assets/fonts + + doPubGet flutter pub get --offline -v + flutter build linux -v --release --split-debug-info="$debug" ${builtins.concatStringsSep " " (map (flag: "\"${flag}\"") flutterBuildFlags)} + + runHook postBuild + ''; + + dontDartInstall = true; + installPhase = args.installPhase or '' + runHook preInstall + + built=build/linux/*/release/bundle + + mkdir -p $out/bin + mv $built $out/app + + for f in $(find $out/app -iname "*.desktop" -type f); do + install -D $f $out/share/applications/$(basename $f) + done + + for f in $(find $out/app -maxdepth 1 -type f); do + ln -s $f $out/bin/$(basename $f) + done + + # make *.so executable + find $out/app -iname "*.so" -type f -exec chmod +x {} + + + # remove stuff like /build/source/packages/ubuntu_desktop_installer/linux/flutter/ephemeral + for f in $(find $out/app -executable -type f); do + if patchelf --print-rpath "$f" | grep /build; then # this ignores static libs (e,g. libapp.so) also + echo "strip RPath of $f" + newrp=$(patchelf --print-rpath $f | sed -r "s|/build.*ephemeral:||g" | sed -r "s|/build.*profile:||g") + patchelf --set-rpath "$newrp" "$f" + fi + done + + runHook postInstall + ''; + + dontWrapGApps = true; + extraWrapProgramArgs = '' + ''${gappsWrapperArgs[@]} \ + ${extraWrapProgramArgs} + ''; +}) |