Merge "Microfactory support for transitive link dependencies"
This commit is contained in:
@@ -87,8 +87,9 @@ type GoPackage struct {
|
|||||||
Name string
|
Name string
|
||||||
|
|
||||||
// Inputs
|
// Inputs
|
||||||
deps []*GoPackage
|
directDeps []*GoPackage // specified directly by the module
|
||||||
files []string
|
allDeps []*GoPackage // direct dependencies and transitive dependencies
|
||||||
|
files []string
|
||||||
|
|
||||||
// Outputs
|
// Outputs
|
||||||
pkgDir string
|
pkgDir string
|
||||||
@@ -102,17 +103,48 @@ type GoPackage struct {
|
|||||||
rebuilt bool
|
rebuilt bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LinkedHashMap<string, GoPackage>
|
||||||
|
type linkedDepSet struct {
|
||||||
|
packageSet map[string](*GoPackage)
|
||||||
|
packageList []*GoPackage
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDepSet() *linkedDepSet {
|
||||||
|
return &linkedDepSet{packageSet: make(map[string]*GoPackage)}
|
||||||
|
}
|
||||||
|
func (s *linkedDepSet) tryGetByName(name string) (*GoPackage, bool) {
|
||||||
|
pkg, contained := s.packageSet[name]
|
||||||
|
return pkg, contained
|
||||||
|
}
|
||||||
|
func (s *linkedDepSet) getByName(name string) *GoPackage {
|
||||||
|
pkg, _ := s.tryGetByName(name)
|
||||||
|
return pkg
|
||||||
|
}
|
||||||
|
func (s *linkedDepSet) add(name string, goPackage *GoPackage) {
|
||||||
|
s.packageSet[name] = goPackage
|
||||||
|
s.packageList = append(s.packageList, goPackage)
|
||||||
|
}
|
||||||
|
func (s *linkedDepSet) ignore(name string) {
|
||||||
|
s.packageSet[name] = nil
|
||||||
|
}
|
||||||
|
|
||||||
// FindDeps searches all applicable go files in `path`, parses all of them
|
// FindDeps searches all applicable go files in `path`, parses all of them
|
||||||
// for import dependencies that exist in pkgMap, then recursively does the
|
// for import dependencies that exist in pkgMap, then recursively does the
|
||||||
// same for all of those dependencies.
|
// same for all of those dependencies.
|
||||||
func (p *GoPackage) FindDeps(path string, pkgMap *pkgPathMapping) error {
|
func (p *GoPackage) FindDeps(path string, pkgMap *pkgPathMapping) error {
|
||||||
return p.findDeps(path, pkgMap, make(map[string]*GoPackage))
|
depSet := newDepSet()
|
||||||
|
err := p.findDeps(path, pkgMap, depSet)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p.allDeps = depSet.packageList
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// findDeps is the recursive version of FindDeps. allPackages is the map of
|
// findDeps is the recursive version of FindDeps. allPackages is the map of
|
||||||
// all locally defined packages so that the same dependency of two different
|
// all locally defined packages so that the same dependency of two different
|
||||||
// packages is only resolved once.
|
// packages is only resolved once.
|
||||||
func (p *GoPackage) findDeps(path string, pkgMap *pkgPathMapping, allPackages map[string]*GoPackage) error {
|
func (p *GoPackage) findDeps(path string, pkgMap *pkgPathMapping, allPackages *linkedDepSet) error {
|
||||||
// If this ever becomes too slow, we can look at reading the files once instead of twice
|
// If this ever becomes too slow, we can look at reading the files once instead of twice
|
||||||
// But that just complicates things today, and we're already really fast.
|
// But that just complicates things today, and we're already really fast.
|
||||||
foundPkgs, err := parser.ParseDir(token.NewFileSet(), path, func(fi os.FileInfo) bool {
|
foundPkgs, err := parser.ParseDir(token.NewFileSet(), path, func(fi os.FileInfo) bool {
|
||||||
@@ -154,7 +186,7 @@ func (p *GoPackage) findDeps(path string, pkgMap *pkgPathMapping, allPackages ma
|
|||||||
return fmt.Errorf("%s: invalid quoted string: <%s> %v", filename, importSpec.Path.Value, err)
|
return fmt.Errorf("%s: invalid quoted string: <%s> %v", filename, importSpec.Path.Value, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if pkg, ok := allPackages[name]; ok && pkg != nil {
|
if pkg, ok := allPackages.tryGetByName(name); ok {
|
||||||
if pkg != nil {
|
if pkg != nil {
|
||||||
if _, ok := localDeps[name]; !ok {
|
if _, ok := localDeps[name]; !ok {
|
||||||
deps = append(deps, name)
|
deps = append(deps, name)
|
||||||
@@ -168,9 +200,9 @@ func (p *GoPackage) findDeps(path string, pkgMap *pkgPathMapping, allPackages ma
|
|||||||
if path, ok, err := pkgMap.Path(name); err != nil {
|
if path, ok, err := pkgMap.Path(name); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if !ok {
|
} else if !ok {
|
||||||
// Probably in the stdlib, compiler will fail we a reasonable error message otherwise.
|
// Probably in the stdlib, but if not, then the compiler will fail with a reasonable error message
|
||||||
// Mark it as such so that we don't try to decode its path again.
|
// Mark it as such so that we don't try to decode its path again.
|
||||||
allPackages[name] = nil
|
allPackages.ignore(name)
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
pkgPath = path
|
pkgPath = path
|
||||||
@@ -180,7 +212,7 @@ func (p *GoPackage) findDeps(path string, pkgMap *pkgPathMapping, allPackages ma
|
|||||||
Name: name,
|
Name: name,
|
||||||
}
|
}
|
||||||
deps = append(deps, name)
|
deps = append(deps, name)
|
||||||
allPackages[name] = pkg
|
allPackages.add(name, pkg)
|
||||||
localDeps[name] = true
|
localDeps[name] = true
|
||||||
|
|
||||||
if err := pkg.findDeps(pkgPath, pkgMap, allPackages); err != nil {
|
if err := pkg.findDeps(pkgPath, pkgMap, allPackages); err != nil {
|
||||||
@@ -196,7 +228,7 @@ func (p *GoPackage) findDeps(path string, pkgMap *pkgPathMapping, allPackages ma
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, dep := range deps {
|
for _, dep := range deps {
|
||||||
p.deps = append(p.deps, allPackages[dep])
|
p.directDeps = append(p.directDeps, allPackages.getByName(dep))
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -212,7 +244,7 @@ func (p *GoPackage) Compile(outDir, trimPath string) error {
|
|||||||
|
|
||||||
// Build all dependencies in parallel, then fail if any of them failed.
|
// Build all dependencies in parallel, then fail if any of them failed.
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
for _, dep := range p.deps {
|
for _, dep := range p.directDeps {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func(dep *GoPackage) {
|
go func(dep *GoPackage) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
@@ -220,7 +252,7 @@ func (p *GoPackage) Compile(outDir, trimPath string) error {
|
|||||||
}(dep)
|
}(dep)
|
||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
for _, dep := range p.deps {
|
for _, dep := range p.directDeps {
|
||||||
if dep.failed != nil {
|
if dep.failed != nil {
|
||||||
p.failed = dep.failed
|
p.failed = dep.failed
|
||||||
return p.failed
|
return p.failed
|
||||||
@@ -246,7 +278,7 @@ func (p *GoPackage) Compile(outDir, trimPath string) error {
|
|||||||
cmd.Args = append(cmd.Args, "-trimpath", trimPath)
|
cmd.Args = append(cmd.Args, "-trimpath", trimPath)
|
||||||
fmt.Fprintln(hash, trimPath)
|
fmt.Fprintln(hash, trimPath)
|
||||||
}
|
}
|
||||||
for _, dep := range p.deps {
|
for _, dep := range p.directDeps {
|
||||||
cmd.Args = append(cmd.Args, "-I", dep.pkgDir)
|
cmd.Args = append(cmd.Args, "-I", dep.pkgDir)
|
||||||
hash.Write(dep.hashResult)
|
hash.Write(dep.hashResult)
|
||||||
}
|
}
|
||||||
@@ -361,7 +393,7 @@ func (p *GoPackage) Link(out string) error {
|
|||||||
if race {
|
if race {
|
||||||
cmd.Args = append(cmd.Args, "-race")
|
cmd.Args = append(cmd.Args, "-race")
|
||||||
}
|
}
|
||||||
for _, dep := range p.deps {
|
for _, dep := range p.allDeps {
|
||||||
cmd.Args = append(cmd.Args, "-L", dep.pkgDir)
|
cmd.Args = append(cmd.Args, "-L", dep.pkgDir)
|
||||||
}
|
}
|
||||||
cmd.Args = append(cmd.Args, p.output)
|
cmd.Args = append(cmd.Args, p.output)
|
||||||
@@ -373,7 +405,7 @@ func (p *GoPackage) Link(out string) error {
|
|||||||
}
|
}
|
||||||
err = cmd.Run()
|
err = cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("command %s failed with error %v", cmd.Args, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ioutil.WriteFile(shaFile, p.hashResult, 0666)
|
return ioutil.WriteFile(shaFile, p.hashResult, 0666)
|
||||||
@@ -481,7 +513,7 @@ func main() {
|
|||||||
|
|
||||||
err = mainPackage.Link(output)
|
err = mainPackage.Link(output)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintln(os.Stderr, "Failed to link:", err)
|
fmt.Fprintln(os.Stderr, "microfactory.go failed to link:", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -236,10 +236,10 @@ func TestRebuildAfterGoChange(t *testing.T) {
|
|||||||
t.Fatal("Error writing a/a.go:", err)
|
t.Fatal("Error writing a/a.go:", err)
|
||||||
}
|
}
|
||||||
}, func(pkg *GoPackage) {
|
}, func(pkg *GoPackage) {
|
||||||
if !pkg.deps[0].rebuilt {
|
if !pkg.directDeps[0].rebuilt {
|
||||||
t.Fatal("android/soong/a should have rebuilt")
|
t.Fatal("android/soong/a should have rebuilt")
|
||||||
}
|
}
|
||||||
if !pkg.deps[1].rebuilt {
|
if !pkg.directDeps[1].rebuilt {
|
||||||
t.Fatal("android/soong/b should have rebuilt")
|
t.Fatal("android/soong/b should have rebuilt")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -253,10 +253,10 @@ func TestRebuildAfterMainChange(t *testing.T) {
|
|||||||
t.Fatal("Error writing main/main.go:", err)
|
t.Fatal("Error writing main/main.go:", err)
|
||||||
}
|
}
|
||||||
}, func(pkg *GoPackage) {
|
}, func(pkg *GoPackage) {
|
||||||
if pkg.deps[0].rebuilt {
|
if pkg.directDeps[0].rebuilt {
|
||||||
t.Fatal("android/soong/a should not have rebuilt")
|
t.Fatal("android/soong/a should not have rebuilt")
|
||||||
}
|
}
|
||||||
if pkg.deps[1].rebuilt {
|
if pkg.directDeps[1].rebuilt {
|
||||||
t.Fatal("android/soong/b should not have rebuilt")
|
t.Fatal("android/soong/b should not have rebuilt")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
Reference in New Issue
Block a user