diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td index 3c036a3e65df4a2e6e1a3a45910f7b73ffff8e9b..b9dbaf2e9e35595e06e9f311113f2e4b618b143f 100644 --- a/include/clang/Basic/DiagnosticLexKinds.td +++ b/include/clang/Basic/DiagnosticLexKinds.td @@ -486,6 +486,8 @@ def err_mmap_umbrella_clash : Error< "umbrella for module '%0' already covers this directory">; def err_mmap_export_module_id : Error< "expected an exported module name or '*'">; +def err_mmap_expected_library_name : Error< + "expected %select{library|framework}0 name as a string">; def err_mmap_missing_module_unqualified : Error< "no module named '%0' visible from '%1'">; def err_mmap_missing_module_qualified : Error< diff --git a/include/clang/Basic/Module.h b/include/clang/Basic/Module.h index b638068e7434d12aa19221e69b0f81444bbced7f..2bda801d188dc33a5b09c17e5c3abe65ad9b3e3f 100644 --- a/include/clang/Basic/Module.h +++ b/include/clang/Basic/Module.h @@ -164,7 +164,28 @@ public: /// \brief The set of export declarations that have yet to be resolved. SmallVector<UnresolvedExportDecl, 2> UnresolvedExports; - + + /// \brief A library or framework to link against when an entity from this + /// module is used. + struct LinkLibrary { + LinkLibrary() : IsFramework(false) { } + LinkLibrary(const std::string &Library, bool IsFramework) + : Library(Library), IsFramework(IsFramework) { } + + /// \brief The library to link against. + /// + /// This will typically be a library or framework name, but can also + /// be an absolute path to the library or framework. + std::string Library; + + /// \brief Whether this is a framework rather than a library. + bool IsFramework; + }; + + /// \brief The set of libraries or frameworks to link against when + /// an entity from this module is used. + llvm::SmallVector<LinkLibrary, 2> LinkLibraries; + /// \brief Construct a top-level module. explicit Module(StringRef Name, SourceLocation DefinitionLoc, bool IsFramework) diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index 2dbe136e893c1d2bfcb1dd4684fc7fdf256e7968..a9386972630987557aa5df749243acd7ed6d1194 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -603,7 +603,9 @@ namespace clang { SUBMODULE_REQUIRES = 8, /// \brief Specifies a header that has been explicitly excluded /// from this submodule. - SUBMODULE_EXCLUDED_HEADER = 9 + SUBMODULE_EXCLUDED_HEADER = 9, + /// \brief Specifies a library or framework to link against. + SUBMODULE_LINK_LIBRARY = 10 }; /// \brief Record types used within a comments block. diff --git a/lib/Basic/Module.cpp b/lib/Basic/Module.cpp index 417c7e57453e9be267b1d1ba85d4fb4361e45798..5e5e431d3117e14f4353c31df310b62bd0b5eb81 100644 --- a/lib/Basic/Module.cpp +++ b/lib/Basic/Module.cpp @@ -257,6 +257,16 @@ void Module::print(raw_ostream &OS, unsigned Indent) const { OS << "\n"; } + for (unsigned I = 0, N = LinkLibraries.size(); I != N; ++I) { + OS.indent(Indent + 2); + OS << "link "; + if (LinkLibraries[I].IsFramework) + OS << "framework "; + OS << "\""; + OS.write_escaped(LinkLibraries[I].Library); + OS << "\""; + } + if (InferSubmodules) { OS.indent(Indent + 2); if (InferExplicitSubmodules) diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 0257ce23f61935ee376b1e84cd869529bd429d2c..da37e4982d4b805425c92973c3f9c70b8528ac06 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -32,6 +32,7 @@ #include "clang/Basic/Builtins.h" #include "clang/Basic/ConvertUTF.h" #include "clang/Basic/Diagnostic.h" +#include "clang/Basic/Module.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/Frontend/CodeGenOptions.h" @@ -172,7 +173,8 @@ void CodeGenModule::Release() { EmitCtorList(GlobalDtors, "llvm.global_dtors"); EmitGlobalAnnotations(); EmitLLVMUsed(); - + EmitLinkLibraries(); + SimplifyPersonality(); if (getCodeGenOpts().EmitDeclMetadata) @@ -714,6 +716,24 @@ void CodeGenModule::EmitLLVMUsed() { GV->setSection("llvm.metadata"); } +void CodeGenModule::EmitLinkLibraries() { + // If there are no libraries to link against, do nothing. + if (LinkLibraries.empty()) + return; + + // Create metadata for each library we're linking against. + llvm::NamedMDNode *Metadata + = getModule().getOrInsertNamedMetadata("llvm.link.libraries"); + for (unsigned I = 0, N = LinkLibraries.size(); I != N; ++I) { + llvm::Value *Args[2] = { + llvm::MDString::get(getLLVMContext(), LinkLibraries[I].Library), + llvm::ConstantInt::get(llvm::Type::getInt1Ty(getLLVMContext()), + LinkLibraries[I].IsFramework) + }; + Metadata->addOperand(llvm::MDNode::get(getLLVMContext(), Args)); + } +} + void CodeGenModule::EmitDeferred() { // Emit code for any potentially referenced deferred decls. Since a // previously unused static decl may become used during the generation of code @@ -2681,7 +2701,6 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { case Decl::TypeAliasTemplate: case Decl::NamespaceAlias: case Decl::Block: - case Decl::Import: break; case Decl::CXXConstructor: // Skip function templates @@ -2762,6 +2781,53 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { break; } + case Decl::Import: { + ImportDecl *Import = cast<ImportDecl>(D); + + // Ignore import declarations that come from imported modules. + if (clang::Module *Owner = Import->getOwningModule()) { + if (getLangOpts().CurrentModule.empty() || + Owner->getTopLevelModule()->Name == getLangOpts().CurrentModule) + break; + } + + // Walk from this module up to its top-level module; we'll import all of + // these modules and their non-explicit child modules. + llvm::SmallVector<clang::Module *, 2> Stack; + for (clang::Module *Mod = Import->getImportedModule(); Mod; + Mod = Mod->Parent) { + if (!ImportedModules.insert(Mod)) + break; + + Stack.push_back(Mod); + } + + // Find all of the non-explicit submodules of the modules we've imported and + // import them. + while (!Stack.empty()) { + clang::Module *Mod = Stack.back(); + Stack.pop_back(); + + // Add the link libraries for this module. + LinkLibraries.insert(LinkLibraries.end(), + Mod->LinkLibraries.begin(), + Mod->LinkLibraries.end()); + + // We've imported this module; now import any of its children that haven't + // already been imported. + for (clang::Module::submodule_iterator Sub = Mod->submodule_begin(), + SubEnd = Mod->submodule_end(); + Sub != SubEnd; ++Sub) { + if ((*Sub)->IsExplicit) + continue; + + if (ImportedModules.insert(*Sub)) + Stack.push_back(*Sub); + } + } + break; + } + default: // Make sure we handled everything we should, every other kind is a // non-top-level decl. FIXME: Would be nice to have an isTopLevelDeclKind diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 34fa19c01087ddb1b3c22d5680b020e5760d344b..0d644a748e053a2192d77b38302ca267aac231de 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -23,7 +23,9 @@ #include "clang/AST/Mangle.h" #include "clang/Basic/ABI.h" #include "clang/Basic/LangOptions.h" +#include "clang/Basic/Module.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringMap.h" #include "llvm/IR/Module.h" @@ -66,6 +68,7 @@ namespace clang { class AnnotateAttr; class CXXDestructorDecl; class MangleBuffer; + class Module; namespace CodeGen { @@ -313,6 +316,12 @@ class CodeGenModule : public CodeGenTypeCache { /// run on termination. std::vector<std::pair<llvm::WeakVH,llvm::Constant*> > CXXGlobalDtors; + /// \brief The complete set of modules that has been imported. + llvm::SetVector<clang::Module *> ImportedModules; + + /// \brief The set of libraries to link against. + std::vector<clang::Module::LinkLibrary> LinkLibraries; + /// @name Cache for Objective-C runtime types /// @{ @@ -989,6 +998,9 @@ private: /// references to global which may otherwise be optimized out. void EmitLLVMUsed(); + /// \brief Emit the set of libraries to link against. + void EmitLinkLibraries(); + void EmitDeclMetadata(); /// EmitCoverageFile - Emit the llvm.gcov metadata used to tell LLVM where diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp index d954bc9fc2757d60a711189e6942091a4f0a3f1b..6b0eb79a10a3f42058b0eb18c104b2346ac838a6 100644 --- a/lib/Lex/ModuleMap.cpp +++ b/lib/Lex/ModuleMap.cpp @@ -645,6 +645,7 @@ namespace clang { ExplicitKeyword, ExportKeyword, FrameworkKeyword, + LinkKeyword, ModuleKeyword, Period, UmbrellaKeyword, @@ -732,6 +733,7 @@ namespace clang { void parseHeaderDecl(SourceLocation UmbrellaLoc, SourceLocation ExcludeLoc); void parseUmbrellaDirDecl(SourceLocation UmbrellaLoc); void parseExportDecl(); + void parseLinkDecl(); void parseInferredModuleDecl(bool Framework, bool Explicit); bool parseOptionalAttributes(Attributes &Attrs); @@ -774,6 +776,7 @@ retry: .Case("explicit", MMToken::ExplicitKeyword) .Case("export", MMToken::ExportKeyword) .Case("framework", MMToken::FrameworkKeyword) + .Case("link", MMToken::LinkKeyword) .Case("module", MMToken::ModuleKeyword) .Case("requires", MMToken::RequiresKeyword) .Case("umbrella", MMToken::UmbrellaKeyword) @@ -944,6 +947,7 @@ namespace { /// header-declaration /// submodule-declaration /// export-declaration +/// link-declaration /// /// submodule-declaration: /// module-declaration @@ -1123,7 +1127,11 @@ void ModuleMapParser::parseModuleDecl() { case MMToken::HeaderKeyword: parseHeaderDecl(SourceLocation(), SourceLocation()); break; - + + case MMToken::LinkKeyword: + parseLinkDecl(); + break; + default: Diags.Report(Tok.getLocation(), diag::err_mmap_expected_member); consumeToken(); @@ -1440,7 +1448,36 @@ void ModuleMapParser::parseExportDecl() { ActiveModule->UnresolvedExports.push_back(Unresolved); } -/// \brief Parse an inferried module declaration (wildcard modules). +/// \brief Parse a link declaration. +/// +/// module-declaration: +/// 'link' 'framework'[opt] string-literal +void ModuleMapParser::parseLinkDecl() { + assert(Tok.is(MMToken::LinkKeyword)); + SourceLocation LinkLoc = consumeToken(); + + // Parse the optional 'framework' keyword. + bool IsFramework = false; + if (Tok.is(MMToken::FrameworkKeyword)) { + consumeToken(); + IsFramework = true; + } + + // Parse the library name + if (!Tok.is(MMToken::StringLiteral)) { + Diags.Report(Tok.getLocation(), diag::err_mmap_expected_library_name) + << IsFramework << SourceRange(LinkLoc); + HadError = true; + return; + } + + std::string LibraryName = Tok.getString(); + consumeToken(); + ActiveModule->LinkLibraries.push_back(Module::LinkLibrary(LibraryName, + IsFramework)); +} + +/// \brief Parse an inferred module declaration (wildcard modules). /// /// module-declaration: /// 'explicit'[opt] 'framework'[opt] 'module' * attributes[opt] @@ -1679,13 +1716,14 @@ bool ModuleMapParser::parseModuleMapFile() { case MMToken::FrameworkKeyword: parseModuleDecl(); break; - + case MMToken::Comma: case MMToken::ExcludeKeyword: case MMToken::ExportKeyword: case MMToken::HeaderKeyword: case MMToken::Identifier: case MMToken::LBrace: + case MMToken::LinkKeyword: case MMToken::LSquare: case MMToken::Period: case MMToken::RBrace: diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 2ed8853bb2a4680939af59422f02644efcea22ce..81d3cea7ba70d11339d3f1e2d5022cbef48cf5f3 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -3413,6 +3413,9 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) { DeserializationListener->ModuleRead(GlobalID, CurrentModule); SubmodulesLoaded[GlobalIndex] = CurrentModule; + + // Clear out link libraries; the module file has them. + CurrentModule->LinkLibraries.clear(); break; } @@ -3600,6 +3603,20 @@ bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) { Context.getTargetInfo()); break; } + + case SUBMODULE_LINK_LIBRARY: + if (First) { + Error("missing submodule metadata record at beginning of block"); + return true; + } + + if (!CurrentModule) + break; + + CurrentModule->LinkLibraries.push_back( + Module::LinkLibrary(StringRef(BlobStart, BlobLen), + Record[0])); + break; } } } diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index fe498bee77fd6a58618871e0c5feaec286273442..d4b0367cac642ab465834747042b2d8c02448a38 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -2107,6 +2107,12 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name unsigned ExcludedHeaderAbbrev = Stream.EmitAbbrev(Abbrev); + Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_LINK_LIBRARY)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsFramework + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name + unsigned LinkLibraryAbbrev = Stream.EmitAbbrev(Abbrev); + // Write the submodule metadata block. RecordData Record; Record.push_back(getNumberOfModules(WritingModule)); @@ -2209,7 +2215,16 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { } Stream.EmitRecord(SUBMODULE_EXPORTS, Record); } - + + // Emit the link libraries. + for (unsigned I = 0, N = Mod->LinkLibraries.size(); I != N; ++I) { + Record.clear(); + Record.push_back(SUBMODULE_LINK_LIBRARY); + Record.push_back(Mod->LinkLibraries[I].IsFramework); + Stream.EmitRecordWithBlob(LinkLibraryAbbrev, Record, + Mod->LinkLibraries[I].Library); + } + // Queue up the submodules of this module. for (Module::submodule_iterator Sub = Mod->submodule_begin(), SubEnd = Mod->submodule_end(); diff --git a/test/Modules/Inputs/autolink-sub.h b/test/Modules/Inputs/autolink-sub.h new file mode 100644 index 0000000000000000000000000000000000000000..60f9aa037e9baf5868196d376cc1ea2995c41ad2 --- /dev/null +++ b/test/Modules/Inputs/autolink-sub.h @@ -0,0 +1 @@ +int autolink_sub(void); diff --git a/test/Modules/Inputs/autolink-sub2.h b/test/Modules/Inputs/autolink-sub2.h new file mode 100644 index 0000000000000000000000000000000000000000..c3ea7021ab36eb8abd50dc0f1a644abb56147e23 --- /dev/null +++ b/test/Modules/Inputs/autolink-sub2.h @@ -0,0 +1 @@ +int autolink_sub2(void); diff --git a/test/Modules/Inputs/autolink.h b/test/Modules/Inputs/autolink.h new file mode 100644 index 0000000000000000000000000000000000000000..1014e29dc6531c45d3d8d0ffcc773d7b52ad7caa --- /dev/null +++ b/test/Modules/Inputs/autolink.h @@ -0,0 +1 @@ +extern int autolink; diff --git a/test/Modules/Inputs/module.map b/test/Modules/Inputs/module.map index 9657c165a80e2860e9032541af3a462065cf1758..702f5c11cd5fa18945edaafc6cb3e692ec8cc8f4 100644 --- a/test/Modules/Inputs/module.map +++ b/test/Modules/Inputs/module.map @@ -124,3 +124,18 @@ module linkage_merge_left { header "linkage-merge-sub.h" } } + +module autolink { + header "autolink.h" + link "autolink" + + explicit module sub { + header "autolink-sub.h" + link "autolink_sub" + } + + explicit module sub2 { + header "autolink-sub2.h" + link framework "autolink_framework" + } +} diff --git a/test/Modules/autolink.m b/test/Modules/autolink.m new file mode 100644 index 0000000000000000000000000000000000000000..e4db6991fca1275f04e2510fd3543d14ace21215 --- /dev/null +++ b/test/Modules/autolink.m @@ -0,0 +1,18 @@ +// RUN: rm -rf %t +// RUN: %clang_cc1 -emit-llvm -o - -fmodule-cache-path %t -fmodules -F %S/Inputs -I %S/Inputs %s | FileCheck %s + +@import autolink.sub2; + +int f() { + return autolink_sub2(); +} + +@import autolink; + +int g() { + return autolink; +} + +// CHECK: !llvm.link.libraries = !{![[AUTOLINK:[0-9]+]], ![[AUTOLINK_FRAMEWORK:[0-9]+]]} +// CHECK: ![[AUTOLINK]] = metadata !{metadata !"autolink", i1 false} +// CHECK: ![[AUTOLINK_FRAMEWORK]] = metadata !{metadata !"autolink_framework", i1 true}