//===--- PrintAsClang.cpp - Emit a header file for a Swift AST ------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// #include "swift/PrintAsClang/PrintAsClang.h" #include "ClangSyntaxPrinter.h" #include "ModuleContentsWriter.h" #include "SwiftToClangInteropContext.h" #include "swift/AST/ASTContext.h" #include "swift/AST/AttrKind.h" #include "swift/AST/Module.h" #include "swift/AST/PrettyStackTrace.h" #include "swift/Basic/Assertions.h" #include "swift/Basic/Version.h" #include "swift/ClangImporter/ClangImporter.h" #include "swift/Frontend/FrontendOptions.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/Module.h" #include "clang/Lex/HeaderSearch.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" using namespace swift; static void emitCxxConditional(raw_ostream &out, llvm::function_ref cxxCase, llvm::function_ref cCase = {}) { out << "#if defined(__cplusplus)\n"; cxxCase(); if (cCase) { out << "#else\n"; cCase(); } out << "#endif\n"; } static void emitObjCConditional(raw_ostream &out, llvm::function_ref objcCase, llvm::function_ref nonObjCCase = {}) { out << "#if defined(__OBJC__)\n"; objcCase(); if (nonObjCCase) { out << "#else\n"; nonObjCCase(); } out << "#endif // defined(__OBJC__)\n"; } static void emitExternC(raw_ostream &out, llvm::function_ref cCase) { emitCxxConditional(out, [&] { out << "extern \"C\" {\n"; }); cCase(); emitCxxConditional(out, [&] { out << "} // extern \"C\"\n"; }); } static void writePtrauthPrologue(raw_ostream &os, ASTContext &ctx) { emitCxxConditional(os, [&]() { ClangSyntaxPrinter(ctx, os).printIgnoredDiagnosticBlock( "non-modular-include-in-framework-module", [&] { os << "#if defined(__arm64e__) && __has_include()\n"; os << "# include \n"; os << "#else\n"; ClangSyntaxPrinter(ctx, os).printIgnoredDiagnosticBlock( "reserved-macro-identifier", [&]() { os << "# ifndef " "__ptrauth_swift_value_witness_function_pointer\n"; os << "# define " "__ptrauth_swift_value_witness_function_pointer(x)\n"; os << "# endif\n"; os << "# ifndef __ptrauth_swift_class_method_pointer\n"; os << "# define __ptrauth_swift_class_method_pointer(x)\n"; os << "# endif\n"; }); os << "#endif\n"; }); }); } static void writePrologue(raw_ostream &out, ASTContext &ctx, StringRef macroGuard) { out << "// Generated by " << version::getSwiftFullVersion(ctx.LangOpts.EffectiveLanguageVersion) << "\n" // Guard against recursive definition. << "#ifndef " << macroGuard << "\n" << "#define " << macroGuard << "\n" "#pragma clang diagnostic push\n" "#pragma clang diagnostic ignored \"-Wgcc-compat\"\n" "\n" "#if !defined(__has_include)\n" "# define __has_include(x) 0\n" "#endif\n" "#if !defined(__has_attribute)\n" "# define __has_attribute(x) 0\n" "#endif\n" "#if !defined(__has_feature)\n" "# define __has_feature(x) 0\n" "#endif\n" "#if !defined(__has_warning)\n" "# define __has_warning(x) 0\n" "#endif\n" "\n" "#if __has_include()\n" "# include \n" "#endif\n" "\n" "#pragma clang diagnostic ignored \"-Wauto-import\"\n"; emitObjCConditional(out, [&] { out << "#include \n"; }); emitCxxConditional( out, [&] { out << "#include \n" "#include \n" "#include \n" "#include \n"; out << "#include \n"; out << "#include \n"; out << "#include \n"; }, [&] { out << "#include \n" "#include \n" "#include \n" "#include \n"; }); writePtrauthPrologue(out, ctx); out << "\n" "#if !defined(SWIFT_TYPEDEFS)\n" "# define SWIFT_TYPEDEFS 1\n" "# if __has_include()\n" "# include \n" "# elif !defined(__cplusplus)\n" "typedef unsigned char char8_t;\n" "typedef uint_least16_t char16_t;\n" "typedef uint_least32_t char32_t;\n" "# endif\n" #define MAP_SIMD_TYPE(C_TYPE, SCALAR_TYPE, _) \ "typedef " #SCALAR_TYPE " swift_" #C_TYPE "2" \ " __attribute__((__ext_vector_type__(2)));\n" \ "typedef " #SCALAR_TYPE " swift_" #C_TYPE "3" \ " __attribute__((__ext_vector_type__(3)));\n" \ "typedef " #SCALAR_TYPE " swift_" #C_TYPE "4" \ " __attribute__((__ext_vector_type__(4)));\n" #include "swift/ClangImporter/SIMDMappedTypes.def" "#endif\n" "\n"; #define CLANG_MACRO_BODY(NAME, BODY) \ out << "#if !defined(" NAME ")\n" \ BODY "\n" \ "#endif\n"; #define CLANG_MACRO(NAME, ARGS, VALUE) CLANG_MACRO_BODY(NAME, "# define " NAME ARGS " " VALUE) #define CLANG_MACRO_ALTERNATIVE(NAME, ARGS, CONDITION, VALUE, ALTERNATIVE) CLANG_MACRO_BODY(NAME, \ "# if " CONDITION "\n" \ "# define " NAME ARGS " " VALUE "\n" \ "# else\n" \ "# define " NAME ARGS " " ALTERNATIVE "\n" \ "# endif") #define CLANG_MACRO_OBJC(NAME, ARGS, VALUE) \ out << "#if defined(__OBJC__)\n" \ "#if !defined(" NAME ")\n" \ "# define " NAME ARGS " " VALUE "\n" \ "#endif\n" \ "#endif\n"; #define CLANG_MACRO_CXX(NAME, ARGS, VALUE, ALTERNATIVE) \ out << "#if defined(__cplusplus)\n" \ "# define " NAME ARGS " " VALUE "\n" \ "#else\n" \ "# define " NAME ARGS " " ALTERNATIVE "\n" \ "#endif\n"; #define CLANG_MACRO_CXX_BODY(NAME, BODY) \ out << "#if defined(__cplusplus)\n" \ BODY "\n" \ "#endif\n"; #include "swift/PrintAsClang/ClangMacros.def" // SWIFT_IMPORT_STDLIB_SYMBOL's expansion can't be calculated in the // preprocessor, so write its definition here auto emitMacro = [&](StringRef name, StringRef value = "") { out << "#if !defined(" << name << ")\n"; out << "# define " << name << " " << value << "\n"; out << "#endif\n"; }; if (ctx.getStdlibModule()->isStaticLibrary()) { emitMacro("SWIFT_IMPORT_STDLIB_SYMBOL"); } else { out << "#if defined(_WIN32)\n"; emitMacro("SWIFT_IMPORT_STDLIB_SYMBOL", "__declspec(dllimport)"); out << "#else\n"; emitMacro("SWIFT_IMPORT_STDLIB_SYMBOL"); out << "#endif\n"; } static_assert(SWIFT_MAX_IMPORTED_SIMD_ELEMENTS == 4, "need to add SIMD typedefs here if max elements is increased"); // For C compilers which don’t support nullability attributes, ignore them; // for ones which do, suppress warnings about them being an extension. out << "#if !__has_feature(nullability)\n" "# define _Nonnull\n" "# define _Nullable\n" "# define _Null_unspecified\n" "#elif !defined(__OBJC__)\n" "# pragma clang diagnostic ignored \"-Wnullability-extension\"\n" "#endif\n" "#if !__has_feature(nullability_nullable_result)\n" "# define _Nullable_result _Nullable\n" "#endif\n"; } static int compareImportModulesByName(const ImportModuleTy *left, const ImportModuleTy *right, bool isCxx) { auto *leftSwiftModule = left->dyn_cast(); auto *rightSwiftModule = right->dyn_cast(); if (leftSwiftModule && !rightSwiftModule) return -compareImportModulesByName(right, left, isCxx); if (leftSwiftModule && rightSwiftModule) return leftSwiftModule->getName().compare(rightSwiftModule->getName()); auto *leftClangModule = cast(*left); assert((isCxx || leftClangModule->isSubModule()) && "top-level modules should use a normal swift::ModuleDecl"); if (rightSwiftModule) { // Because the Clang module is a submodule, its full name will never be // equal to a Swift module's name, even if the top-level name is the same; // it will always come before or after. if (leftClangModule->getTopLevelModuleName() < rightSwiftModule->getName().str()) { return -1; } return 1; } auto *rightClangModule = cast(*right); assert((isCxx || rightClangModule->isSubModule()) && "top-level modules should use a normal swift::ModuleDecl"); SmallVector leftReversePath( ModuleDecl::ReverseFullNameIterator(leftClangModule), {}); SmallVector rightReversePath( ModuleDecl::ReverseFullNameIterator(rightClangModule), {}); assert(leftReversePath != rightReversePath && "distinct Clang modules should not have the same full name"); if (std::lexicographical_compare(leftReversePath.rbegin(), leftReversePath.rend(), rightReversePath.rbegin(), rightReversePath.rend())) { return -1; } return 1; } // Makes the provided path absolute and removes any "." or ".." segments from // the path static llvm::SmallString<128> normalizePath(const llvm::StringRef path) { llvm::SmallString<128> result = path; llvm::sys::path::remove_dots(result, /* remove_dot_dot */ true); llvm::sys::fs::make_absolute(result); return result; } // Collect the set of header includes needed to import the given Clang module // into an ObjectiveC program. Modeled after collectModuleHeaderIncludes in the // Clang frontend (FrontendAction.cpp) // Augment requiredTextualIncludes with the set of headers required. static void collectClangModuleHeaderIncludes( const clang::Module *clangModule, clang::FileManager &fileManager, llvm::SmallSet, 10> &requiredTextualIncludes, llvm::SmallSet &visitedModules, const llvm::SmallSet, 10> &includeDirs, const llvm::StringRef cwd) { if (!visitedModules.insert(clangModule).second) return; auto addHeader = [&](llvm::StringRef headerPath, llvm::StringRef pathRelativeToRootModuleDir) { if (!clangModule->Directory) return; llvm::SmallString<128> textualInclude = normalizePath(headerPath); llvm::SmallString<128> containingSearchDirPath; for (auto &includeDir : includeDirs) { if (textualInclude.str().starts_with(includeDir)) { if (includeDir.size() > containingSearchDirPath.size()) { containingSearchDirPath = includeDir; } } } if (!containingSearchDirPath.empty()) { llvm::SmallString<128> prefixToRemove = llvm::formatv("{0}/", containingSearchDirPath); llvm::sys::path::replace_path_prefix(textualInclude, prefixToRemove, ""); } else { // If we cannot find find the module map on the search path, // fallback to including the header using the provided path relative // to the module map textualInclude = pathRelativeToRootModuleDir; } if (clangModule->getTopLevelModule()->IsFramework) { llvm::SmallString<32> frameworkName = clangModule->getTopLevelModuleName(); llvm::SmallString<64> oldFrameworkPrefix = llvm::formatv("{0}.framework/Headers", frameworkName); llvm::sys::path::replace_path_prefix(textualInclude, oldFrameworkPrefix, frameworkName); } requiredTextualIncludes.insert(textualInclude); }; if (std::optional umbrellaHeader = clangModule->getUmbrellaHeaderAsWritten()) { addHeader(umbrellaHeader->Entry.getFileEntry().tryGetRealPathName(), umbrellaHeader->PathRelativeToRootModuleDirectory); } else if (std::optional umbrellaDir = clangModule->getUmbrellaDirAsWritten()) { SmallString<128> nativeUmbrellaDirPath; std::error_code errorCode; llvm::sys::path::native(umbrellaDir->Entry.getName(), nativeUmbrellaDirPath); llvm::vfs::FileSystem &fileSystem = fileManager.getVirtualFileSystem(); for (llvm::vfs::recursive_directory_iterator dir(fileSystem, nativeUmbrellaDirPath, errorCode), end; dir != end && !errorCode; dir.increment(errorCode)) { if (llvm::StringSwitch(llvm::sys::path::extension(dir->path())) .Cases(".h", ".H", ".hh", ".hpp", true) .Default(false)) { // Compute path to the header relative to the root of the module // (location of the module map) First compute the relative path from // umbrella directory to header file SmallVector pathComponents; auto pathIt = llvm::sys::path::rbegin(dir->path()); for (int i = 0; i != dir.level() + 1; ++i, ++pathIt) pathComponents.push_back(*pathIt); // Then append this to the path from module root to umbrella dir SmallString<128> relativeHeaderPath; if (umbrellaDir->PathRelativeToRootModuleDirectory != ".") relativeHeaderPath += umbrellaDir->PathRelativeToRootModuleDirectory; for (auto it = pathComponents.rbegin(), end = pathComponents.rend(); it != end; ++it) { llvm::sys::path::append(relativeHeaderPath, *it); } addHeader(dir->path(), relativeHeaderPath); } } } else { for (clang::Module::HeaderKind headerKind : {clang::Module::HK_Normal, clang::Module::HK_Textual}) { for (const clang::Module::Header &header : clangModule->getHeaders(headerKind)) { addHeader(header.Entry.getFileEntry().tryGetRealPathName(), header.PathRelativeToRootModuleDirectory); } } for (auto submodule : clangModule->submodules()) { if (submodule->IsExplicit) continue; collectClangModuleHeaderIncludes(submodule, fileManager, requiredTextualIncludes, visitedModules, includeDirs, cwd); } } } static void writeImports(raw_ostream &out, llvm::SmallPtrSetImpl &imports, ModuleDecl &M, StringRef bridgingHeader, const FrontendOptions &frontendOpts, clang::HeaderSearch &clangHeaderSearchInfo, const llvm::StringMap &exposedModuleHeaderNames, bool useCxxImport = false, bool useNonModularIncludes = false) { useNonModularIncludes |= frontendOpts.EmitClangHeaderWithNonModularIncludes; // Note: we can't use has_feature(modules) as it's always enabled in C++20 // mode. out << "#if __has_feature(objc_modules)\n"; out << "#if __has_warning(\"-Watimport-in-framework-header\")\n" << "#pragma clang diagnostic ignored \"-Watimport-in-framework-header\"\n" << "#endif\n"; // Sort alphabetically for determinism and consistency. SmallVector sortedImports{imports.begin(), imports.end()}; std::stable_sort( sortedImports.begin(), sortedImports.end(), [&](const ImportModuleTy &left, const ImportModuleTy &right) -> bool { return compareImportModulesByName(&left, &right, useCxxImport) < 0; }); auto isUnderlyingModule = [&M, bridgingHeader](ModuleDecl *import) -> bool { if (bridgingHeader.empty()) return import != &M && import->getName() == M.getName(); return import->isClangHeaderImportModule(); }; clang::FileSystemOptions fileSystemOptions; clang::FileManager fileManager{fileSystemOptions}; llvm::SmallSet, 10> requiredTextualIncludes; // Only included without modules. llvm::SmallVector textualIncludes; // always included. llvm::SmallSet visitedModules; llvm::SmallSet, 10> includeDirs; llvm::vfs::FileSystem &fileSystem = fileManager.getVirtualFileSystem(); llvm::ErrorOr cwd = fileSystem.getCurrentWorkingDirectory(); if (useNonModularIncludes) { assert(cwd && "Access to current working directory required"); for (auto searchDir = clangHeaderSearchInfo.search_dir_begin(); searchDir != clangHeaderSearchInfo.search_dir_end(); ++searchDir) { includeDirs.insert(normalizePath(searchDir->getName())); } const clang::Module *foundationModule = clangHeaderSearchInfo.lookupModule( "Foundation", clang::SourceLocation(), false, false); const clang::Module *darwinModule = clangHeaderSearchInfo.lookupModule( "Darwin", clang::SourceLocation(), false, false); std::function collectTransitiveSubmoduleClosure; collectTransitiveSubmoduleClosure = [&](const clang::Module *module) { if (!module) return; visitedModules.insert(module); for (auto submodule : module->submodules()) { collectTransitiveSubmoduleClosure(submodule); } }; collectTransitiveSubmoduleClosure(foundationModule); collectTransitiveSubmoduleClosure(darwinModule); } // Track printed names to handle overlay modules. llvm::SmallPtrSet seenImports; bool includeUnderlying = false; StringRef importDirective = useCxxImport ? "#pragma clang module import" : "@import"; StringRef importDirectiveLineEnd = useCxxImport ? "\n" : ";\n"; for (auto import : sortedImports) { if (auto *swiftModule = import.dyn_cast()) { if (useCxxImport) { // Do not import Swift modules into the C++ section of the generated // header unless explicitly exposed. auto it = exposedModuleHeaderNames.find(swiftModule->getName().str()); if (it != exposedModuleHeaderNames.end()) textualIncludes.push_back(it->getValue()); continue; } auto Name = swiftModule->getName(); if (isUnderlyingModule(swiftModule)) { includeUnderlying = true; continue; } if (seenImports.insert(Name).second) { out << importDirective << ' ' << Name.str() << importDirectiveLineEnd; if (useNonModularIncludes) { if (const clang::Module *underlyingClangModule = swiftModule->findUnderlyingClangModule()) { collectClangModuleHeaderIncludes( underlyingClangModule, fileManager, requiredTextualIncludes, visitedModules, includeDirs, cwd.get()); } else if ((underlyingClangModule = clangHeaderSearchInfo.lookupModule( Name.str(), clang::SourceLocation(), true, true))) { collectClangModuleHeaderIncludes( underlyingClangModule, fileManager, requiredTextualIncludes, visitedModules, includeDirs, cwd.get()); } } } } else { const auto *clangModule = cast(import); assert((useCxxImport || clangModule->isSubModule()) && "top-level modules should use a normal swift::ModuleDecl"); out << importDirective << ' '; ModuleDecl::ReverseFullNameIterator(clangModule).printForward(out); out << importDirectiveLineEnd; if (useNonModularIncludes) { collectClangModuleHeaderIncludes( clangModule, fileManager, requiredTextualIncludes, visitedModules, includeDirs, cwd.get()); } } } if (useNonModularIncludes && !requiredTextualIncludes.empty()) { out << "#elif defined(__OBJC__)\n"; for (auto header : requiredTextualIncludes) out << "#import <" << header << ">\n"; out << "#else\n"; for (auto header : requiredTextualIncludes) out << "#include <" << header << ">\n"; } out << "#endif\n\n"; for (const auto header : textualIncludes) { out << "#include <" << header << ">\n"; } if (includeUnderlying) { if (bridgingHeader.empty()) out << "#import <" << M.getName().str() << '/' << M.getName().str() << ".h>\n\n"; else { out << "#if defined(__OBJC__)\n"; out << "#import \"" << bridgingHeader << "\"\n"; out << "#else\n"; out << "#include \"" << bridgingHeader << "\"\n"; out << "#endif\n\n"; } } } static void writePostImportPrologue(raw_ostream &os, ModuleDecl &M) { os << "#pragma clang diagnostic ignored \"-Wproperty-attribute-mismatch\"\n" "#pragma clang diagnostic ignored \"-Wduplicate-method-arg\"\n" "#if __has_warning(\"-Wpragma-clang-attribute\")\n" "# pragma clang diagnostic ignored \"-Wpragma-clang-attribute\"\n" "#endif\n" "#pragma clang diagnostic ignored \"-Wunknown-pragmas\"\n" "#pragma clang diagnostic ignored \"-Wnullability\"\n" "#pragma clang diagnostic ignored " "\"-Wdollar-in-identifier-extension\"\n" "#pragma clang diagnostic ignored " "\"-Wunsafe-buffer-usage\"\n" "\n" "#if __has_attribute(external_source_symbol)\n" "# pragma push_macro(\"any\")\n" "# undef any\n" "# pragma clang attribute push(" "__attribute__((external_source_symbol(language=\"Swift\", " "defined_in=\"" << M.getNameStr() << "\",generated_declaration))), " "apply_to=any(function,enum,objc_interface,objc_category," "objc_protocol))\n" "# pragma pop_macro(\"any\")\n" "#endif\n\n"; } static void writeObjCEpilogue(raw_ostream &os) { // Pop out of `external_source_symbol` attribute // before emitting the C++ section as the C++ section // might include other files in it. os << "#if __has_attribute(external_source_symbol)\n" "# pragma clang attribute pop\n" "#endif\n"; } static void writeEpilogue(raw_ostream &os) { os << "#pragma clang diagnostic pop\n" // For the macro guard against recursive definition "#endif\n"; } static std::string computeMacroGuard(const ModuleDecl *M) { return (llvm::Twine(M->getNameStr().upper()) + "_SWIFT_H").str(); } bool swift::printAsClangHeader(raw_ostream &os, ModuleDecl *M, StringRef bridgingHeader, const FrontendOptions &frontendOpts, const IRGenOptions &irGenOpts, clang::HeaderSearch &clangHeaderSearchInfo) { llvm::PrettyStackTraceString trace("While generating Clang header"); SwiftToClangInteropContext interopContext(*M, irGenOpts); writePrologue(os, M->getASTContext(), computeMacroGuard(M)); // C content (@c) std::string moduleContentsScratch; { SmallPtrSet imports; llvm::raw_string_ostream cModuleContents{moduleContentsScratch}; printModuleContentsAsC(cModuleContents, imports, *M, interopContext, frontendOpts.ClangHeaderMinAccess); llvm::StringMap exposedModuleHeaderNames; writeImports(os, imports, *M, bridgingHeader, frontendOpts, clangHeaderSearchInfo, exposedModuleHeaderNames, /*useCxxImport=*/false, /*useNonModularIncludes*/true); emitExternC(os, [&] { os << "\n" << cModuleContents.str(); }); moduleContentsScratch.clear(); } // Objective-C content SmallPtrSet imports; llvm::raw_string_ostream objcModuleContents{moduleContentsScratch}; printModuleContentsAsObjC(objcModuleContents, imports, *M, interopContext, frontendOpts.ClangHeaderMinAccess); emitObjCConditional(os, [&] { llvm::StringMap exposedModuleHeaderNames; writeImports(os, imports, *M, bridgingHeader, frontendOpts, clangHeaderSearchInfo, exposedModuleHeaderNames); }); writePostImportPrologue(os, *M); emitObjCConditional(os, [&] { os << "\n" << objcModuleContents.str(); }); writeObjCEpilogue(os); // C++ content emitCxxConditional(os, [&] { // FIXME: Expose Swift with @expose by default. bool enableCxx = frontendOpts.ClangHeaderExposedDecls.has_value() || M->DeclContext::getASTContext().LangOpts.EnableCXXInterop; if (!enableCxx) return; llvm::StringSet<> exposedModules; for (const auto &mod : frontendOpts.clangHeaderExposedImports) exposedModules.insert(mod.moduleName); // Include the shim header only in the C++ mode. ClangSyntaxPrinter(M->getASTContext(), os).printIncludeForShimHeader( "_SwiftCxxInteroperability.h"); // Explicit @expose attribute is required only when the user specifies // -clang-header-expose-decls flag. // FIXME: should we detect any presence of @expose and require it then? bool requiresExplicitExpose = frontendOpts.ClangHeaderExposedDecls.has_value() && (*frontendOpts.ClangHeaderExposedDecls == FrontendOptions::ClangHeaderExposeBehavior::HasExposeAttr || *frontendOpts.ClangHeaderExposedDecls == FrontendOptions::ClangHeaderExposeBehavior:: HasExposeAttrOrImplicitDeps); // Swift stdlib dependencies are emitted into the same header when // -clang-header-expose-decls flag is not specified, or when it allows // implicit dependency emission. bool addStdlibDepsInline = !frontendOpts.ClangHeaderExposedDecls.has_value() || *frontendOpts.ClangHeaderExposedDecls == FrontendOptions::ClangHeaderExposeBehavior:: HasExposeAttrOrImplicitDeps || *frontendOpts.ClangHeaderExposedDecls == FrontendOptions::ClangHeaderExposeBehavior::AllPublic; std::string moduleContentsBuf; llvm::raw_string_ostream moduleContents{moduleContentsBuf}; auto deps = printModuleContentsAsCxx( moduleContents, *M, interopContext, frontendOpts.ClangHeaderMinAccess.value_or(AccessLevel::Public), /*requiresExposedAttribute=*/requiresExplicitExpose, exposedModules); // FIXME: In ObjC++ mode, we do not need to reimport duplicate modules. llvm::StringMap exposedModuleHeaderNames; for (const auto &mod : frontendOpts.clangHeaderExposedImports) exposedModuleHeaderNames.insert({mod.moduleName, mod.headerName}); writeImports(os, deps.imports, *M, bridgingHeader, frontendOpts, clangHeaderSearchInfo, exposedModuleHeaderNames, /*useCxxImport=*/true); // Embed the standard library directly. if (addStdlibDepsInline && deps.dependsOnStandardLibrary) { assert(!M->isStdlibModule()); SwiftToClangInteropContext interopContext( *M->getASTContext().getStdlibModule(), irGenOpts); auto macroGuard = computeMacroGuard(M->getASTContext().getStdlibModule()); os << "#ifndef " << macroGuard << "\n"; os << "#define " << macroGuard << "\n"; printModuleContentsAsCxx(os, *M->getASTContext().getStdlibModule(), interopContext, AccessLevel::Public, /*requiresExposedAttribute=*/true, exposedModules); os << "#endif // " << macroGuard << "\n"; } os << moduleContents.str(); }); writeEpilogue(os); return false; }