Skip to content

Commit 8a3a7f4

Browse files
committed
Resolve shared libraries in an architecture independent way
Instead of relying on the hosts ldd, implement a pure golang resolver for shared libraries which can also be used for cross-compilation. Signed-off-by: Roman Mohr <[email protected]>
1 parent dfed740 commit 8a3a7f4

File tree

6 files changed

+127
-19
lines changed

6 files changed

+127
-19
lines changed

cmd/BUILD.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ go_library(
2323
"//pkg/api",
2424
"//pkg/api/bazeldnf",
2525
"//pkg/bazel",
26+
"//pkg/ldd",
2627
"//pkg/order",
2728
"//pkg/reducer",
2829
"//pkg/repo",
@@ -31,7 +32,6 @@ go_library(
3132
"@com_github_sassoftware_go_rpmutils//:go_default_library",
3233
"@com_github_sirupsen_logrus//:go_default_library",
3334
"@com_github_spf13_cobra//:go_default_library",
34-
"@com_github_u_root_u_root//pkg/ldd:go_default_library",
3535
"@org_golang_x_crypto//openpgp:go_default_library",
3636
],
3737
)

cmd/ldd.go

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ import (
88
"strings"
99

1010
"github.com/rmohr/bazeldnf/pkg/bazel"
11+
"github.com/rmohr/bazeldnf/pkg/ldd"
1112
"github.com/rmohr/bazeldnf/pkg/rpm"
1213
"github.com/sirupsen/logrus"
1314
"github.com/spf13/cobra"
14-
"github.com/u-root/u-root/pkg/ldd"
1515
)
1616

1717
type lddOpts struct {
@@ -46,19 +46,18 @@ func NewlddCmd() *cobra.Command {
4646
objects[i] = filepath.Join(tmpRoot, objects[i])
4747
}
4848

49-
err = os.Setenv("LD_LIBRARY_PATH", filepath.Join(tmpRoot, "/usr/lib64"))
50-
if err != nil {
51-
return err
52-
}
53-
5449
files := []string{}
55-
dependencies, err := ldd.Ldd(objects)
50+
dependencies, err := ldd.Resolve(objects, filepath.Join(tmpRoot, "/usr/lib64"))
5651
if err != nil {
5752
return err
5853
}
5954
for _, dep := range dependencies {
60-
if strings.HasPrefix(dep.FullName, tmpRoot) {
61-
files = append(files, strings.TrimPrefix(dep.FullName, tmpRoot))
55+
if strings.HasPrefix(dep, tmpRoot) {
56+
if strings.HasPrefix(filepath.Base(dep), "ld-") {
57+
// don't link against ld itself
58+
continue
59+
}
60+
files = append(files, strings.TrimPrefix(dep, tmpRoot))
6261
}
6362
}
6463
err = filepath.Walk(filepath.Join(tmpRoot, "/usr/include"),

deps.bzl

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -589,14 +589,6 @@ def bazeldnf_dependencies():
589589
sum = "h1:LnC5Kc/wtumK+WB441p7ynQJzVuNRJiqddSIE3IlSEQ=",
590590
version = "v0.0.0-20190109142713-0ad062ec5ee5",
591591
)
592-
_maybe(
593-
_go_repository,
594-
name = "com_github_u_root_u_root",
595-
importpath = "github.com/u-root/u-root",
596-
sum = "h1:u+KSS04pSxJGI5E7WE4Bs9+Zd75QjFv+REkjy/aoAc8=",
597-
version = "v7.0.0+incompatible",
598-
)
599-
600592
_maybe(
601593
_go_repository,
602594
name = "com_github_ugorji_go",

go.mod

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ require (
99
github.com/sassoftware/go-rpmutils v0.1.1
1010
github.com/sirupsen/logrus v1.6.0
1111
github.com/spf13/cobra v1.0.0
12-
github.com/u-root/u-root v7.0.0+incompatible
1312
sigs.k8s.io/yaml v1.2.0
1413
)
1514

pkg/ldd/BUILD.bazel

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
load("@io_bazel_rules_go//go:def.bzl", "go_library")
2+
3+
go_library(
4+
name = "ldd",
5+
srcs = ["ldd.go"],
6+
importpath = "github.com/rmohr/bazeldnf/pkg/ldd",
7+
visibility = ["//visibility:public"],
8+
)

pkg/ldd/ldd.go

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
package ldd
2+
3+
import (
4+
"debug/elf"
5+
"os"
6+
"path/filepath"
7+
)
8+
9+
func Resolve(objects []string, library_path string) (finalFiles []string, err error) {
10+
discovered := map[string]struct{}{}
11+
for _, obj := range objects {
12+
if files, err := resolve(obj, library_path); err != nil {
13+
return nil, err
14+
} else {
15+
for _, l := range files {
16+
if _, exists := discovered[l]; !exists {
17+
discovered[l] = struct{}{}
18+
finalFiles = append(finalFiles, l)
19+
}
20+
}
21+
}
22+
}
23+
return
24+
}
25+
26+
func resolve(library string, library_path string) ([]string, error) {
27+
28+
next := []string{library}
29+
processed := map[string]struct{}{}
30+
31+
finalFiles := []string{}
32+
for {
33+
if len(next) == 0 {
34+
break
35+
}
36+
if d, err := ldd(next[0], library_path); err != nil {
37+
return nil, err
38+
} else {
39+
for _, l := range d {
40+
if _, exists := processed[l]; !exists {
41+
next = append(next, l)
42+
processed[l] = struct{}{}
43+
finalFiles = append(finalFiles, l)
44+
}
45+
}
46+
if len(next) > 1 {
47+
next = next[1 : len(next)-1]
48+
} else {
49+
next = []string{}
50+
}
51+
}
52+
}
53+
54+
finalFiles = append(finalFiles, library)
55+
symlinks, err := followSymlinks(library)
56+
if err != nil {
57+
return nil, err
58+
}
59+
finalFiles = append(finalFiles, symlinks...)
60+
61+
return finalFiles, nil
62+
}
63+
64+
func ldd(library string, library_path string) (discovered []string, err error) {
65+
bin, err := elf.Open(library)
66+
if err != nil {
67+
return nil, err
68+
}
69+
libs, err := bin.ImportedLibraries()
70+
if err != nil {
71+
return nil, err
72+
}
73+
for _, l := range libs {
74+
_, err := os.Stat(filepath.Join(library_path, l))
75+
if err != nil {
76+
return nil, err
77+
}
78+
discovered = append(discovered, filepath.Join(library_path, l))
79+
symlinks, err := followSymlinks(filepath.Join(library_path, l))
80+
if err != nil {
81+
return nil, err
82+
}
83+
discovered = append(discovered, symlinks...)
84+
}
85+
return discovered, nil
86+
}
87+
88+
func followSymlinks(file string) (files []string, err error) {
89+
dir := filepath.Dir(file)
90+
for {
91+
info, err := os.Lstat(file)
92+
if err != nil {
93+
return nil, err
94+
}
95+
if info.Mode()&os.ModeSymlink == os.ModeSymlink {
96+
file, err = os.Readlink(file)
97+
if err != nil {
98+
return nil, err
99+
}
100+
if !filepath.IsAbs(file) {
101+
file = filepath.Join(dir, file)
102+
}
103+
files = append(files, file)
104+
} else {
105+
files = append(files, file)
106+
break
107+
}
108+
}
109+
return
110+
}

0 commit comments

Comments
 (0)