Skip to content
3 changes: 3 additions & 0 deletions include/swift/AST/SearchPathOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ class SearchPathOptions {
/// would for a non-system header.
bool DisableModulesValidateSystemDependencies = false;

/// The paths to a set of explicitly built modules from interfaces.
std::vector<std::string> ExplicitSwiftModules;

private:
static StringRef
pathStringFromFrameworkSearchPath(const FrameworkSearchPath &next) {
Expand Down
1 change: 1 addition & 0 deletions include/swift/ClangImporter/ClangImporter.h
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,7 @@ class ClangImporter final : public ClangModuleLoader {

bool isSerializable(const clang::Type *type,
bool checkCanonical) const override;
ArrayRef<std::string> getExtraClangArgs() const;
};

ImportDecl *createImportDecl(ASTContext &Ctx, DeclContext *DC, ClangNode ClangN,
Expand Down
4 changes: 4 additions & 0 deletions include/swift/ClangImporter/ClangImporterOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ class ClangImporterOptions {
/// DWARFImporter delegate.
bool DisableSourceImport = false;

/// When set, use ExtraArgs alone to configure clang instance because ExtraArgs
/// contains the full option set.
bool ExtraArgsOnly = false;

/// Return a hash code of any components from these options that should
/// contribute to a Swift Bridging PCH hash.
llvm::hash_code getPCHHashComponents() const {
Expand Down
4 changes: 4 additions & 0 deletions include/swift/Frontend/FrontendOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,10 @@ class FrontendOptions {
/// By default, we include ImplicitObjCHeaderPath directly.
llvm::Optional<std::string> BridgingHeaderDirForPrint;

/// Disable implicitly built Swift modules because they are explicitly
/// built and given to the compiler invocation.
bool DisableImplicitModules = false;

/// The different modes for validating TBD against the LLVM IR.
enum class TBDValidationMode {
Default, ///< Do the default validation for the current platform.
Expand Down
39 changes: 22 additions & 17 deletions include/swift/Frontend/ModuleInterfaceLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,16 @@ class LangOptions;
class SearchPathOptions;
class CompilerInvocation;

struct ModuleInterfaceLoaderOptions {
bool remarkOnRebuildFromInterface = false;
bool disableInterfaceLock = false;
bool disableImplicitSwiftModule = false;
ModuleInterfaceLoaderOptions(const FrontendOptions &Opts):
remarkOnRebuildFromInterface(Opts.RemarkOnRebuildFromModuleInterface),
disableInterfaceLock(Opts.DisableInterfaceFileLock),
disableImplicitSwiftModule(Opts.DisableImplicitModules) {}
ModuleInterfaceLoaderOptions() = default;
};
/// A ModuleLoader that runs a subordinate \c CompilerInvocation and
/// \c CompilerInstance to convert .swiftinterface files to .swiftmodule
/// files on the fly, caching the resulting .swiftmodules in the module cache
Expand All @@ -137,21 +147,17 @@ class ModuleInterfaceLoader : public SerializedModuleLoaderBase {
ASTContext &ctx, StringRef cacheDir, StringRef prebuiltCacheDir,
DependencyTracker *tracker, ModuleLoadingMode loadMode,
ArrayRef<std::string> PreferInterfaceForModules,
bool RemarkOnRebuildFromInterface, bool IgnoreSwiftSourceInfoFile,
bool DisableInterfaceFileLock)
bool IgnoreSwiftSourceInfoFile, ModuleInterfaceLoaderOptions Opts)
: SerializedModuleLoaderBase(ctx, tracker, loadMode,
IgnoreSwiftSourceInfoFile),
CacheDir(cacheDir), PrebuiltCacheDir(prebuiltCacheDir),
RemarkOnRebuildFromInterface(RemarkOnRebuildFromInterface),
DisableInterfaceFileLock(DisableInterfaceFileLock),
PreferInterfaceForModules(PreferInterfaceForModules)
{}
PreferInterfaceForModules(PreferInterfaceForModules),
Opts(Opts) {}

std::string CacheDir;
std::string PrebuiltCacheDir;
bool RemarkOnRebuildFromInterface;
bool DisableInterfaceFileLock;
ArrayRef<std::string> PreferInterfaceForModules;
ModuleInterfaceLoaderOptions Opts;

std::error_code findModuleFilesInDirectory(
AccessPathElem ModuleID,
Expand All @@ -168,16 +174,14 @@ class ModuleInterfaceLoader : public SerializedModuleLoaderBase {
create(ASTContext &ctx, StringRef cacheDir, StringRef prebuiltCacheDir,
DependencyTracker *tracker, ModuleLoadingMode loadMode,
ArrayRef<std::string> PreferInterfaceForModules = {},
bool RemarkOnRebuildFromInterface = false,
bool IgnoreSwiftSourceInfoFile = false,
bool DisableInterfaceFileLock = false) {
ModuleInterfaceLoaderOptions Opts = ModuleInterfaceLoaderOptions(),
bool IgnoreSwiftSourceInfoFile = false) {
return std::unique_ptr<ModuleInterfaceLoader>(
new ModuleInterfaceLoader(ctx, cacheDir, prebuiltCacheDir,
tracker, loadMode,
PreferInterfaceForModules,
RemarkOnRebuildFromInterface,
IgnoreSwiftSourceInfoFile,
DisableInterfaceFileLock));
Opts));
}

/// Append visible module names to \p names. Note that names are possibly
Expand All @@ -192,10 +196,11 @@ class ModuleInterfaceLoader : public SerializedModuleLoaderBase {
static bool buildSwiftModuleFromSwiftInterface(
SourceManager &SourceMgr, DiagnosticEngine &Diags,
const SearchPathOptions &SearchPathOpts, const LangOptions &LangOpts,
const ClangImporterOptions &ClangOpts,
StringRef CacheDir, StringRef PrebuiltCacheDir,
StringRef ModuleName, StringRef InPath, StringRef OutPath,
bool SerializeDependencyHashes, bool TrackSystemDependencies,
bool RemarkOnRebuildFromInterface, bool DisableInterfaceFileLock);
ModuleInterfaceLoaderOptions Opts);
};

struct InterfaceSubContextDelegateImpl: InterfaceSubContextDelegate {
Expand Down Expand Up @@ -231,14 +236,13 @@ struct InterfaceSubContextDelegateImpl: InterfaceSubContextDelegate {
DiagnosticEngine &Diags,
const SearchPathOptions &searchPathOpts,
const LangOptions &langOpts,
ModuleInterfaceLoaderOptions LoaderOpts,
ClangModuleLoader *clangImporter,
bool buildModuleCacheDirIfAbsent,
StringRef moduleCachePath,
StringRef prebuiltCachePath,
bool serializeDependencyHashes,
bool trackSystemDependencies,
bool remarkOnRebuildFromInterface,
bool disableInterfaceFileLock);
bool trackSystemDependencies);
bool runInSubContext(StringRef moduleName,
StringRef interfacePath,
StringRef outputPath,
Expand All @@ -258,6 +262,7 @@ struct InterfaceSubContextDelegateImpl: InterfaceSubContextDelegate {
llvm::SmallString<256> &OutPath,
StringRef &CacheHash);
std::string getCacheHash(StringRef useInterfacePath);
void addExtraClangArg(StringRef Arg);
};
}

Expand Down
8 changes: 8 additions & 0 deletions include/swift/Option/FrontendOptions.td
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,12 @@ def disable_objc_attr_requires_foundation_module :
def enable_resilience : Flag<["-"], "enable-resilience">,
HelpText<"Deprecated, use -enable-library-evolution instead">;

def disable_implicit_swift_modules: Flag<["-"], "disable-implicit-swift-modules">,
HelpText<"Disable building Swift modules explicitly by the compiler">;

def swift_module_file
: Separate<["-"], "swift-module-file">, MetaVarName<"<path>">,
HelpText<"Specify Swift module explicitly built from textual interface">;
}


Expand Down Expand Up @@ -712,4 +718,6 @@ def target_sdk_version : Separate<["-"], "target-sdk-version">,
def target_variant_sdk_version : Separate<["-"], "target-variant-sdk-version">,
HelpText<"The version of target variant SDK used for compilation">;

def extra_clang_options_only : Flag<["-"], "only-use-extra-clang-opts">,
HelpText<"Options passed via -Xcc are sufficient for Clang configuration">;
} // end let Flags = [FrontendOption, NoDriverOption, HelpHidden]
9 changes: 8 additions & 1 deletion lib/ClangImporter/ClangImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -908,6 +908,9 @@ ClangImporter::getOrCreatePCH(const ClangImporterOptions &ImporterOptions,
std::vector<std::string>
ClangImporter::getClangArguments(ASTContext &ctx,
const ClangImporterOptions &importerOpts) {
if (importerOpts.ExtraArgsOnly) {
return importerOpts.ExtraArgs;
}
std::vector<std::string> invocationArgStrs;
// Clang expects this to be like an actual command line. So we need to pass in
// "clang" for argv[0]
Expand Down Expand Up @@ -957,6 +960,10 @@ ClangImporter::createClangInvocation(ClangImporter *importer,
nullptr, false, CC1Args);
}

ArrayRef<std::string> ClangImporter::getExtraClangArgs() const {
return Impl.ExtraClangArgs;
}

std::unique_ptr<ClangImporter>
ClangImporter::create(ASTContext &ctx, const ClangImporterOptions &importerOpts,
std::string swiftPCHHash, DependencyTracker *tracker,
Expand All @@ -965,7 +972,7 @@ ClangImporter::create(ASTContext &ctx, const ClangImporterOptions &importerOpts,
new ClangImporter(ctx, importerOpts, tracker, dwarfImporterDelegate)};
importer->Impl.ClangArgs = getClangArguments(ctx, importerOpts);
ArrayRef<std::string> invocationArgStrs = importer->Impl.ClangArgs;

importer->Impl.ExtraClangArgs = importerOpts.ExtraArgs;
if (importerOpts.DumpClangDiagnostics) {
llvm::errs() << "'";
llvm::interleave(
Expand Down
64 changes: 9 additions & 55 deletions lib/ClangImporter/ClangModuleDependencyScanner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,20 +188,6 @@ static ClangModuleDependenciesCacheImpl *getOrCreateClangImpl(
return clangImpl;
}

static std::string getModuleFilePath(StringRef moduleCacheDir,
StringRef moduleName,
StringRef contextHash) {
SmallString<128> outputPath(moduleCacheDir);
llvm::sys::path::append(outputPath, (llvm::Twine(moduleName)
+ "-" + contextHash + ".pcm").str());
return outputPath.str().str();
}

static std::string getModuleFilePath(StringRef moduleCacheDir,
const ModuleDeps &dep) {
return getModuleFilePath(moduleCacheDir, dep.ModuleName, dep.ContextHash);
}

/// Record the module dependencies we found by scanning Clang modules into
/// the module dependencies cache.
void ClangImporter::recordModuleDependencies(
Expand All @@ -213,23 +199,7 @@ void ClangImporter::recordModuleDependencies(
};
auto ModuleCacheDir = swift::getModuleCachePathFromClang(getClangInstance());

// A map keyed by module name and context hash.
llvm::StringMap<llvm::StringMap<ModuleInfo>> moduleInfoMap;

// Traverse all Clang modules to populate moduleInfoMap for cross
// referencing later.
for (const auto &clangModuleDep : clangDependencies.DiscoveredModules) {
moduleInfoMap[clangModuleDep.ModuleName][clangModuleDep.ContextHash] =
{
// Keep track of pcm path for output.
getModuleFilePath(ModuleCacheDir, clangModuleDep),
// Keep track of modulemap file for input.
clangModuleDep.ClangModuleMapFile
};
}
for (const auto &clangModuleDep : clangDependencies.DiscoveredModules) {
assert(moduleInfoMap[clangModuleDep.ModuleName]
.count(clangModuleDep.ContextHash));
// If we've already cached this information, we're done.
if (cache.hasDependencies(clangModuleDep.ModuleName,
ModuleDependenciesKind::Clang))
Expand All @@ -241,48 +211,32 @@ void ClangImporter::recordModuleDependencies(
fileDeps.push_back(fileDep.getKey().str());
}
// Inherit all Clang driver args when creating the clang importer.
std::vector<std::string> allArgs = Impl.ClangArgs;
ArrayRef<std::string> allArgs = Impl.ClangArgs;
ClangImporterOptions Opts;
std::vector<std::string> cc1Args;

// Calling this to convert driver args to CC1 args.
createClangInvocation(this, Opts, allArgs, &cc1Args);
// Ensure the arguments we collected is sufficient to create a Clang
// invocation.
assert(createClangInvocation(this, Opts, allArgs));

std::vector<std::string> swiftArgs;
// We are using Swift frontend mode.
swiftArgs.push_back("-frontend");
// We pass the entire argument list via -Xcc, so the invocation should
// use extra clang options alone.
swiftArgs.push_back("-only-use-extra-clang-opts");
auto addClangArg = [&](StringRef arg) {
swiftArgs.push_back("-Xcc");
swiftArgs.push_back("-Xclang");
swiftArgs.push_back("-Xcc");
swiftArgs.push_back(arg.str());
};
// Add all args inheritted from creating the importer.
for (auto arg: cc1Args) {
addClangArg(arg);
}
// Add all args reported from the Clang dependencies scanner.
for(auto arg: clangModuleDep.NonPathCommandLine) {
for (auto arg: allArgs) {
addClangArg(arg);
}

// Add -fmodule-map-file and -fmodule-file for direct dependencies.
for (auto &dep: clangModuleDep.ClangModuleDeps) {
assert(moduleInfoMap[dep.ModuleName].count(dep.ContextHash));
addClangArg((llvm::Twine("-fmodule-map-file=")
+ moduleInfoMap[dep.ModuleName][dep.ContextHash].ModuleMapPath).str());
addClangArg((llvm::Twine("-fmodule-file=")
+ moduleInfoMap[dep.ModuleName][dep.ContextHash].PCMPath).str());
}
// Swift frontend action: -emit-pcm
swiftArgs.push_back("-emit-pcm");
swiftArgs.push_back("-module-name");
swiftArgs.push_back(clangModuleDep.ModuleName);

// Swift frontend option for output file path (Foo.pcm).
swiftArgs.push_back("-o");
swiftArgs.push_back(moduleInfoMap[clangModuleDep.ModuleName]
[clangModuleDep.ContextHash].PCMPath);

// Swift frontend option for input file path (Foo.modulemap).
swiftArgs.push_back(clangModuleDep.ClangModuleMapFile);
// Module-level dependencies.
Expand Down
3 changes: 3 additions & 0 deletions lib/ClangImporter/ImporterImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,9 @@ class LLVM_LIBRARY_VISIBILITY ClangImporter::Implementation

/// Clang arguments used to create the Clang invocation.
std::vector<std::string> ClangArgs;

/// Extra clang args specified via "-Xcc"
std::vector<std::string> ExtraClangArgs;
public:
/// Mapping of already-imported declarations.
llvm::DenseMap<std::pair<const clang::Decl *, Version>, Decl *> ImportedDecls;
Expand Down
2 changes: 2 additions & 0 deletions lib/Frontend/ArgsToFrontendOptionsConverter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ bool ArgsToFrontendOptionsConverter::convert(

Opts.TrackSystemDeps |= Args.hasArg(OPT_track_system_dependencies);

Opts.DisableImplicitModules |= Args.hasArg(OPT_disable_implicit_swift_modules);

// Always track system dependencies when scanning dependencies.
if (const Arg *ModeArg = Args.getLastArg(OPT_modes_Group)) {
if (ModeArg->getOption().matches(OPT_scan_dependencies))
Expand Down
5 changes: 5 additions & 0 deletions lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -802,6 +802,8 @@ static bool ParseClangImporterArgs(ClangImporterOptions &Opts,

Opts.DisableOverlayModules |= Args.hasArg(OPT_emit_imported_modules);

Opts.ExtraArgsOnly |= Args.hasArg(OPT_extra_clang_options_only);

if (const Arg *A = Args.getLastArg(OPT_pch_output_dir)) {
Opts.PrecompiledHeaderOutputDir = A->getValue();
Opts.PCHDisableValidation |= Args.hasArg(OPT_pch_disable_validation);
Expand Down Expand Up @@ -863,6 +865,9 @@ static bool ParseSearchPathArgs(SearchPathOptions &Opts,
Opts.DisableModulesValidateSystemDependencies |=
Args.hasArg(OPT_disable_modules_validate_system_headers);

for (auto A: Args.filtered(OPT_swift_module_file)) {
Opts.ExplicitSwiftModules.push_back(resolveSearchPath(A->getValue()));
}
// Opts.RuntimeIncludePath is set by calls to
// setRuntimeIncludePath() or setMainExecutablePath().
// Opts.RuntimeImportPath is set by calls to
Expand Down
6 changes: 3 additions & 3 deletions lib/Frontend/Frontend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -455,12 +455,12 @@ bool CompilerInstance::setUpModuleLoaders() {
std::string ModuleCachePath = getModuleCachePathFromClang(Clang);
auto &FEOpts = Invocation.getFrontendOptions();
StringRef PrebuiltModuleCachePath = FEOpts.PrebuiltModuleCachePath;
ModuleInterfaceLoaderOptions LoaderOpts(FEOpts);
auto PIML = ModuleInterfaceLoader::create(
*Context, ModuleCachePath, PrebuiltModuleCachePath,
getDependencyTracker(), MLM, FEOpts.PreferInterfaceForModules,
FEOpts.RemarkOnRebuildFromModuleInterface,
IgnoreSourceInfoFile,
FEOpts.DisableInterfaceFileLock);
LoaderOpts,
IgnoreSourceInfoFile);
Context->addModuleLoader(std::move(PIML));
}

Expand Down
Loading