-
Notifications
You must be signed in to change notification settings - Fork 81
Initial cross-compiling support #23
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
GeertJohan
merged 10 commits into
go-flutter-desktop:master
from
provokateurin:feature/cross-compiling
Sep 24, 2019
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
27584d3
Initial cross-compiling support
provokateurin 3ecbbd7
Enable cache for docker builds
provokateurin b6d9bb2
Fix cross-builds for linux
provokateurin ad1da4c
Add documentation for cross-compiling
provokateurin b154e58
Fix requested code changes
provokateurin 06f6740
Merge branch 'master' into feature/cross-compiling
provokateurin 7ee1d1d
Fix log messages
c84e670
Add --docker flag and create seperate Dockerfiles for different build…
provokateurin 8af5830
Move build command from Dockerfile to docker run and fix file permiss…
provokateurin 56091f4
Change behavior if go not found
provokateurin File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ import ( | |
"fmt" | ||
"os" | ||
"os/exec" | ||
"os/user" | ||
"path/filepath" | ||
"regexp" | ||
"runtime" | ||
|
@@ -27,16 +28,24 @@ var ( | |
buildCachePath string | ||
buildOmitEmbedder bool | ||
buildOmitFlutterBundle bool | ||
buildDocker bool | ||
) | ||
|
||
const buildPath = "go" | ||
|
||
const mingwGccBinName = "x86_64-w64-mingw32-gcc" | ||
const clangBinName = "o32-clang" | ||
|
||
var crossCompile = false | ||
var engineCachePath string | ||
|
||
func init() { | ||
buildCmd.PersistentFlags().StringVarP(&buildTarget, "target", "t", "lib/main_desktop.dart", "The main entry-point file of the application.") | ||
buildCmd.PersistentFlags().StringVarP(&buildManifest, "manifest", "m", "pubspec.yaml", "Flutter manifest file of the application.") | ||
buildCmd.PersistentFlags().StringVarP(&buildBranch, "branch", "b", "", "The 'go-flutter' version to use. (@master or @v0.20.0 for example)") | ||
buildCmd.PersistentFlags().BoolVar(&buildDebug, "debug", false, "Build a debug version of the app.") | ||
buildCmd.PersistentFlags().StringVarP(&buildCachePath, "cache-path", "", "", "The path that hover uses to cache dependencies such as the Flutter engine .so/.dll (defaults to the standard user cache directory)") | ||
buildCmd.PersistentFlags().BoolVar(&buildDocker, "docker", false, "Compile in Docker container only. No need to install go") | ||
buildCmd.AddCommand(buildLinuxCmd) | ||
buildCmd.AddCommand(buildLinuxSnapCmd) | ||
buildCmd.AddCommand(buildLinuxDebCmd) | ||
|
@@ -146,12 +155,107 @@ func outputBinaryPath(projectName string, targetOS string) string { | |
return outputBinaryPath | ||
} | ||
|
||
func build(projectName string, targetOS string, vmArguments []string) { | ||
if targetOS != runtime.GOOS { | ||
fmt.Println("hover: Cross-compiling is currently not supported") | ||
func dockerBuild(projectName string, targetOS string, vmArguments []string) { | ||
crossCompilingDir, err := filepath.Abs(filepath.Join(buildPath, "cross-compiling")) | ||
err = os.MkdirAll(crossCompilingDir, 0755) | ||
if err != nil { | ||
fmt.Printf("hover: Cannot create the cross-compiling directory: %v\n", err) | ||
os.Exit(1) | ||
} | ||
userCacheDir, err := os.UserCacheDir() | ||
if err != nil { | ||
fmt.Printf("hover: Cannot get the path for the system cache directory: %v\n", err) | ||
os.Exit(1) | ||
} | ||
goPath := filepath.Join(userCacheDir, "hover-cc") | ||
err = os.MkdirAll(goPath, 0755) | ||
if err != nil { | ||
fmt.Printf("hover: Cannot create the hover-cc GOPATH under the system cache directory: %v\n", err) | ||
os.Exit(1) | ||
} | ||
wd, err := os.Getwd() | ||
if err != nil { | ||
fmt.Printf("hover: Cannot get the path for current directory %s", err) | ||
os.Exit(1) | ||
} | ||
var engineCachePath string | ||
dockerFilePath, err := filepath.Abs(filepath.Join(crossCompilingDir, "Dockerfile")) | ||
if err != nil { | ||
fmt.Printf("hover: Failed to resolve absolute path for Dockerfile %s: %v\n", dockerFilePath, err) | ||
os.Exit(1) | ||
} | ||
if _, err := os.Stat(dockerFilePath); os.IsNotExist(err) { | ||
dockerFile, err := os.Create(dockerFilePath) | ||
if err != nil { | ||
fmt.Printf("hover: Failed to create Dockerfile %s: %v\n", dockerFilePath, err) | ||
os.Exit(1) | ||
} | ||
dockerFileContent := []string{ | ||
"FROM dockercore/golang-cross", | ||
"RUN apt-get install libgl1-mesa-dev xorg-dev -y", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @GeertJohan So i'm failing on this due to wayland :) |
||
} | ||
|
||
for _, line := range dockerFileContent { | ||
if _, err := dockerFile.WriteString(line + "\n"); err != nil { | ||
fmt.Printf("hover: Could not write Dockerfile: %v\n", err) | ||
os.Exit(1) | ||
} | ||
} | ||
err = dockerFile.Close() | ||
if err != nil { | ||
fmt.Printf("hover: Could not close Dockerfile: %v\n", err) | ||
os.Exit(1) | ||
} | ||
fmt.Printf("hover: A Dockerfile for cross-compiling for %s has been created at %s. You can add it to git.\n", targetOS, filepath.Join(buildPath, "cross-compiling", targetOS)) | ||
} | ||
dockerBuildCmd := exec.Command(dockerBin, "build", "-t", "hover-build-cc", ".") | ||
dockerBuildCmd.Stderr = os.Stderr | ||
dockerBuildCmd.Dir = crossCompilingDir | ||
err = dockerBuildCmd.Run() | ||
if err != nil { | ||
fmt.Printf("hover: Docker build failed: %v\n", err) | ||
os.Exit(1) | ||
} | ||
|
||
fmt.Println("hover: Cross-Compiling 'go-flutter' and plugins using docker") | ||
|
||
u, err := user.Current() | ||
if err != nil { | ||
fmt.Printf("hover: Couldn't get current user: %v\n", err) | ||
os.Exit(1) | ||
} | ||
args := []string{ | ||
"run", | ||
"-w", "/app/go", | ||
"-v", goPath + ":/go", | ||
"-v", wd + ":/app", | ||
"-v", engineCachePath + ":/engine", | ||
"-v", filepath.Join(userCacheDir, "go-build") + ":/cache", | ||
} | ||
for _, env := range buildEnv(targetOS, "/engine") { | ||
args = append(args, "-e", env) | ||
} | ||
args = append(args, "hover-build-cc") | ||
chownStr := "" | ||
if runtime.GOOS != "windows" { | ||
chownStr = fmt.Sprintf(" && chown %s:%s build/ -R", u.Uid, u.Gid) | ||
} | ||
args = append(args, "bash", "-c", fmt.Sprintf("%s%s", strings.Join(buildCommand(targetOS, vmArguments, "build/outputs/"+targetOS+"/"+outputBinaryName(projectName, targetOS)), " "), chownStr)) | ||
dockerRunCmd := exec.Command(dockerBin, args...) | ||
dockerRunCmd.Stderr = os.Stderr | ||
dockerRunCmd.Stdout = os.Stdout | ||
dockerRunCmd.Dir = crossCompilingDir | ||
err = dockerRunCmd.Run() | ||
if err != nil { | ||
fmt.Printf("hover: Docker run failed: %v\n", err) | ||
os.Exit(1) | ||
} | ||
fmt.Println("hover: Successfully cross-compiled for " + targetOS) | ||
} | ||
|
||
func build(projectName string, targetOS string, vmArguments []string) { | ||
crossCompile = targetOS != runtime.GOOS | ||
buildDocker = crossCompile || buildDocker | ||
|
||
if buildCachePath != "" { | ||
engineCachePath = enginecache.ValidateOrUpdateEngineAtPath(targetOS, buildCachePath) | ||
} else { | ||
|
@@ -265,19 +369,6 @@ func build(projectName string, targetOS string, vmArguments []string) { | |
return | ||
} | ||
|
||
var cgoLdflags string | ||
switch targetOS { | ||
case "darwin": | ||
cgoLdflags = fmt.Sprintf("-F%s -Wl,-rpath,@executable_path", engineCachePath) | ||
case "linux": | ||
cgoLdflags = fmt.Sprintf("-L%s", engineCachePath) | ||
case "windows": | ||
cgoLdflags = fmt.Sprintf("-L%s", engineCachePath) | ||
default: | ||
fmt.Printf("hover: Target platform %s is not supported, cgo_ldflags not implemented.\n", targetOS) | ||
os.Exit(1) | ||
} | ||
|
||
wd, err := os.Getwd() | ||
if err != nil { | ||
fmt.Printf("hover: Failed to get working dir: %v\n", err) | ||
|
@@ -323,28 +414,19 @@ func build(projectName string, targetOS string, vmArguments []string) { | |
} | ||
} | ||
|
||
var ldflags []string | ||
if !buildDebug { | ||
vmArguments = append(vmArguments, "--disable-dart-asserts") | ||
vmArguments = append(vmArguments, "--disable-observatory") | ||
|
||
if targetOS == "windows" { | ||
ldflags = append(ldflags, "-H=windowsgui") | ||
if buildDocker { | ||
if crossCompile { | ||
fmt.Printf("hover: Because %s is not able to compile for %s out of the box, a cross-compiling container is used\n", runtime.GOOS, targetOS) | ||
} | ||
ldflags = append(ldflags, "-s") | ||
ldflags = append(ldflags, "-w") | ||
dockerBuild(projectName, targetOS, vmArguments) | ||
return | ||
} | ||
ldflags = append(ldflags, fmt.Sprintf("-X main.vmArguments=%s", strings.Join(vmArguments, ";"))) | ||
|
||
cmdGoBuild := exec.Command(goBin, "build", | ||
"-o", outputBinaryPath(projectName, targetOS), | ||
fmt.Sprintf("-ldflags=%s", strings.Join(ldflags, " ")), | ||
dotSlash+"cmd", | ||
) | ||
buildCommandString := buildCommand(targetOS, vmArguments, outputBinaryPath(projectName, targetOS)) | ||
cmdGoBuild := exec.Command(buildCommandString[0], buildCommandString[1:]...) | ||
cmdGoBuild.Dir = filepath.Join(wd, buildPath) | ||
cmdGoBuild.Env = append(os.Environ(), | ||
"GO111MODULE=on", | ||
"CGO_LDFLAGS="+cgoLdflags, | ||
buildEnv(targetOS, engineCachePath)..., | ||
) | ||
|
||
cmdGoBuild.Stderr = os.Stderr | ||
|
@@ -356,4 +438,71 @@ func build(projectName string, targetOS string, vmArguments []string) { | |
fmt.Printf("hover: Go build failed: %v\n", err) | ||
os.Exit(1) | ||
} | ||
fmt.Println("hover: Successfully compiled") | ||
} | ||
|
||
func buildEnv(targetOS string, engineCachePath string) []string { | ||
var cgoLdflags string | ||
switch targetOS { | ||
case "darwin": | ||
cgoLdflags = fmt.Sprintf("-F%s -Wl,-rpath,@executable_path", engineCachePath) | ||
case "linux": | ||
cgoLdflags = fmt.Sprintf("-L%s", engineCachePath) | ||
case "windows": | ||
cgoLdflags = fmt.Sprintf("-L%s", engineCachePath) | ||
default: | ||
fmt.Printf("hover: Target platform %s is not supported, cgo_ldflags not implemented.\n", targetOS) | ||
os.Exit(1) | ||
} | ||
env := []string{ | ||
"GO111MODULE=on", | ||
"CGO_LDFLAGS=" + cgoLdflags, | ||
"GOOS=" + targetOS, | ||
"GOARCH=amd64", | ||
"CGO_ENABLED=1", | ||
} | ||
if buildDocker { | ||
env = append(env, | ||
"GOCACHE=/cache", | ||
) | ||
if targetOS == "windows" { | ||
env = append(env, | ||
"CC="+mingwGccBinName, | ||
) | ||
} | ||
if targetOS == "darwin" { | ||
env = append(env, | ||
"CC="+clangBinName, | ||
) | ||
} | ||
} | ||
return env | ||
} | ||
|
||
func buildCommand(targetOS string, vmArguments []string, outputBinaryPath string) []string { | ||
var ldflags []string | ||
if !buildDebug { | ||
vmArguments = append(vmArguments, "--disable-dart-asserts") | ||
vmArguments = append(vmArguments, "--disable-observatory") | ||
|
||
if targetOS == "windows" { | ||
ldflags = append(ldflags, "-H=windowsgui") | ||
} | ||
ldflags = append(ldflags, "-s") | ||
ldflags = append(ldflags, "-w") | ||
} | ||
ldflags = append(ldflags, fmt.Sprintf("-X main.vmArguments=%s", strings.Join(vmArguments, ";"))) | ||
outputCommand := []string{ | ||
"go", | ||
"build", | ||
"-o", outputBinaryPath, | ||
"-v", | ||
} | ||
if buildDocker { | ||
outputCommand = append(outputCommand, fmt.Sprintf("-ldflags=\"%s\"", strings.Join(ldflags, " "))) | ||
} else { | ||
outputCommand = append(outputCommand, fmt.Sprintf("-ldflags=%s", strings.Join(ldflags, " "))) | ||
} | ||
outputCommand = append(outputCommand, dotSlash+"cmd") | ||
return outputCommand | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.