Skip to content

Commit

Permalink
cmd/link: add -importcfg to specify import resolution
Browse files Browse the repository at this point in the history
Adds the ability to specify the file location of each imported package,
like in the -importcfg added to cmd/compile in a related CL.
In effect, -importcfg is a generalization of and supersedes -installsuffix
and -L. Of course, those flags will continue to be supported, for
compatibility with other tools.

Having this flag in Go 1.9 will let us try some experiments involving
package management without needing guinea pigs to build a custom
Go toolchain.

This flag also helps with #14271 at some later point.

For #20579.

Change-Id: Ie4c171bcd3aa2faa446ac340e36516f2f9853882
Reviewed-on: https://go-review.googlesource.com/44851
Run-TryBot: Russ Cox <[email protected]>
Reviewed-by: Ian Lance Taylor <[email protected]>
  • Loading branch information
rsc committed Jun 6, 2017
1 parent 4d6b08d commit 4f2269e
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 13 deletions.
83 changes: 70 additions & 13 deletions src/cmd/link/internal/ld/ld.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,59 @@ package ld

import (
"io/ioutil"
"log"
"os"
"path"
"path/filepath"
"strconv"
"strings"
)

func (ctxt *Link) readImportCfg(file string) {
ctxt.PackageFile = make(map[string]string)
ctxt.PackageShlib = make(map[string]string)
data, err := ioutil.ReadFile(file)
if err != nil {
log.Fatalf("-importcfg: %v", err)
}

for lineNum, line := range strings.Split(string(data), "\n") {
lineNum++ // 1-based
line = strings.TrimSpace(line)
if line == "" {
continue
}
if line == "" || strings.HasPrefix(line, "#") {
continue
}

var verb, args string
if i := strings.Index(line, " "); i < 0 {
verb = line
} else {
verb, args = line[:i], strings.TrimSpace(line[i+1:])
}
var before, after string
if i := strings.Index(args, "="); i >= 0 {
before, after = args[:i], args[i+1:]
}
switch verb {
default:
log.Fatalf("%s:%d: unknown directive %q", file, lineNum, verb)
case "packagefile":
if before == "" || after == "" {
log.Fatalf(`%s:%d: invalid packagefile: syntax is "packagefile path=filename"`, file, lineNum)
}
ctxt.PackageFile[before] = after
case "packageshlib":
if before == "" || after == "" {
log.Fatalf(`%s:%d: invalid packageshlib: syntax is "packageshlib path=filename"`, file, lineNum)
}
ctxt.PackageShlib[before] = after
}
}
}

func addlib(ctxt *Link, src string, obj string, pathname string) *Library {
name := path.Clean(pathname)

Expand All @@ -56,27 +102,38 @@ func addlib(ctxt *Link, src string, obj string, pathname string) *Library {

var pname string
isshlib := false
if filepath.IsAbs(name) {
pname = name

if *FlagLinkshared && ctxt.PackageShlib[name] != "" {
pname = ctxt.PackageShlib[name]
isshlib = true
} else if ctxt.PackageFile != nil {
pname = ctxt.PackageFile[name]
if pname == "" {
ctxt.Logf("cannot find package %s (using -importcfg)\n", name)
return nil
}
} else {
// try dot, -L "libdir", and then goroot.
for _, dir := range ctxt.Libdir {
if *FlagLinkshared {
pname = dir + "/" + pkg + ".shlibname"
if filepath.IsAbs(name) {
pname = name
} else {
// try dot, -L "libdir", and then goroot.
for _, dir := range ctxt.Libdir {
if *FlagLinkshared {
pname = dir + "/" + pkg + ".shlibname"
if _, err := os.Stat(pname); err == nil {
isshlib = true
break
}
}
pname = dir + "/" + name
if _, err := os.Stat(pname); err == nil {
isshlib = true
break
}
}
pname = dir + "/" + name
if _, err := os.Stat(pname); err == nil {
break
}
}
pname = path.Clean(pname)
}

pname = path.Clean(pname)

if ctxt.Debugvlog > 1 {
ctxt.Logf("%5.2f addlib: %s %s pulls in %s isshlib %v\n", elapsed(), obj, src, pname, isshlib)
}
Expand Down
13 changes: 13 additions & 0 deletions src/cmd/link/internal/ld/lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,19 @@ func errorexit() {
}

func loadinternal(ctxt *Link, name string) *Library {
if *FlagLinkshared && ctxt.PackageShlib != nil {
if shlibname := ctxt.PackageShlib[name]; shlibname != "" {
return addlibpath(ctxt, "internal", "internal", "", name, shlibname)
}
}
if ctxt.PackageFile != nil {
if pname := ctxt.PackageFile[name]; pname != "" {
return addlibpath(ctxt, "internal", "internal", pname, name, "")
}
ctxt.Logf("loadinternal: cannot find %s\n", name)
return nil
}

for i := 0; i < len(ctxt.Libdir); i++ {
if *FlagLinkshared {
shlibname := filepath.Join(ctxt.Libdir[i], name+".shlibname")
Expand Down
3 changes: 3 additions & 0 deletions src/cmd/link/internal/ld/link.go
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,9 @@ type Link struct {
Filesyms []*Symbol
Moduledata *Symbol

PackageFile map[string]string
PackageShlib map[string]string

tramps []*Symbol // trampolines
}

Expand Down
1 change: 1 addition & 0 deletions src/cmd/link/internal/ld/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ func Main() {
objabi.Flagfn0("V", "print version and exit", doversion)
objabi.Flagfn1("X", "add string value `definition` of the form importpath.name=value", func(s string) { addstrdata1(ctxt, s) })
objabi.Flagcount("v", "print link trace", &ctxt.Debugvlog)
objabi.Flagfn1("importcfg", "read import configuration from `file`", ctxt.readImportCfg)

objabi.Flagparse(usage)

Expand Down

0 comments on commit 4f2269e

Please sign in to comment.