Skip to content

Add AOT building #147

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
333 changes: 253 additions & 80 deletions cmd/build.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion cmd/bumpversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ var upgradeCmd = &cobra.Command{
}

func upgrade(targetOS string) (err error) {
enginecache.ValidateOrUpdateEngine(targetOS, buildOrRunCachePath, "")
enginecache.ValidateOrUpdateEngine(targetOS, buildOrRunCachePath, "", build.DebugMode)
return upgradeGoFlutter(targetOS)
}

Expand Down
1 change: 0 additions & 1 deletion cmd/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import (
)

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

Expand Down
14 changes: 8 additions & 6 deletions cmd/packaging/noop.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package packaging

import "github.com/go-flutter-desktop/hover/internal/build"

type noopTask struct{}

var NoopTask Task = &noopTask{}

func (_ *noopTask) Name() string { return "" }
func (_ *noopTask) Init() {}
func (_ *noopTask) IsInitialized() bool { return true }
func (_ *noopTask) AssertInitialized() {}
func (_ *noopTask) Pack(string) {}
func (_ *noopTask) AssertSupported() {}
func (_ *noopTask) Name() string { return "" }
func (_ *noopTask) Init() {}
func (_ *noopTask) IsInitialized() bool { return true }
func (_ *noopTask) AssertInitialized() {}
func (_ *noopTask) Pack(string, build.Mode) {}
func (_ *noopTask) AssertSupported() {}
20 changes: 10 additions & 10 deletions cmd/packaging/packaging.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ func (t *packagingTask) init(ignoreAlreadyExists bool) {
}
}

func (t *packagingTask) Pack(fullVersion string) {
func (t *packagingTask) Pack(fullVersion string, mode build.Mode) {
projectName := pubspec.GetPubSpec().Name
version := strings.Split(fullVersion, "+")[0]
var release string
Expand All @@ -137,7 +137,7 @@ func (t *packagingTask) Pack(fullVersion string) {
} else {
release = strings.ReplaceAll(fullVersion, ".", "")
}
description := pubspec.GetPubSpec().Description
description := pubspec.GetPubSpec().GetDescription()
organizationName := androidmanifest.AndroidOrganizationName()
author := pubspec.GetPubSpec().GetAuthor()
applicationName := config.GetConfig().GetApplicationName(projectName)
Expand All @@ -158,17 +158,17 @@ func (t *packagingTask) Pack(fullVersion string) {
}
templateData["iconPath"] = executeStringTemplate(t.linuxDesktopFileIconPath, templateData)
templateData["executablePath"] = executeStringTemplate(t.linuxDesktopFileExecutablePath, templateData)
t.pack(templateData, packageName, projectName, applicationName, executableName, version, release)
t.pack(templateData, packageName, projectName, applicationName, executableName, version, release, mode)
}

func (t *packagingTask) pack(templateData map[string]string, packageName, projectName, applicationName, executableName, version, release string) {
func (t *packagingTask) pack(templateData map[string]string, packageName, projectName, applicationName, executableName, version, release string, mode build.Mode) {
if t.extraTemplateData != nil {
for key, value := range t.extraTemplateData(packageName, packagingFormatPath(t.packagingFormatName)) {
templateData[key] = value
}
}
for task := range t.dependsOn {
task.pack(templateData, packageName, projectName, applicationName, executableName, version, release)
task.pack(templateData, packageName, projectName, applicationName, executableName, version, release, mode)
}
tmpPath := getTemporaryBuildDirectory(projectName, t.packagingFormatName)
defer func() {
Expand All @@ -181,14 +181,14 @@ func (t *packagingTask) pack(templateData map[string]string, packageName, projec
log.Infof("Packaging %s in %s", strings.Split(t.packagingFormatName, "-")[1], tmpPath)

if t.flutterBuildOutputDirectory != "" {
err := copy.Copy(build.OutputDirectoryPath(strings.Split(t.packagingFormatName, "-")[0]), executeStringTemplate(filepath.Join(tmpPath, t.flutterBuildOutputDirectory), templateData))
err := copy.Copy(build.OutputDirectoryPath(strings.Split(t.packagingFormatName, "-")[0], mode), executeStringTemplate(filepath.Join(tmpPath, t.flutterBuildOutputDirectory), templateData))
if err != nil {
log.Errorf("Could not copy build folder: %v", err)
os.Exit(1)
}
}
for task, destination := range t.dependsOn {
err := copy.Copy(build.OutputDirectoryPath(task.packagingFormatName), filepath.Join(tmpPath, destination))
err := copy.Copy(build.OutputDirectoryPath(task.packagingFormatName, mode), filepath.Join(tmpPath, destination))
if err != nil {
log.Errorf("Could not copy build folder of %s: %v", task.packagingFormatName, err)
os.Exit(1)
Expand All @@ -208,10 +208,10 @@ func (t *packagingTask) pack(templateData map[string]string, packageName, projec
}
}

err := os.RemoveAll(build.OutputDirectoryPath(t.packagingFormatName))
err := os.RemoveAll(build.OutputDirectoryPath(t.packagingFormatName, mode))
log.Printf("Cleaning the build directory")
if err != nil {
log.Errorf("Failed to clean output directory %s: %v", build.OutputDirectoryPath(t.packagingFormatName), err)
log.Errorf("Failed to clean output directory %s: %v", build.OutputDirectoryPath(t.packagingFormatName, mode), err)
os.Exit(1)
}

Expand All @@ -225,7 +225,7 @@ func (t *packagingTask) pack(templateData map[string]string, packageName, projec
os.Exit(1)
}
outputFileName := filepath.Base(relativeOutputFilePath)
outputFilePath := filepath.Join(build.OutputDirectoryPath(t.packagingFormatName), outputFileName)
outputFilePath := filepath.Join(build.OutputDirectoryPath(t.packagingFormatName, mode), outputFileName)
err = copy.Copy(filepath.Join(tmpPath, relativeOutputFilePath), outputFilePath)
if err != nil {
log.Errorf("Could not move %s file: %v", outputFileName, err)
Expand Down
4 changes: 3 additions & 1 deletion cmd/packaging/task.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package packaging

import "github.com/go-flutter-desktop/hover/internal/build"

// Task contains all configuration options for a given packaging method.
// TODO: Rename to something that suits it more? Mabe Executor?
type Task interface {
Name() string
Init()
IsInitialized() bool
AssertInitialized()
Pack(buildVersion string)
Pack(buildVersion string, mode build.Mode)
AssertSupported()
}
51 changes: 10 additions & 41 deletions cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"io"
"os"
"os/exec"
"path/filepath"
"regexp"
"runtime"

Expand All @@ -20,19 +19,15 @@ import (
)

var (
runObservatoryPort string
runInitialRoute string
runOmitEmbedder bool
runOmitFlutterBundle bool
runObservatoryPort string
runInitialRoute string
)

func init() {
initCompileFlags(runCmd)

runCmd.Flags().StringVar(&runInitialRoute, "route", "", "Which route to load when running the app.")
runCmd.Flags().StringVarP(&runObservatoryPort, "observatory-port", "", "50300", "The observatory port used to connect hover to VM services (hot-reload/debug/..)")
runCmd.Flags().BoolVar(&runOmitFlutterBundle, "omit-flutter", false, "Don't (re)compile the current Flutter project, useful when only working with Golang code (plugin)")
runCmd.Flags().BoolVar(&runOmitEmbedder, "omit-embedder", false, "Don't (re)compile 'go-flutter' source code, useful when only working with Dart code")
rootCmd.AddCommand(runCmd)
}

Expand All @@ -43,49 +38,23 @@ var runCmd = &cobra.Command{
projectName := pubspec.GetPubSpec().Name
assertHoverInitialized()

// ensure we have something to build
if runOmitEmbedder && runOmitFlutterBundle {
log.Errorf("Flags omit-embedder and omit-flutter are not compatible.")
os.Exit(1)
}

// Can only run on host OS
targetOS := runtime.GOOS

// forcefully enable --debug as it is not optional for 'hover run'
buildDebug = true
initBuildParameters(targetOS, build.DebugMode)
subcommandBuild(targetOS, packaging.NoopTask, []string{
"--observatory-port=" + runObservatoryPort,
"--enable-service-port-fallback",
"--disable-service-auth-codes",
})

if runOmitFlutterBundle {
log.Infof("Omiting flutter build bundle")
} else {
// TODO: cleaning can't be enabled because it would break when users --omit-embedder.
// cleanBuildOutputsDir(targetOS)
buildFlutterBundle(targetOS)
}
if runOmitEmbedder {
log.Infof("Omiting build the embedder")
} else {
vmArguments := []string{"--observatory-port=" + runObservatoryPort, "--enable-service-port-fallback", "--disable-service-auth-codes"}
if buildOrRunDocker {
var buildFlags []string
buildFlags = append(buildFlags, commonFlags()...)
buildFlags = append(buildFlags, []string{
"--skip-flutter-build-bundle",
"--skip-engine-download",
"--debug",
}...)
dockerHoverBuild(targetOS, packaging.NoopTask, buildFlags, vmArguments)
} else {
buildGoBinary(targetOS, vmArguments)
}
}
log.Infof("Build finished, starting app...")
runAndAttach(projectName, targetOS)
},
}

func runAndAttach(projectName string, targetOS string) {
cmdApp := exec.Command(dotSlash + filepath.Join(build.BuildPath, "build", "outputs", targetOS, config.GetConfig().GetExecutableName(projectName)))
cmdApp := exec.Command(build.OutputBinaryPath(config.GetConfig().GetExecutableName(projectName), targetOS, buildOrRunMode))
cmdApp.Env = append(os.Environ(),
"GOFLUTTER_ROUTE="+runInitialRoute)
cmdFlutterAttach := exec.Command("flutter", "attach")
Expand Down Expand Up @@ -123,7 +92,7 @@ func runAndAttach(projectName string, targetOS string) {
// Non-blockingly echo command stderr to terminal
go io.Copy(os.Stderr, stderrApp)

log.Infof("Running %s in debug mode", projectName)
log.Infof("Running %s in %s mode", projectName, buildOrRunMode.Name)
err = cmdApp.Start()
if err != nil {
log.Errorf("Failed to start app '%s': %v", projectName, err)
Expand Down
53 changes: 38 additions & 15 deletions internal/build/build.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package build

import (
"fmt"
"os"
"path/filepath"

Expand All @@ -13,8 +14,8 @@ const BuildPath = "go"

// buildDirectoryPath returns the path in `BuildPath`/build.
// If needed, the directory is create at the returned path.
func buildDirectoryPath(targetOS, path string) string {
outputDirectoryPath, err := filepath.Abs(filepath.Join(BuildPath, "build", path, targetOS))
func buildDirectoryPath(targetOS string, mode Mode, path string) string {
outputDirectoryPath, err := filepath.Abs(filepath.Join(BuildPath, "build", path, fmt.Sprintf("%s-%s", targetOS, mode.Name)))
if err != nil {
log.Errorf("Failed to resolve absolute path for output directory: %v", err)
os.Exit(1)
Expand All @@ -32,8 +33,8 @@ func buildDirectoryPath(targetOS, path string) string {
// OutputDirectoryPath returns the path where the go-flutter binary and flutter
// binaries blobs will be stored for a particular platform.
// If needed, the directory is create at the returned path.
func OutputDirectoryPath(targetOS string) string {
return buildDirectoryPath(targetOS, "outputs")
func OutputDirectoryPath(targetOS string, mode Mode) string {
return buildDirectoryPath(targetOS, mode, "outputs")
}

// IntermediatesDirectoryPath returns the path where the intermediates stored.
Expand All @@ -42,8 +43,8 @@ func OutputDirectoryPath(targetOS string) string {
// Those intermediates include the dynamic library dependencies of go-flutter plugins.
// hover copies these intermediates from flutter plugins folder when `hover plugins get`, and
// copies to go-flutter's binary output folder before build.
func IntermediatesDirectoryPath(targetOS string) string {
return buildDirectoryPath(targetOS, "intermediates")
func IntermediatesDirectoryPath(targetOS string, mode Mode) string {
return buildDirectoryPath(targetOS, mode, "intermediates")
}

// OutputBinary returns the string of the executable used to launch the
Expand All @@ -66,24 +67,46 @@ func OutputBinary(executableName, targetOS string) string {

// OutputBinaryPath returns the path to the go-flutter Application for a
// specified platform.
func OutputBinaryPath(executableName, targetOS string) string {
outputBinaryPath := filepath.Join(OutputDirectoryPath(targetOS), OutputBinary(executableName, targetOS))
func OutputBinaryPath(executableName, targetOS string, mode Mode) string {
outputBinaryPath := filepath.Join(OutputDirectoryPath(targetOS, mode), OutputBinary(executableName, targetOS))
return outputBinaryPath
}

// EngineFilename returns the name of the engine file from flutter for the
// specified platform.
func EngineFilename(targetOS string) string {
// ExecutableExtension returns the extension of binary files on a given platform
func ExecutableExtension(targetOS string) string {
switch targetOS {
case "darwin":
return "FlutterEmbedder.framework"
// no special filename
return ""
case "linux":
return "libflutter_engine.so"
// no special filename
return ""
case "windows":
return "flutter_engine.dll"
return ".exe"
default:
log.Errorf("%s has no implemented engine file", targetOS)
log.Errorf("Target platform %s is not supported.", targetOS)
os.Exit(1)
return ""
}
}

// EngineFiles returns the names of the engine files from flutter for the
// specified platform and build mode.
func EngineFiles(targetOS string, mode Mode) []string {
switch targetOS {
case "darwin":
return []string{"libflutter_engine.dylib"}
case "linux":
return []string{"libflutter_engine.so"}
case "windows":
if mode.IsAot {
return []string{"flutter_engine.dll", "flutter_engine.exp", "flutter_engine.lib", "flutter_engine.pdb"}
} else {
return []string{"flutter_engine.dll"}
}
default:
log.Errorf("%s has no implemented engine file", targetOS)
os.Exit(1)
return []string{}
}
}
21 changes: 21 additions & 0 deletions internal/build/mode.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package build

type Mode struct {
Name string
IsAot bool
}

var DebugMode = Mode{
Name: "debug_unopt",
IsAot: false,
}

var ReleaseMode = Mode{
Name: "release",
IsAot: true,
}

var ProfileMode = Mode{
Name: "profile",
IsAot: true,
}
Loading