diff --git a/cl/builtin_test.go b/cl/builtin_test.go index 70803fc8..7d14e476 100644 --- a/cl/builtin_test.go +++ b/cl/builtin_test.go @@ -36,10 +36,10 @@ func TestPkgNoInit(t *testing.T) { } func TestPkgKind(t *testing.T) { - if v := pkgKind("noinit"); v != pkgNoInit { + if v := pkgKind("noinit"); v != PkgNoInit { t.Fatal("pkgKind:", v) } - if v := pkgKind(""); v != pkgNormal { + if v := pkgKind(""); v != PkgLLGo { t.Fatal("pkgKind:", v) } } diff --git a/cl/compile.go b/cl/compile.go index b8556a76..ed182b14 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -82,7 +82,7 @@ func (p *context) funcKind(vfn ssa.Value) int { func (p *context) pkgNoInit(pkg *types.Package) bool { p.ensureLoaded(pkg) if i, ok := p.loaded[pkg]; ok { - return i.kind != pkgNormal + return i.kind >= PkgNoInit } return false } @@ -119,9 +119,10 @@ type instrOrValue interface { } const ( - pkgNormal = iota - pkgNoInit // noinit: a package that don't need to be initialized - pkgDeclOnly // decl: a package that only have declarations + PkgNormal = iota + PkgLLGo + PkgNoInit // noinit: a package that don't need to be initialized + PkgDeclOnly // decl: a package that only have declarations ) type pkgInfo struct { @@ -494,7 +495,7 @@ func NewPackage(prog llssa.Program, pkg *ssa.Package, files []*ast.File) (ret ll link: make(map[string]string), vargs: make(map[*ssa.Alloc][]llssa.Expr), loaded: map[*types.Package]*pkgInfo{ - types.Unsafe: {kind: pkgNoInit}, // TODO(xsw): pkgNoInit or pkgDeclOnly? + types.Unsafe: {kind: PkgDeclOnly}, // TODO(xsw): PkgNoInit or PkgDeclOnly? }, } ctx.initFiles(pkgPath, files) diff --git a/cl/import.go b/cl/import.go index bd9a28fb..249402a6 100644 --- a/cl/import.go +++ b/cl/import.go @@ -44,27 +44,45 @@ func contentOf(m contentMap, file string) (lines contentLines, err error) { return } +// PkgKindOf returns the kind of a package. +func PkgKindOf(pkg *types.Package) int { + scope := pkg.Scope() + kind := pkgKindByScope(scope) + if kind == PkgNormal { + kind = pkgKindByPath(pkg.Path()) + } + return kind +} + // decl: a package that only contains declarations // noinit: a package that does not need to be initialized func pkgKind(v string) int { switch v { case "decl": - return pkgDeclOnly + return PkgDeclOnly case "noinit": - return pkgNoInit + return PkgNoInit } - return pkgNormal + return PkgLLGo +} + +func pkgKindByScope(scope *types.Scope) int { + if v, ok := scope.Lookup("LLGoPackage").(*types.Const); ok { + if v := v.Val(); v.Kind() == constant.String { + return pkgKind(constant.StringVal(v)) + } + return PkgLLGo + } + return PkgNormal } func (p *context) importPkg(pkg *types.Package, i *pkgInfo) { scope := pkg.Scope() - llpkg, ok := scope.Lookup("LLGoPackage").(*types.Const) - if !ok { + kind := pkgKindByScope(scope) + if kind == PkgNormal { return } - if v := llpkg.Val(); v.Kind() == constant.String { - i.kind = pkgKind(constant.StringVal(v)) - } + i.kind = kind fset := p.fset names := scope.Names() contents := make(contentMap) @@ -199,8 +217,8 @@ func (p *context) ensureLoaded(pkgTypes *types.Package) *types.Package { func pkgKindByPath(pkgPath string) int { switch pkgPath { - case "syscall", "runtime/cgo": - return pkgNoInit + case "syscall", "runtime/cgo", "unsafe": + return PkgDeclOnly } - return pkgNormal + return PkgNormal } diff --git a/internal/build/build.go b/internal/build/build.go index 7868025c..e17ee2f1 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -183,7 +183,7 @@ func linkMainPkg(pkg *packages.Package, runtimeFiles []string, conf *Config, mod args[2] = "-Wno-override-module" needRuntime := false packages.Visit([]*packages.Package{pkg}, nil, func(p *packages.Package) { - if p.PkgPath != "unsafe" { // TODO(xsw): maybe can remove this special case + if p.ExportFile != "" { // skip packages that only contain declarations args = append(args, p.ExportFile+".ll") if !needRuntime { needRuntime = isNeedRuntime(p) @@ -220,6 +220,12 @@ func linkMainPkg(pkg *packages.Package, runtimeFiles []string, conf *Config, mod func buildPkg(prog llssa.Program, aPkg aPackage, mode Mode, verbose bool) { pkg := aPkg.Package + if cl.PkgKindOf(pkg.Types) == cl.PkgDeclOnly { + // skip packages that only contain declarations + // and set no export file + pkg.ExportFile = "" + return + } pkgPath := pkg.PkgPath if verbose { fmt.Fprintln(os.Stderr, pkgPath) @@ -320,7 +326,7 @@ func allLinkFiles(rt []*packages.Package) (outFiles []string) { outFiles = make([]string, 0, len(rt)) root := rootLLGo(rt[0]) packages.Visit(rt, nil, func(p *packages.Package) { - if isPkgInLLGo(p.PkgPath) { + if hasLinkFile(p) { outFile := filepath.Join(root+p.PkgPath[len(llgoModPath):], "llgo_autogen.ll") outFiles = append(outFiles, outFile) } @@ -328,6 +334,13 @@ func allLinkFiles(rt []*packages.Package) (outFiles []string) { return } +func hasLinkFile(pkg *packages.Package) bool { + if isPkgInLLGo(pkg.PkgPath) { + return cl.PkgKindOf(pkg.Types) != cl.PkgDeclOnly + } + return false +} + // TODO(xsw): llgo root dir func rootLLGo(runtime *packages.Package) string { return runtime.Module.Dir