Skip to content

Commit 21cfee5

Browse files
committed
Transitively test library dependencies for --no-allow-shlib-undefined
This change is needed to build sci-libs/spqr-2.0.9-r4::gentoo
1 parent 06203c4 commit 21cfee5

File tree

2 files changed

+53
-7
lines changed

2 files changed

+53
-7
lines changed

src/passes.cc

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1113,17 +1113,34 @@ void check_shlib_undefined(Context<E> &ctx) {
11131113
return false;
11141114
};
11151115

1116-
// Obtain a list of known shared library names.
1117-
std::unordered_set<std::string_view> sonames;
1116+
// We want to skip a file that (either directly or indirectly) depends
1117+
// on another .so file we know nothing about. This is because missing
1118+
// symbols might be provided by that unknown file.
1119+
//
1120+
// We need recursion for indirect dependencies.
1121+
std::unordered_map<std::string_view, std::vector<std::string_view>> deps;
11181122
for (std::unique_ptr<SharedFile<E>> &file : ctx.dso_pool)
1119-
sonames.insert(file->soname);
1123+
deps[file->soname] = file->get_dt_needed(ctx);
1124+
1125+
std::function<bool(std::string_view, i64)> can_check;
1126+
can_check = [&](std::string_view soname, i64 depth) -> bool {
1127+
if (depth == deps.size())
1128+
Fatal(ctx) << "--no-allow-shlib-defined: mutually-recursive .so detected: "
1129+
<< soname;
1130+
1131+
auto it = deps.find(soname);
1132+
if (it == deps.end())
1133+
return false;
1134+
for (std::string_view needed : it->second)
1135+
if (!can_check(needed, depth + 1))
1136+
return false;
1137+
return true;
1138+
};
11201139

11211140
tbb::parallel_for_each(ctx.dsos, [&](SharedFile<E> *file) {
11221141
// Skip the file if it depends on a file that we know nothing about.
1123-
// This is because missing symbols may be provided by that unknown file.
1124-
for (std::string_view needed : file->get_dt_needed(ctx))
1125-
if (!sonames.contains(needed))
1126-
return;
1142+
if (!can_check(file->soname, 0))
1143+
return;
11271144

11281145
// Check if all undefined symbols have been resolved.
11291146
for (i64 i = 0; i < file->elf_syms.size(); i++) {

test/no-allow-shlib-undefined3.sh

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#!/bin/bash
2+
. $(dirname $0)/common.inc
3+
4+
cat <<EOF | $CC -B. -shared -fPIC -o $t/libfoo.so -xc -
5+
void foo() {}
6+
EOF
7+
8+
cat <<EOF | $CC -B. -shared -fPIC -o $t/libbar.so -xc - -L$t -lfoo
9+
void foo();
10+
void bar() { foo(); }
11+
EOF
12+
13+
cat <<EOF | $CC -B. -shared -fPIC -o $t/libbaz.so -xc - -L$t -lbar
14+
void bar();
15+
void baz() { bar(); }
16+
EOF
17+
18+
cat <<EOF | $CC -c -o $t/a.o -c -xc -
19+
int baz();
20+
int main() { baz(); }
21+
EOF
22+
23+
mv $t/libfoo.so $t/libfoo.so.bak
24+
echo | $CC -B. -shared -fPIC -o $t/libfoo.so -xc -
25+
26+
$CC -B. -o $t/exe1 $t/a.o -Wl,--no-allow-shlib-undefined -L$t -lbar -lbaz
27+
28+
not $CC -B. -o $t/exe2 $t/a.o -Wl,--no-allow-shlib-undefined \
29+
-L$t -lfoo -lbar -lbaz |& grep 'no-allow-shlib-undefined: undefined symbol: foo'

0 commit comments

Comments
 (0)