build: PkgLinkExtern

This commit is contained in:
xushiwei
2024-05-09 14:51:01 +08:00
parent 093af00bbe
commit b133f70b6b
4 changed files with 40 additions and 23 deletions

View File

@@ -140,16 +140,19 @@ func TestPkgNoInit(t *testing.T) {
} }
func TestPkgKind(t *testing.T) { func TestPkgKind(t *testing.T) {
if v := pkgKind("noinit"); v != PkgNoInit { if v, _ := pkgKind("link: hello.a"); v != PkgLinkExtern {
t.Fatal("pkgKind:", v) t.Fatal("pkgKind:", v)
} }
if v := pkgKind(""); v != PkgLLGo { if v, _ := pkgKind("noinit"); v != PkgNoInit {
t.Fatal("pkgKind:", v)
}
if v, _ := pkgKind(""); v != PkgLLGo {
t.Fatal("pkgKind:", v) t.Fatal("pkgKind:", v)
} }
} }
func TestPkgKindOf(t *testing.T) { func TestPkgKindOf(t *testing.T) {
if v := PkgKindOf(types.Unsafe); v != PkgDeclOnly { if v, _ := PkgKindOf(types.Unsafe); v != PkgDeclOnly {
t.Fatal("PkgKindOf unsafe:", v) t.Fatal("PkgKindOf unsafe:", v)
} }
pkg := types.NewPackage("foo", "foo") pkg := types.NewPackage("foo", "foo")
@@ -158,7 +161,7 @@ func TestPkgKindOf(t *testing.T) {
0, pkg, "LLGoPackage", types.Typ[types.String], 0, pkg, "LLGoPackage", types.Typ[types.String],
constant.MakeString("noinit")), constant.MakeString("noinit")),
) )
if v := PkgKindOf(pkg); v != PkgNoInit { if v, _ := PkgKindOf(pkg); v != PkgNoInit {
t.Fatal("PkgKindOf foo:", v) t.Fatal("PkgKindOf foo:", v)
} }
} }

View File

@@ -123,9 +123,10 @@ type instrOrValue interface {
const ( const (
PkgNormal = iota PkgNormal = iota
PkgLLGo PkgLLGo
PkgNoInit // noinit: a package that don't need to be initialized PkgNoInit // noinit: a package that don't need to be initialized
PkgDeclOnly // decl: a package that only have declarations PkgDeclOnly // decl: a package that only have declarations
PkgLinkIR // link llvm ir (.ll) PkgLinkIR // link llvm ir (.ll)
PkgLinkExtern // link external object (.a/.so/.dll/.dylib/etc.)
// PkgLinkBitCode // link bitcode (.bc) // PkgLinkBitCode // link bitcode (.bc)
) )

View File

@@ -77,44 +77,48 @@ func (p *pkgSymInfo) initLinknames(ctx *context) {
} }
// PkgKindOf returns the kind of a package. // PkgKindOf returns the kind of a package.
func PkgKindOf(pkg *types.Package) int { func PkgKindOf(pkg *types.Package) (int, string) {
scope := pkg.Scope() scope := pkg.Scope()
kind := pkgKindByScope(scope) kind, param := pkgKindByScope(scope)
if kind == PkgNormal { if kind == PkgNormal {
kind = pkgKindByPath(pkg.Path()) kind = pkgKindByPath(pkg.Path())
} }
return kind return kind, param
} }
// decl: a package that only contains declarations // decl: a package that only contains declarations
// noinit: a package that does not need to be initialized // noinit: a package that does not need to be initialized
func pkgKind(v string) int { func pkgKind(v string) (int, string) {
switch v { switch v {
case "link": case "link":
return PkgLinkIR return PkgLinkIR, ""
// case "link:bc":
// return PkgLinkBitCode
case "decl": case "decl":
return PkgDeclOnly return PkgDeclOnly, ""
case "noinit": case "noinit":
return PkgNoInit return PkgNoInit, ""
default:
// case "link:bc":
// return PkgLinkBitCode
if strings.HasPrefix(v, "link:") { // "link: <libpath>"
return PkgLinkExtern, v[5:]
}
} }
return PkgLLGo return PkgLLGo, ""
} }
func pkgKindByScope(scope *types.Scope) int { func pkgKindByScope(scope *types.Scope) (int, string) {
if v, ok := scope.Lookup("LLGoPackage").(*types.Const); ok { if v, ok := scope.Lookup("LLGoPackage").(*types.Const); ok {
if v := v.Val(); v.Kind() == constant.String { if v := v.Val(); v.Kind() == constant.String {
return pkgKind(constant.StringVal(v)) return pkgKind(constant.StringVal(v))
} }
return PkgLLGo return PkgLLGo, ""
} }
return PkgNormal return PkgNormal, ""
} }
func (p *context) importPkg(pkg *types.Package, i *pkgInfo) { func (p *context) importPkg(pkg *types.Package, i *pkgInfo) {
scope := pkg.Scope() scope := pkg.Scope()
kind := pkgKindByScope(scope) kind, _ := pkgKindByScope(scope)
if kind == PkgNormal { if kind == PkgNormal {
return return
} }

View File

@@ -167,12 +167,12 @@ func buildAllPkgs(prog llssa.Program, initial []*packages.Package, mode Mode, ve
} }
for _, aPkg := range pkgs { for _, aPkg := range pkgs {
pkg := aPkg.Package pkg := aPkg.Package
switch kind := cl.PkgKindOf(pkg.Types); kind { switch kind, param := cl.PkgKindOf(pkg.Types); kind {
case cl.PkgDeclOnly: case cl.PkgDeclOnly:
// skip packages that only contain declarations // skip packages that only contain declarations
// and set no export file // and set no export file
pkg.ExportFile = "" pkg.ExportFile = ""
case cl.PkgLinkIR: // cl.PkgLinkBitCode: case cl.PkgLinkIR:
// skip packages that don't need to be compiled but need to be linked // skip packages that don't need to be compiled but need to be linked
pkgPath := pkg.PkgPath pkgPath := pkg.PkgPath
if isPkgInLLGo(pkgPath) { if isPkgInLLGo(pkgPath) {
@@ -180,6 +180,15 @@ func buildAllPkgs(prog llssa.Program, initial []*packages.Package, mode Mode, ve
} else { } else {
panic("todo") panic("todo")
} }
case cl.PkgLinkExtern:
// skip packages that don't need to be compiled but need to be linked with external library
linkFile := os.ExpandEnv(strings.TrimSpace(param))
dir, lib := filepath.Split(linkFile)
command := " -l " + lib
if dir != "" {
command += " -L " + dir
}
pkg.ExportFile = command
default: default:
buildPkg(prog, aPkg, mode, verbose) buildPkg(prog, aPkg, mode, verbose)
if prog.NeedRuntime() { if prog.NeedRuntime() {