2023-04-13 13:00:24 +01:00
|
|
|
{ lib
|
2023-04-15 15:17:41 +01:00
|
|
|
, callPackage
|
2023-08-27 14:11:24 +01:00
|
|
|
, runCommand
|
2023-04-16 10:25:42 +01:00
|
|
|
, makeWrapper
|
2024-04-26 21:24:03 +01:00
|
|
|
, wrapGAppsHook3
|
2023-10-21 14:31:58 +01:00
|
|
|
, buildDartApplication
|
2023-04-13 13:00:24 +01:00
|
|
|
, cacert
|
2023-08-28 02:59:44 +01:00
|
|
|
, glib
|
2023-04-13 13:00:24 +01:00
|
|
|
, flutter
|
2023-10-28 14:20:50 +01:00
|
|
|
, pkg-config
|
2023-10-25 12:29:28 +01:00
|
|
|
, jq
|
|
|
|
, yq
|
2021-11-23 11:02:55 +00:00
|
|
|
}:
|
|
|
|
|
|
|
|
# absolutely no mac support for now
|
|
|
|
|
2024-06-11 04:03:32 +01:00
|
|
|
{ pubGetScript ? null
|
2023-04-16 10:25:42 +01:00
|
|
|
, flutterBuildFlags ? [ ]
|
2024-01-19 00:07:33 +00:00
|
|
|
, targetFlutterPlatform ? "linux"
|
2023-05-14 16:10:49 +01:00
|
|
|
, extraWrapProgramArgs ? ""
|
2024-06-11 04:03:32 +01:00
|
|
|
, flutterMode ? null
|
2023-04-15 15:17:41 +01:00
|
|
|
, ...
|
|
|
|
}@args:
|
2023-10-21 14:31:58 +01:00
|
|
|
|
2024-01-17 23:16:55 +00:00
|
|
|
let
|
2024-06-11 04:03:32 +01:00
|
|
|
hasEngine = flutter ? engine && flutter.engine != null && flutter.engine.meta.available;
|
|
|
|
flutterMode = args.flutterMode or (if hasEngine then flutter.engine.runtimeMode else "release");
|
|
|
|
|
|
|
|
flutterFlags = lib.optional hasEngine "--local-engine host_${flutterMode}${lib.optionalString (!flutter.engine.isOptimized) "_unopt"}";
|
|
|
|
|
|
|
|
flutterBuildFlags = [
|
|
|
|
"--${flutterMode}"
|
|
|
|
] ++ (args.flutterBuildFlags or []) ++ flutterFlags;
|
|
|
|
|
2024-01-18 03:20:03 +00:00
|
|
|
builderArgs = rec {
|
2024-01-17 23:16:55 +00:00
|
|
|
universal = args // {
|
2024-06-11 04:03:32 +01:00
|
|
|
inherit flutterMode flutterFlags flutterBuildFlags;
|
|
|
|
|
2024-01-17 23:16:55 +00:00
|
|
|
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"
|
2024-06-11 04:03:32 +01:00
|
|
|
flutter config $flutterFlags --no-analytics &>/dev/null # mute first-run
|
|
|
|
flutter config $flutterFlags --enable-linux-desktop >/dev/null
|
2024-01-17 23:16:55 +00:00
|
|
|
'';
|
|
|
|
|
2024-06-11 04:03:32 +01:00
|
|
|
pubGetScript = args.pubGetScript or "flutter${lib.optionalString hasEngine " --local-engine $flutterMode"} pub get";
|
2024-01-17 23:16:55 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
'';
|
2024-06-13 22:42:37 +01:00
|
|
|
# https://github.com/dart-lang/pub/blob/e1fbda73d1ac597474b82882ee0bf6ecea5df108/lib/src/sdk/dart.dart#L80
|
|
|
|
"dart" = name: runCommand "dart-sdk-${name}" { passthru.packageRoot = "."; } ''
|
|
|
|
for path in '${flutter.dart}/pkg/${name}'; do
|
|
|
|
if [ -d "$path" ]; then
|
|
|
|
ln -s "$path" "$out"
|
|
|
|
break
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
|
|
|
|
if [ ! -e "$out" ]; then
|
|
|
|
echo 1>&2 'The Dart SDK does not contain the requested package: ${name}!'
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
'';
|
2024-01-17 23:16:55 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
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
|
2024-05-30 22:06:11 +01:00
|
|
|
export TEMP_PACKAGES=$(mktemp)
|
2024-01-17 23:16:55 +00:00
|
|
|
'${jq}/bin/jq' '.packages |= . + [{
|
|
|
|
name: "flutter_gen",
|
|
|
|
rootUri: "flutter_gen",
|
|
|
|
languageVersion: "2.12",
|
2024-05-30 22:06:11 +01:00
|
|
|
}]' "$out" > "$TEMP_PACKAGES"
|
|
|
|
cp "$TEMP_PACKAGES" "$out"
|
|
|
|
rm "$TEMP_PACKAGES"
|
|
|
|
unset TEMP_PACKAGES
|
2023-10-25 12:29:28 +01:00
|
|
|
fi
|
2024-01-17 23:16:55 +00:00
|
|
|
'';
|
|
|
|
};
|
2023-10-25 12:29:28 +01:00
|
|
|
|
2024-01-17 23:16:55 +00:00
|
|
|
linux = universal // {
|
|
|
|
outputs = universal.outputs or [ ] ++ [ "debug" ];
|
|
|
|
|
|
|
|
nativeBuildInputs = (universal.nativeBuildInputs or [ ]) ++ [
|
2024-04-26 21:24:03 +01:00
|
|
|
wrapGAppsHook3
|
2024-01-17 23:16:55 +00:00
|
|
|
|
|
|
|
# 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 ];
|
|
|
|
|
|
|
|
dontDartBuild = true;
|
|
|
|
buildPhase = universal.buildPhase or ''
|
|
|
|
runHook preBuild
|
|
|
|
|
|
|
|
mkdir -p build/flutter_assets/fonts
|
|
|
|
|
2024-06-11 04:03:32 +01:00
|
|
|
flutter build linux -v --split-debug-info="$debug" $flutterBuildFlags
|
2024-01-17 23:16:55 +00:00
|
|
|
|
|
|
|
runHook postBuild
|
|
|
|
'';
|
|
|
|
|
|
|
|
dontDartInstall = true;
|
|
|
|
installPhase = universal.installPhase or ''
|
|
|
|
runHook preInstall
|
|
|
|
|
2024-06-11 04:03:32 +01:00
|
|
|
built=build/linux/*/$flutterMode/bundle
|
2024-01-17 23:16:55 +00:00
|
|
|
|
|
|
|
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
|
2023-10-25 12:29:28 +01:00
|
|
|
|
2024-01-17 23:16:55 +00:00
|
|
|
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}
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
web = universal // {
|
|
|
|
dontDartBuild = true;
|
|
|
|
buildPhase = universal.buildPhase or ''
|
|
|
|
runHook preBuild
|
|
|
|
|
|
|
|
mkdir -p build/flutter_assets/fonts
|
|
|
|
|
2024-06-11 04:03:32 +01:00
|
|
|
flutter build web -v $flutterBuildFlags
|
2024-01-17 23:16:55 +00:00
|
|
|
|
|
|
|
runHook postBuild
|
|
|
|
'';
|
|
|
|
|
|
|
|
dontDartInstall = true;
|
|
|
|
installPhase = universal.installPhase or ''
|
|
|
|
runHook preInstall
|
|
|
|
|
|
|
|
cp -r build/web "$out"
|
|
|
|
|
|
|
|
runHook postInstall
|
|
|
|
'';
|
|
|
|
};
|
2024-01-19 00:07:33 +00:00
|
|
|
}.${targetFlutterPlatform} or (throw "Unsupported Flutter host platform: ${targetFlutterPlatform}");
|
2024-01-18 03:20:03 +00:00
|
|
|
|
2024-01-19 00:07:33 +00:00
|
|
|
minimalFlutter = flutter.override { supportedTargetFlutterPlatforms = [ "universal" targetFlutterPlatform ]; };
|
2024-01-18 03:20:03 +00:00
|
|
|
|
|
|
|
buildAppWith = flutter: buildDartApplication.override { dart = flutter; };
|
2024-01-17 23:16:55 +00:00
|
|
|
in
|
2024-01-18 03:20:03 +00:00
|
|
|
buildAppWith minimalFlutter (builderArgs // { passthru = builderArgs.passthru or { } // { multiShell = buildAppWith flutter builderArgs; }; })
|