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

Nico Weber via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 2 08:07:16 PDT 2021


Author: Nico Weber
Date: 2021-06-02T11:06:42-04:00
New Revision: 66a1ecd2cf905d6119477516601126f44be297a8

URL: https://github.com/llvm/llvm-project/commit/66a1ecd2cf905d6119477516601126f44be297a8
DIFF: https://github.com/llvm/llvm-project/commit/66a1ecd2cf905d6119477516601126f44be297a8.diff

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

These allow overriding dead_strip_dylibs.

Differential Revision: https://reviews.llvm.org/D103499

Added: 
    

Modified: 
    lld/MachO/Driver.cpp
    lld/MachO/InputFiles.h
    lld/MachO/Options.td
    lld/MachO/Writer.cpp
    lld/test/MachO/dead-strip-dylibs.s

Removed: 
    


################################################################################
diff  --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp
index 3a51fde3cb89..b568609a65e1 100644
--- a/lld/MachO/Driver.cpp
+++ b/lld/MachO/Driver.cpp
@@ -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:

diff  --git a/lld/MachO/InputFiles.h b/lld/MachO/InputFiles.h
index 321ea0e6774f..c26cd0f97622 100644
--- a/lld/MachO/InputFiles.h
+++ b/lld/MachO/InputFiles.h
@@ -156,6 +156,7 @@ class DylibFile : public InputFile {
   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;

diff  --git a/lld/MachO/Options.td b/lld/MachO/Options.td
index cc5ab09ef550..47c6d9997e98 100644
--- a/lld/MachO/Options.td
+++ b/lld/MachO/Options.td
@@ -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">,

diff  --git a/lld/MachO/Writer.cpp b/lld/MachO/Writer.cpp
index 22bb20aa4604..da2ae690c45b 100644
--- a/lld/MachO/Writer.cpp
+++ b/lld/MachO/Writer.cpp
@@ -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;

diff  --git a/lld/test/MachO/dead-strip-dylibs.s b/lld/test/MachO/dead-strip-dylibs.s
index 821c36c565b0..4ea5041c59d6 100644
--- a/lld/test/MachO/dead-strip-dylibs.s
+++ b/lld/test/MachO/dead-strip-dylibs.s
@@ -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


        


More information about the llvm-commits mailing list