From fd4db5331e512d23d2d1c832065acbe226e7616d Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Wed, 7 Feb 2018 01:46:46 +0000 Subject: [PATCH] Support `#pragma comment(lib, "name")` in the frontend for ELF This adds the frontend support required to support the use of the comment pragma to enable auto linking on ELFish targets. This is a generic ELF extension supported by LLVM. We need to change the handling for the "dependentlib" in order to accommodate the previously discussed encoding for the dependent library descriptor. Without the custom handling of the PCK_Lib directive, the -l prefixed option would be encoded into the resulting object (which is treated as a frontend error). llvm-svn: 324438 --- clang/docs/LanguageExtensions.rst | 8 ++++++++ clang/lib/CodeGen/CodeGenModule.cpp | 12 +++++++++++- clang/lib/CodeGen/CodeGenModule.h | 2 ++ clang/lib/Parse/ParsePragma.cpp | 12 ++++++++++-- clang/test/CodeGen/elf-linker-options.c | 7 +++++++ clang/test/CodeGen/pragma-comment.c | 7 +++---- clang/test/Preprocessor/pragma-comment-linux.c | 5 +++++ clang/test/Preprocessor/pragma_microsoft.c | 4 ++-- 8 files changed, 48 insertions(+), 9 deletions(-) create mode 100644 clang/test/CodeGen/elf-linker-options.c create mode 100644 clang/test/Preprocessor/pragma-comment-linux.c diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index 41f161302f2b..6d9bbcbd3a55 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -2725,3 +2725,11 @@ The ``#pragma clang section`` directive obeys the following rules: * The decision about which section-kind applies to each global is taken in the back-end. Once the section-kind is known, appropriate section name, as specified by the user using ``#pragma clang section`` directive, is applied to that global. + +Specifying Linker Options on ELF Targets +======================================== + +The ``#pragma comment(lib, ...)`` directive is supported on all ELF targets. +The second parameter is the library name (without the traditional Unix prefix of +``lib``). This allows you to provide an implicit link of dependent libraries. + diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 760327deb173..b39e0f445c79 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -1411,6 +1411,12 @@ void CodeGenModule::AddDetectMismatch(StringRef Name, StringRef Value) { LinkerOptionsMetadata.push_back(llvm::MDNode::get(getLLVMContext(), MDOpts)); } +void CodeGenModule::AddELFLibDirective(StringRef Lib) { + auto &C = getLLVMContext(); + LinkerOptionsMetadata.push_back(llvm::MDNode::get( + C, {llvm::MDString::get(C, "lib"), llvm::MDString::get(C, Lib)})); +} + void CodeGenModule::AddDependentLib(StringRef Lib) { llvm::SmallString<24> Opt; getTargetCodeGenInfo().getDependentLibraryOption(Lib, Opt); @@ -4329,7 +4335,11 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { AppendLinkerOptions(PCD->getArg()); break; case PCK_Lib: - AddDependentLib(PCD->getArg()); + if (getTarget().getTriple().isOSBinFormatELF() && + !getTarget().getTriple().isPS4()) + AddELFLibDirective(PCD->getArg()); + else + AddDependentLib(PCD->getArg()); break; case PCK_Compiler: case PCK_ExeStr: diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 42e9e1be3166..61b97e61248e 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -1094,6 +1094,8 @@ public: /// value. void AddDependentLib(StringRef Lib); + void AddELFLibDirective(StringRef Lib); + llvm::GlobalVariable::LinkageTypes getFunctionLinkage(GlobalDecl GD); void setFunctionLinkage(GlobalDecl GD, llvm::Function *F) { diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp index 8152176484df..3517264d4e94 100644 --- a/clang/lib/Parse/ParsePragma.cpp +++ b/clang/lib/Parse/ParsePragma.cpp @@ -295,7 +295,8 @@ void Parser::initializePragmaHandlers() { OpenMPHandler.reset(new PragmaNoOpenMPHandler()); PP.AddPragmaHandler(OpenMPHandler.get()); - if (getLangOpts().MicrosoftExt || getTargetInfo().getTriple().isPS4()) { + if (getLangOpts().MicrosoftExt || + getTargetInfo().getTriple().isOSBinFormatELF()) { MSCommentHandler.reset(new PragmaCommentHandler(Actions)); PP.AddPragmaHandler(MSCommentHandler.get()); } @@ -377,7 +378,8 @@ void Parser::resetPragmaHandlers() { PP.RemovePragmaHandler(OpenMPHandler.get()); OpenMPHandler.reset(); - if (getLangOpts().MicrosoftExt || getTargetInfo().getTriple().isPS4()) { + if (getLangOpts().MicrosoftExt || + getTargetInfo().getTriple().isOSBinFormatELF()) { PP.RemovePragmaHandler(MSCommentHandler.get()); MSCommentHandler.reset(); } @@ -2449,6 +2451,12 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP, return; } + if (PP.getTargetInfo().getTriple().isOSBinFormatELF() && Kind != PCK_Lib) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_comment_ignored) + << II->getName(); + return; + } + // On PS4, issue a warning about any pragma comments other than // #pragma comment lib. if (PP.getTargetInfo().getTriple().isPS4() && Kind != PCK_Lib) { diff --git a/clang/test/CodeGen/elf-linker-options.c b/clang/test/CodeGen/elf-linker-options.c new file mode 100644 index 000000000000..cf2d1b92b998 --- /dev/null +++ b/clang/test/CodeGen/elf-linker-options.c @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -triple i686---elf -emit-llvm %s -o - | FileCheck %s + +#pragma comment(lib, "alpha") + +// CHECK: !llvm.linker.options = !{[[NODE:![0-9]+]]} +// CHECK: [[NODE]] = !{!"lib", !"alpha"} + diff --git a/clang/test/CodeGen/pragma-comment.c b/clang/test/CodeGen/pragma-comment.c index fae9b8fb9ed8..1896e5c0fb98 100644 --- a/clang/test/CodeGen/pragma-comment.c +++ b/clang/test/CodeGen/pragma-comment.c @@ -23,10 +23,9 @@ // CHECK: ![[bar]] = !{!" /bar=2"} // CHECK: ![[foo]] = !{!" /foo=\22foo bar\22"} -// LINUX: !{!"-lmsvcrt.lib"} -// LINUX: !{!"-lkernel32"} -// LINUX: !{!"-lUSER32.LIB"} -// LINUX: !{!" /bar=2"} +// LINUX: !{!"lib", !"msvcrt.lib"} +// LINUX: !{!"lib", !"kernel32"} +// LINUX: !{!"lib", !"USER32.LIB"} // PS4: !{!"\01msvcrt.lib"} // PS4: !{!"\01kernel32"} diff --git a/clang/test/Preprocessor/pragma-comment-linux.c b/clang/test/Preprocessor/pragma-comment-linux.c new file mode 100644 index 000000000000..fcac049f46e8 --- /dev/null +++ b/clang/test/Preprocessor/pragma-comment-linux.c @@ -0,0 +1,5 @@ +// RUN: %clang_cc1 -triple i686-unknown-linux-gnu -fsyntax-only -verify %s -Wunknown-pragmas + +#pragma comment(linker, "") +// expected-warning@-1 {{'#pragma comment linker' ignored}} + diff --git a/clang/test/Preprocessor/pragma_microsoft.c b/clang/test/Preprocessor/pragma_microsoft.c index b256b2bee6cf..5d0894327325 100644 --- a/clang/test/Preprocessor/pragma_microsoft.c +++ b/clang/test/Preprocessor/pragma_microsoft.c @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 %s -fsyntax-only -verify -fms-extensions -Wunknown-pragmas -// RUN: not %clang_cc1 %s -fms-extensions -E | FileCheck %s +// RUN: %clang_cc1 -triple i686-unknown-windows-msvc %s -fsyntax-only -verify -fms-extensions -Wunknown-pragmas +// RUN: not %clang_cc1 -triple i686-unknown-windows-msvc %s -fms-extensions -E | FileCheck %s // REQUIRES: non-ps4-sdk // rdar://6495941 -- 2.34.1