[ELF] Refactor the way we handle -plugin-opt= (GCC collect2 or clang LTO related...
authorFangrui Song <maskray@google.com>
Tue, 14 Apr 2020 21:17:29 +0000 (14:17 -0700)
committerFangrui Song <maskray@google.com>
Wed, 15 Apr 2020 15:00:50 +0000 (08:00 -0700)
GCC collect2 passes several options to the linker even if LTO is not used
(note, lld does not support GCC LTO). The lto-wrapper may be a relative
path (especially during development, when gcc is in a build directory), e.g.

  -plugin-opt=relative/path/to/lto-wrapper

We need to ignore such options, which are currently interpreted by
cl::ParseCommandLineOptions() and will fail with `error: --plugin-opt: ld.lld: Unknown command line argument 'relative/path/to/lto-wrapper'`
because the path is apparently not an option registered by an `llvm::cl::opt`.

See lto-plugin-ignore.s for how we interpret various -plugin-opt= options now.

Reviewed By: grimar, tejohnson

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

lld/ELF/Driver.cpp
lld/ELF/Options.td
lld/test/ELF/lto-plugin-ignore.s

index 2aeeb84..d223ed4 100644 (file)
@@ -1035,8 +1035,16 @@ static void readConfigs(opt::InputArgList &args) {
     parseClangOption(saver.save("-mcpu=" + StringRef(arg->getValue())),
                      arg->getSpelling());
 
-  for (auto *arg : args.filtered(OPT_plugin_opt))
-    parseClangOption(arg->getValue(), arg->getSpelling());
+  for (opt::Arg *arg : args.filtered(OPT_plugin_opt_eq_minus))
+    parseClangOption(std::string("-") + arg->getValue(), arg->getSpelling());
+
+  // GCC collect2 passes -plugin-opt=path/to/lto-wrapper with an absolute or
+  // relative path. Just ignore. If not ended with "lto-wrapper", consider it an
+  // unsupported LLVMgold.so option and error.
+  for (opt::Arg *arg : args.filtered(OPT_plugin_opt_eq))
+    if (!StringRef(arg->getValue()).endswith("lto-wrapper"))
+      error(arg->getSpelling() + ": unknown plugin option '" + arg->getValue() +
+            "'");
 
   // Parse -mllvm options.
   for (auto *arg : args.filtered(OPT_mllvm))
index 83b9fa4..8dd5251 100644 (file)
@@ -504,7 +504,6 @@ def opt_remarks_with_hotness: Flag<["--"], "opt-remarks-with-hotness">,
   HelpText<"Include hotness information in the optimization remarks file">;
 def opt_remarks_format: Separate<["--"], "opt-remarks-format">,
   HelpText<"The format used for serializing remarks (default: YAML)">;
-defm plugin_opt: Eq<"plugin-opt", "specifies LTO options for compatibility with GNU linkers">;
 def save_temps: F<"save-temps">;
 def lto_basicblock_sections: J<"lto-basicblock-sections=">,
   HelpText<"Enable basic block sections for LTO">;
@@ -571,10 +570,17 @@ def: J<"plugin-opt=thinlto-prefix-replace=">,
 // --version output.
 defm plugin: Eq<"plugin", "Ignored for compatibility with GNU linkers">;
 
-def plugin_opt_fresolution_eq: J<"plugin-opt=-fresolution=">;
-def plugin_opt_pass_through_eq: J<"plugin-opt=-pass-through=">;
-def plugin_opt_thinlto: J<"plugin-opt=thinlto">;
-def plugin_opt_slash: J<"plugin-opt=/">;
+def plugin_opt_eq_minus: J<"plugin-opt=-">,
+  HelpText<"Specify an LLVM option for compatibility with LLVMgold.so">;
+def: J<"plugin-opt=thinlto">;
+
+// Ignore GCC collect2 LTO plugin related options. Note that we don't support
+// GCC LTO, but GCC collect2 passes these options even in non-LTO mode.
+def: J<"plugin-opt=-fresolution=">;
+def: J<"plugin-opt=-pass-through=">;
+// This may be either an unhandled LLVMgold.so feature or GCC passed
+// -plugin-opt=path/to/{liblto_plugin.so,lto-wrapper}
+def plugin_opt_eq : J<"plugin-opt=">;
 
 // Options listed below are silently ignored for now for compatibility.
 def: F<"detect-odr-violations">;
index 0370d45..2935bad 100644 (file)
@@ -1,10 +1,28 @@
 # REQUIRES: x86
+## Test we ignore some LTO related options from clang/GCC collect2.
 
-# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
-# RUN: ld.lld %t -plugin-opt=/foo/bar -plugin-opt=-fresolution=zed \
-# RUN:   -plugin-opt=-pass-through=-lgcc -plugin-opt=-function-sections \
-# RUN:   -plugin-opt=-data-sections -plugin-opt=thinlto -o /dev/null
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o
 
-# RUN: not ld.lld %t -plugin-opt=-abc -plugin-opt=-xyz 2>&1 | FileCheck %s
-# CHECK: ld.lld: error: --plugin-opt: ld.lld{{.*}}: Unknown command line argument '-abc'
-# CHECK: ld.lld: error: --plugin-opt: ld.lld{{.*}}: Unknown command line argument '-xyz'
+## GCC collect2 passes several LTO related options to the linker even if -flto is not used.
+## We need to ignore them. Note that the lto-wrapper path can be relative.
+# RUN: ld.lld %t.o -o /dev/null \
+# RUN:   -plugin path/to/liblto_plugin.so \
+# RUN:   -plugin-opt=/path/to/lto-wrapper \
+# RUN:   -plugin-opt=relative/path/to/lto-wrapper \
+# RUN:   -plugin-opt=-fresolution=zed \
+# RUN:   -plugin-opt=-pass-through=-lgcc \
+# RUN:   -plugin-opt=-pass-through=-lgcc_eh \
+# RUN:   -plugin-opt=-pass-through=-lc
+
+## Clang LTO passes several options to the linker, which are intended to be consumed by
+## LLVMgold.so. We need to ignore them.
+# RUN: ld.lld %t.o -o /dev/null -plugin /path/to/LLVMgold.so -plugin-opt=thinlto
+
+## Other -plugin-opt=- prefixed options are passed through to cl::ParseCommandLineOptions.
+# RUN: not ld.lld %t.o -o /dev/null -plugin-opt=-abc -plugin-opt=-xyz 2>&1 | FileCheck %s
+# CHECK: ld.lld: error: -plugin-opt=-: ld.lld{{.*}}: Unknown command line argument '-abc'
+# CHECK: ld.lld: error: -plugin-opt=-: ld.lld{{.*}}: Unknown command line argument '-xyz'
+
+## Error if the option is an unhandled LLVMgold.so feature.
+# RUN: not ld.lld %t.o -o /dev/null -plugin-opt=LLVMgold-feature 2>&1 | FileCheck --check-prefix=GOLD %s
+# GOLD: ld.lld: error: -plugin-opt=: unknown plugin option 'LLVMgold-feature'