diff --git a/cmd/fyne/internal/mobile/bind.go b/cmd/fyne/internal/mobile/bind.go index 2571b1f8d4..6bf5408859 100644 --- a/cmd/fyne/internal/mobile/bind.go +++ b/cmd/fyne/internal/mobile/bind.go @@ -10,6 +10,9 @@ import ( "io/ioutil" "os" "path/filepath" + "strings" + + "golang.org/x/tools/go/packages" ) // ctx, pkg, tmpdir in build.go @@ -61,3 +64,12 @@ func writeFile(filename string, generate func(io.Writer) error) error { return generate(f) } + +func packagesConfig(targetOS string) *packages.Config { + config := &packages.Config{} + config.Env = append(os.Environ(), "GOARCH=arm", "GOOS="+targetOS) + if len(ctx.BuildTags) > 0 { + config.BuildFlags = []string{"-tags=" + strings.Join(ctx.BuildTags, ",")} + } + return config +} diff --git a/cmd/fyne/internal/mobile/build.go b/cmd/fyne/internal/mobile/build.go index 234a720db6..95a5ba9558 100644 --- a/cmd/fyne/internal/mobile/build.go +++ b/cmd/fyne/internal/mobile/build.go @@ -14,8 +14,11 @@ import ( "io" "os" "os/exec" + "path" "regexp" "strings" + + "golang.org/x/tools/go/packages" ) var ctx = build.Default @@ -77,7 +80,7 @@ func runBuild(cmd *command) (err error) { // runBuildImpl builds a package for mobiles based on the given commands. // runBuildImpl returns a built package information and an error if exists. -func runBuildImpl(cmd *command) (*build.Package, error) { cleanup, err := buildEnvInit() +func runBuildImpl(cmd *command) (*packages.Package, error) { cleanup, err := buildEnvInit() if err != nil { return nil, err } @@ -90,14 +93,13 @@ func runBuildImpl(cmd *command) (*build.Package, error) { cleanup, err := buildE return nil, fmt.Errorf(`invalid -target=%q: %v`, buildTarget, err) } + // TODO(hajimehoshi): ctx is now used only for recording build tags in build. Remove this. oldCtx := ctx defer func() { ctx = oldCtx }() - ctx.GOARCH = targetArchs[0] - ctx.GOOS = targetOS - if ctx.GOOS == "darwin" { + if targetOS == "darwin" { ctx.BuildTags = append(ctx.BuildTags, "ios") if buildRelease { @@ -106,19 +108,27 @@ func runBuildImpl(cmd *command) (*build.Package, error) { cleanup, err := buildE } } - var pkg *build.Package + var buildPath string switch len(args) { case 0: - pkg, err = ctx.ImportDir(cwd, build.ImportComment) + buildPath = "." case 1: - pkg, err = ctx.Import(args[0], cwd, build.ImportComment) + buildPath = path.Clean(args[0]) default: cmd.usage() os.Exit(1) } + pkgs, err := packages.Load(packagesConfig(targetOS), buildPath) if err != nil { return nil, err } + // len(pkgs) can be more than 1 e.g., when the specified path includes `...`. + if len(pkgs) != 1 { + cmd.usage() + os.Exit(1) + } + + pkg := pkgs[0] if pkg.Name != "main" && buildO != "" { return nil, fmt.Errorf("cannot set -o when building non-main package") @@ -133,7 +143,7 @@ func runBuildImpl(cmd *command) (*build.Package, error) { cleanup, err := buildE if pkg.Name != "main" { for _, arch := range targetArchs { env := androidEnv[arch] - if err := goBuild(pkg.ImportPath, env); err != nil { + if err := goBuild(pkg.PkgPath, env); err != nil { return nil, err } } @@ -150,7 +160,7 @@ func runBuildImpl(cmd *command) (*build.Package, error) { cleanup, err := buildE if pkg.Name != "main" { for _, arch := range targetArchs { env := darwinEnv[arch] - if err := goBuild(pkg.ImportPath, env); err != nil { + if err := goBuild(pkg.PkgPath, env); err != nil { return nil, err } } @@ -163,7 +173,7 @@ func runBuildImpl(cmd *command) (*build.Package, error) { cleanup, err := buildE } if !nmpkgs["golang.org/x/mobile/app"] { - return nil, fmt.Errorf(`%s does not import "golang.org/x/mobile/app"`, pkg.ImportPath) + return nil, fmt.Errorf(`%s does not import "golang.org/x/mobile/app"`, pkg.PkgPath) } return pkg, nil diff --git a/cmd/fyne/internal/mobile/build_androidapp.go b/cmd/fyne/internal/mobile/build_androidapp.go index e23c5957b0..d25fd38094 100644 --- a/cmd/fyne/internal/mobile/build_androidapp.go +++ b/cmd/fyne/internal/mobile/build_androidapp.go @@ -12,7 +12,6 @@ import ( "encoding/xml" "errors" "fmt" - "go/build" "io" "io/ioutil" "log" @@ -21,15 +20,21 @@ import ( "strings" "fyne.io/fyne/cmd/fyne/internal/mobile/binres" + "golang.org/x/tools/go/packages" ) -func goAndroidBuild(pkg *build.Package, bundleID string, androidArchs []string, iconPath, appName string) (map[string]bool, error) { +func goAndroidBuild(pkg *packages.Package, bundleID string, androidArchs []string, iconPath, appName string) (map[string]bool, error) { ndkRoot, err := ndkRoot() if err != nil { return nil, err } libName := androidPkgName(appName) - manifestPath := filepath.Join(pkg.Dir, "AndroidManifest.xml") + + // TODO(hajimehoshi): This works only with Go tools that assume all source files are in one directory. + // Fix this to work with other Go tools. + dir := filepath.Dir(pkg.GoFiles[0]) + + manifestPath := filepath.Join(dir, "AndroidManifest.xml") manifestData, err := ioutil.ReadFile(manifestPath) if err != nil { if !os.IsNotExist(err) { @@ -70,7 +75,7 @@ func goAndroidBuild(pkg *build.Package, bundleID string, androidArchs []string, return nil, err } err = goBuild( - pkg.ImportPath, + pkg.PkgPath, env, "-buildmode=c-shared", "-o", libAbsPath, @@ -182,7 +187,7 @@ func goAndroidBuild(pkg *build.Package, bundleID string, androidArchs []string, iconPath string } arsc.iconPath = iconPath - assetsDir := filepath.Join(pkg.Dir, "assets") + assetsDir := filepath.Join(dir, "assets") assetsDirExists := true fi, err := os.Stat(assetsDir) if err != nil { diff --git a/cmd/fyne/internal/mobile/build_iosapp.go b/cmd/fyne/internal/mobile/build_iosapp.go index 64cbb66d51..b28bb786ba 100644 --- a/cmd/fyne/internal/mobile/build_iosapp.go +++ b/cmd/fyne/internal/mobile/build_iosapp.go @@ -9,7 +9,6 @@ import ( "crypto/x509" "encoding/pem" "fmt" - "go/build" "io/ioutil" "os" "os/exec" @@ -17,10 +16,12 @@ import ( "path/filepath" "strings" "text/template" + + "golang.org/x/tools/go/packages" ) -func goIOSBuild(pkg *build.Package, bundleID string, archs []string, appName string) (map[string]bool, error) { - src := pkg.ImportPath +func goIOSBuild(pkg *packages.Package, bundleID string, archs []string, appName string) (map[string]bool, error) { + src := pkg.PkgPath buildO = rfc1034Label(appName) + ".app" infoplist := new(bytes.Buffer) @@ -108,7 +109,7 @@ func goIOSBuild(pkg *build.Package, bundleID string, archs []string, appName str // TODO(jbd): Fallback to copying if renaming fails. if buildO == "" { - n := pkg.ImportPath + n := pkg.PkgPath if n == "." { // use cwd name cwd, err := os.Getwd() @@ -168,13 +169,15 @@ func detectTeamID() (string, error) { return cert.Subject.OrganizationalUnit[0], nil } -func iosCopyAssets(pkg *build.Package, xcodeProjDir string) error { +func iosCopyAssets(pkg *packages.Package, xcodeProjDir string) error { dstAssets := xcodeProjDir + "/main/assets" if err := mkdir(dstAssets); err != nil { return err } - srcAssets := filepath.Join(pkg.Dir, "assets") + // TODO(hajimehoshi): This works only with Go tools that assume all source files are in one directory. + // Fix this to work with other Go tools. + srcAssets := filepath.Join(filepath.Dir(pkg.GoFiles[0]), "assets") fi, err := os.Stat(srcAssets) if err != nil { if os.IsNotExist(err) { diff --git a/cmd/fyne/internal/mobile/env.go b/cmd/fyne/internal/mobile/env.go index fb32f4c7ba..0aab213753 100644 --- a/cmd/fyne/internal/mobile/env.go +++ b/cmd/fyne/internal/mobile/env.go @@ -13,7 +13,6 @@ import ( // General mobile build environment. Initialized by envInit. var ( - cwd string gomobilepath string // $GOPATH/pkg/gomobile androidEnv map[string][]string // android arch -> []string @@ -74,12 +73,6 @@ func buildEnvInit() (cleanup func(), err error) { } func envInit() (err error) { - // TODO(crawshaw): cwd only used by ctx.Import, which can take "." - cwd, err = os.Getwd() - if err != nil { - return err - } - // Setup the cross-compiler environments. if ndkRoot, err := ndkRoot(); err == nil { androidEnv = make(map[string][]string)