[lld/mac] Implement -needed_framework, -needed_library, -needed-l

These allow overriding dead_strip_dylibs.

Differential Revision: https://reviews.llvm.org/D103499
This commit is contained in:
Nico Weber 2021-06-02 11:06:42 -04:00
parent e14fd7d879
commit 66a1ecd2cf
5 changed files with 48 additions and 14 deletions

View File

@ -326,11 +326,13 @@ static InputFile *addFile(StringRef path, bool forceLoadArchive,
return newFile;
}
static void addLibrary(StringRef name, bool isWeak, bool isReexport,
bool isExplicit) {
static void addLibrary(StringRef name, bool isNeeded, bool isWeak,
bool isReexport, bool isExplicit) {
if (Optional<StringRef> path = findLibrary(name)) {
if (auto *dylibFile = dyn_cast_or_null<DylibFile>(
addFile(*path, /*forceLoadArchive=*/false, isExplicit))) {
if (isNeeded)
dylibFile->forceNeeded = true;
if (isWeak)
dylibFile->forceWeakImport = true;
if (isReexport) {
@ -343,11 +345,13 @@ static void addLibrary(StringRef name, bool isWeak, bool isReexport,
error("library not found for -l" + name);
}
static void addFramework(StringRef name, bool isWeak, bool isReexport,
bool isExplicit) {
static void addFramework(StringRef name, bool isNeeded, bool isWeak,
bool isReexport, bool isExplicit) {
if (Optional<std::string> path = findFramework(name)) {
if (auto *dylibFile = dyn_cast_or_null<DylibFile>(
addFile(*path, /*forceLoadArchive=*/false, isExplicit))) {
if (isNeeded)
dylibFile->forceNeeded = true;
if (isWeak)
dylibFile->forceWeakImport = true;
if (isReexport) {
@ -383,12 +387,12 @@ void macho::parseLCLinkerOption(InputFile *f, unsigned argc, StringRef data) {
for (const Arg *arg : args) {
switch (arg->getOption().getID()) {
case OPT_l:
addLibrary(arg->getValue(), /*isWeak=*/false, /*isReexport=*/false,
/*isExplicit=*/false);
addLibrary(arg->getValue(), /*isNeeded=*/false, /*isWeak=*/false,
/*isReexport=*/false, /*isExplicit=*/false);
break;
case OPT_framework:
addFramework(arg->getValue(), /*isWeak=*/false, /*isReexport=*/false,
/*isExplicit=*/false);
addFramework(arg->getValue(), /*isNeeded=*/false, /*isWeak=*/false,
/*isReexport=*/false, /*isExplicit=*/false);
break;
default:
error(arg->getSpelling() + " is not allowed in LC_LINKER_OPTION");
@ -880,6 +884,11 @@ void createFiles(const InputArgList &args) {
case OPT_INPUT:
addFile(rerootPath(arg->getValue()), /*forceLoadArchive=*/false);
break;
case OPT_needed_library:
if (auto *dylibFile = dyn_cast_or_null<DylibFile>(
addFile(rerootPath(arg->getValue()), false)))
dylibFile->forceNeeded = true;
break;
case OPT_reexport_library:
if (auto *dylibFile = dyn_cast_or_null<DylibFile>(addFile(
rerootPath(arg->getValue()), /*forceLoadArchive=*/false))) {
@ -899,15 +908,19 @@ void createFiles(const InputArgList &args) {
addFile(rerootPath(arg->getValue()), /*forceLoadArchive=*/true);
break;
case OPT_l:
case OPT_needed_l:
case OPT_reexport_l:
case OPT_weak_l:
addLibrary(arg->getValue(), opt.getID() == OPT_weak_l,
opt.getID() == OPT_reexport_l, /*isExplicit=*/true);
addLibrary(arg->getValue(), opt.getID() == OPT_needed_l,
opt.getID() == OPT_weak_l, opt.getID() == OPT_reexport_l,
/*isExplicit=*/true);
break;
case OPT_framework:
case OPT_needed_framework:
case OPT_reexport_framework:
case OPT_weak_framework:
addFramework(arg->getValue(), opt.getID() == OPT_weak_framework,
addFramework(arg->getValue(), opt.getID() == OPT_needed_framework,
opt.getID() == OPT_weak_framework,
opt.getID() == OPT_reexport_framework, /*isExplicit=*/true);
break;
default:

View File

@ -156,6 +156,7 @@ public:
int64_t ordinal = 0; // Ordinal numbering starts from 1, so 0 is a sentinel
RefState refState;
bool reexport = false;
bool forceNeeded = false;
bool forceWeakImport = false;
bool deadStrippable = false;
bool explicitlyLinked = false;

View File

@ -114,6 +114,14 @@ def weak_library : Separate<["-"], "weak_library">,
MetaVarName<"<path>">,
HelpText<"Like bare <path>, but mark library and its references as weak imports">,
Group<grp_libs>;
def needed_l : Joined<["-"], "needed-l">,
MetaVarName<"<name>">,
HelpText<"Like -l<name>, but link library even if its symbols are not used and -dead_strip_dylibs is active">,
Group<grp_libs>;
def needed_library : Separate<["-"], "needed_library">,
MetaVarName<"<path>">,
HelpText<"Like bare <path>, but link library even if its symbols are not used and -dead_strip_dylibs is active">,
Group<grp_libs>;
def reexport_l : Joined<["-"], "reexport-l">,
MetaVarName<"<name>">,
HelpText<"Like -l<name>, but export all symbols of <name> from newly created library">,
@ -157,6 +165,10 @@ def weak_framework : Separate<["-"], "weak_framework">,
MetaVarName<"<name>">,
HelpText<"Like -framework <name>, but mark framework and its references as weak imports">,
Group<grp_libs>;
def needed_framework : Separate<["-"], "needed_framework">,
MetaVarName<"<name>">,
HelpText<"Like -framework <name>, but link <name> even if none of its symbols are used and -dead_strip_dylibs is active">,
Group<grp_libs>;
def reexport_framework : Separate<["-"], "reexport_framework">,
MetaVarName<"<name>">,
HelpText<"Like -framework <name>, but export all symbols of <name> from the newly created library">,

View File

@ -697,7 +697,7 @@ template <class LP> void Writer::createLoadCommands() {
// FIXME: `isReferenced()` is currently computed before dead code
// stripping, so references from dead code keep a dylib alive. This
// matches ld64, but it's something we should do better.
if (!dylibFile->isReferenced() &&
if (!dylibFile->isReferenced() && !dylibFile->forceNeeded &&
(!dylibFile->explicitlyLinked || dylibFile->deadStrippable ||
config->deadStripDylibs))
continue;

View File

@ -4,6 +4,7 @@
# RUN: llvm-mc %t/bar.s -triple=x86_64-apple-macos -filetype=obj -o %t/bar.o
# RUN: %lld -dylib %t/bar.o -o %t/bar.dylib
# RUN: %lld -dylib %t/bar.o -o %t/libbar.dylib
# RUN: %lld -dylib -mark_dead_strippable_dylib %t/bar.o -o %t/bar-strip.dylib
# RUN: llvm-mc %t/foo.s -triple=x86_64-apple-macos -filetype=obj -o %t/foo.o
@ -36,7 +37,7 @@
# RUN: -dead_strip_dylibs
# RUN: llvm-otool -L %t/main | FileCheck --check-prefix=NOBAR %s
## ...or bar is explicitly marked dead-strippable
## ...or bar is explicitly marked dead-strippable.
# RUN: %lld -lSystem %t/main.o -o %t/main %t/foo.dylib %t/bar-strip.dylib
# RUN: llvm-otool -L %t/main | FileCheck --check-prefix=NOBARSTRIP %s
# NOBARSTRIP-NOT: bar-strip.dylib
@ -45,9 +46,16 @@
# NOBARSTRIP: foo.dylib
# NOBARSTRIP-NOT: bar-strip.dylib
## But -needed_library and -needed-l win over -dead_strip_dylibs again.
# RUN: %lld -lSystem %t/main.o -o %t/main %t/foo_with_bar.dylib \
# RUN: -needed_library %t/bar.dylib -dead_strip_dylibs
# RUN: llvm-otool -L %t/main | FileCheck --check-prefix=BAR %s
# RUN: %lld -lSystem %t/main.o -o %t/main %t/foo_with_bar.dylib \
# RUN: -L%t -needed-lbar -dead_strip_dylibs
# RUN: llvm-otool -L %t/main | FileCheck --check-prefix=BAR %s
## LC_LINKER_OPTION does not count as an explicit reference.
# RUN: llvm-mc %t/linkopt_bar.s -triple=x86_64-apple-macos -filetype=obj -o %t/linkopt_bar.o
# RUN: %lld -dylib %t/bar.o -o %t/libbar.dylib
# RUN: %lld -lSystem %t/main.o %t/linkopt_bar.o -o %t/main -L %t %t/foo.dylib
# RUN: llvm-otool -L %t/main | FileCheck --check-prefix=NOLIBBAR %s
# NOLIBBAR-NOT: libbar.dylib