Example #1
0
File: link.go Project: minux/llgo
// linkdeps links dependencies into the specified output file.
func linkdeps(pkg *build.Package, output string) error {
	depslist := []string{"runtime"}
	deps := make(map[string]bool)
	deps["runtime"] = true
	deps["unsafe"] = true
	if len(pkg.CgoFiles) > 0 {
		pkg.Imports = append(pkg.Imports, "runtime/cgo")
		pkg.Imports = append(pkg.Imports, "syscall")
	}

	var mkdeps func(imports ...string) error
	mkdeps = func(imports ...string) error {
		for _, path := range imports {
			if path == "C" {
				if err := mkdeps("runtime/cgo", "syscall"); err != nil {
					return err
				}
				continue
			}
			if !deps[path] {
				deps[path] = true
				pkg, err := build.Import(path, "", 0)
				if err != nil {
					return err
				}
				if err = mkdeps(pkg.Imports...); err != nil {
					return err
				}
				depslist = append(depslist, path)
			}
		}
		return nil
	}

	err := mkdeps(pkg.Imports...)
	if err != nil {
		return err
	}
	if test {
		if err = mkdeps(pkg.TestImports...); err != nil {
			return err
		}
		if err = mkdeps(pkg.XTestImports...); err != nil {
			return err
		}
	}

	for i := 0; i < len(depslist)/2; i++ {
		j := len(depslist) - i - 1
		depslist[i], depslist[j] = depslist[j], depslist[i]
	}

	llvmlink := filepath.Join(llvmbindir, "llvm-link")
	args := []string{"-o", output, output}
	var ldflags []string
	for _, path := range depslist {
		if path == pkg.ImportPath {
			continue
		}
		bcfile := filepath.Join(pkgroot, path+".bc")
		if buildDeps {
			if _, err := os.Stat(bcfile); err != nil {
				if err = buildPackages([]string{path}); err != nil {
					return err
				}
			}
		}
		args = append(args, bcfile)
		if pkgldflags, err := readLdflags(path); err != nil {
			return err
		} else {
			ldflags = append(ldflags, pkgldflags...)
		}
	}
	cmd := exec.Command(llvmlink, args...)
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	if err = runCmd(cmd); err != nil {
		return err
	}

	if !emitllvm || triple == "pnacl" {
		input := output
		if strings.Contains(triple, "darwin") || strings.Contains(triple, "mac") {
			// Not doing this intermediate step will make it invoke "dsymutil"
			// which then asserts and kills the build.
			// See discussion in issue #49 for more details.
			input += ".o"
			args := []string{"-g", "-c", "-o", input, output}
			cmd := exec.Command(clang, args...)
			cmd.Stdout = os.Stdout
			cmd.Stderr = os.Stderr
			if err = runCmd(cmd); err != nil {
				return err
			}
		}

		args := []string{"-pthread", "-v", "-g", "-o", output, input}
		if triple == "pnacl" {
			args = append(args, "-l", "ppapi")
		}
		args = append(args, ldflags...)
		cmd := exec.Command(clang+"++", args...)
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
		if err = runCmd(cmd); err != nil {
			return err
		}
	}

	return nil
}
Example #2
0
// fillPackage full of info. Assumes a build.Package discovered in build.FindOnly mode
func fillPackage(p *build.Package) error {

	if p.Goroot {
		return nil
	}

	var buildMatch = "+build "
	var buildFieldSplit = func(r rune) bool {
		return unicode.IsSpace(r) || r == ','
	}

	debugln("Filling package:", p.ImportPath, "from", p.Dir)
	gofiles, err := filepath.Glob(filepath.Join(p.Dir, "*.go"))
	if err != nil {
		debugln("Error globbing", err)
		return err
	}

	var testImports []string
	var imports []string
NextFile:
	for _, file := range gofiles {
		debugln(file)
		fset := token.NewFileSet()
		pf, err := parser.ParseFile(fset, file, nil, parser.ParseComments)
		if err != nil {
			return err
		}
		testFile := strings.HasSuffix(file, "_test.go")
		fname := filepath.Base(file)
		if testFile {
			p.TestGoFiles = append(p.TestGoFiles, fname)
		} else {
			p.GoFiles = append(p.GoFiles, fname)
		}
		if len(pf.Comments) > 0 {
			for _, c := range pf.Comments {
				ct := c.Text()
				if i := strings.Index(ct, buildMatch); i != -1 {
					for _, b := range strings.FieldsFunc(ct[i+len(buildMatch):], buildFieldSplit) {
						//TODO: appengine is a special case for now: https://github.com/tools/godep/issues/353
						if b == "ignore" || b == "appengine" {
							p.IgnoredGoFiles = append(p.IgnoredGoFiles, fname)
							continue NextFile
						}
					}
				}
			}
		}
		for _, is := range pf.Imports {
			name, err := strconv.Unquote(is.Path.Value)
			if err != nil {
				return err // can't happen?
			}
			if testFile {
				testImports = append(testImports, name)
			} else {
				imports = append(imports, name)
			}
		}
	}
	imports = uniq(imports)
	testImports = uniq(testImports)
	p.Imports = imports
	p.TestImports = testImports
	return nil
}
Example #3
0
// fillPackage full of info. Assumes p.Dir is set at a minimum
func fillPackage(p *build.Package) error {
	if p.Goroot {
		return nil
	}

	if p.SrcRoot == "" {
		for _, base := range build.Default.SrcDirs() {
			if strings.HasPrefix(p.Dir, base) {
				p.SrcRoot = base
			}
		}
	}

	if p.SrcRoot == "" {
		return errors.New("Unable to find SrcRoot for package " + p.ImportPath)
	}

	if p.Root == "" {
		p.Root = filepath.Dir(p.SrcRoot)
	}

	var buildMatch = "+build "
	var buildFieldSplit = func(r rune) bool {
		return unicode.IsSpace(r) || r == ','
	}

	debugln("Filling package:", p.ImportPath, "from", p.Dir)
	gofiles, err := filepath.Glob(filepath.Join(p.Dir, "*.go"))
	if err != nil {
		debugln("Error globbing", err)
		return err
	}

	var testImports []string
	var imports []string
NextFile:
	for _, file := range gofiles {
		debugln(file)
		pf, err := parser.ParseFile(token.NewFileSet(), file, nil, parser.ImportsOnly|parser.ParseComments)
		if err != nil {
			return err
		}
		testFile := strings.HasSuffix(file, "_test.go")
		fname := filepath.Base(file)
		for _, c := range pf.Comments {
			ct := c.Text()
			if i := strings.Index(ct, buildMatch); i != -1 {
				for _, t := range strings.FieldsFunc(ct[i+len(buildMatch):], buildFieldSplit) {
					for _, tag := range ignoreTags {
						if t == tag {
							p.IgnoredGoFiles = append(p.IgnoredGoFiles, fname)
							continue NextFile
						}
					}

					if versionMatch.MatchString(t) && !isSameOrNewer(t, majorGoVersion) {
						debugln("Adding", fname, "to ignored list because of version tag", t)
						p.IgnoredGoFiles = append(p.IgnoredGoFiles, fname)
						continue NextFile
					}
					if versionNegativeMatch.MatchString(t) && isSameOrNewer(t[1:], majorGoVersion) {
						debugln("Adding", fname, "to ignored list because of version tag", t)
						p.IgnoredGoFiles = append(p.IgnoredGoFiles, fname)
						continue NextFile
					}
				}
			}
		}
		if testFile {
			p.TestGoFiles = append(p.TestGoFiles, fname)
		} else {
			p.GoFiles = append(p.GoFiles, fname)
		}
		for _, is := range pf.Imports {
			name, err := strconv.Unquote(is.Path.Value)
			if err != nil {
				return err // can't happen?
			}
			if testFile {
				testImports = append(testImports, name)
			} else {
				imports = append(imports, name)
			}
		}
	}
	imports = uniq(imports)
	testImports = uniq(testImports)
	p.Imports = imports
	p.TestImports = testImports
	return nil
}