Commit 725cd2ea authored by Michael Hudson-Doyle's avatar Michael Hudson-Doyle Committed by Ian Lance Taylor

cmd/go: support -buildmode=shared

You can now do 'go install -buildmode=shared std' and get yourself
a nice (33 meg) libstd.so (which is not useful until there is -linkshared
support as well, of course).

Change-Id: Ie9b7e7f72abc7d369a6e3ecc98903a9d197bd6e6
Reviewed-on: https://go-review.googlesource.com/8300
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: 's avatarIan Lance Taylor <iant@golang.org>
parent 6e83ef6d
...@@ -326,9 +326,8 @@ func buildModeInit() { ...@@ -326,9 +326,8 @@ func buildModeInit() {
switch platform { switch platform {
case "linux/amd64": case "linux/amd64":
codegenArg = "-shared" codegenArg = "-shared"
buildGcflags = append(buildGcflags, codegenArg)
case "linux/arm": case "linux/arm":
codegenArg = "-shared" buildAsmflags = append(buildAsmflags, "-shared")
case "android/arm": case "android/arm":
default: default:
fatalf("-buildmode=c-shared not supported on %s\n", platform) fatalf("-buildmode=c-shared not supported on %s\n", platform)
...@@ -339,6 +338,18 @@ func buildModeInit() { ...@@ -339,6 +338,18 @@ func buildModeInit() {
case "exe": case "exe":
pkgsFilter = pkgsMain pkgsFilter = pkgsMain
ldBuildmode = "exe" ldBuildmode = "exe"
case "shared":
pkgsFilter = pkgsNotMain
switch platform {
case "linux/amd64":
default:
fatalf("-buildmode=shared not supported on %s\n", platform)
}
if *buildO != "" {
fatalf("-buildmode=shared and -o not supported together")
}
codegenArg = "-dynlink"
ldBuildmode = "shared"
default: default:
fatalf("buildmode=%s not supported", buildBuildmode) fatalf("buildmode=%s not supported", buildBuildmode)
} }
...@@ -348,7 +359,6 @@ func buildModeInit() { ...@@ -348,7 +359,6 @@ func buildModeInit() {
os.Exit(2) os.Exit(2)
} }
codegenArg = "-dynlink" codegenArg = "-dynlink"
buildGcflags = append(buildGcflags, codegenArg)
// TODO(mwhudson): remove -w when that gets fixed in linker. // TODO(mwhudson): remove -w when that gets fixed in linker.
buildLdflags = append(buildLdflags, "-linkshared", "-w") buildLdflags = append(buildLdflags, "-linkshared", "-w")
} }
...@@ -357,6 +367,7 @@ func buildModeInit() { ...@@ -357,6 +367,7 @@ func buildModeInit() {
} }
if codegenArg != "" { if codegenArg != "" {
buildAsmflags = append(buildAsmflags, codegenArg) buildAsmflags = append(buildAsmflags, codegenArg)
buildGcflags = append(buildGcflags, codegenArg)
if buildContext.InstallSuffix != "" { if buildContext.InstallSuffix != "" {
buildContext.InstallSuffix += "_" buildContext.InstallSuffix += "_"
} }
...@@ -393,6 +404,7 @@ func runBuild(cmd *Command, args []string) { ...@@ -393,6 +404,7 @@ func runBuild(cmd *Command, args []string) {
} }
depMode := modeBuild depMode := modeBuild
mode := modeBuild
if buildI { if buildI {
depMode = modeInstall depMode = modeInstall
} }
...@@ -411,9 +423,15 @@ func runBuild(cmd *Command, args []string) { ...@@ -411,9 +423,15 @@ func runBuild(cmd *Command, args []string) {
return return
} }
a := &action{} var a *action
if buildBuildmode == "shared" {
a = b.libaction(libname(args))
mode = depMode
} else {
a = &action{}
}
for _, p := range pkgsFilter(packages(args)) { for _, p := range pkgsFilter(packages(args)) {
a.deps = append(a.deps, b.action(modeBuild, depMode, p)) a.deps = append(a.deps, b.action(mode, depMode, p))
} }
b.do(a) b.do(a)
} }
...@@ -432,8 +450,33 @@ See also: go build, go get, go clean. ...@@ -432,8 +450,33 @@ See also: go build, go get, go clean.
`, `,
} }
// libname returns the filename to use for the shared library when using
// -buildmode=shared. The rules we use are:
// 1) Drop any trailing "/..."s if present
// 2) Change / to -
// 3) Join arguments with ,
// So std -> libstd.so
// a b/... -> liba,b.so
// gopkg.in/tomb.v2 -> libgopkg.in-tomb.v2.so
func libname(args []string) string {
var libname string
for _, arg := range args {
arg = strings.TrimSuffix(arg, "/...")
arg = strings.Replace(arg, "/", "-", -1)
if libname == "" {
libname = arg
} else {
libname += "," + arg
}
}
// TODO(mwhudson): Needs to change for platforms that use different naming
// conventions...
return "lib" + libname + ".so"
}
func runInstall(cmd *Command, args []string) { func runInstall(cmd *Command, args []string) {
raceInit() raceInit()
buildModeInit()
pkgs := pkgsFilter(packagesForBuild(args)) pkgs := pkgsFilter(packagesForBuild(args))
for _, p := range pkgs { for _, p := range pkgs {
...@@ -452,25 +495,54 @@ func runInstall(cmd *Command, args []string) { ...@@ -452,25 +495,54 @@ func runInstall(cmd *Command, args []string) {
var b builder var b builder
b.init() b.init()
a := &action{} a := &action{}
var tools []*action if buildBuildmode == "shared" {
for _, p := range pkgs { var libdir string
// If p is a tool, delay the installation until the end of the build. for _, p := range pkgs {
// This avoids installing assemblers/compilers that are being executed plibdir := p.build.PkgTargetRoot
// by other steps in the build. if libdir == "" {
// cmd/cgo is handled specially in b.action, so that we can libdir = plibdir
// both build and use it in the same 'go install'. } else if libdir != plibdir {
action := b.action(modeInstall, modeInstall, p) fatalf("multiple roots %s & %s", libdir, plibdir)
if goTools[p.ImportPath] == toTool && p.ImportPath != "cmd/cgo" { }
a.deps = append(a.deps, action.deps...)
action.deps = append(action.deps, a)
tools = append(tools, action)
continue
} }
a.deps = append(a.deps, action)
} a.f = (*builder).install
if len(tools) > 0 { libfilename := libname(args)
a = &action{ linkSharedAction := b.libaction(libfilename)
deps: tools, a.target = filepath.Join(libdir, libfilename)
a.deps = append(a.deps, linkSharedAction)
for _, p := range pkgs {
if p.target == "" {
continue
}
shlibnameaction := &action{}
shlibnameaction.f = (*builder).installShlibname
shlibnameaction.target = p.target[:len(p.target)-2] + ".shlibname"
a.deps = append(a.deps, shlibnameaction)
shlibnameaction.deps = append(shlibnameaction.deps, linkSharedAction)
linkSharedAction.deps = append(linkSharedAction.deps, b.action(modeInstall, modeInstall, p))
}
} else {
var tools []*action
for _, p := range pkgs {
// If p is a tool, delay the installation until the end of the build.
// This avoids installing assemblers/compilers that are being executed
// by other steps in the build.
// cmd/cgo is handled specially in b.action, so that we can
// both build and use it in the same 'go install'.
action := b.action(modeInstall, modeInstall, p)
if goTools[p.ImportPath] == toTool && p.ImportPath != "cmd/cgo" {
a.deps = append(a.deps, action.deps...)
action.deps = append(action.deps, a)
tools = append(tools, action)
continue
}
a.deps = append(a.deps, action)
}
if len(tools) > 0 {
a = &action{
deps: tools,
}
} }
} }
b.do(a) b.do(a)
...@@ -769,6 +841,13 @@ func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action ...@@ -769,6 +841,13 @@ func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action
return a return a
} }
func (b *builder) libaction(libname string) *action {
a := &action{}
a.f = (*builder).linkShared
a.target = filepath.Join(b.work, libname)
return a
}
// actionList returns the list of actions in the dag rooted at root // actionList returns the list of actions in the dag rooted at root
// as visited in a depth-first post-order traversal. // as visited in a depth-first post-order traversal.
func actionList(root *action) []*action { func actionList(root *action) []*action {
...@@ -1188,6 +1267,34 @@ func (b *builder) getPkgConfigFlags(p *Package) (cflags, ldflags []string, err e ...@@ -1188,6 +1267,34 @@ func (b *builder) getPkgConfigFlags(p *Package) (cflags, ldflags []string, err e
return return
} }
func (b *builder) installShlibname(a *action) error {
a1 := a.deps[0]
err := ioutil.WriteFile(a.target, []byte(filepath.Base(a1.target)+"\n"), 0644)
if err != nil {
return err
}
if buildX {
b.showcmd("", "echo '%s' > %s # internal", filepath.Base(a1.target), a.target)
}
return nil
}
func (b *builder) linkShared(a *action) (err error) {
// TODO(mwhudson): obvious copy pasting from gcToolchain.ld, should make a few
// changes to that function and then call it. And support gccgo.
allactions := actionList(a)
importArgs := b.includeArgs("-L", allactions[:len(allactions)-1])
// TODO(mwhudson): this does not check for cxx-ness, extldflags etc
ldflags := []string{"-installsuffix", buildContext.InstallSuffix}
ldflags = append(ldflags, buildLdflags...)
for _, d := range a.deps {
if d.target != "" { // omit unsafe etc
ldflags = append(ldflags, d.p.ImportPath+"="+d.target)
}
}
return b.run(".", a.target, nil, buildToolExec, tool(archChar()+"l"), "-o", a.target, importArgs, ldflags)
}
// install is the action for installing a single package or executable. // install is the action for installing a single package or executable.
func (b *builder) install(a *action) (err error) { func (b *builder) install(a *action) (err error) {
defer func() { defer func() {
......
...@@ -674,6 +674,11 @@ are: ...@@ -674,6 +674,11 @@ are:
non-main packages are built into .a files (the default non-main packages are built into .a files (the default
behavior). behavior).
-buildmode=shared
Combine all the listed non-main packages into a single shared
library that will be used when building with the -linkshared
option. Packages named main are ignored.
-buildmode=exe -buildmode=exe
Build the listed main packages and everything they import into Build the listed main packages and everything they import into
executables. Packages not named main are ignored. executables. Packages not named main are ignored.
......
...@@ -393,6 +393,11 @@ are: ...@@ -393,6 +393,11 @@ are:
non-main packages are built into .a files (the default non-main packages are built into .a files (the default
behavior). behavior).
-buildmode=shared
Combine all the listed non-main packages into a single shared
library that will be used when building with the -linkshared
option. Packages named main are ignored.
-buildmode=exe -buildmode=exe
Build the listed main packages and everything they import into Build the listed main packages and everything they import into
executables. Packages not named main are ignored. executables. Packages not named main are ignored.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment