// Compiles and archives a package. func (b *Builder) buildPackage(bpkg *BuildPackage) error { c, err := b.newCompiler(bpkg, b.PkgBinDir(bpkg)) if err != nil { return err } srcDirs := []string{} if len(bpkg.SourceDirectories) > 0 { for _, relDir := range bpkg.SourceDirectories { dir := bpkg.BasePath() + "/" + relDir if util.NodeNotExist(dir) { return util.NewNewtError(fmt.Sprintf( "Specified source directory %s, does not exist.", dir)) } srcDirs = append(srcDirs, dir) } } else { srcDir := bpkg.BasePath() + "/src" if util.NodeNotExist(srcDir) { // Nothing to compile. return nil } srcDirs = append(srcDirs, srcDir) } // Make sure we restore the current working dir to whatever it was when this function was called cwd, err := os.Getwd() if err != nil { return util.NewNewtError(fmt.Sprintf("Unable to determine current working directory: %v", err)) } defer os.Chdir(cwd) for _, dir := range srcDirs { if err = buildDir(dir, c, b.targetBuilder.bspPkg.Arch, nil); err != nil { return err } } // Create a static library ("archive"). if err := os.Chdir(bpkg.BasePath() + "/"); err != nil { return util.NewNewtError(err.Error()) } archiveFile := b.ArchivePath(bpkg) if err = c.CompileArchive(archiveFile); err != nil { return err } return nil }
// Generates a dependency Makefile (.d) for the specified source C file. // // @param file The name of the source file. func (c *Compiler) GenDepsForFile(file string) error { if util.NodeNotExist(c.dstDir) { os.MkdirAll(c.dstDir, 0755) } depFile := c.dstDir + "/" + strings.TrimSuffix(file, filepath.Ext(file)) + ".d" depFile = filepath.ToSlash(depFile) var cmd string var err error cmd = c.ccPath + " " + c.cflagsString() + " " + c.includesString() + " -MM -MG " + file + " > " + depFile o, err := util.ShellCommand(cmd) if err != nil { return util.NewNewtError(string(o)) } // Append the extra dependencies (.yml files) to the .d file. f, err := os.OpenFile(depFile, os.O_APPEND|os.O_WRONLY, 0666) if err != nil { return util.NewNewtError(err.Error()) } defer f.Close() objFile := strings.TrimSuffix(file, filepath.Ext(file)) + ".o" if _, err := f.WriteString(objFile + ": " + c.depsString()); err != nil { return util.NewNewtError(err.Error()) } return nil }
func (ps *ProjectState) Init() error { ps.installedRepos = map[string]*repo.Version{} path := ps.StateFile() // Read project state file. If doesn't exist, it will be empty until somebody // installs a repo if util.NodeNotExist(path) { return nil } file, err := os.Open(path) if err != nil { return err } defer file.Close() scanner := bufio.NewScanner(file) for scanner.Scan() { line := strings.Split(scanner.Text(), ",") if len(line) != 2 { return util.NewNewtError(fmt.Sprintf( "Invalid format for line in project.state file: %s\n", line)) } repoName := line[0] repoVers, err := repo.LoadVersion(line[1]) if err != nil { return err } ps.installedRepos[repoName] = repoVers } return nil }
func (r *Repo) ReadDesc() (*RepoDesc, []*Repo, error) { if util.NodeNotExist(r.repoFilePath() + REPO_FILE_NAME) { return nil, nil, util.NewNewtError("No configuration exists for repository " + r.name) } v, err := util.ReadConfig(r.repoFilePath(), strings.TrimSuffix(REPO_FILE_NAME, ".yml")) if err != nil { return nil, nil, err } name := v.GetString("repo.name") versMap := v.GetStringMapString("repo.versions") rdesc, err := NewRepoDesc(name, versMap) if err != nil { return nil, nil, err } r.rdesc = rdesc repos, err := r.readDepRepos(v) if err != nil { return nil, nil, err } return rdesc, repos, nil }
// Download the repository description. func (r *Repo) DownloadDesc() error { dl := r.downloader util.StatusMessage(util.VERBOSITY_VERBOSE, "Downloading "+ "repository description for %s...\n", r.Name()) // Configuration path cpath := r.repoFilePath() if util.NodeNotExist(cpath) { if err := os.MkdirAll(cpath, REPO_DEFAULT_PERMS); err != nil { return util.NewNewtError(err.Error()) } } dl.SetBranch("master") if err := dl.FetchFile("repository.yml", cpath+"/"+"repository.yml"); err != nil { util.StatusMessage(util.VERBOSITY_VERBOSE, " failed\n") return err } util.StatusMessage(util.VERBOSITY_VERBOSE, " success!\n") return nil }
func ReadLocalPackageRecursive(repo *repo.Repo, pkgList map[string]interfaces.PackageInterface, basePath string, pkgName string) ([]string, error) { var warnings []string dirList, err := repo.FilteredSearchList(pkgName) if err != nil { return warnings, util.NewNewtError(err.Error()) } for _, name := range dirList { if LocalPackageSpecialName(name) || strings.HasPrefix(name, ".") { continue } subWarnings, err := ReadLocalPackageRecursive(repo, pkgList, basePath, filepath.Join(pkgName, name)) warnings = append(warnings, subWarnings...) if err != nil { return warnings, err } } if util.NodeNotExist(filepath.Join(basePath, pkgName, PACKAGE_FILE_NAME)) { return warnings, nil } pkg, err := LoadLocalPackage(repo, filepath.Join(basePath, pkgName)) if err != nil { warnings = append(warnings, err.Error()) return warnings, nil } if oldPkg, ok := pkgList[pkg.Name()]; ok { oldlPkg := oldPkg.(*LocalPackage) warnings = append(warnings, fmt.Sprintf("Multiple packages with same pkg.name=%s "+ "in repo %s; path1=%s path2=%s", oldlPkg.Name(), repo.Name(), oldlPkg.BasePath(), pkg.BasePath())) return warnings, nil } pkgList[pkg.Name()] = pkg return warnings, nil }
// Compile the specified C or assembly file. // // @param file The filename of the source file to compile. // @param compilerType One of the COMPILER_TYPE_[...] constants. func (c *Compiler) CompileFile(file string, compilerType int) error { if util.NodeNotExist(c.dstDir) { os.MkdirAll(c.dstDir, 0755) } objFile := strings.TrimSuffix(file, filepath.Ext(file)) + ".o" objPath := c.dstDir + "/" + objFile c.ObjPathList[filepath.ToSlash(objPath)] = true cmd, err := c.CompileFileCmd(file, compilerType) if err != nil { return err } switch compilerType { case COMPILER_TYPE_C: util.StatusMessage(util.VERBOSITY_DEFAULT, "Compiling %s\n", file) case COMPILER_TYPE_CPP: util.StatusMessage(util.VERBOSITY_DEFAULT, "Compiling %s\n", file) case COMPILER_TYPE_ASM: util.StatusMessage(util.VERBOSITY_DEFAULT, "Assembling %s\n", file) default: return util.NewNewtError("Unknown compiler type") } _, err = util.ShellCommand(cmd) if err != nil { return err } err = writeCommandFile(objPath, cmd) if err != nil { return err } // Tell the dependency tracker that an object file was just rebuilt. c.depTracker.MostRecent = time.Now() return nil }
func ReadLocalPackages(repo *repo.Repo, basePath string) ( pkgMap *map[string]interfaces.PackageInterface, warnings []string, err error) { pkgMap = &map[string]interfaces.PackageInterface{} warnings = []string{} searchPaths, err := repo.FilteredSearchList("") if err != nil { return } for _, path := range searchPaths { pkgDir := basePath + "/" + path if util.NodeNotExist(pkgDir) { continue } var dirList []string if dirList, err = repo.FilteredSearchList(path); err != nil { return } for _, subDir := range dirList { var subWarnings []string subWarnings, err = ReadLocalPackageRecursive(repo, *pkgMap, basePath, filepath.Join(path, subDir)) warnings = append(warnings, subWarnings...) if err != nil { return } } } return }
// Recursively compiles all the .c and .s files in the specified directory. // Architecture-specific files are also compiled. func buildDir(srcDir string, c *toolchain.Compiler, arch string, ignDirs []string) error { // Quietly succeed if the source directory doesn't exist. if util.NodeNotExist(srcDir) { return nil } util.StatusMessage(util.VERBOSITY_VERBOSE, "Compiling src in base directory: %s\n", srcDir) // Start from the source directory. if err := os.Chdir(srcDir); err != nil { return util.NewNewtError(err.Error()) } // Ignore architecture-specific source files for now. Use a temporary // string slice here so that the "arch" directory is not ignored in the // subsequent architecture-specific compile phase. if err := c.RecursiveCompile(toolchain.COMPILER_TYPE_C, append(ignDirs, "arch")); err != nil { return err } // Compile CPP files if err := c.RecursiveCompile(toolchain.COMPILER_TYPE_CPP, append(ignDirs, "arch")); err != nil { return err } // Copy in pre-compiled library files if err := c.RecursiveCompile(toolchain.COMPILER_TYPE_ARCHIVE, append(ignDirs, "arch")); err != nil { return err } archDir := srcDir + "/arch/" + arch + "/" if util.NodeExist(archDir) { util.StatusMessage(util.VERBOSITY_VERBOSE, "Compiling architecture specific src pkgs in directory: %s\n", archDir) if err := os.Chdir(archDir); err != nil { return util.NewNewtError(err.Error()) } // Compile C source. if err := c.RecursiveCompile(toolchain.COMPILER_TYPE_C, ignDirs); err != nil { return err } // Compile CPP source if err := c.RecursiveCompile(toolchain.COMPILER_TYPE_CPP, ignDirs); err != nil { return err } // Compile assembly source (only architecture-specific). if err := c.RecursiveCompile(toolchain.COMPILER_TYPE_ASM, ignDirs); err != nil { return err } // Copy in pre-compiled library files if err := c.RecursiveCompile(toolchain.COMPILER_TYPE_ARCHIVE, ignDirs); err != nil { return err } } return nil }
// Determines if the specified C or assembly file needs to be built. A compile // is required if any of the following is true: // * The destination object file does not exist. // * The existing object file was built with a different compiler // invocation. // * The source file has a newer modification time than the object file. // * One or more included header files has a newer modification time than // the object file. func (tracker *DepTracker) CompileRequired(srcFile string, compilerType int) (bool, error) { objFile := tracker.compiler.DstDir() + "/" + strings.TrimSuffix(srcFile, filepath.Ext(srcFile)) + ".o" depFile := tracker.compiler.DstDir() + "/" + strings.TrimSuffix(srcFile, filepath.Ext(srcFile)) + ".d" // If the object was previously built with a different set of options, a // rebuild is necessary. cmd, err := tracker.compiler.CompileFileCmd(srcFile, compilerType) if err != nil { return false, err } if commandHasChanged(objFile, cmd) { util.StatusMessage(util.VERBOSITY_VERBOSE, "%s - rebuild required; "+ "different command\n", srcFile) err := tracker.compiler.GenDepsForFile(srcFile) if err != nil { return false, err } return true, nil } if util.NodeNotExist(depFile) { err := tracker.compiler.GenDepsForFile(srcFile) if err != nil { return false, err } } srcModTime, err := util.FileModificationTime(srcFile) if err != nil { return false, err } objModTime, err := util.FileModificationTime(objFile) if err != nil { return false, err } // If the object doesn't exist or is older than the source file, a build is // required; no need to check dependencies. if srcModTime.After(objModTime) { util.StatusMessage(util.VERBOSITY_VERBOSE, "%s - rebuild required; "+ "source newer than obj\n", srcFile) return true, nil } // Determine if the dependency (.d) file needs to be generated. If it // doesn't exist or is older than the source file, it is out of date and // needs to be created. depModTime, err := util.FileModificationTime(depFile) if err != nil { return false, err } if srcModTime.After(depModTime) { err := tracker.compiler.GenDepsForFile(srcFile) if err != nil { return false, err } } // Extract the dependency filenames from the dependency file. deps, err := ParseDepsFile(depFile) if err != nil { return false, err } // Check if any dependencies are newer than the destination object file. for _, dep := range deps { if util.NodeNotExist(dep) { // The dependency has been deleted; a rebuild is required. Also, // the dependency file is out of date, so it needs to be deleted. // We cannot regenerate it now because the source file might be // including a nonexistent header. os.Remove(depFile) return true, nil } else { depModTime, err = util.FileModificationTime(dep) if err != nil { return false, err } } if depModTime.After(objModTime) { util.StatusMessage(util.VERBOSITY_VERBOSE, "%s - rebuild required; obj older than dependency (%s)\n", srcFile, dep) return true, nil } } return false, nil }