diff --git a/doc/languages-frameworks/dart.section.md b/doc/languages-frameworks/dart.section.md index fca87fa70e4e..58ee2d5050ac 100644 --- a/doc/languages-frameworks/dart.section.md +++ b/doc/languages-frameworks/dart.section.md @@ -80,6 +80,8 @@ Do _not_ use `dart run `, as this will attempt to download depende ### Usage with nix-shell {#ssec-dart-applications-nix-shell} +#### Using dependencies from the Nix store {#ssec-dart-applications-nix-shell-deps} + As `buildDartApplication` provides dependencies instead of `pub get`, Dart needs to be explicitly told where to find them. Run the following commands in the source directory to configure Dart appropriately. @@ -103,6 +105,9 @@ flutter.buildFlutterApplication { pname = "firmware-updater"; version = "unstable-2023-04-30"; + # To build for the Web, use the targetFlutterPlatform argument. + # targetFlutterPlatform = "web"; + src = fetchFromGitHub { owner = "canonical"; repo = "firmware-updater"; @@ -117,4 +122,15 @@ flutter.buildFlutterApplication { ### Usage with nix-shell {#ssec-dart-flutter-nix-shell} -See the [Dart documentation](#ssec-dart-applications-nix-shell) for nix-shell instructions. +Flutter-specific `nix-shell` usage notes are included here. See the [Dart documentation](#ssec-dart-applications-nix-shell) for general `nix-shell` instructions. + +#### Entering the shell {#ssec-dart-flutter-nix-shell-enter} + +By default, dependencies for only the `targetFlutterPlatform` are available in the +build environment. This is useful for keeping closures small, but be problematic +during development. It's common, for example, to build Web apps for Linux during +development to take advantage of native features such as stateful hot reload. + +To enter a shell with all the usual target platforms available, use the `multiShell` attribute. + +e.g. `nix-shell '' -A fluffychat-web.multiShell`. diff --git a/pkgs/applications/networking/instant-messengers/fluffychat/default.nix b/pkgs/applications/networking/instant-messengers/fluffychat/default.nix index bdd41c4cfa64..cfe0bb8e8ab2 100644 --- a/pkgs/applications/networking/instant-messengers/fluffychat/default.nix +++ b/pkgs/applications/networking/instant-messengers/fluffychat/default.nix @@ -1,4 +1,5 @@ { lib +, fetchzip , fetchFromGitHub , imagemagick , mesa @@ -7,13 +8,15 @@ , pulseaudio , makeDesktopItem , gnome + +, targetFlutterPlatform ? "linux" }: let libwebrtcRpath = lib.makeLibraryPath [ mesa libdrm ]; in -flutter313.buildFlutterApplication rec { - pname = "fluffychat"; +flutter313.buildFlutterApplication (rec { + pname = "fluffychat-${targetFlutterPlatform}"; version = "1.14.1"; src = fetchFromGitHub { @@ -30,6 +33,25 @@ flutter313.buildFlutterApplication rec { wakelock_windows = "sha256-Dfwe3dSScD/6kvkP67notcbb+EgTQ3kEYcH7wpra2dI="; }; + inherit targetFlutterPlatform; + + meta = with lib; { + description = "Chat with your friends (matrix client)"; + homepage = "https://fluffychat.im/"; + license = licenses.agpl3Plus; + maintainers = with maintainers; [ mkg20001 gilice ]; + platforms = [ "x86_64-linux" "aarch64-linux" ]; + sourceProvenance = [ sourceTypes.fromSource ]; + }; +} // lib.optionalAttrs (targetFlutterPlatform == "linux") { + nativeBuildInputs = [ imagemagick ]; + + runtimeDependencies = [ pulseaudio ]; + + extraWrapProgramArgs = "--prefix PATH : ${gnome.zenity}/bin"; + + env.NIX_LDFLAGS = "-rpath-link ${libwebrtcRpath}"; + desktopItem = makeDesktopItem { name = "Fluffychat"; exec = "@out@/bin/fluffychat"; @@ -39,9 +61,6 @@ flutter313.buildFlutterApplication rec { categories = [ "Chat" "Network" "InstantMessaging" ]; }; - nativeBuildInputs = [ imagemagick ]; - runtimeDependencies = [ pulseaudio ]; - extraWrapProgramArgs = "--prefix PATH : ${gnome.zenity}/bin"; postInstall = '' FAV=$out/app/data/flutter_assets/assets/favicon.png ICO=$out/share/icons @@ -59,15 +78,21 @@ flutter313.buildFlutterApplication rec { patchelf --add-rpath ${libwebrtcRpath} $out/app/lib/libwebrtc.so ''; - - env.NIX_LDFLAGS = "-rpath-link ${libwebrtcRpath}"; - - meta = with lib; { - description = "Chat with your friends (matrix client)"; - homepage = "https://fluffychat.im/"; - license = licenses.agpl3Plus; - maintainers = with maintainers; [ mkg20001 gilice ]; - platforms = [ "x86_64-linux" "aarch64-linux" ]; - sourceProvenance = [ sourceTypes.fromSource ]; - }; -} +} // lib.optionalAttrs (targetFlutterPlatform == "web") { + prePatch = + # https://github.com/krille-chan/fluffychat/blob/v1.17.1/scripts/prepare-web.sh + let + # Use Olm 1.3.2, the oldest version, for FluffyChat 1.14.1 which depends on olm_flutter 1.2.0. + # In the future, this should be changed to use self.pubspecLock.dependencyVersions.flutter_olm as the script does. + olmVersion = "1.3.2"; + olmJs = fetchzip { + url = "https://github.com/famedly/olm/releases/download/v${olmVersion}/olm.zip"; + stripRoot = false; + hash = "sha256-Vl3Cp2OaYzM5CPOOtTHtUb1W48VXePzOV6FeiIzyD1Y="; + }; + in + '' + rm -r assets/js/package + cp -r '${olmJs}/javascript' assets/js/package + ''; +}) diff --git a/pkgs/build-support/dart/build-dart-application/default.nix b/pkgs/build-support/dart/build-dart-application/default.nix index f9a49fec3a2d..c99b8bbf325e 100644 --- a/pkgs/build-support/dart/build-dart-application/default.nix +++ b/pkgs/build-support/dart/build-dart-application/default.nix @@ -87,7 +87,7 @@ let dartCompileCommand dartOutputType dartRuntimeCommand dartCompileFlags dartJitFlags; - outputs = args.outputs or [ ] ++ [ "out" "pubcache" ]; + outputs = [ "out" "pubcache" ] ++ args.outputs or [ ]; dartEntryPoints = if (dartEntryPoints != null) diff --git a/pkgs/build-support/dart/build-dart-application/hooks/dart-install-hook.sh b/pkgs/build-support/dart/build-dart-application/hooks/dart-install-hook.sh index 888e12a07d83..349a0dfdef0e 100644 --- a/pkgs/build-support/dart/build-dart-application/hooks/dart-install-hook.sh +++ b/pkgs/build-support/dart/build-dart-application/hooks/dart-install-hook.sh @@ -19,15 +19,25 @@ dartInstallHook() { fi done < <(_getDartEntryPoints) - # Install the package_config.json file. - mkdir -p "$pubcache" - cp .dart_tool/package_config.json "$pubcache/package_config.json" - runHook postInstall echo "Finished dartInstallHook" } +dartInstallCacheHook() { + echo "Executing dartInstallCacheHook" + + # Install the package_config.json file. + mkdir -p "$pubcache" + cp .dart_tool/package_config.json "$pubcache/package_config.json" + + echo "Finished dartInstallCacheHook" +} + if [ -z "${dontDartInstall-}" ] && [ -z "${installPhase-}" ]; then installPhase=dartInstallHook fi + +if [ -z "${dontDartInstallCache-}" ]; then + postInstallHooks+=(dartInstallCacheHook) +fi diff --git a/pkgs/build-support/flutter/default.nix b/pkgs/build-support/flutter/default.nix index 4d00e177370e..5d7cd7d984c1 100644 --- a/pkgs/build-support/flutter/default.nix +++ b/pkgs/build-support/flutter/default.nix @@ -17,134 +17,163 @@ { pubGetScript ? "flutter pub get" , flutterBuildFlags ? [ ] +, targetFlutterPlatform ? "linux" , extraWrapProgramArgs ? "" , ... }@args: -(buildDartApplication.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 - # - # Dart does not respect SSL_CERT_FILE... - # https://github.com/dart-lang/sdk/issues/48506 - # ...and Flutter does not support --root-certs-file, so the path cannot be manually set. - # https://github.com/flutter/flutter/issues/56607 - # https://github.com/flutter/flutter/issues/113594 - # - # libredirect is of no use either, as Flutter does not pass any - # environment variables (including LD_PRELOAD) to the Pub process. - # - # Instead, Flutter is patched to allow the path to the Dart binary used for - # Pub commands to be overriden. - export NIX_FLUTTER_PUB_DART="${runCommand "dart-with-certs" { nativeBuildInputs = [ makeWrapper ]; } '' - mkdir -p "$out/bin" - makeWrapper ${flutter.dart}/bin/dart "$out/bin/dart" \ - --add-flags "--root-certs-file=${cacert}/etc/ssl/certs/ca-bundle.crt" - ''}/bin/dart" +let + builderArgs = rec { + universal = 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 + # + # Dart does not respect SSL_CERT_FILE... + # https://github.com/dart-lang/sdk/issues/48506 + # ...and Flutter does not support --root-certs-file, so the path cannot be manually set. + # https://github.com/flutter/flutter/issues/56607 + # https://github.com/flutter/flutter/issues/113594 + # + # libredirect is of no use either, as Flutter does not pass any + # environment variables (including LD_PRELOAD) to the Pub process. + # + # Instead, Flutter is patched to allow the path to the Dart binary used for + # Pub commands to be overriden. + export NIX_FLUTTER_PUB_DART="${runCommand "dart-with-certs" { nativeBuildInputs = [ makeWrapper ]; } '' + mkdir -p "$out/bin" + makeWrapper ${flutter.dart}/bin/dart "$out/bin/dart" \ + --add-flags "--root-certs-file=${cacert}/etc/ssl/certs/ca-bundle.crt" + ''}/bin/dart" - export HOME="$NIX_BUILD_TOP" - flutter config --no-analytics &>/dev/null # mute first-run - flutter config --enable-linux-desktop >/dev/null - ''; + export HOME="$NIX_BUILD_TOP" + flutter config --no-analytics &>/dev/null # mute first-run + flutter config --enable-linux-desktop >/dev/null + ''; - inherit pubGetScript; + inherit pubGetScript; - sdkSourceBuilders = { - # https://github.com/dart-lang/pub/blob/68dc2f547d0a264955c1fa551fa0a0e158046494/lib/src/sdk/flutter.dart#L81 - "flutter" = name: runCommand "flutter-sdk-${name}" { passthru.packageRoot = "."; } '' - for path in '${flutter}/packages/${name}' '${flutter}/bin/cache/pkg/${name}'; do - if [ -d "$path" ]; then - ln -s "$path" "$out" - break + sdkSourceBuilders = { + # https://github.com/dart-lang/pub/blob/68dc2f547d0a264955c1fa551fa0a0e158046494/lib/src/sdk/flutter.dart#L81 + "flutter" = name: runCommand "flutter-sdk-${name}" { passthru.packageRoot = "."; } '' + for path in '${flutter}/packages/${name}' '${flutter}/bin/cache/pkg/${name}'; do + if [ -d "$path" ]; then + ln -s "$path" "$out" + break + fi + done + + if [ ! -e "$out" ]; then + echo 1>&2 'The Flutter SDK does not contain the requested package: ${name}!' + exit 1 + fi + ''; + }; + + extraPackageConfigSetup = '' + # https://github.com/flutter/flutter/blob/3.13.8/packages/flutter_tools/lib/src/dart/pub.dart#L755 + if [ "$('${yq}/bin/yq' '.flutter.generate // false' pubspec.yaml)" = "true" ]; then + '${jq}/bin/jq' '.packages |= . + [{ + name: "flutter_gen", + rootUri: "flutter_gen", + languageVersion: "2.12", + }]' "$out" | '${moreutils}/bin/sponge' "$out" fi - done + ''; + }; - if [ ! -e "$out" ]; then - echo 1>&2 'The Flutter SDK does not contain the requested package: ${name}!' - exit 1 - fi - ''; - }; + linux = universal // { + outputs = universal.outputs or [ ] ++ [ "debug" ]; - extraPackageConfigSetup = '' - # https://github.com/flutter/flutter/blob/3.13.8/packages/flutter_tools/lib/src/dart/pub.dart#L755 - if [ "$('${yq}/bin/yq' '.flutter.generate // false' pubspec.yaml)" = "true" ]; then - '${jq}/bin/jq' '.packages |= . + [{ - name: "flutter_gen", - rootUri: "flutter_gen", - languageVersion: "2.12", - }]' "$out" | '${moreutils}/bin/sponge' "$out" - fi - ''; + nativeBuildInputs = (universal.nativeBuildInputs or [ ]) ++ [ + wrapGAppsHook - nativeBuildInputs = (args.nativeBuildInputs or [ ]) ++ [ - wrapGAppsHook + # Flutter requires pkg-config for Linux desktop support, and many plugins + # attempt to use it. + # + # It is available to the `flutter` tool through its wrapper, but it must be + # added here as well so the setup hook adds plugin dependencies to the + # pkg-config search paths. + pkg-config + ]; - # Flutter requires pkg-config for Linux desktop support, and many plugins - # attempt to use it. - # - # It is available to the `flutter` tool through its wrapper, but it must be - # added here as well so the setup hook adds plugin dependencies to the - # pkg-config search paths. - pkg-config - ]; + buildInputs = (universal.buildInputs or [ ]) ++ [ glib ]; - buildInputs = (args.buildInputs or [ ]) ++ [ glib ]; + dontDartBuild = true; + buildPhase = universal.buildPhase or '' + runHook preBuild - dontDartBuild = true; - buildPhase = args.buildPhase or '' - runHook preBuild + mkdir -p build/flutter_assets/fonts - mkdir -p build/flutter_assets/fonts + flutter build linux -v --release --split-debug-info="$debug" ${builtins.concatStringsSep " " (map (flag: "\"${flag}\"") flutterBuildFlags)} - flutter build linux -v --release --split-debug-info="$debug" ${builtins.concatStringsSep " " (map (flag: "\"${flag}\"") flutterBuildFlags)} + runHook postBuild + ''; - runHook postBuild - ''; + dontDartInstall = true; + installPhase = universal.installPhase or '' + runHook preInstall - dontDartInstall = true; - installPhase = args.installPhase or '' - runHook preInstall + built=build/linux/*/release/bundle - built=build/linux/*/release/bundle + mkdir -p $out/bin + mv $built $out/app - 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 -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 - 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 {} + - # 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 - # 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 + ''; - # Install the package_config.json file. - # This is normally done by dartInstallHook, but we disable it. - mkdir -p "$pubcache" - cp .dart_tool/package_config.json "$pubcache/package_config.json" + dontWrapGApps = true; + extraWrapProgramArgs = '' + ''${gappsWrapperArgs[@]} \ + ${extraWrapProgramArgs} + ''; + }; - runHook postInstall - ''; + web = universal // { + dontDartBuild = true; + buildPhase = universal.buildPhase or '' + runHook preBuild - dontWrapGApps = true; - extraWrapProgramArgs = '' - ''${gappsWrapperArgs[@]} \ - ${extraWrapProgramArgs} - ''; -}) + mkdir -p build/flutter_assets/fonts + + flutter build web -v --release ${builtins.concatStringsSep " " (map (flag: "\"${flag}\"") flutterBuildFlags)} + + runHook postBuild + ''; + + dontDartInstall = true; + installPhase = universal.installPhase or '' + runHook preInstall + + cp -r build/web "$out" + + runHook postInstall + ''; + }; + }.${targetFlutterPlatform} or (throw "Unsupported Flutter host platform: ${targetFlutterPlatform}"); + + minimalFlutter = flutter.override { supportedTargetFlutterPlatforms = [ "universal" targetFlutterPlatform ]; }; + + buildAppWith = flutter: buildDartApplication.override { dart = flutter; }; +in +buildAppWith minimalFlutter (builderArgs // { passthru = builderArgs.passthru or { } // { multiShell = buildAppWith flutter builderArgs; }; }) diff --git a/pkgs/development/compilers/flutter/default.nix b/pkgs/development/compilers/flutter/default.nix index 29d5d415b8a0..6d2d90466033 100644 --- a/pkgs/development/compilers/flutter/default.nix +++ b/pkgs/development/compilers/flutter/default.nix @@ -51,12 +51,7 @@ let (mkCustomFlutter args).overrideAttrs (prev: next: { passthru = next.passthru // rec { inherit wrapFlutter mkCustomFlutter mkFlutter; - buildFlutterApplication = callPackage ../../../build-support/flutter { - # Package a minimal version of Flutter that only uses Linux desktop release artifacts. - flutter = (wrapFlutter (mkCustomFlutter args)).override { - supportedTargetFlutterPlatforms = [ "universal" "linux" ]; - }; - }; + buildFlutterApplication = callPackage ../../../build-support/flutter { flutter = wrapFlutter (mkCustomFlutter args); }; }; }); diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index a9335b7d381e..2be7ceca607f 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -3848,6 +3848,8 @@ with pkgs; fluffychat = callPackage ../applications/networking/instant-messengers/fluffychat { }; + fluffychat-web = fluffychat.override { targetFlutterPlatform = "web"; }; + fxlinuxprintutil = callPackage ../tools/misc/fxlinuxprintutil { }; gbl = callPackage ../tools/archivers/gbl {