From 4f2269edbd1b3e09484001c9cc7897b49c828b45 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 31 May 2017 11:35:29 -0400 Subject: [PATCH] cmd/link: add -importcfg to specify import resolution 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 Reviewed-by: Ian Lance Taylor --- src/cmd/link/internal/ld/ld.go | 83 +++++++++++++++++++++++++++----- src/cmd/link/internal/ld/lib.go | 13 +++++ src/cmd/link/internal/ld/link.go | 3 ++ src/cmd/link/internal/ld/main.go | 1 + 4 files changed, 87 insertions(+), 13 deletions(-) diff --git a/src/cmd/link/internal/ld/ld.go b/src/cmd/link/internal/ld/ld.go index c6cad49f26..fc4137213f 100644 --- a/src/cmd/link/internal/ld/ld.go +++ b/src/cmd/link/internal/ld/ld.go @@ -33,6 +33,7 @@ package ld import ( "io/ioutil" + "log" "os" "path" "path/filepath" @@ -40,6 +41,51 @@ import ( "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) @@ -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) } diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index 8906d2f91a..625287112c 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -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") diff --git a/src/cmd/link/internal/ld/link.go b/src/cmd/link/internal/ld/link.go index 45ce20a700..302364c299 100644 --- a/src/cmd/link/internal/ld/link.go +++ b/src/cmd/link/internal/ld/link.go @@ -230,6 +230,9 @@ type Link struct { Filesyms []*Symbol Moduledata *Symbol + PackageFile map[string]string + PackageShlib map[string]string + tramps []*Symbol // trampolines } diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go index 0078064f28..f03460d2b4 100644 --- a/src/cmd/link/internal/ld/main.go +++ b/src/cmd/link/internal/ld/main.go @@ -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) -- 2.50.0