Skip to content

Commit e43f0fe

Browse files
committed
Forward #pragma comment(lib/linker) through as flags metadata
Summary: Most of this change is wiring the pragma all the way through from the lexer, parser, and sema to codegen. I considered adding a Decl AST node for this, but it seemed too heavyweight. Mach-O already uses a metadata flag called "Linker Options" to do this kind of auto-linking. This change follows that pattern. LLVM knows how to forward the "Linker Options" metadata into the COFF .drectve section where these flags belong. ELF support is not implemented, but possible. This is related to auto-linking, which is http://llvm.org/PR13016. CC: cfe-commits Differential Revision: http://llvm-reviews.chandlerc.com/D723 llvm-svn: 181426
1 parent 7bbd7aa commit e43f0fe

File tree

14 files changed

+163
-27
lines changed

14 files changed

+163
-27
lines changed

clang/include/clang/AST/ASTConsumer.h

+11
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
#ifndef LLVM_CLANG_AST_ASTCONSUMER_H
1515
#define LLVM_CLANG_AST_ASTCONSUMER_H
1616

17+
#include "llvm/ADT/StringRef.h"
18+
1719
namespace clang {
1820
class ASTContext;
1921
class CXXRecordDecl;
@@ -86,6 +88,15 @@ class ASTConsumer {
8688
/// The default implementation passes it to HandleTopLevelDecl.
8789
virtual void HandleImplicitImportDecl(ImportDecl *D);
8890

91+
/// \brief Handle a pragma that appends to Linker Options. Currently this
92+
/// only exists to support Microsoft's #pragma comment(linker, "/foo").
93+
virtual void HandleLinkerOptionPragma(llvm::StringRef Opts) {}
94+
95+
/// \brief Handle a dependent library created by a pragma in the source.
96+
/// Currently this only exists to support Microsoft's
97+
/// #pragma comment(lib, "/foo").
98+
virtual void HandleDependentLibrary(llvm::StringRef Lib) {}
99+
89100
/// CompleteTentativeDefinition - Callback invoked at the end of a translation
90101
/// unit to notify the consumer that the given tentative definition should be
91102
/// completed.

clang/include/clang/Parse/Parser.h

+4
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,10 @@ class Parser : public CodeCompletionHandler {
418418
/// #pragma ms_struct...
419419
void HandlePragmaMSStruct();
420420

421+
/// \brief Handle the annotation token produced for
422+
/// #pragma comment...
423+
void HandlePragmaMSComment();
424+
421425
/// \brief Handle the annotation token produced for
422426
/// #pragma align...
423427
void HandlePragmaAlign();

clang/include/clang/Sema/Sema.h

+13
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
#include "llvm/MC/MCParser/MCAsmParser.h"
5050
#include <deque>
5151
#include <string>
52+
#include <vector>
5253

5354
namespace llvm {
5455
class APSInt;
@@ -6584,6 +6585,15 @@ class Sema {
65846585
PMSST_ON // #pragms ms_struct on
65856586
};
65866587

6588+
enum PragmaMSCommentKind {
6589+
PCK_Unknown,
6590+
PCK_Linker, // #pragma comment(linker, ...)
6591+
PCK_Lib, // #pragma comment(lib, ...)
6592+
PCK_Compiler, // #pragma comment(compiler, ...)
6593+
PCK_ExeStr, // #pragma comment(exestr, ...)
6594+
PCK_User // #pragma comment(user, ...)
6595+
};
6596+
65876597
/// ActOnPragmaPack - Called on well formed \#pragma pack(...).
65886598
void ActOnPragmaPack(PragmaPackKind Kind,
65896599
IdentifierInfo *Name,
@@ -6595,6 +6605,9 @@ class Sema {
65956605
/// ActOnPragmaMSStruct - Called on well formed \#pragma ms_struct [on|off].
65966606
void ActOnPragmaMSStruct(PragmaMSStructKind Kind);
65976607

6608+
/// ActOnPragmaMSStruct - Called on well formed \#pragma comment(kind, "arg").
6609+
void ActOnPragmaMSComment(PragmaMSCommentKind Kind, StringRef Arg);
6610+
65986611
/// ActOnPragmaUnused - Called on well-formed '\#pragma unused'.
65996612
void ActOnPragmaUnused(const Token &Identifier,
66006613
Scope *curScope,

clang/lib/CodeGen/CodeGenAction.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,14 @@ namespace clang {
179179
Gen->HandleVTable(RD, DefinitionRequired);
180180
}
181181

182+
virtual void HandleLinkerOptionPragma(llvm::StringRef Opts) {
183+
Gen->HandleLinkerOptionPragma(Opts);
184+
}
185+
186+
virtual void HandleDependentLibrary(llvm::StringRef Opts) {
187+
Gen->HandleDependentLibrary(Opts);
188+
}
189+
182190
static void InlineAsmDiagHandler(const llvm::SMDiagnostic &SM,void *Context,
183191
unsigned LocCookie) {
184192
SourceLocation Loc = SourceLocation::getFromRawEncoding(LocCookie);

clang/lib/CodeGen/CodeGenModule.cpp

+30-15
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,8 @@ void CodeGenModule::Release() {
186186
EmitStaticExternCAliases();
187187
EmitLLVMUsed();
188188

189-
if (CodeGenOpts.Autolink && Context.getLangOpts().Modules) {
189+
if (CodeGenOpts.Autolink &&
190+
(Context.getLangOpts().Modules || !LinkerOptionsMetadata.empty())) {
190191
EmitModuleLinkOptions();
191192
}
192193

@@ -762,31 +763,41 @@ void CodeGenModule::EmitLLVMUsed() {
762763
GV->setSection("llvm.metadata");
763764
}
764765

766+
void CodeGenModule::AppendLinkerOptions(StringRef Opts) {
767+
llvm::Value *MDOpts = llvm::MDString::get(getLLVMContext(), Opts);
768+
LinkerOptionsMetadata.push_back(llvm::MDNode::get(getLLVMContext(), MDOpts));
769+
}
770+
771+
void CodeGenModule::AddDependentLib(StringRef Lib) {
772+
llvm::SmallString<24> Opt;
773+
getTargetCodeGenInfo().getDependentLibraryOption(Lib, Opt);
774+
llvm::Value *MDOpts = llvm::MDString::get(getLLVMContext(), Opt);
775+
LinkerOptionsMetadata.push_back(llvm::MDNode::get(getLLVMContext(), MDOpts));
776+
}
777+
765778
/// \brief Add link options implied by the given module, including modules
766779
/// it depends on, using a postorder walk.
767-
static void addLinkOptionsPostorder(llvm::LLVMContext &Context,
780+
static void addLinkOptionsPostorder(CodeGenModule &CGM,
768781
Module *Mod,
769782
SmallVectorImpl<llvm::Value *> &Metadata,
770783
llvm::SmallPtrSet<Module *, 16> &Visited) {
771784
// Import this module's parent.
772785
if (Mod->Parent && Visited.insert(Mod->Parent)) {
773-
addLinkOptionsPostorder(Context, Mod->Parent, Metadata, Visited);
786+
addLinkOptionsPostorder(CGM, Mod->Parent, Metadata, Visited);
774787
}
775788

776789
// Import this module's dependencies.
777790
for (unsigned I = Mod->Imports.size(); I > 0; --I) {
778791
if (Visited.insert(Mod->Imports[I-1]))
779-
addLinkOptionsPostorder(Context, Mod->Imports[I-1], Metadata, Visited);
792+
addLinkOptionsPostorder(CGM, Mod->Imports[I-1], Metadata, Visited);
780793
}
781794

782795
// Add linker options to link against the libraries/frameworks
783796
// described by this module.
797+
llvm::LLVMContext &Context = CGM.getLLVMContext();
784798
for (unsigned I = Mod->LinkLibraries.size(); I > 0; --I) {
785-
// FIXME: -lfoo is Unix-centric and -framework Foo is Darwin-centric.
786-
// We need to know more about the linker to know how to encode these
787-
// options propertly.
788-
789-
// Link against a framework.
799+
// Link against a framework. Frameworks are currently Darwin only, so we
800+
// don't to ask TargetCodeGenInfo for the spelling of the linker option.
790801
if (Mod->LinkLibraries[I-1].IsFramework) {
791802
llvm::Value *Args[2] = {
792803
llvm::MDString::get(Context, "-framework"),
@@ -798,9 +809,10 @@ static void addLinkOptionsPostorder(llvm::LLVMContext &Context,
798809
}
799810

800811
// Link against a library.
801-
llvm::Value *OptString
802-
= llvm::MDString::get(Context,
803-
"-l" + Mod->LinkLibraries[I-1].Library);
812+
llvm::SmallString<24> Opt;
813+
CGM.getTargetCodeGenInfo().getDependentLibraryOption(
814+
Mod->LinkLibraries[I-1].Library, Opt);
815+
llvm::Value *OptString = llvm::MDString::get(Context, Opt);
804816
Metadata.push_back(llvm::MDNode::get(Context, OptString));
805817
}
806818
}
@@ -852,20 +864,23 @@ void CodeGenModule::EmitModuleLinkOptions() {
852864
}
853865

854866
// Add link options for all of the imported modules in reverse topological
855-
// order.
867+
// order. We don't do anything to try to order import link flags with respect
868+
// to linker options inserted by things like #pragma comment().
856869
SmallVector<llvm::Value *, 16> MetadataArgs;
857870
Visited.clear();
858871
for (llvm::SetVector<clang::Module *>::iterator M = LinkModules.begin(),
859872
MEnd = LinkModules.end();
860873
M != MEnd; ++M) {
861874
if (Visited.insert(*M))
862-
addLinkOptionsPostorder(getLLVMContext(), *M, MetadataArgs, Visited);
875+
addLinkOptionsPostorder(*this, *M, MetadataArgs, Visited);
863876
}
864877
std::reverse(MetadataArgs.begin(), MetadataArgs.end());
878+
LinkerOptionsMetadata.append(MetadataArgs.begin(), MetadataArgs.end());
865879

866880
// Add the linker options metadata flag.
867881
getModule().addModuleFlag(llvm::Module::AppendUnique, "Linker Options",
868-
llvm::MDNode::get(getLLVMContext(), MetadataArgs));
882+
llvm::MDNode::get(getLLVMContext(),
883+
LinkerOptionsMetadata));
869884
}
870885

871886
void CodeGenModule::EmitDeferred() {

clang/lib/CodeGen/CodeGenModule.h

+9
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,9 @@ class CodeGenModule : public CodeGenTypeCache {
355355
/// \brief The complete set of modules that has been imported.
356356
llvm::SetVector<clang::Module *> ImportedModules;
357357

358+
/// \brief A vector of metadata strings.
359+
SmallVector<llvm::Value *, 16> LinkerOptionsMetadata;
360+
358361
/// @name Cache for Objective-C runtime types
359362
/// @{
360363

@@ -906,6 +909,12 @@ class CodeGenModule : public CodeGenTypeCache {
906909

907910
void EmitVTable(CXXRecordDecl *Class, bool DefinitionRequired);
908911

912+
/// \brief Appends Opts to the "Linker Options" metadata value.
913+
void AppendLinkerOptions(StringRef Opts);
914+
915+
/// \brief Appends a dependent lib to the "Linker Options" metadata value.
916+
void AddDependentLib(StringRef Lib);
917+
909918
llvm::GlobalVariable::LinkageTypes
910919
getFunctionLinkage(const FunctionDecl *FD);
911920

clang/lib/CodeGen/ModuleBuilder.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "clang/Basic/TargetInfo.h"
2121
#include "clang/Frontend/CodeGenOptions.h"
2222
#include "llvm/ADT/OwningPtr.h"
23+
#include "llvm/ADT/StringRef.h"
2324
#include "llvm/IR/DataLayout.h"
2425
#include "llvm/IR/LLVMContext.h"
2526
#include "llvm/IR/Module.h"
@@ -115,6 +116,14 @@ namespace {
115116

116117
Builder->EmitVTable(RD, DefinitionRequired);
117118
}
119+
120+
virtual void HandleLinkerOptionPragma(llvm::StringRef Opts) {
121+
Builder->AppendLinkerOptions(Opts);
122+
}
123+
124+
virtual void HandleDependentLibrary(llvm::StringRef Lib) {
125+
Builder->AddDependentLib(Lib);
126+
}
118127
};
119128
}
120129

clang/lib/CodeGen/TargetInfo.cpp

+30-2
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,16 @@ bool TargetCodeGenInfo::isNoProtoCallVariadic(const CallArgList &args,
143143
return false;
144144
}
145145

146+
void
147+
TargetCodeGenInfo::getDependentLibraryOption(llvm::StringRef Lib,
148+
llvm::SmallString<24> &Opt) const {
149+
// This assumes the user is passing a library name like "rt" instead of a
150+
// filename like "librt.a/so", and that they don't care whether it's static or
151+
// dynamic.
152+
Opt = "-l";
153+
Opt += Lib;
154+
}
155+
146156
static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays);
147157

148158
/// isEmptyField - Return true iff a the field is "empty", that is it
@@ -1256,6 +1266,18 @@ class X86_64TargetCodeGenInfo : public TargetCodeGenInfo {
12561266

12571267
};
12581268

1269+
class WinX86_32TargetCodeGenInfo : public X86_32TargetCodeGenInfo {
1270+
public:
1271+
WinX86_32TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned RegParms)
1272+
: X86_32TargetCodeGenInfo(CGT, false, true, true, RegParms) {}
1273+
1274+
void getDependentLibraryOption(llvm::StringRef Lib,
1275+
llvm::SmallString<24> &Opt) const {
1276+
Opt = "/DEFAULTLIB:";
1277+
Opt += Lib;
1278+
}
1279+
};
1280+
12591281
class WinX86_64TargetCodeGenInfo : public TargetCodeGenInfo {
12601282
public:
12611283
WinX86_64TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
@@ -1274,6 +1296,12 @@ class WinX86_64TargetCodeGenInfo : public TargetCodeGenInfo {
12741296
AssignToArrayRange(CGF.Builder, Address, Eight8, 0, 16);
12751297
return false;
12761298
}
1299+
1300+
void getDependentLibraryOption(llvm::StringRef Lib,
1301+
llvm::SmallString<24> &Opt) const {
1302+
Opt = "/DEFAULTLIB:";
1303+
Opt += Lib;
1304+
}
12771305
};
12781306

12791307
}
@@ -5173,8 +5201,8 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() {
51735201

51745202
case llvm::Triple::Win32:
51755203
return *(TheTargetCodeGenInfo =
5176-
new X86_32TargetCodeGenInfo(Types, false, true, true,
5177-
CodeGenOpts.NumRegisterParameters));
5204+
new WinX86_32TargetCodeGenInfo(Types,
5205+
CodeGenOpts.NumRegisterParameters));
51785206

51795207
default:
51805208
return *(TheTargetCodeGenInfo =

clang/lib/CodeGen/TargetInfo.h

+6
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "clang/AST/Type.h"
1919
#include "clang/Basic/LLVM.h"
2020
#include "llvm/ADT/StringRef.h"
21+
#include "llvm/ADT/SmallString.h"
2122

2223
namespace llvm {
2324
class GlobalValue;
@@ -167,6 +168,11 @@ namespace clang {
167168
/// that unprototyped calls to varargs functions still succeed.
168169
virtual bool isNoProtoCallVariadic(const CodeGen::CallArgList &args,
169170
const FunctionNoProtoType *fnType) const;
171+
172+
/// Gets the linker options necessary to link a dependent library on this
173+
/// platform.
174+
virtual void getDependentLibraryOption(llvm::StringRef Lib,
175+
llvm::SmallString<24> &Opt) const;
170176
};
171177
}
172178

clang/lib/Parse/ParsePragma.cpp

+16-7
Original file line numberDiff line numberDiff line change
@@ -821,10 +821,16 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP,
821821
}
822822

823823
// Verify that this is one of the 5 whitelisted options.
824-
// FIXME: warn that 'exestr' is deprecated.
825-
const IdentifierInfo *II = Tok.getIdentifierInfo();
826-
if (!II->isStr("compiler") && !II->isStr("exestr") && !II->isStr("lib") &&
827-
!II->isStr("linker") && !II->isStr("user")) {
824+
IdentifierInfo *II = Tok.getIdentifierInfo();
825+
Sema::PragmaMSCommentKind Kind =
826+
llvm::StringSwitch<Sema::PragmaMSCommentKind>(II->getName())
827+
.Case("linker", Sema::PCK_Linker)
828+
.Case("lib", Sema::PCK_Lib)
829+
.Case("compiler", Sema::PCK_Compiler)
830+
.Case("exestr", Sema::PCK_ExeStr)
831+
.Case("user", Sema::PCK_User)
832+
.Default(Sema::PCK_Unknown);
833+
if (Kind == Sema::PCK_Unknown) {
828834
PP.Diag(Tok.getLocation(), diag::err_pragma_comment_unknown_kind);
829835
return;
830836
}
@@ -837,11 +843,12 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP,
837843
/*MacroExpansion=*/true))
838844
return;
839845

846+
// FIXME: warn that 'exestr' is deprecated.
840847
// FIXME: If the kind is "compiler" warn if the string is present (it is
841848
// ignored).
842-
// FIXME: 'lib' requires a comment string.
843-
// FIXME: 'linker' requires a comment string, and has a specific list of
844-
// things that are allowable.
849+
// The MSDN docs say that "lib" and "linker" require a string and have a short
850+
// whitelist of linker options they support, but in practice MSVC doesn't
851+
// issue a diagnostic. Therefore neither does clang.
845852

846853
if (Tok.isNot(tok::r_paren)) {
847854
PP.Diag(Tok.getLocation(), diag::err_pragma_comment_malformed);
@@ -857,4 +864,6 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP,
857864
// If the pragma is lexically sound, notify any interested PPCallbacks.
858865
if (PP.getPPCallbacks())
859866
PP.getPPCallbacks()->PragmaComment(CommentLoc, II, ArgumentString);
867+
868+
Actions.ActOnPragmaMSComment(Kind, ArgumentString);
860869
}

clang/lib/Parse/ParsePragma.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,12 @@ class PragmaOpenMPHandler : public PragmaHandler {
116116
/// PragmaCommentHandler - "\#pragma comment ...".
117117
class PragmaCommentHandler : public PragmaHandler {
118118
public:
119-
PragmaCommentHandler() : PragmaHandler("comment") {}
119+
PragmaCommentHandler(Sema &Actions)
120+
: PragmaHandler("comment"), Actions(Actions) {}
120121
virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
121122
Token &FirstToken);
123+
private:
124+
Sema &Actions;
122125
};
123126

124127
} // end namespace clang

clang/lib/Parse/Parser.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies)
103103
PP.AddPragmaHandler(OpenMPHandler.get());
104104

105105
if (getLangOpts().MicrosoftExt) {
106-
MSCommentHandler.reset(new PragmaCommentHandler());
106+
MSCommentHandler.reset(new PragmaCommentHandler(actions));
107107
PP.AddPragmaHandler(MSCommentHandler.get());
108108
}
109109

0 commit comments

Comments
 (0)