diff --git a/ui/build/bazel.go b/ui/build/bazel.go index c5702c086..698283c11 100644 --- a/ui/build/bazel.go +++ b/ui/build/bazel.go @@ -15,6 +15,8 @@ package build import ( + "io/ioutil" + "os" "path/filepath" "strings" ) @@ -51,4 +53,57 @@ func runBazel(ctx Context, config Config) { cmd.Dir = filepath.Join(config.OutDir(), "..") ctx.Status.Status("Starting Bazel..") cmd.RunAndStreamOrFatal() + + // Obtain the Bazel output directory for ninja_build. + infoArgs := []string{ + "info", + "output_path", + } + + infoCmd := Command(ctx, config, "bazel", bazelExecutable, infoArgs...) + + infoCmd.Environment.Set("DIST_DIR", config.DistDir()) + infoCmd.Environment.Set("SHELL", "/bin/bash") + infoCmd.Dir = filepath.Join(config.OutDir(), "..") + ctx.Status.Status("Getting Bazel Info..") + outputBasePath := string(infoCmd.OutputOrFatal()) + // TODO: Don't hardcode out/ as the bazel output directory. This is + // currently hardcoded as ninja_build.output_root. + bazelNinjaBuildOutputRoot := filepath.Join(outputBasePath, "..", "out") + + symlinkOutdir(ctx, config, bazelNinjaBuildOutputRoot, ".") +} + +// For all files F recursively under rootPath/relativePath, creates symlinks +// such that OutDir/F resolves to rootPath/F via symlinks. +func symlinkOutdir(ctx Context, config Config, rootPath string, relativePath string) { + destDir := filepath.Join(rootPath, relativePath) + os.MkdirAll(destDir, 0755) + files, err := ioutil.ReadDir(destDir) + if err != nil { + ctx.Fatal(err) + } + for _, f := range files { + destPath := filepath.Join(destDir, f.Name()) + srcPath := filepath.Join(config.OutDir(), relativePath, f.Name()) + if statResult, err := os.Stat(srcPath); err == nil { + if statResult.Mode().IsDir() && f.IsDir() { + // Directory under OutDir already exists, so recurse on its contents. + symlinkOutdir(ctx, config, rootPath, filepath.Join(relativePath, f.Name())) + } else if !statResult.Mode().IsDir() && !f.IsDir() { + // File exists both in source and destination, and it's not a directory + // in either location. Do nothing. + // This can arise for files which are generated under OutDir outside of + // soong_build, such as .bootstrap files. + } else { + // File is a directory in one location but not the other. Raise an error. + ctx.Fatalf("Could not link %s to %s due to conflict", srcPath, destPath) + } + } else if os.IsNotExist(err) { + // Create symlink srcPath -> fullDestPath. + os.Symlink(destPath, srcPath) + } else { + ctx.Fatalf("Unable to stat %s: %s", srcPath, err) + } + } }