at master 8.1 kB view raw
1{ 2 lib, 3 callPackage, 4 runCommand, 5 makeWrapper, 6 wrapGAppsHook3, 7 buildDartApplication, 8 cacert, 9 glib, 10 flutter, 11 pkg-config, 12 buildPackages, 13}: 14 15# absolutely no mac support for now 16 17{ 18 pubGetScript ? null, 19 flutterBuildFlags ? [ ], 20 targetFlutterPlatform ? "linux", 21 extraWrapProgramArgs ? "", 22 flutterMode ? null, 23 ... 24}@args: 25 26let 27 hasEngine = flutter ? engine && flutter.engine != null && flutter.engine.meta.available; 28 flutterMode = args.flutterMode or (if hasEngine then flutter.engine.runtimeMode else "release"); 29 30 flutterFlags = lib.optional hasEngine "--local-engine host_${flutterMode}${ 31 lib.optionalString (!flutter.engine.isOptimized) "_unopt" 32 }"; 33 34 flutterBuildFlags = [ 35 "--${flutterMode}" 36 ] 37 ++ (args.flutterBuildFlags or [ ]) 38 ++ flutterFlags; 39 40 builderArgs = 41 let 42 universal = args // { 43 inherit flutterMode flutterFlags flutterBuildFlags; 44 45 sdkSetupScript = '' 46 # Pub needs SSL certificates. Dart normally looks in a hardcoded path. 47 # https://github.com/dart-lang/sdk/blob/3.1.0/runtime/bin/security_context_linux.cc#L48 48 # 49 # Dart does not respect SSL_CERT_FILE... 50 # https://github.com/dart-lang/sdk/issues/48506 51 # ...and Flutter does not support --root-certs-file, so the path cannot be manually set. 52 # https://github.com/flutter/flutter/issues/56607 53 # https://github.com/flutter/flutter/issues/113594 54 # 55 # libredirect is of no use either, as Flutter does not pass any 56 # environment variables (including LD_PRELOAD) to the Pub process. 57 # 58 # Instead, Flutter is patched to allow the path to the Dart binary used for 59 # Pub commands to be overriden. 60 export NIX_FLUTTER_PUB_DART="${ 61 runCommand "dart-with-certs" { nativeBuildInputs = [ makeWrapper ]; } '' 62 mkdir -p "$out/bin" 63 makeWrapper ${flutter.dart}/bin/dart "$out/bin/dart" \ 64 --add-flags "--root-certs-file=${cacert}/etc/ssl/certs/ca-bundle.crt" 65 '' 66 }/bin/dart" 67 68 export HOME="$NIX_BUILD_TOP" 69 flutter config $flutterFlags --no-analytics &>/dev/null # mute first-run 70 flutter config $flutterFlags --enable-linux-desktop >/dev/null 71 ''; 72 73 pubGetScript = 74 args.pubGetScript 75 or "flutter${lib.optionalString hasEngine " --local-engine $flutterMode"} pub get"; 76 77 sdkSourceBuilders = { 78 # https://github.com/dart-lang/pub/blob/68dc2f547d0a264955c1fa551fa0a0e158046494/lib/src/sdk/flutter.dart#L81 79 "flutter" = 80 name: 81 runCommand "flutter-sdk-${name}" { passthru.packageRoot = "."; } '' 82 for path in '${flutter}/packages/${name}' '${flutter}/bin/cache/pkg/${name}'; do 83 if [ -d "$path" ]; then 84 ln -s "$path" "$out" 85 break 86 fi 87 done 88 89 if [ ! -e "$out" ]; then 90 echo 1>&2 'The Flutter SDK does not contain the requested package: ${name}!' 91 exit 1 92 fi 93 ''; 94 # https://github.com/dart-lang/pub/blob/e1fbda73d1ac597474b82882ee0bf6ecea5df108/lib/src/sdk/dart.dart#L80 95 "dart" = 96 name: 97 runCommand "dart-sdk-${name}" { passthru.packageRoot = "."; } '' 98 for path in '${flutter.dart}/pkg/${name}'; do 99 if [ -d "$path" ]; then 100 ln -s "$path" "$out" 101 break 102 fi 103 done 104 105 if [ ! -e "$out" ]; then 106 echo 1>&2 'The Dart SDK does not contain the requested package: ${name}!' 107 exit 1 108 fi 109 ''; 110 }; 111 112 # https://github.com/flutter/flutter/blob/edada7c56edf4a183c1735310e123c7f923584f1/packages/flutter_tools/lib/src/dart/pub.dart#L804 113 extraPackageConfigSetup = lib.optionalString (lib.versionOlder flutter.version "3.34.0") '' 114 if [ "$("${lib.getExe buildPackages.yq}" '.flutter.generate // false' pubspec.yaml)" = "true" ]; then 115 if ! "${lib.getExe buildPackages.jq}" -e '.packages[] | select(.name == "flutter_gen")' "$out" >/dev/null 2>&1; then 116 export TEMP_PACKAGES=$(mktemp) 117 "${lib.getExe buildPackages.jq}" '.packages |= . + [{ 118 name: "flutter_gen", 119 rootUri: "flutter_gen", 120 languageVersion: "2.12" 121 }]' "$out" > "$TEMP_PACKAGES" 122 cp "$TEMP_PACKAGES" "$out" 123 rm "$TEMP_PACKAGES" 124 unset TEMP_PACKAGES 125 fi 126 fi 127 ''; 128 }; 129 in 130 { 131 inherit universal; 132 133 linux = universal // { 134 outputs = universal.outputs or [ ] ++ [ "debug" ]; 135 136 nativeBuildInputs = (universal.nativeBuildInputs or [ ]) ++ [ 137 wrapGAppsHook3 138 139 # Flutter requires pkg-config for Linux desktop support, and many plugins 140 # attempt to use it. 141 # 142 # It is available to the `flutter` tool through its wrapper, but it must be 143 # added here as well so the setup hook adds plugin dependencies to the 144 # pkg-config search paths. 145 pkg-config 146 ]; 147 148 buildInputs = (universal.buildInputs or [ ]) ++ [ glib ]; 149 150 dontDartBuild = true; 151 buildPhase = 152 universal.buildPhase or '' 153 runHook preBuild 154 155 mkdir -p build/flutter_assets/fonts 156 157 flutter build linux -v --split-debug-info="$debug" $flutterBuildFlags 158 159 runHook postBuild 160 ''; 161 162 dontDartInstall = true; 163 installPhase = 164 universal.installPhase or '' 165 runHook preInstall 166 167 built=build/linux/*/$flutterMode/bundle 168 169 mkdir -p $out/bin 170 mkdir -p $out/app 171 mv $built $out/app/$pname 172 173 for f in $(find $out/app/$pname -iname "*.desktop" -type f); do 174 install -D $f $out/share/applications/$(basename $f) 175 done 176 177 for f in $(find $out/app/$pname -maxdepth 1 -type f); do 178 ln -s $f $out/bin/$(basename $f) 179 done 180 181 # make *.so executable 182 find $out/app/$pname -iname "*.so" -type f -exec chmod +x {} + 183 184 # remove stuff like /build/source/packages/ubuntu_desktop_installer/linux/flutter/ephemeral 185 for f in $(find $out/app/$pname -executable -type f); do 186 if patchelf --print-rpath "$f" | grep /build; then # this ignores static libs (e,g. libapp.so) also 187 echo "strip RPath of $f" 188 newrp=$(patchelf --print-rpath $f | sed -r "s|/build.*ephemeral:||g" | sed -r "s|/build.*profile:||g") 189 patchelf --set-rpath "$newrp" "$f" 190 fi 191 done 192 193 runHook postInstall 194 ''; 195 196 dontWrapGApps = true; 197 extraWrapProgramArgs = '' 198 ''${gappsWrapperArgs[@]} \ 199 ${extraWrapProgramArgs} 200 ''; 201 }; 202 203 web = universal // { 204 dontDartBuild = true; 205 buildPhase = 206 universal.buildPhase or '' 207 runHook preBuild 208 209 mkdir -p build/flutter_assets/fonts 210 211 flutter build web -v $flutterBuildFlags 212 213 runHook postBuild 214 ''; 215 216 dontDartInstall = true; 217 installPhase = 218 universal.installPhase or '' 219 runHook preInstall 220 221 cp -r build/web "$out" 222 223 runHook postInstall 224 ''; 225 }; 226 } 227 .${targetFlutterPlatform} or (throw "Unsupported Flutter host platform: ${targetFlutterPlatform}"); 228 229 minimalFlutter = flutter.override { 230 supportedTargetFlutterPlatforms = [ 231 "universal" 232 targetFlutterPlatform 233 ]; 234 }; 235 236 buildAppWith = flutter: buildDartApplication.override { dart = flutter; }; 237in 238buildAppWith minimalFlutter ( 239 builderArgs 240 // { 241 passthru = builderArgs.passthru or { } // { 242 multiShell = buildAppWith flutter builderArgs; 243 }; 244 } 245)