Skip to content

Commit 861c9b1

Browse files
committed
Add AOT building
1 parent 0f7cd8e commit 861c9b1

File tree

7 files changed

+352
-123
lines changed

7 files changed

+352
-123
lines changed

cmd/build.go

Lines changed: 161 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ var (
3434
buildOrRunOpenGlVersion string
3535
buildOrRunEngineVersion string
3636
buildOrRunDocker bool
37+
buildOrRunDebug bool
38+
buildOrRunRelease bool
39+
buildOrRunProfile bool
40+
buildOrRunMode build.Mode
3741
)
3842

3943
func initCompileFlags(cmd *cobra.Command) {
@@ -43,13 +47,15 @@ func initCompileFlags(cmd *cobra.Command) {
4347
cmd.PersistentFlags().StringVar(&buildOrRunOpenGlVersion, "opengl", config.BuildOpenGlVersionDefault, "The OpenGL version specified here is only relevant for external texture plugin (i.e. video_plugin).\nIf 'none' is provided, texture won't be supported. Note: the Flutter Engine still needs a OpenGL compatible context.")
4448
cmd.PersistentFlags().StringVar(&buildOrRunEngineVersion, "engine-version", config.BuildEngineDefault, "The flutter engine version to use.")
4549
cmd.PersistentFlags().BoolVar(&buildOrRunDocker, "docker", false, "Execute the go build and packaging in a docker container. The Flutter build is always run locally")
50+
cmd.PersistentFlags().BoolVar(&buildOrRunDebug, "debug", false, "Build a debug version of the app.")
51+
cmd.PersistentFlags().BoolVar(&buildOrRunRelease, "release", false, "Enable release builds. Currently very experimental and only for linux available")
52+
cmd.PersistentFlags().BoolVar(&buildOrRunProfile, "profile", false, "Enable profile builds. Currently very experimental and only for linux available")
4653

4754
cmd.PersistentFlags().MarkHidden("branch")
4855
}
4956

5057
var (
5158
// `hover build`-only build flags
52-
buildDebug bool
5359
buildVersionNumber string
5460
buildSkipEngineDownload bool
5561
buildSkipFlutterBuildBundle bool
@@ -64,9 +70,9 @@ func init() {
6470
initCompileFlags(buildCmd)
6571

6672
buildCmd.PersistentFlags().StringVar(&buildVersionNumber, "version-number", "", "Override the version number used in build and packaging. You may use it with $(git describe --tags)")
67-
buildCmd.PersistentFlags().BoolVar(&buildDebug, "debug", false, "Build a debug version of the app.")
6873
buildCmd.PersistentFlags().BoolVar(&buildSkipEngineDownload, "skip-engine-download", false, "Skip donwloading the Flutter Engine and artifacts.")
6974
buildCmd.PersistentFlags().BoolVar(&buildSkipFlutterBuildBundle, "skip-flutter-build-bundle", false, "Skip the 'flutter build bundle' step.")
75+
7076
buildCmd.AddCommand(buildLinuxCmd)
7177
buildCmd.AddCommand(buildLinuxSnapCmd)
7278
buildCmd.AddCommand(buildLinuxDebCmd)
@@ -191,6 +197,8 @@ func subcommandBuild(targetOS string, packagingTask packaging.Task) {
191197
packagingTask.AssertSupported()
192198
}
193199

200+
initBuildParameters(targetOS, build.ReleaseMode)
201+
194202
if !buildSkipFlutterBuildBundle {
195203
cleanBuildOutputsDir(targetOS)
196204
buildFlutterBundle(targetOS)
@@ -203,9 +211,15 @@ func subcommandBuild(targetOS string, packagingTask packaging.Task) {
203211
if buildVersionNumber != "" {
204212
buildFlags = append(buildFlags, "--version-number", buildVersionNumber)
205213
}
206-
if buildDebug {
214+
if buildOrRunDebug {
207215
buildFlags = append(buildFlags, "--debug")
208216
}
217+
if buildOrRunRelease {
218+
buildFlags = append(buildFlags, "--release")
219+
}
220+
if buildOrRunProfile {
221+
buildFlags = append(buildFlags, "--profile")
222+
}
209223
dockerHoverBuild(targetOS, packagingTask, buildFlags, nil)
210224
} else {
211225
buildGoBinary(targetOS, nil)
@@ -216,7 +230,7 @@ func subcommandBuild(targetOS string, packagingTask packaging.Task) {
216230
// initBuildParameters is used to initialize all the build parameters. It sets
217231
// fallback values based on config or defaults for values that have not
218232
// explicitly been set through flags.
219-
func initBuildParameters(targetOS string) {
233+
func initBuildParameters(targetOS string, defaultbuildOrRunMode build.Mode) {
220234
if buildOrRunCachePath == "" {
221235
log.Errorf("Missing cache path, cannot continue. Please see previous warning.")
222236
os.Exit(1)
@@ -241,14 +255,43 @@ func initBuildParameters(targetOS string) {
241255
buildVersionNumber = pubspec.GetPubSpec().GetVersion()
242256
}
243257

244-
engineCachePath = enginecache.EngineCachePath(targetOS, buildOrRunCachePath)
258+
numberOfbuildOrRunModeFlagsSet := 0
259+
for _, flag := range []bool{buildOrRunDebug, buildOrRunRelease, buildOrRunProfile} {
260+
if flag {
261+
numberOfbuildOrRunModeFlagsSet++
262+
}
263+
}
264+
if numberOfbuildOrRunModeFlagsSet > 1 {
265+
log.Errorf("Only one of --debug, --release or --profile can be set at one time")
266+
os.Exit(1)
267+
}
268+
if numberOfbuildOrRunModeFlagsSet == 0 {
269+
buildOrRunMode = defaultbuildOrRunMode
270+
}
271+
272+
if buildOrRunDebug {
273+
buildOrRunMode = build.DebugMode
274+
}
275+
if buildOrRunRelease {
276+
buildOrRunMode = build.ReleaseMode
277+
}
278+
if buildOrRunProfile {
279+
buildOrRunMode = build.ProfileMode
280+
}
281+
282+
if buildOrRunMode.IsAot && targetOS != runtime.GOOS {
283+
log.Errorf("AOT builds currently only work on their host OS")
284+
os.Exit(1)
285+
}
286+
287+
engineCachePath = enginecache.EngineCachePath(targetOS, buildOrRunCachePath, buildOrRunMode)
245288
if !buildSkipEngineDownload {
246-
enginecache.ValidateOrUpdateEngine(targetOS, buildOrRunCachePath, buildOrRunEngineVersion)
289+
enginecache.ValidateOrUpdateEngine(targetOS, buildOrRunCachePath, buildOrRunEngineVersion, buildOrRunMode)
247290
}
248291
}
249292

250293
func commonFlags() []string {
251-
f := []string{}
294+
var f []string
252295
if buildOrRunFlutterTarget != config.BuildTargetDefault {
253296
f = append(f, "--target", buildOrRunFlutterTarget)
254297
}
@@ -319,53 +362,135 @@ func buildFlutterBundle(targetOS string) {
319362
}
320363

321364
checkFlutterChannel()
365+
var trackWidgetCreation string
366+
if buildOrRunMode == build.DebugMode {
367+
trackWidgetCreation = "--track-widget-creation"
368+
}
322369

323-
var flutterBuildBundleArgs = []string{
324-
"build", "bundle",
370+
cmdFlutterBuild := exec.Command(build.FlutterBin(), "build", "bundle",
325371
"--asset-dir", filepath.Join(build.OutputDirectoryPath(targetOS), "flutter_assets"),
326372
"--target", buildOrRunFlutterTarget,
327-
}
328-
if buildDebug {
329-
flutterBuildBundleArgs = append(flutterBuildBundleArgs, "--track-widget-creation")
330-
}
331-
cmdFlutterBuildBundle := exec.Command(build.FlutterBin(), flutterBuildBundleArgs...)
332-
cmdFlutterBuildBundle.Stderr = os.Stderr
333-
cmdFlutterBuildBundle.Stdout = os.Stdout
373+
trackWidgetCreation,
374+
)
375+
cmdFlutterBuild.Stderr = os.Stderr
376+
cmdFlutterBuild.Stdout = os.Stdout
334377

335-
log.Infof("Building flutter bundle")
336-
err = cmdFlutterBuildBundle.Run()
378+
log.Infof("Bundling flutter app")
379+
err = cmdFlutterBuild.Run()
337380
if err != nil {
338381
log.Errorf("Flutter build failed: %v", err)
339382
os.Exit(1)
340383
}
384+
if buildOrRunMode.IsAot {
385+
err := os.Remove(filepath.Join(build.OutputDirectoryPath(targetOS), "flutter_assets", "isolate_snapshot_data"))
386+
if err != nil {
387+
log.Errorf("Failed to remove unused isolate_snapshot_data: %v", err)
388+
os.Exit(1)
389+
}
390+
err = os.Remove(filepath.Join(build.OutputDirectoryPath(targetOS), "flutter_assets", "vm_snapshot_data"))
391+
if err != nil {
392+
log.Errorf("Failed to remove unused vm_snapshot_data: %v", err)
393+
os.Exit(1)
394+
}
395+
err = os.Remove(filepath.Join(build.OutputDirectoryPath(targetOS), "flutter_assets", "kernel_blob.bin"))
396+
if err != nil {
397+
log.Errorf("Failed to remove unused kernel_blob.bin: %v", err)
398+
os.Exit(1)
399+
}
400+
dart := filepath.Join(engineCachePath, "dart-sdk", "bin", "dart"+build.ExecutableExtension(targetOS))
401+
var genSnapshot string
402+
if targetOS == "darwin" {
403+
genSnapshot = filepath.Join(engineCachePath, "artifacts", "gen_snapshot"+build.ExecutableExtension(targetOS))
404+
} else {
405+
genSnapshot = filepath.Join(engineCachePath, "gen_snapshot"+build.ExecutableExtension(targetOS))
406+
}
407+
kernelSnapshot := filepath.Join(build.OutputDirectoryPath(targetOS), "kernel_snapshot.dill")
408+
elfSnapshot := filepath.Join(build.OutputDirectoryPath(targetOS), "libapp.so")
409+
cmdGenerateKernelSnapshot := exec.Command(
410+
dart,
411+
filepath.Join(engineCachePath, "artifacts", "frontend_server.dart.snapshot"),
412+
"--sdk-root="+filepath.Join(engineCachePath, "flutter_patched_sdk_product"),
413+
"--target=flutter",
414+
"--aot",
415+
"--tfa",
416+
"-Ddart.vm.product=true",
417+
"--packages=.packages",
418+
"--output-dill="+kernelSnapshot,
419+
buildOrRunFlutterTarget,
420+
)
421+
cmdGenerateKernelSnapshot.Stderr = os.Stderr
422+
log.Infof("Generating kernel snapshot")
423+
output, err := cmdGenerateKernelSnapshot.Output()
424+
if err != nil {
425+
log.Errorf("Generating kernel snapshot failed: %v", err)
426+
log.Errorf(string(output))
427+
os.Exit(1)
428+
}
429+
generateAotSnapshotCommand := []string{
430+
genSnapshot,
431+
"--no-causal-async-stacks",
432+
"--lazy-async-stacks",
433+
"--deterministic",
434+
"--snapshot_kind=app-aot-elf",
435+
"--elf=" + elfSnapshot,
436+
}
437+
if buildOrRunMode == build.ReleaseMode {
438+
generateAotSnapshotCommand = append(generateAotSnapshotCommand, "--strip")
439+
}
440+
if targetOS == "darwin" {
441+
generateAotSnapshotCommand = append(generateAotSnapshotCommand,
442+
"--dedup-instructions",
443+
"--no-code-comments",
444+
)
445+
}
446+
generateAotSnapshotCommand = append(generateAotSnapshotCommand, kernelSnapshot)
447+
cmdGenerateAotSnapshot := exec.Command(
448+
generateAotSnapshotCommand[0],
449+
generateAotSnapshotCommand[1:]...,
450+
)
451+
cmdGenerateAotSnapshot.Stderr = os.Stderr
452+
log.Infof("Generating ELF snapshot")
453+
output, err = cmdGenerateAotSnapshot.Output()
454+
if err != nil {
455+
log.Errorf("Generating AOT snapshot failed: %v", err)
456+
log.Errorf(string(output))
457+
os.Exit(1)
458+
}
459+
err = os.Remove(kernelSnapshot)
460+
if err != nil {
461+
log.Errorf("Failed to remove kernel_snapshot.dill: %v", err)
462+
os.Exit(1)
463+
}
464+
}
341465
}
342466

343467
func buildGoBinary(targetOS string, vmArguments []string) {
344468
if vmArgsFromEnv := os.Getenv("HOVER_IN_DOCKER_BUILD_VMARGS"); len(vmArgsFromEnv) > 0 {
345469
vmArguments = append(vmArguments, strings.Split(vmArgsFromEnv, ",")...)
346470
}
347-
initBuildParameters(targetOS)
348471

349472
fileutils.CopyDir(build.IntermediatesDirectoryPath(targetOS), build.OutputDirectoryPath(targetOS))
350473

351-
outputEngineFile := filepath.Join(build.OutputDirectoryPath(targetOS), build.EngineFilename(targetOS))
352-
if _, err := os.Stat(outputEngineFile); err == nil || os.IsExist(err) {
353-
err = os.RemoveAll(outputEngineFile)
474+
for _, engineFile := range build.EngineFiles(targetOS, buildOrRunMode) {
475+
outputEngineFile := filepath.Join(build.OutputDirectoryPath(targetOS), engineFile)
476+
if _, err := os.Stat(outputEngineFile); err == nil || os.IsExist(err) {
477+
err = os.RemoveAll(outputEngineFile)
478+
if err != nil {
479+
log.Errorf("Failed to remove old engine: %v", err)
480+
os.Exit(1)
481+
}
482+
}
483+
err := copy.Copy(
484+
filepath.Join(engineCachePath, engineFile),
485+
outputEngineFile,
486+
)
354487
if err != nil {
355-
log.Errorf("Failed to remove old engine: %v", err)
488+
log.Errorf("Failed to copy %s: %v", engineFile, err)
356489
os.Exit(1)
357490
}
358491
}
359-
err := copy.Copy(
360-
filepath.Join(engineCachePath, build.EngineFilename(targetOS)),
361-
outputEngineFile,
362-
)
363-
if err != nil {
364-
log.Errorf("Failed to copy %s: %v", build.EngineFilename(targetOS), err)
365-
os.Exit(1)
366-
}
367492

368-
err = copy.Copy(
493+
err := copy.Copy(
369494
filepath.Join(engineCachePath, "artifacts", "icudtl.dat"),
370495
filepath.Join(build.OutputDirectoryPath(targetOS), "icudtl.dat"),
371496
)
@@ -433,14 +558,6 @@ func buildGoBinary(targetOS string, vmArguments []string) {
433558
log.Warnf("The '--opengl=none' flag makes go-flutter incompatible with texture plugins!")
434559
}
435560

436-
if !buildDebug && targetOS == "linux" {
437-
err = exec.Command("strip", "-s", outputEngineFile).Run()
438-
if err != nil {
439-
log.Errorf("Failed to strip %s: %v", outputEngineFile, err)
440-
os.Exit(1)
441-
}
442-
}
443-
444561
buildCommandString := buildCommand(targetOS, vmArguments, build.OutputBinaryPath(config.GetConfig().GetExecutableName(pubspec.GetPubSpec().Name), targetOS))
445562
cmdGoBuild := exec.Command(buildCommandString[0], buildCommandString[1:]...)
446563
cmdGoBuild.Dir = filepath.Join(wd, build.BuildPath)
@@ -471,11 +588,14 @@ func buildEnv(targetOS string, engineCachePath string) []string {
471588
cgoLdflags = fmt.Sprintf("-F%s -Wl,-rpath,@executable_path", engineCachePath)
472589
cgoLdflags += fmt.Sprintf(" -F%s -L%s", outputDirPath, outputDirPath)
473590
cgoLdflags += " -mmacosx-version-min=10.10"
591+
cgoLdflags += fmt.Sprintf(" -framework %s", build.LibraryName(targetOS))
474592
cgoCflags = "-mmacosx-version-min=10.10"
475593
case "linux":
476594
cgoLdflags = fmt.Sprintf("-L%s -L%s", engineCachePath, outputDirPath)
595+
cgoLdflags += fmt.Sprintf(" -l%s -Wl,-rpath,$ORIGIN", build.LibraryName(targetOS))
477596
case "windows":
478597
cgoLdflags = fmt.Sprintf("-L%s -L%s", engineCachePath, outputDirPath)
598+
cgoLdflags += fmt.Sprintf(" -l%s", build.LibraryName(targetOS))
479599
default:
480600
log.Errorf("Target platform %s is not supported, cgo_ldflags not implemented.", targetOS)
481601
os.Exit(1)
@@ -517,7 +637,7 @@ func buildCommand(targetOS string, vmArguments []string, outputBinaryPath string
517637
}
518638

519639
var ldflags []string
520-
if !buildDebug {
640+
if buildOrRunMode != build.DebugMode {
521641
vmArguments = append(vmArguments, "--disable-dart-asserts")
522642
vmArguments = append(vmArguments, "--disable-observatory")
523643

cmd/bumpversion.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ var upgradeCmd = &cobra.Command{
3636
}
3737

3838
func upgrade(targetOS string) (err error) {
39-
enginecache.ValidateOrUpdateEngine(targetOS, buildOrRunCachePath, "")
39+
enginecache.ValidateOrUpdateEngine(targetOS, buildOrRunCachePath, "", build.DebugMode)
4040
return upgradeGoFlutter(targetOS)
4141
}
4242

cmd/docker.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import (
1616
)
1717

1818
func dockerHoverBuild(targetOS string, packagingTask packaging.Task, buildFlags []string, vmArguments []string) {
19-
initBuildParameters(targetOS)
2019
var err error
2120
dockerBin := build.DockerBin()
2221

cmd/run.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,7 @@ var runCmd = &cobra.Command{
5252
// Can only run on host OS
5353
targetOS := runtime.GOOS
5454

55-
// forcefully enable --debug as it is not optional for 'hover run'
56-
buildDebug = true
55+
initBuildParameters(targetOS, build.DebugMode)
5756

5857
if runOmitFlutterBundle {
5958
log.Infof("Omiting flutter build bundle")
@@ -123,7 +122,7 @@ func runAndAttach(projectName string, targetOS string) {
123122
// Non-blockingly echo command stderr to terminal
124123
go io.Copy(os.Stderr, stderrApp)
125124

126-
log.Infof("Running %s in debug mode", projectName)
125+
log.Infof("Running %s in %s mode", projectName, buildOrRunMode.Name)
127126
err = cmdApp.Start()
128127
if err != nil {
129128
log.Errorf("Failed to start app '%s': %v", projectName, err)

0 commit comments

Comments
 (0)