1// Copyright 2014 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5import '../../artifacts.dart';
6import '../../base/file_system.dart';
7import '../../build_info.dart';
8import '../../devfs.dart';
9import '../build_system.dart';
10import '../depfile.dart';
11import '../exceptions.dart';
12import 'assets.dart';
13import 'common.dart';
14import 'desktop.dart';
15import 'icon_tree_shaker.dart';
16import 'native_assets.dart';
17
18/// The only files/subdirectories we care about.
19const _kWindowsArtifacts = <String>[
20 'flutter_windows.dll',
21 'flutter_windows.dll.exp',
22 'flutter_windows.dll.lib',
23 'flutter_windows.dll.pdb',
24 'flutter_export.h',
25 'flutter_messenger.h',
26 'flutter_plugin_registrar.h',
27 'flutter_texture_registrar.h',
28 'flutter_windows.h',
29];
30
31const _kWindowsDepfile = 'windows_engine_sources.d';
32
33/// Copies the Windows desktop embedding files to the copy directory.
34class UnpackWindows extends Target {
35 const UnpackWindows(this.targetPlatform);
36
37 final TargetPlatform targetPlatform;
38
39 @override
40 String get name => 'unpack_windows';
41
42 @override
43 List<Source> get inputs => const <Source>[
44 Source.pattern(
45 '{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/windows.dart',
46 ),
47 ];
48
49 @override
50 List<Source> get outputs => const <Source>[];
51
52 @override
53 List<String> get depfiles => const <String>[_kWindowsDepfile];
54
55 @override
56 List<Target> get dependencies => const <Target>[];
57
58 @override
59 Future<void> build(Environment environment) async {
60 final String? buildModeEnvironment = environment.defines[kBuildMode];
61 if (buildModeEnvironment == null) {
62 throw MissingDefineException(kBuildMode, name);
63 }
64 final buildMode = BuildMode.fromCliName(buildModeEnvironment);
65 final String engineSourcePath = environment.artifacts.getArtifactPath(
66 Artifact.windowsDesktopPath,
67 platform: targetPlatform,
68 mode: buildMode,
69 );
70 final String clientSourcePath = environment.artifacts.getArtifactPath(
71 Artifact.windowsCppClientWrapper,
72 platform: targetPlatform,
73 mode: buildMode,
74 );
75 final Directory outputDirectory = environment.fileSystem.directory(
76 environment.fileSystem.path.join(
77 environment.projectDir.path,
78 'windows',
79 'flutter',
80 'ephemeral',
81 ),
82 );
83 final Depfile depfile = unpackDesktopArtifacts(
84 fileSystem: environment.fileSystem,
85 artifacts: _kWindowsArtifacts,
86 engineSourcePath: engineSourcePath,
87 outputDirectory: outputDirectory,
88 clientSourcePaths: <String>[clientSourcePath],
89 icuDataPath: environment.artifacts.getArtifactPath(
90 Artifact.icuData,
91 platform: targetPlatform,
92 ),
93 );
94 environment.depFileService.writeToFile(
95 depfile,
96 environment.buildDir.childFile(_kWindowsDepfile),
97 );
98 }
99}
100
101/// Creates a bundle for the Windows desktop target.
102abstract class BundleWindowsAssets extends Target {
103 const BundleWindowsAssets(this.targetPlatform);
104
105 final TargetPlatform targetPlatform;
106
107 @override
108 List<Target> get dependencies => <Target>[
109 const KernelSnapshot(),
110 const InstallCodeAssets(),
111 UnpackWindows(targetPlatform),
112 ];
113
114 @override
115 List<Source> get inputs => const <Source>[
116 Source.pattern(
117 '{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/windows.dart',
118 ),
119 Source.pattern('{PROJECT_DIR}/pubspec.yaml'),
120 ...IconTreeShaker.inputs,
121 ];
122
123 @override
124 List<String> get depfiles => const <String>['flutter_assets.d'];
125
126 @override
127 Future<void> build(Environment environment) async {
128 final String? buildModeEnvironment = environment.defines[kBuildMode];
129 if (buildModeEnvironment == null) {
130 throw MissingDefineException(kBuildMode, 'bundle_windows_assets');
131 }
132 final buildMode = BuildMode.fromCliName(buildModeEnvironment);
133 final Directory outputDirectory = environment.outputDir.childDirectory('flutter_assets');
134 if (!outputDirectory.existsSync()) {
135 outputDirectory.createSync();
136 }
137
138 // Only copy the kernel blob in debug mode.
139 if (buildMode == BuildMode.debug) {
140 environment.buildDir
141 .childFile('app.dill')
142 .copySync(outputDirectory.childFile('kernel_blob.bin').path);
143 }
144 final Depfile depfile = await copyAssets(
145 environment,
146 outputDirectory,
147 targetPlatform: targetPlatform,
148 buildMode: buildMode,
149 additionalContent: <String, DevFSContent>{
150 'NativeAssetsManifest.json': DevFSFileContent(
151 environment.buildDir.childFile('native_assets.json'),
152 ),
153 },
154 );
155 environment.depFileService.writeToFile(
156 depfile,
157 environment.buildDir.childFile('flutter_assets.d'),
158 );
159 }
160}
161
162/// A wrapper for AOT compilation that copies app.so into the output directory.
163class WindowsAotBundle extends Target {
164 /// Create a [WindowsAotBundle] wrapper for [aotTarget].
165 const WindowsAotBundle(this.aotTarget);
166
167 /// The [AotElfBase] subclass that produces the app.so.
168 final AotElfBase aotTarget;
169
170 @override
171 String get name => 'windows_aot_bundle';
172
173 @override
174 List<Source> get inputs => const <Source>[Source.pattern('{BUILD_DIR}/app.so')];
175
176 @override
177 List<Source> get outputs => const <Source>[Source.pattern('{OUTPUT_DIR}/windows/app.so')];
178
179 @override
180 List<Target> get dependencies => <Target>[aotTarget];
181
182 @override
183 Future<void> build(Environment environment) async {
184 final File outputFile = environment.buildDir.childFile('app.so');
185 final Directory outputDirectory = environment.outputDir.childDirectory('windows');
186 if (!outputDirectory.existsSync()) {
187 outputDirectory.createSync(recursive: true);
188 }
189 outputFile.copySync(outputDirectory.childFile('app.so').path);
190 }
191}
192
193class ReleaseBundleWindowsAssets extends BundleWindowsAssets {
194 const ReleaseBundleWindowsAssets(super.targetPlatform);
195
196 @override
197 String get name => 'release_bundle_${getNameForTargetPlatform(targetPlatform)}_assets';
198
199 @override
200 List<Source> get outputs => const <Source>[];
201
202 @override
203 List<Target> get dependencies => <Target>[
204 ...super.dependencies,
205 WindowsAotBundle(AotElfRelease(targetPlatform)),
206 ];
207}
208
209class ProfileBundleWindowsAssets extends BundleWindowsAssets {
210 const ProfileBundleWindowsAssets(super.targetPlatform);
211
212 @override
213 String get name => 'profile_bundle_${getNameForTargetPlatform(targetPlatform)}_assets';
214
215 @override
216 List<Source> get outputs => const <Source>[];
217
218 @override
219 List<Target> get dependencies => <Target>[
220 ...super.dependencies,
221 WindowsAotBundle(AotElfProfile(targetPlatform)),
222 ];
223}
224
225class DebugBundleWindowsAssets extends BundleWindowsAssets {
226 const DebugBundleWindowsAssets(super.targetPlatform);
227
228 @override
229 String get name => 'debug_bundle_${getNameForTargetPlatform(targetPlatform)}_assets';
230
231 @override
232 List<Source> get inputs => <Source>[const Source.pattern('{BUILD_DIR}/app.dill')];
233
234 @override
235 List<Source> get outputs => <Source>[
236 const Source.pattern('{OUTPUT_DIR}/flutter_assets/kernel_blob.bin'),
237 ];
238}
239