// linkdeps links dependencies into the specified output file. func linkdeps(pkg *build.Package, output string) error { depslist := []string{"runtime"} deps := make(map[string]bool) deps["runtime"] = true deps["unsafe"] = true if len(pkg.CgoFiles) > 0 { pkg.Imports = append(pkg.Imports, "runtime/cgo") pkg.Imports = append(pkg.Imports, "syscall") } var mkdeps func(imports ...string) error mkdeps = func(imports ...string) error { for _, path := range imports { if path == "C" { if err := mkdeps("runtime/cgo", "syscall"); err != nil { return err } continue } if !deps[path] { deps[path] = true pkg, err := build.Import(path, "", 0) if err != nil { return err } if err = mkdeps(pkg.Imports...); err != nil { return err } depslist = append(depslist, path) } } return nil } err := mkdeps(pkg.Imports...) if err != nil { return err } if test { if err = mkdeps(pkg.TestImports...); err != nil { return err } if err = mkdeps(pkg.XTestImports...); err != nil { return err } } for i := 0; i < len(depslist)/2; i++ { j := len(depslist) - i - 1 depslist[i], depslist[j] = depslist[j], depslist[i] } llvmlink := filepath.Join(llvmbindir, "llvm-link") args := []string{"-o", output, output} var ldflags []string for _, path := range depslist { if path == pkg.ImportPath { continue } bcfile := filepath.Join(pkgroot, path+".bc") if buildDeps { if _, err := os.Stat(bcfile); err != nil { if err = buildPackages([]string{path}); err != nil { return err } } } args = append(args, bcfile) if pkgldflags, err := readLdflags(path); err != nil { return err } else { ldflags = append(ldflags, pkgldflags...) } } cmd := exec.Command(llvmlink, args...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err = runCmd(cmd); err != nil { return err } if !emitllvm || triple == "pnacl" { input := output if strings.Contains(triple, "darwin") || strings.Contains(triple, "mac") { // Not doing this intermediate step will make it invoke "dsymutil" // which then asserts and kills the build. // See discussion in issue #49 for more details. input += ".o" args := []string{"-g", "-c", "-o", input, output} cmd := exec.Command(clang, args...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err = runCmd(cmd); err != nil { return err } } args := []string{"-pthread", "-v", "-g", "-o", output, input} if triple == "pnacl" { args = append(args, "-l", "ppapi") } args = append(args, ldflags...) cmd := exec.Command(clang+"++", args...) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err = runCmd(cmd); err != nil { return err } } return nil }
// fillPackage full of info. Assumes a build.Package discovered in build.FindOnly mode func fillPackage(p *build.Package) error { if p.Goroot { return nil } var buildMatch = "+build " var buildFieldSplit = func(r rune) bool { return unicode.IsSpace(r) || r == ',' } debugln("Filling package:", p.ImportPath, "from", p.Dir) gofiles, err := filepath.Glob(filepath.Join(p.Dir, "*.go")) if err != nil { debugln("Error globbing", err) return err } var testImports []string var imports []string NextFile: for _, file := range gofiles { debugln(file) fset := token.NewFileSet() pf, err := parser.ParseFile(fset, file, nil, parser.ParseComments) if err != nil { return err } testFile := strings.HasSuffix(file, "_test.go") fname := filepath.Base(file) if testFile { p.TestGoFiles = append(p.TestGoFiles, fname) } else { p.GoFiles = append(p.GoFiles, fname) } if len(pf.Comments) > 0 { for _, c := range pf.Comments { ct := c.Text() if i := strings.Index(ct, buildMatch); i != -1 { for _, b := range strings.FieldsFunc(ct[i+len(buildMatch):], buildFieldSplit) { //TODO: appengine is a special case for now: https://github.com/tools/godep/issues/353 if b == "ignore" || b == "appengine" { p.IgnoredGoFiles = append(p.IgnoredGoFiles, fname) continue NextFile } } } } } for _, is := range pf.Imports { name, err := strconv.Unquote(is.Path.Value) if err != nil { return err // can't happen? } if testFile { testImports = append(testImports, name) } else { imports = append(imports, name) } } } imports = uniq(imports) testImports = uniq(testImports) p.Imports = imports p.TestImports = testImports return nil }
// fillPackage full of info. Assumes p.Dir is set at a minimum func fillPackage(p *build.Package) error { if p.Goroot { return nil } if p.SrcRoot == "" { for _, base := range build.Default.SrcDirs() { if strings.HasPrefix(p.Dir, base) { p.SrcRoot = base } } } if p.SrcRoot == "" { return errors.New("Unable to find SrcRoot for package " + p.ImportPath) } if p.Root == "" { p.Root = filepath.Dir(p.SrcRoot) } var buildMatch = "+build " var buildFieldSplit = func(r rune) bool { return unicode.IsSpace(r) || r == ',' } debugln("Filling package:", p.ImportPath, "from", p.Dir) gofiles, err := filepath.Glob(filepath.Join(p.Dir, "*.go")) if err != nil { debugln("Error globbing", err) return err } var testImports []string var imports []string NextFile: for _, file := range gofiles { debugln(file) pf, err := parser.ParseFile(token.NewFileSet(), file, nil, parser.ImportsOnly|parser.ParseComments) if err != nil { return err } testFile := strings.HasSuffix(file, "_test.go") fname := filepath.Base(file) for _, c := range pf.Comments { ct := c.Text() if i := strings.Index(ct, buildMatch); i != -1 { for _, t := range strings.FieldsFunc(ct[i+len(buildMatch):], buildFieldSplit) { for _, tag := range ignoreTags { if t == tag { p.IgnoredGoFiles = append(p.IgnoredGoFiles, fname) continue NextFile } } if versionMatch.MatchString(t) && !isSameOrNewer(t, majorGoVersion) { debugln("Adding", fname, "to ignored list because of version tag", t) p.IgnoredGoFiles = append(p.IgnoredGoFiles, fname) continue NextFile } if versionNegativeMatch.MatchString(t) && isSameOrNewer(t[1:], majorGoVersion) { debugln("Adding", fname, "to ignored list because of version tag", t) p.IgnoredGoFiles = append(p.IgnoredGoFiles, fname) continue NextFile } } } } if testFile { p.TestGoFiles = append(p.TestGoFiles, fname) } else { p.GoFiles = append(p.GoFiles, fname) } for _, is := range pf.Imports { name, err := strconv.Unquote(is.Path.Value) if err != nil { return err // can't happen? } if testFile { testImports = append(testImports, name) } else { imports = append(imports, name) } } } imports = uniq(imports) testImports = uniq(testImports) p.Imports = imports p.TestImports = testImports return nil }