1
0
mirror of https://github.com/golang/go synced 2024-09-29 22:14:29 -06:00

cmd/go: fix bad shared lib name with buildmode=shared

Use import paths of packages to build a shared lib name.
Use arguments for meta-packages 'std', 'cmd', and 'all'.

Fixes #12236

Change-Id: If274d63301686ef34e198287eb012f9062541ea0
Reviewed-on: https://go-review.googlesource.com/13921
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
Aleksandr Demakin 2015-08-25 19:54:57 +03:00 committed by Ian Lance Taylor
parent 148b13c3bb
commit c5aa53c8c5
3 changed files with 137 additions and 15 deletions

View File

@ -480,7 +480,12 @@ func runBuild(cmd *Command, args []string) {
var a *action var a *action
if buildBuildmode == "shared" { if buildBuildmode == "shared" {
a = b.libaction(libname(args), pkgsFilter(packages(args)), modeBuild, depMode) pkgs := pkgsFilter(packages(args))
if libName, err := libname(args, pkgs); err != nil {
fatalf("%s", err.Error())
} else {
a = b.libaction(libName, pkgs, modeBuild, depMode)
}
} else { } else {
a = &action{} a = &action{}
for _, p := range pkgsFilter(packages(args)) { for _, p := range pkgsFilter(packages(args)) {
@ -504,28 +509,49 @@ See also: go build, go get, go clean.
`, `,
} }
// isMetaPackage checks if name is a reserved package name that expands to multiple packages
func isMetaPackage(name string) bool {
return name == "std" || name == "cmd" || name == "all"
}
// libname returns the filename to use for the shared library when using // libname returns the filename to use for the shared library when using
// -buildmode=shared. The rules we use are: // -buildmode=shared. The rules we use are:
// 1) Drop any trailing "/..."s if present // Use arguments for special 'meta' packages:
// 2) Change / to - // std --> libstd.so
// 3) Join arguments with , // std cmd --> libstd,cmd.so
// So std -> libstd.so // Use import paths for other cases, changing '/' to '-':
// a b/... -> liba,b.so // somelib --> libsubdir-somelib.so
// gopkg.in/tomb.v2 -> libgopkg.in-tomb.v2.so // ./ or ../ --> libsubdir-somelib.so
func libname(args []string) string { // gopkg.in/tomb.v2 -> libgopkg.in-tomb.v2.so
// ./... ---> libpkg1,pkg2.so - subset of all import paths
// Name parts are joined with ','.
func libname(args []string, pkgs []*Package) (string, error) {
var libname string var libname string
for _, arg := range args { appendName := func(arg string) {
arg = strings.TrimSuffix(arg, "/...")
arg = strings.Replace(arg, "/", "-", -1)
if libname == "" { if libname == "" {
libname = arg libname = arg
} else { } else {
libname += "," + arg libname += "," + arg
} }
} }
var haveNonMeta bool
for _, arg := range args {
if isMetaPackage(arg) {
appendName(arg)
} else {
haveNonMeta = true
}
}
if len(libname) == 0 { // non-meta packages only. use import paths
for _, pkg := range pkgs {
appendName(strings.Replace(pkg.ImportPath, "/", "-", -1))
}
} else if haveNonMeta { // have both meta package and a non-meta one
return "", errors.New("mixing of meta and non-meta packages is not allowed")
}
// TODO(mwhudson): Needs to change for platforms that use different naming // TODO(mwhudson): Needs to change for platforms that use different naming
// conventions... // conventions...
return "lib" + libname + ".so" return "lib" + libname + ".so", nil
} }
func runInstall(cmd *Command, args []string) { func runInstall(cmd *Command, args []string) {
@ -558,7 +584,11 @@ func runInstall(cmd *Command, args []string) {
b.init() b.init()
var a *action var a *action
if buildBuildmode == "shared" { if buildBuildmode == "shared" {
a = b.libaction(libname(args), pkgs, modeInstall, modeInstall) if libName, err := libname(args, pkgs); err != nil {
fatalf("%s", err.Error())
} else {
a = b.libaction(libName, pkgs, modeInstall, modeInstall)
}
} else { } else {
a = &action{} a = &action{}
var tools []*action var tools []*action

View File

@ -353,7 +353,7 @@ func importPathsNoDotExpansion(args []string) []string {
} else { } else {
a = path.Clean(a) a = path.Clean(a)
} }
if a == "all" || a == "std" || a == "cmd" { if isMetaPackage(a) {
out = append(out, allPackages(a)...) out = append(out, allPackages(a)...)
continue continue
} }
@ -554,7 +554,7 @@ func allPackages(pattern string) []string {
func matchPackages(pattern string) []string { func matchPackages(pattern string) []string {
match := func(string) bool { return true } match := func(string) bool { return true }
treeCanMatch := func(string) bool { return true } treeCanMatch := func(string) bool { return true }
if pattern != "all" && pattern != "std" && pattern != "cmd" { if !isMetaPackage(pattern) {
match = matchPattern(pattern) match = matchPattern(pattern)
treeCanMatch = treeCanMatchPattern(pattern) treeCanMatch = treeCanMatchPattern(pattern)
} }

View File

@ -71,3 +71,95 @@ func TestParseMetaGoImports(t *testing.T) {
} }
} }
} }
func TestSharedLibName(t *testing.T) {
// TODO(avdva) - make these values platform-specific
prefix := "lib"
suffix := ".so"
testData := []struct {
args []string
pkgs []*Package
expected string
expectErr bool
}{
{
[]string{"std"},
[]*Package{},
"std",
false,
},
{
[]string{"std", "cmd"},
[]*Package{},
"std,cmd",
false,
},
{
[]string{},
[]*Package{&Package{ImportPath: "gopkg.in/somelib"}},
"gopkg.in-somelib",
false,
},
{
[]string{"./..."},
[]*Package{&Package{ImportPath: "somelib"}},
"somelib",
false,
},
{
[]string{"../somelib", "../somelib"},
[]*Package{&Package{ImportPath: "somelib"}},
"somelib",
false,
},
{
[]string{"../lib1", "../lib2"},
[]*Package{&Package{ImportPath: "gopkg.in/lib1"}, &Package{ImportPath: "gopkg.in/lib2"}},
"gopkg.in-lib1,gopkg.in-lib2",
false,
},
{
[]string{"./..."},
[]*Package{
&Package{ImportPath: "gopkg.in/dir/lib1"},
&Package{ImportPath: "gopkg.in/lib2"},
&Package{ImportPath: "gopkg.in/lib3"},
},
"gopkg.in-dir-lib1,gopkg.in-lib2,gopkg.in-lib3",
false,
},
{
[]string{"std", "../lib2"},
[]*Package{},
"",
true,
},
{
[]string{"all", "./"},
[]*Package{},
"",
true,
},
{
[]string{"cmd", "fmt"},
[]*Package{},
"",
true,
},
}
for _, data := range testData {
computed, err := libname(data.args, data.pkgs)
if err != nil {
if !data.expectErr {
t.Errorf("libname returned an error %q, expected a name", err.Error())
}
} else if data.expectErr {
t.Errorf("libname returned %q, expected an error", computed)
} else {
expected := prefix + data.expected + suffix
if expected != computed {
t.Errorf("libname returned %q, expected %q", computed, expected)
}
}
}
}