// 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
}
Exemple #4
0
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
}
Exemple #5
0
// 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
}
Exemple #10
0
// 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
}