You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by ma...@apache.org on 2016/03/09 21:23:20 UTC

[05/50] incubator-mynewt-newt git commit: Test command

Test command


Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/commit/928e0344
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/tree/928e0344
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/diff/928e0344

Branch: refs/heads/develop
Commit: 928e0344dfc04f0dda96075b3f4ba0b70b0d2f73
Parents: 516dd1e
Author: Christopher Collins <cc...@gmail.com>
Authored: Mon Mar 7 19:18:30 2016 -0800
Committer: Christopher Collins <cc...@gmail.com>
Committed: Mon Mar 7 21:28:00 2016 -0800

----------------------------------------------------------------------
 newt/builder/build.go      | 298 ++++++++++++++++++++++++++++++----------
 newt/builder/cmds.go       |  51 +++++++
 newt/pkg/dependency.go     |   1 -
 newt/target/target.go      |  14 +-
 newt/toolchain/compiler.go |  22 +--
 5 files changed, 303 insertions(+), 83 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/928e0344/newt/builder/build.go
----------------------------------------------------------------------
diff --git a/newt/builder/build.go b/newt/builder/build.go
index 11221b6..46e8133 100644
--- a/newt/builder/build.go
+++ b/newt/builder/build.go
@@ -36,7 +36,10 @@ type Builder struct {
 	Packages map[*pkg.LocalPackage]*BuildPackage
 	features map[string]bool
 	apis     map[string]*BuildPackage
-	Bsp      *pkg.BspPackage
+
+	Bsp          *pkg.BspPackage
+	compilerPkg  *pkg.LocalPackage
+	compilerInfo *toolchain.CompilerInfo
 
 	target *target.Target
 }
@@ -49,13 +52,19 @@ func (b *Builder) AddFeature(feature string) {
 	b.features[feature] = true
 }
 
-func (b *Builder) AddPackage(npkg *pkg.LocalPackage) {
+func (b *Builder) AddPackage(npkg *pkg.LocalPackage) *BuildPackage {
 	// Don't allow nil entries to the map
 	if npkg == nil {
 		panic("Cannot add nil package builder map")
 	}
 
-	b.Packages[npkg] = NewBuildPackage(npkg)
+	bpkg := b.Packages[npkg]
+	if bpkg == nil {
+		bpkg = NewBuildPackage(npkg)
+		b.Packages[npkg] = bpkg
+	}
+
+	return bpkg
 }
 
 // @return bool                 true if this is a new API.
@@ -74,6 +83,25 @@ func (b *Builder) AddApi(apiString string, bpkg *BuildPackage) bool {
 	}
 }
 
+func (b *Builder) logFeatures() {
+	var buffer bytes.Buffer
+	buffer.WriteString("Building with the following feature set: [")
+
+	first := true
+	for feature, _ := range b.Features() {
+		if !first {
+			buffer.WriteString(" ")
+		} else {
+			first = false
+		}
+
+		buffer.WriteString(feature)
+	}
+	buffer.WriteString("]\n")
+
+	cli.StatusMessage(cli.VERBOSITY_VERBOSE, buffer.String())
+}
+
 func (b *Builder) loadDeps() error {
 	// Circularly resolve dependencies, identities, APIs, and required APIs
 	// until no new ones exist.
@@ -94,6 +122,9 @@ func (b *Builder) loadDeps() error {
 			break
 		}
 	}
+
+	b.logFeatures()
+
 	return nil
 }
 
@@ -137,18 +168,19 @@ func (b *Builder) verifyApisSatisfied() error {
 
 // 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, t *target.Target,
+func buildDir(srcDir string, c *toolchain.Compiler, arch string,
 	ignDirs []string) error {
 
-	var err error
+	// Quietly succeed if the source directory doesn't exist.
+	if cli.NodeNotExist(srcDir) {
+		return nil
+	}
 
 	cli.StatusMessage(util.VERBOSITY_VERBOSE,
 		"compiling src in base directory: %s\n", srcDir)
 
-	// First change into the pkg src directory, and build all the objects
-	// there
-	err = os.Chdir(srcDir)
-	if err != nil {
+	// Start from the source directory.
+	if err := os.Chdir(srcDir); err != nil {
 		return util.NewNewtError(err.Error())
 	}
 
@@ -157,16 +189,15 @@ func buildDir(srcDir string, c *toolchain.Compiler, t *target.Target,
 	ignDirs = append(ignDirs, "bin")
 
 	// Ignore architecture-specific source files for now.  Use a temporary
-	// string array here so that the "arch" directory is not ignored in the
+	// string slice here so that the "arch" directory is not ignored in the
 	// subsequent architecture-specific compile phase.
-	baseIgnDirs := append(ignDirs, "arch")
+	if err := c.RecursiveCompile(toolchain.COMPILER_TYPE_C,
+		append(ignDirs, "arch")); err != nil {
 
-	if err = c.RecursiveCompile(toolchain.COMPILER_TYPE_C,
-		baseIgnDirs); err != nil {
 		return err
 	}
 
-	archDir := srcDir + "/arch/" + t.Arch + "/"
+	archDir := srcDir + "/arch/" + arch + "/"
 	cli.StatusMessage(util.VERBOSITY_VERBOSE,
 		"compiling architecture specific src pkgs in directory: %s\n",
 		archDir)
@@ -177,12 +208,14 @@ func buildDir(srcDir string, c *toolchain.Compiler, t *target.Target,
 		}
 		if err := c.RecursiveCompile(toolchain.COMPILER_TYPE_C,
 			ignDirs); err != nil {
+
 			return err
 		}
 
 		// compile assembly sources in recursive compile as well
-		if err = c.RecursiveCompile(toolchain.COMPILER_TYPE_ASM,
+		if err := c.RecursiveCompile(toolchain.COMPILER_TYPE_ASM,
 			ignDirs); err != nil {
+
 			return err
 		}
 	}
@@ -199,36 +232,33 @@ func (b *Builder) pkgBinDir(pkgName string) string {
 }
 
 // Generates the path+filename of the specified package's .a file.
-func (b *Builder) archivePath(bpkg *BuildPackage) string {
-	return b.pkgBinDir(bpkg.Name()) + "/" + filepath.Base(bpkg.Name()) + ".a"
+func (b *Builder) archivePath(pkgName string) string {
+	return b.pkgBinDir(pkgName) + "/" + filepath.Base(pkgName) + ".a"
 }
 
-func (b *Builder) elfPath() string {
-	appPkg := b.target.App()
-	if appPkg == nil {
-		return ""
-	}
+func (b *Builder) appElfPath() string {
+	pkgName := b.target.App().Name()
+	return b.pkgBinDir(pkgName) + "/" + filepath.Base(pkgName) + ".elf"
+}
 
-	return b.pkgBinDir(appPkg.Name()) + "/" +
-		filepath.Base(appPkg.Name()) + ".elf"
+func (b *Builder) testExePath(pkgName string) string {
+	return b.pkgBinDir(pkgName) + "/test_" + filepath.Base(pkgName)
 }
 
 // Compiles and archives a package.
-func (b *Builder) buildPackage(bpkg *BuildPackage,
-	baseCi *toolchain.CompilerInfo, compilerPkg *pkg.LocalPackage) error {
-
+func (b *Builder) buildPackage(bpkg *BuildPackage) error {
 	srcDir := bpkg.BasePath() + "/src"
 	if cli.NodeNotExist(srcDir) {
 		// Nothing to compile.
 		return nil
 	}
 
-	c, err := toolchain.NewCompiler(compilerPkg.BasePath(),
+	c, err := toolchain.NewCompiler(b.compilerPkg.BasePath(),
 		b.pkgBinDir(bpkg.Name()), "default") // XXX Use correct compiler def
 	if err != nil {
 		return err
 	}
-	c.AddInfo(baseCi)
+	c.AddInfo(b.compilerInfo)
 
 	ci, err := bpkg.CompilerInfo(b)
 	if err != nil {
@@ -236,26 +266,30 @@ func (b *Builder) buildPackage(bpkg *BuildPackage,
 	}
 	c.AddInfo(ci)
 
-	// For now, ignore test code.  Tests get built later if the test
-	// feature is in effect.
-	ignDirs := []string{"test"}
-
-	// Compile the source files.
-	err = buildDir(srcDir, c, b.target, ignDirs)
-	if err != nil {
+	// Build the package source in two phases:
+	// 1. Non-test code.
+	// 2. Test code (if the "test" feature is enabled).
+	//
+	// This is done in two passes because the structure of
+	// architecture-specific directories is different for normal code and test
+	// code, and not easy to generalize into a single operation:
+	//     * src/arch/<target-arch>
+	//     * src/test/arch/<target-arch>
+	if err = buildDir(srcDir, c, b.target.Arch, []string{"test"}); err != nil {
 		return err
 	}
-
-	// Archive everything into a static library, which can be linked with a
-	// main program
-	if err := os.Chdir(bpkg.BasePath() + "/"); err != nil {
-		return util.NewNewtError(err.Error())
+	if b.features["test"] {
+		testSrcDir := srcDir + "/test"
+		if err = buildDir(testSrcDir, c, b.target.Arch, nil); err != nil {
+			return err
+		}
 	}
 
-	archiveFile := b.archivePath(bpkg)
-	if err := os.MkdirAll(filepath.Dir(archiveFile), 0755); err != nil {
+	// Create a static library ("archive").
+	if err := os.Chdir(bpkg.BasePath() + "/"); err != nil {
 		return util.NewNewtError(err.Error())
 	}
+	archiveFile := b.archivePath(bpkg.Name())
 	if err = c.CompileArchive(archiveFile); err != nil {
 		return err
 	}
@@ -263,18 +297,16 @@ func (b *Builder) buildPackage(bpkg *BuildPackage,
 	return nil
 }
 
-func (b *Builder) linkApp(baseCi *toolchain.CompilerInfo,
-	compilerPkg *pkg.LocalPackage) error {
-
-	c, err := toolchain.NewCompiler(compilerPkg.BasePath(),
-		b.pkgBinDir(b.target.App().Name()), "default") // XXX
+func (b *Builder) link(elfName string) error {
+	c, err := toolchain.NewCompiler(b.compilerPkg.BasePath(),
+		b.pkgBinDir(elfName), "default") // XXX
 	if err != nil {
 		return err
 	}
 
 	pkgNames := []string{}
 	for _, bpkg := range b.Packages {
-		archivePath := b.archivePath(bpkg)
+		archivePath := b.archivePath(bpkg.Name())
 		if cli.NodeExist(archivePath) {
 			pkgNames = append(pkgNames, archivePath)
 		}
@@ -283,7 +315,7 @@ func (b *Builder) linkApp(baseCi *toolchain.CompilerInfo,
 	if b.Bsp.LinkerScript != "" {
 		c.LinkerScript = b.Bsp.BasePath() + b.Bsp.LinkerScript
 	}
-	err = c.CompileElf(b.elfPath(), pkgNames)
+	err = c.CompileElf(elfName, pkgNames)
 	if err != nil {
 		return err
 	}
@@ -291,62 +323,188 @@ func (b *Builder) linkApp(baseCi *toolchain.CompilerInfo,
 	return nil
 }
 
-func (b *Builder) Build() error {
+// Populates the builder with all the packages that need to be built, and
+// configures each package's build settings.  After this function executes,
+// packages are ready to be built.
+func (b *Builder) prepBuild() error {
+	// Collect the seed packages.
+	bspPkg := b.target.Bsp()
+	if bspPkg == nil {
+		return util.NewNewtError("bsp package not specified")
+	}
+
 	compilerPkg := b.target.Compiler()
 	if compilerPkg == nil {
-		return util.NewNewtError("compiler package not found")
+		return util.NewNewtError("compiler package not specified")
+	}
+
+	// An app package is not required (e.g., unit tests).
+	appPkg := b.target.App()
+
+	// Seed the builder with the app (if present), bsp, compiler, and target
+	// packages.
+
+	var appBpkg *BuildPackage
+	if appPkg != nil {
+		appBpkg = b.Packages[appPkg]
+		if appBpkg == nil {
+			appBpkg = b.AddPackage(appPkg)
+		}
+	}
+
+	bspBpkg := b.Packages[bspPkg]
+	if bspBpkg == nil {
+		bspBpkg = b.AddPackage(bspPkg)
 	}
 
-	b.AddPackage(b.target.Bsp())
-	b.AddPackage(b.target.App())
-	b.AddPackage(b.target.Compiler())
+	compilerBpkg := b.Packages[compilerPkg]
+	if compilerBpkg == nil {
+		compilerBpkg = b.AddPackage(compilerPkg)
+	}
+
+	targetBpkg := b.AddPackage(b.target.Package())
 
+	// Populate the full set of packages to be built and resolve the feature
+	// set.
 	if err := b.loadDeps(); err != nil {
 		return err
 	}
 
+	// Terminate if any package has an unmet API requirement.
 	if err := b.verifyApisSatisfied(); err != nil {
 		return err
 	}
 
-	bspPackage := b.Packages[b.target.Bsp()]
-	if bspPackage == nil {
-		return util.NewNewtError("BSP package not found!")
+	// Populate the base set of compiler flags.  Flags from the following
+	// packages get applied to every source file:
+	//     * app (if present)
+	//     * bsp
+	//     * compiler
+	//     * target
+
+	baseCi := toolchain.NewCompilerInfo()
+
+	if appBpkg != nil {
+		appCi, err := appBpkg.CompilerInfo(b)
+		if err != nil {
+			return err
+		}
+		baseCi.AddCompilerInfo(appCi)
+	}
+
+	bspCi, err := bspBpkg.CompilerInfo(b)
+	if err != nil {
+		return err
+	}
+	baseCi.AddCompilerInfo(bspCi)
+
+	targetCi, err := targetBpkg.CompilerInfo(b)
+	if err != nil {
+		return err
+	}
+	baseCi.AddCompilerInfo(targetCi)
+
+	// Read the BSP configuration.  These settings are necessary for the link
+	// step.
+	b.Bsp = pkg.NewBspPackage(bspPkg, b.Features())
+
+	b.compilerPkg = compilerPkg
+	b.compilerInfo = baseCi
+
+	return nil
+}
+
+func (b *Builder) Build() error {
+	if b.target.App() == nil {
+		return util.NewNewtError("app package not specified")
 	}
 
-	bspCi, err := bspPackage.CompilerInfo(b)
+	// Populate the package and feature sets and calculate the base compiler
+	// flags.
+	err := b.prepBuild()
 	if err != nil {
 		return err
 	}
-	b.Bsp = pkg.NewBspPackage(bspPackage.LocalPackage, b.Features())
 
-	appPackage := b.Packages[b.target.App()]
-	if appPackage == nil {
-		return util.NewNewtError("App package not found")
+	// XXX: If any yml files have changed, a full rebuild is required.  We
+	// don't currently check this.
+
+	for _, bpkg := range b.Packages {
+		err = b.buildPackage(bpkg)
+		if err != nil {
+			return err
+		}
+	}
+
+	err = b.link(b.appElfPath())
+	if err != nil {
+		return err
 	}
-	appCi, err := appPackage.CompilerInfo(b)
+
+	return nil
+}
+
+func (b *Builder) Test(p *pkg.LocalPackage) error {
+	// Seed the builder with the package under test.
+	testBpkg := b.AddPackage(p)
+
+	// A few features are automatically supported when the test command is
+	// used:
+	//     * test:      ensures that the test code gets compiled.
+	//     * selftest:  indicates that there is no app.
+	b.AddFeature("test")
+	b.AddFeature("selftest")
+
+	// Populate the package and feature sets and calculate the base compiler
+	// flags.
+	err := b.prepBuild()
 	if err != nil {
 		return err
 	}
 
-	baseCi := toolchain.NewCompilerInfo()
-	baseCi.AddCompilerInfo(bspCi)
-	baseCi.AddCompilerInfo(appCi)
+	// Define the PKG_TEST symbol while the package under test is being
+	// compiled.  This symbol enables the appropriate main function that
+	// usually comes from an app.
+	testPkgCi, err := testBpkg.CompilerInfo(b)
+	if err != nil {
+		return err
+	}
+	testPkgCi.Cflags = append(testPkgCi.Cflags, "-DPKG_TEST")
 
-	// XXX: If any yml files have changed, a full rebuild is required.
+	// XXX: If any yml files have changed, a full rebuild is required.  We
+	// don't currently check this.
 
 	for _, bpkg := range b.Packages {
-		err = b.buildPackage(bpkg, baseCi, compilerPkg)
+		err = b.buildPackage(bpkg)
 		if err != nil {
 			return err
 		}
 	}
 
-	err = b.linkApp(baseCi, compilerPkg)
+	testFilename := b.testExePath(p.Name())
+	err = b.link(testFilename)
 	if err != nil {
 		return err
 	}
 
+	// Run the tests.
+	cli.StatusMessage(cli.VERBOSITY_DEFAULT, "Testing package %s\n", p.Name())
+
+	if err := os.Chdir(filepath.Dir(testFilename)); err != nil {
+		return err
+	}
+
+	o, err := cli.ShellCommand(testFilename)
+	if err != nil {
+		cli.StatusMessage(cli.VERBOSITY_DEFAULT, "%s", string(o))
+
+		// Always terminate on test failure since only one test is being run.
+		return util.NewtErrorNoTrace("Test failed: " + testFilename)
+	}
+
+	cli.StatusMessage(cli.VERBOSITY_VERBOSE, "%s", string(o))
+	cli.StatusMessage(cli.VERBOSITY_DEFAULT, "Test %s ok!\n", testFilename)
+
 	return nil
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/928e0344/newt/builder/cmds.go
----------------------------------------------------------------------
diff --git a/newt/builder/cmds.go b/newt/builder/cmds.go
index 484a487..5cb3889 100644
--- a/newt/builder/cmds.go
+++ b/newt/builder/cmds.go
@@ -24,10 +24,14 @@ import (
 
 	"github.com/spf13/cobra"
 	"mynewt.apache.org/newt/newt/cli"
+	"mynewt.apache.org/newt/newt/pkg"
+	"mynewt.apache.org/newt/newt/project"
 	"mynewt.apache.org/newt/newt/target"
 	"mynewt.apache.org/newt/util"
 )
 
+const TARGET_TEST_NAME = "targets/unittest"
+
 func buildRunCmd(cmd *cobra.Command, args []string) {
 	if len(args) < 1 {
 		cli.NewtUsage(cmd, nil)
@@ -70,6 +74,41 @@ func cleanRunCmd(cmd *cobra.Command, args []string) {
 	}
 }
 
+func testRunCmd(cmd *cobra.Command, args []string) {
+	if len(args) < 1 {
+		cli.NewtUsage(cmd, nil)
+	}
+
+	t := target.GetTargets()[TARGET_TEST_NAME]
+	if t == nil {
+		cli.NewtUsage(cmd, util.NewNewtError("can't find unit test target: "+
+			TARGET_TEST_NAME))
+	}
+
+	b, err := NewBuilder(t)
+	if err != nil {
+		fmt.Println(err)
+	}
+
+	pkgString := args[0]
+	dep, err := pkg.NewDependency(nil, pkgString)
+	if err != nil {
+		cli.NewtUsage(cmd, err)
+	}
+	if dep == nil {
+		cli.NewtUsage(cmd, util.NewNewtError("invalid package name"))
+	}
+	pack := project.GetProject().ResolveDependency(dep)
+	if pack == nil {
+		cli.NewtUsage(cmd, util.NewNewtError("invalid package name"))
+	}
+
+	err = b.Test(pack.(*pkg.LocalPackage))
+	if err != nil {
+		fmt.Println(err)
+	}
+}
+
 func AddCommands(cmd *cobra.Command) {
 	buildHelpText := ""
 	buildHelpEx := ""
@@ -94,4 +133,16 @@ func AddCommands(cmd *cobra.Command) {
 	}
 
 	cmd.AddCommand(cleanCmd)
+
+	testHelpText := ""
+	testHelpEx := ""
+	testCmd := &cobra.Command{
+		Use:     "test",
+		Short:   "Executes unit tests for one or more packages",
+		Long:    testHelpText,
+		Example: testHelpEx,
+		Run:     testRunCmd,
+	}
+
+	cmd.AddCommand(testCmd)
 }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/928e0344/newt/pkg/dependency.go
----------------------------------------------------------------------
diff --git a/newt/pkg/dependency.go b/newt/pkg/dependency.go
index c4d5741..58d33ea 100644
--- a/newt/pkg/dependency.go
+++ b/newt/pkg/dependency.go
@@ -130,7 +130,6 @@ func (dep *Dependency) Init(parentRepo interfaces.RepoInterface, depStr string)
 			return err
 		}
 		verParts := strings.Split(parts[1], "#")
-
 		if err := dep.SetVersionReqs(verParts[0]); err != nil {
 			return err
 		}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/928e0344/newt/target/target.go
----------------------------------------------------------------------
diff --git a/newt/target/target.go b/newt/target/target.go
index 67555ac..c48affe 100644
--- a/newt/target/target.go
+++ b/newt/target/target.go
@@ -113,9 +113,17 @@ func (target *Target) Compiler() *pkg.LocalPackage {
 }
 
 func (target *Target) App() *pkg.LocalPackage {
-	dep, _ := pkg.NewDependency(nil, target.AppName)
-	mypkg := project.GetProject().ResolveDependency(dep).(*pkg.LocalPackage)
-	return mypkg
+	dep, err := pkg.NewDependency(nil, target.AppName)
+	if err != nil {
+		return nil
+	}
+
+	appPkg := project.GetProject().ResolveDependency(dep)
+	if appPkg == nil {
+		return nil
+	}
+
+	return appPkg.(*pkg.LocalPackage)
 }
 
 func (target *Target) Bsp() *pkg.LocalPackage {

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/928e0344/newt/toolchain/compiler.go
----------------------------------------------------------------------
diff --git a/newt/toolchain/compiler.go b/newt/toolchain/compiler.go
index cb3017c..21c2ef1 100644
--- a/newt/toolchain/compiler.go
+++ b/newt/toolchain/compiler.go
@@ -30,7 +30,7 @@ import (
 	"time"
 
 	"mynewt.apache.org/newt/newt/cli"
-	. "mynewt.apache.org/newt/util"
+	"mynewt.apache.org/newt/util"
 )
 
 const (
@@ -101,7 +101,7 @@ func NewCompiler(compilerDir string, dstDir string,
 }
 
 func (c *Compiler) load(compilerDir string, cDef string) error {
-	v, err := ReadConfig(compilerDir, "compiler")
+	v, err := util.ReadConfig(compilerDir, "compiler")
 	if err != nil {
 		return err
 	}
@@ -205,7 +205,7 @@ func (c *Compiler) CompileFileCmd(file string,
 	case COMPILER_TYPE_ASM:
 		cmd = c.asPath
 	default:
-		return "", NewNewtError("Unknown compiler type")
+		return "", util.NewNewtError("Unknown compiler type")
 	}
 
 	cmd += " -c " + "-o " + objPath + " " + file +
@@ -281,7 +281,7 @@ func (c *Compiler) CompileFile(file string, compilerType int) error {
 	case COMPILER_TYPE_ASM:
 		cli.StatusMessage(cli.VERBOSITY_DEFAULT, "Assembling %s\n", file)
 	default:
-		return NewNewtError("Unknown compiler type")
+		return util.NewNewtError("Unknown compiler type")
 	}
 
 	rsp, err := cli.ShellCommand(cmd)
@@ -389,13 +389,13 @@ func (c *Compiler) RecursiveCompile(cType int, ignDirs []string) error {
 
 	wd, err := os.Getwd()
 	if err != nil {
-		return NewNewtError(err.Error())
+		return util.NewNewtError(err.Error())
 	}
 	wd = filepath.ToSlash(wd)
 
 	dirList, err := ioutil.ReadDir(wd)
 	if err != nil {
-		return NewNewtError(err.Error())
+		return util.NewNewtError(err.Error())
 	}
 
 	for _, node := range dirList {
@@ -418,7 +418,7 @@ func (c *Compiler) RecursiveCompile(cType int, ignDirs []string) error {
 	case COMPILER_TYPE_ASM:
 		return c.CompileAs()
 	default:
-		return NewNewtError("Wrong compiler type specified to RecursiveCompile")
+		return util.NewNewtError("Wrong compiler type specified to RecursiveCompile")
 	}
 }
 
@@ -573,7 +573,7 @@ func (c *Compiler) CompileElf(binFile string, objFiles []string) error {
 	}
 	if linkRequired {
 		if err := os.MkdirAll(filepath.Dir(binFile), 0755); err != nil {
-			return NewNewtError(err.Error())
+			return util.NewNewtError(err.Error())
 		}
 		err := c.CompileBinary(binFile, options, objFiles)
 		if err != nil {
@@ -618,6 +618,10 @@ func (c *Compiler) CompileArchive(archiveFile string) error {
 		return nil
 	}
 
+	if err := os.MkdirAll(filepath.Dir(archiveFile), 0755); err != nil {
+		return util.NewNewtError(err.Error())
+	}
+
 	cli.StatusMessage(cli.VERBOSITY_DEFAULT, "Archiving %s\n",
 		path.Base(archiveFile))
 	objList := c.getObjFiles([]string{})
@@ -627,7 +631,7 @@ func (c *Compiler) CompileArchive(archiveFile string) error {
 	// Delete the old archive, if it exists.
 	err = os.Remove(archiveFile)
 	if err != nil && !os.IsNotExist(err) {
-		return NewNewtError(err.Error())
+		return util.NewNewtError(err.Error())
 	}
 
 	cmd := c.CompileArchiveCmd(archiveFile, objFiles)