diff --git a/cl/builtin_test.go b/cl/builtin_test.go index f2152f91..30841981 100644 --- a/cl/builtin_test.go +++ b/cl/builtin_test.go @@ -140,16 +140,19 @@ func TestPkgNoInit(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) } - if v := pkgKind(""); v != PkgLLGo { + if v, _ := pkgKind("noinit"); v != PkgNoInit { + t.Fatal("pkgKind:", v) + } + if v, _ := pkgKind(""); v != PkgLLGo { t.Fatal("pkgKind:", v) } } func TestPkgKindOf(t *testing.T) { - if v := PkgKindOf(types.Unsafe); v != PkgDeclOnly { + if v, _ := PkgKindOf(types.Unsafe); v != PkgDeclOnly { t.Fatal("PkgKindOf unsafe:", v) } pkg := types.NewPackage("foo", "foo") @@ -158,7 +161,7 @@ func TestPkgKindOf(t *testing.T) { 0, pkg, "LLGoPackage", types.Typ[types.String], constant.MakeString("noinit")), ) - if v := PkgKindOf(pkg); v != PkgNoInit { + if v, _ := PkgKindOf(pkg); v != PkgNoInit { t.Fatal("PkgKindOf foo:", v) } } diff --git a/cl/compile.go b/cl/compile.go index 354f27ed..62b4fc0c 100644 --- a/cl/compile.go +++ b/cl/compile.go @@ -123,9 +123,10 @@ type instrOrValue interface { const ( PkgNormal = iota PkgLLGo - PkgNoInit // noinit: a package that don't need to be initialized - PkgDeclOnly // decl: a package that only have declarations - PkgLinkIR // link llvm ir (.ll) + PkgNoInit // noinit: a package that don't need to be initialized + PkgDeclOnly // decl: a package that only have declarations + PkgLinkIR // link llvm ir (.ll) + PkgLinkExtern // link external object (.a/.so/.dll/.dylib/etc.) // PkgLinkBitCode // link bitcode (.bc) ) diff --git a/cl/import.go b/cl/import.go index a298eb6e..3f3e08ae 100644 --- a/cl/import.go +++ b/cl/import.go @@ -77,44 +77,48 @@ func (p *pkgSymInfo) initLinknames(ctx *context) { } // PkgKindOf returns the kind of a package. -func PkgKindOf(pkg *types.Package) int { +func PkgKindOf(pkg *types.Package) (int, string) { scope := pkg.Scope() - kind := pkgKindByScope(scope) + kind, param := pkgKindByScope(scope) if kind == PkgNormal { kind = pkgKindByPath(pkg.Path()) } - return kind + return kind, param } // decl: a package that only contains declarations // noinit: a package that does not need to be initialized -func pkgKind(v string) int { +func pkgKind(v string) (int, string) { switch v { case "link": - return PkgLinkIR - // case "link:bc": - // return PkgLinkBitCode + return PkgLinkIR, "" case "decl": - return PkgDeclOnly + return PkgDeclOnly, "" case "noinit": - return PkgNoInit + return PkgNoInit, "" + default: + // case "link:bc": + // return PkgLinkBitCode + if strings.HasPrefix(v, "link:") { // "link: " + 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 := v.Val(); v.Kind() == constant.String { return pkgKind(constant.StringVal(v)) } - return PkgLLGo + return PkgLLGo, "" } - return PkgNormal + return PkgNormal, "" } func (p *context) importPkg(pkg *types.Package, i *pkgInfo) { scope := pkg.Scope() - kind := pkgKindByScope(scope) + kind, _ := pkgKindByScope(scope) if kind == PkgNormal { return } diff --git a/internal/build/build.go b/internal/build/build.go index 78774111..034e58c4 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -167,12 +167,12 @@ func buildAllPkgs(prog llssa.Program, initial []*packages.Package, mode Mode, ve } for _, aPkg := range pkgs { pkg := aPkg.Package - switch kind := cl.PkgKindOf(pkg.Types); kind { + switch kind, param := cl.PkgKindOf(pkg.Types); kind { case cl.PkgDeclOnly: // skip packages that only contain declarations // and set no export file pkg.ExportFile = "" - case cl.PkgLinkIR: // cl.PkgLinkBitCode: + case cl.PkgLinkIR: // skip packages that don't need to be compiled but need to be linked pkgPath := pkg.PkgPath if isPkgInLLGo(pkgPath) { @@ -180,6 +180,15 @@ func buildAllPkgs(prog llssa.Program, initial []*packages.Package, mode Mode, ve } else { 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: buildPkg(prog, aPkg, mode, verbose) if prog.NeedRuntime() {