Example #1
1
func compile(bp *build.Package) error {
	if ok, err := checkPkg(bp); err != nil {
		return err
	} else if ok {
		return nil
	}
	if verbosity > 0 {
		defer fmt.Println(bp.ImportPath)
	}

	// Parse

	flist := make([]*ast.File, 0, len(bp.GoFiles)+1)
	fset := token.NewFileSet()

	for _, fname := range bp.GoFiles {
		fname = filepath.Join(bp.Dir, fname)
		f, err := parser.ParseFile(fset, fname, nil, 0)
		if err != nil {
			return err
		}
		flist = append(flist, f)
	}

	var iimp string

	ppath := bp.ImportPath
	if bp.Name == "main" {
		ppath = "main"
		iimp = `_ "runtime";_ "builtin"`
	} else if bp.ImportPath != "builtin" {
		iimp = `_ "builtin"`
	}

	f, err := parser.ParseFile(
		fset,
		"_iimports.go",
		"package "+bp.Name+";import("+iimp+")",
		0,
	)
	if err != nil {
		return err
	}
	flist = append(flist, f)

	// Type check

	tc := &types.Config{
		Import: NewImporter().Import,
		Sizes:  &types.StdSizes{4, 4}, // BUG: set sizes based on EGARCH
	}
	ti := &types.Info{
		Types:      make(map[ast.Expr]types.TypeAndValue),
		Defs:       make(map[*ast.Ident]types.Object),
		Uses:       make(map[*ast.Ident]types.Object),
		Selections: make(map[*ast.SelectorExpr]*types.Selection),
	}

	pkg, err := tc.Check(ppath, fset, flist, ti)
	if err != nil {
		return err
	}

	// Translate to C

	work := filepath.Join(tmpDir, ppath)
	if err = os.MkdirAll(work, 0700); err != nil {
		return err
	}

	var (
		hpath string
		objs  []string
	)

	if ppath == "main" {
		hpath = filepath.Join(bp.Dir, "_.h")
	} else {
		hpath = filepath.Join(bp.PkgRoot, buildCtx.GOOS+"_"+buildCtx.GOARCH, ppath+".h")
		expath := filepath.Join(work, "__.EXPORTS")
		impath := filepath.Join(work, "__.IMPORTS")
		objs = append(objs, expath, impath, hpath)

		err = os.MkdirAll(filepath.Dir(hpath), 0755)
		if err != nil && !os.IsExist(err) {
			return err
		}
		wp, err := os.Create(expath)
		if err != nil {
			return err
		}
		edata := importer.ExportData(pkg)
		_, err = wp.Write(edata)
		if err != nil {
			return err
		}
		wp.Close()
		wp, err = os.Create(impath)
		if err != nil {
			return err
		}
		for _, p := range pkg.Imports() {
			if _, err := io.WriteString(wp, p.Path()+"\n"); err != nil {
				return err
			}
		}
		wp.Close()
	}

	wh, err := os.Create(hpath)
	if err != nil {
		return err
	}
	defer wh.Close()

	wc, err := os.Create(filepath.Join(bp.Dir, "_.c"))
	if err != nil {
		return err
	}
	defer wc.Close()

	up := strings.Replace(ppath, "/", "$", -1)
	_, err = io.WriteString(wh, "#ifndef "+up+"\n#define "+up+"\n\n")
	if err != nil {
		return err
	}

	gtc := gotoc.NewGTC(pkg, ti)
	gtc.SetInlineThres(12)
	if err = gtc.Translate(wh, wc, flist); err != nil {
		return err
	}

	for _, h := range bp.HFiles {
		if !strings.HasSuffix(h, "+.h") {
			continue
		}
		f, err := os.Open(filepath.Join(bp.Dir, h))
		if err != nil {
			return err
		}
		if _, err = io.WriteString(wh, "\n// included "+h+"\n"); err != nil {
			return err
		}
		if _, err = bufio.NewReader(f).WriteTo(wh); err != nil {
			return err
		}
	}

	if _, err = io.WriteString(wh, "\n#endif\n"); err != nil {
		return err
	}

	var csfiles = []string{"_.c"}

	for _, c := range bp.CFiles {
		if !strings.HasSuffix(c, "+.c") {
			csfiles = append(csfiles, c)
			continue
		}
		f, err := os.Open(filepath.Join(bp.Dir, c))
		if err != nil {
			return err
		}
		if _, err = io.WriteString(wc, "\n// included "+c+"\n"); err != nil {
			return err
		}
		if _, err = bufio.NewReader(f).WriteTo(wc); err != nil {
			return err
		}
	}
	csfiles = append(csfiles, bp.SFiles...)

	// Build (package or binary)

	bt, err := NewBuildTools(&buildCtx)
	if err != nil {
		return err
	}

	if verbosity > 1 {
		bt.Log = os.Stdout
	}

	for _, c := range csfiles {
		// TODO: avoid recompile up to date objects
		o := filepath.Join(work, c[:len(c)-1]+"o")
		c = filepath.Join(bp.Dir, c)
		if err = bt.Compile(o, c); err != nil {
			return err
		}
		objs = append(objs, o)
	}

	if ppath != "main" {
		if err := bt.Archive(hpath[:len(hpath)-1]+"a", objs...); err != nil {
			return err
		}
		now := time.Now()
		return os.Chtimes(hpath, now, now)
	}

	imports := make([]string, len(pkg.Imports()))
	for i, p := range pkg.Imports() {
		imports[i] = p.Path()
	}
	return bt.Link(filepath.Join(bp.Dir, mainbin), imports, objs...)
}
Example #2
0
func (s sampleDecl) testDecl() error {
	src := "package foo\n" + s.goDecl

	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, s.filePos, src, 0)
	if err != nil {
		return err
	}

	ti := &types.Info{
		Types:      make(map[ast.Expr]types.TypeAndValue),
		Defs:       make(map[*ast.Ident]types.Object),
		Uses:       make(map[*ast.Ident]types.Object),
		Selections: make(map[*ast.SelectorExpr]*types.Selection),
	}
	pkg, err := new(types.Config).Check("foo", fset, []*ast.File{f}, ti)
	if err != nil {
		return err
	}

	gtc := gotoc.NewGTC(pkg, ti)
	var cdds []*gotoc.CDD
	for _, decl := range f.Decls {
		cdds = append(cdds, gtc.Decl(decl, 0)...)
	}

	if len(cdds) < len(s.c) {
		return s.noCDDError(len(cdds))
	}
	if len(cdds) > len(s.c) {
		return s.noExpError(cdds[len(s.c)])
	}
	for i, cdd := range cdds {
		cddDecl := string(cdd.Decl)
		if cddDecl != s.c[i].decl {
			return s.notMatch("decl", cddDecl, s.c[i].decl)
		}
		cddDef := string(cdd.Def)
		if cddDef != s.c[i].def {
			return s.notMatch("def", cddDef, s.c[i].def)
		}
		cddInit := string(cdd.Init)
		if cddInit != s.c[i].init {
			return s.notMatch("init", cddInit, s.c[i].init)
		}
	}
	return nil
}