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...) }
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 }