Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
add /lib symlink farm subdir to packages
This changes the rpath from being a large list to being a single directory in
which all libs (symlinks, actually) are found, speeding up library loading
significantly.
  • Loading branch information
stapelberg committed Jun 4, 2019
1 parent 5fd28e1 commit 19f3420
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 37 deletions.
60 changes: 27 additions & 33 deletions cmd/distri/build.go
Expand Up @@ -461,7 +461,9 @@ func (b *buildctx) env(deps []string, hermetic bool) []string {
// Exclude LDFLAGS for glibc as per
// https://github.com/Linuxbrew/legacy-linuxbrew/issues/126
if b.Pkg != "glibc" && b.Pkg != "glibc-i686" {
env = append(env, "LDFLAGS=-Wl,-rpath="+strings.Join(libDirs, " -Wl,-rpath=")+" -Wl,--dynamic-linker=/ro/glibc-amd64-2.27/out/lib/ld-linux-x86-64.so.2 "+strings.Join(b.Proto.GetCbuilder().GetExtraLdflag(), " ")) // for ld
env = append(env, "LDFLAGS=-Wl,-rpath="+b.Prefix+"/lib "+
"-Wl,--dynamic-linker=/ro/glibc-amd64-2.27/out/lib/ld-linux-x86-64.so.2 "+
strings.Join(b.Proto.GetCbuilder().GetExtraLdflag(), " ")) // for ld
}
return env
}
Expand Down Expand Up @@ -647,8 +649,6 @@ func (b *buildctx) builderdeps(p *pb.Build) []string {
"linux",
"findutils", // find(1) is used by libtool, build of e.g. libidn2 will fail if not present

"patchelf", // for shrinking the RPATH

"strace", // useful for interactive debugging
}

Expand Down Expand Up @@ -698,7 +698,6 @@ func (b *buildctx) builderdeps(p *pb.Build) []string {
deps = append(deps, []string{
"bash-" + native,
"coreutils-" + native,
"patchelf-" + native, // e.g. cloud.google.com/go includes .elf files
}...)

case *pb.Build_Cbuilder:
Expand Down Expand Up @@ -773,7 +772,7 @@ func (b *buildctx) build() (*pb.Meta, error) {
}

if b.FUSE {
if _, err = cmdfuse.Mount([]string{"-overlays=/bin,/out/lib/pkgconfig,/out/include,/out/share/aclocal,/out/share/gir-1.0,/out/share/mime,/out/gopath,/out/lib/gio,/out/lib/girepository-1.0,/out/share/gettext", "-pkgs=" + strings.Join(deps, ","), depsdir}); err != nil {
if _, err = cmdfuse.Mount([]string{"-overlays=/bin,/out/lib/pkgconfig,/out/include,/out/share/aclocal,/out/share/gir-1.0,/out/share/mime,/out/gopath,/out/lib/gio,/out/lib/girepository-1.0,/out/share/gettext,/out/lib", "-pkgs=" + strings.Join(deps, ","), depsdir}); err != nil {
return nil, err
}
defer fuse.Unmount(depsdir)
Expand Down Expand Up @@ -974,6 +973,10 @@ func (b *buildctx) build() (*pb.Meta, error) {
}
}

if err := os.Symlink("/ro/lib", filepath.Join(b.ChrootDir, b.DestDir, "lib")); err != nil {
return nil, err
}

if err := os.Symlink("/ro/share", filepath.Join(b.ChrootDir, "usr", "share")); err != nil {
return nil, err
}
Expand Down Expand Up @@ -1314,6 +1317,7 @@ func (b *buildctx) build() (*pb.Meta, error) {
// Find shlibdeps while we’re still in the chroot, so that ldd(1) locates
// the dependencies.
depPkgs := make(map[string]bool)
libs := make(map[string]bool)
destDir := filepath.Join(b.DestDir, b.Prefix)
var buf [4]byte
err = filepath.Walk(destDir, func(path string, info os.FileInfo, err error) error {
Expand All @@ -1335,40 +1339,16 @@ func (b *buildctx) build() (*pb.Meta, error) {
return nil
}
// TODO: detect whether the binary is statically or dynamically linked (the latter has an INTERP section)
pkgs, err := findShlibDeps(path, env)
libDeps, err := findShlibDeps(path, env)
if err != nil {
if err == errLddFailed {
return nil // skip patchelf
}
return err
}
for _, pkg := range pkgs {
depPkgs[pkg] = true
}

// TODO: make patchelf able to operate on itself
if b.Pkg != "patchelf" &&
filepath.Base(path) != "Mcrt1.o" &&
filepath.Base(path) != "Scrt1.o" &&
filepath.Base(path) != "crti.o" &&
filepath.Base(path) != "crtn.o" &&
filepath.Base(path) != "gcrt1.o" &&
filepath.Base(path) != "crt1.o" &&
!strings.HasSuffix(path, ".a") {
// patchelf does not preserve the setuid bit, so restore it:
fi, err := os.Stat(path)
if err != nil {
return err
}
patchelf := exec.Command("patchelf", "--shrink-rpath", path)
patchelf.Stdout = os.Stdout
patchelf.Stderr = os.Stderr
if err := patchelf.Run(); err != nil {
return xerrors.Errorf("%v: %v", patchelf.Args, err)
}
if err := os.Chmod(path, fi.Mode()); err != nil {
return err
}
for _, d := range libDeps {
depPkgs[d.pkg] = true
libs[d.path] = true
}

buildid, err := readBuildid(path)
Expand Down Expand Up @@ -1402,6 +1382,20 @@ func (b *buildctx) build() (*pb.Meta, error) {
return nil, err
}

// Replace the symlink to /ro/lib with a directory of links to the
// actually required libraries:
libDir := filepath.Join(b.DestDir, b.Prefix, "lib")
if err := os.MkdirAll(libDir, 0755); err != nil {
return nil, err
}
for lib := range libs {
newname := filepath.Join(libDir, filepath.Base(lib))
oldname := lib
if err := os.Symlink(oldname, newname); err != nil && !os.IsExist(err) {
return nil, err
}
}

// TODO(optimization): these could be build-time dependencies, as they are
// only required when building against the library, not when using it.
pkgconfig := filepath.Join(destDir, "out", "lib", "pkgconfig")
Expand Down
16 changes: 12 additions & 4 deletions cmd/distri/shlibdeps.go
Expand Up @@ -9,11 +9,16 @@ import (
"strings"
)

var lddRe = regexp.MustCompile(`^\t([^ ]+) => /ro/([^/]+)`)
var lddRe = regexp.MustCompile(`^\t([^ ]+) => (/ro/([^/]+)[^\s]+)`)

var errLddFailed = errors.New("ldd failed") // sentinel

func findShlibDeps(fn string, env []string) ([]string, error) {
type libDep struct {
pkg string
path string
}

func findShlibDeps(fn string, env []string) ([]libDep, error) {
cmd := exec.Command("ldd", fn)
cmd.Env = env
cmd.Stderr = os.Stderr
Expand All @@ -23,13 +28,16 @@ func findShlibDeps(fn string, env []string) ([]string, error) {
return nil, errLddFailed // TODO: fix
return nil, err
}
var pkgs []string
var pkgs []libDep
for _, line := range strings.Split(strings.TrimSpace(string(out)), "\n") {
matches := lddRe.FindStringSubmatch(line)
if matches == nil {
continue
}
pkgs = append(pkgs, matches[2])
pkgs = append(pkgs, libDep{
pkg: matches[3],
path: matches[2],
})
}
return pkgs, nil
}

0 comments on commit 19f3420

Please sign in to comment.