Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions include/swift/Basic/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -969,6 +969,10 @@ namespace swift {
/// Using ClangIncludeTreeRoot for compilation.
bool HasClangIncludeTreeRoot = false;

/// Whether the dependency scanner should construct all swift-frontend
/// invocations directly from clang cc1 args.
bool ClangImporterDirectCC1Scan = 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
3 changes: 3 additions & 0 deletions include/swift/ClangImporter/ClangImporter.h
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,9 @@ class ClangImporter final : public ClangModuleLoader {

std::string getClangModuleHash() const;

/// Get clang import creation cc1 args for swift explicit module build.
std::vector<std::string> getSwiftExplicitModuleDirectCC1Args() const;

/// If we already imported a given decl successfully, return the corresponding
/// Swift decl as an Optional<Decl *>, but if we previously tried and failed
/// to import said decl then return nullptr.
Expand Down
1 change: 0 additions & 1 deletion include/swift/Frontend/ModuleInterfaceLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -643,7 +643,6 @@ struct InterfaceSubContextDelegateImpl: InterfaceSubContextDelegate {
llvm::StringSaver ArgSaver;
std::vector<StringRef> GenericArgs;
CompilerInvocation genericSubInvocation;
llvm::Triple ParentInvocationTarget;

template<typename ...ArgTypes>
InFlightDiagnostic diagnose(StringRef interfacePath,
Expand Down
7 changes: 6 additions & 1 deletion include/swift/Option/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -1454,7 +1454,7 @@ def index_file_path : Separate<["-"], "index-file-path">,
MetaVarName<"<path>">;

def index_store_path : Separate<["-"], "index-store-path">,
Flags<[FrontendOption, ArgumentIsPath]>, MetaVarName<"<path>">,
Flags<[FrontendOption, ArgumentIsPath, CacheInvariant]>, MetaVarName<"<path>">,
HelpText<"Store indexing data to <path>">;

def index_unit_output_path : Separate<["-"], "index-unit-output-path">,
Expand Down Expand Up @@ -1894,6 +1894,11 @@ def gcc_toolchain: Separate<["-"], "gcc-toolchain">,
MetaVarName<"<path>">,
HelpText<"Specify a directory where the clang importer and clang linker can find headers and libraries">;

def experimental_clang_importer_direct_cc1_scan:
Flag<["-"], "experimental-clang-importer-direct-cc1-scan">,
Flags<[FrontendOption, NewDriverOnlyOption, HelpHidden]>,
HelpText<"Enables swift driver to construct swift-frontend invocations using -direct-clang-cc1-module-build">;

def cache_compile_job: Flag<["-"], "cache-compile-job">,
Flags<[FrontendOption, NewDriverOnlyOption]>,
HelpText<"Enable compiler caching">;
Expand Down
8 changes: 5 additions & 3 deletions include/swift/Serialization/SerializedModuleLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "swift/AST/ModuleLoader.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/PrefixMapper.h"
#include "llvm/TargetParser/Triple.h"

namespace swift {
class ModuleFile;
Expand Down Expand Up @@ -552,9 +553,10 @@ class SerializedASTFile final : public LoadedFile {
};

/// Extract compiler arguments from an interface file buffer.
bool extractCompilerFlagsFromInterface(StringRef interfacePath,
StringRef buffer, llvm::StringSaver &ArgSaver,
SmallVectorImpl<const char *> &SubArgs);
bool extractCompilerFlagsFromInterface(
StringRef interfacePath, StringRef buffer, llvm::StringSaver &ArgSaver,
SmallVectorImpl<const char *> &SubArgs,
std::optional<llvm::Triple> PreferredTarget = std::nullopt);

/// Extract the user module version number from an interface file.
llvm::VersionTuple extractUserModuleVersionFromInterface(StringRef moduleInterfacePath);
Expand Down
145 changes: 115 additions & 30 deletions lib/ClangImporter/ClangImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@
#include "clang/Basic/Module.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Version.h"
#include "clang/CAS/CASOptions.h"
#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Frontend/Utils.h"
Expand All @@ -73,8 +75,10 @@
#include "clang/Sema/Sema.h"
#include "clang/Serialization/ASTReader.h"
#include "clang/Serialization/ASTWriter.h"
#include "clang/Tooling/DependencyScanning/ScanAndUpdateArgs.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/FileCollector.h"
Expand Down Expand Up @@ -1067,26 +1071,7 @@ std::optional<std::vector<std::string>> ClangImporter::getClangCC1Arguments(
ClangImporter *importer, ASTContext &ctx,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
bool ignoreClangTarget) {
// If using direct cc1 module build, return extra args only.
if (ctx.ClangImporterOpts.DirectClangCC1ModuleBuild)
return ctx.ClangImporterOpts.ExtraArgs;

// Otherwise, create cc1 arguments from driver args.
auto driverArgs = getClangDriverArguments(ctx, ignoreClangTarget);

llvm::SmallVector<const char *> invocationArgs;
invocationArgs.reserve(driverArgs.size());
llvm::for_each(driverArgs, [&](const std::string &Arg) {
invocationArgs.push_back(Arg.c_str());
});

if (ctx.ClangImporterOpts.DumpClangDiagnostics) {
llvm::errs() << "clang importer driver args: '";
llvm::interleave(
invocationArgs, [](StringRef arg) { llvm::errs() << arg; },
[] { llvm::errs() << "' '"; });
llvm::errs() << "'\n";
}
std::unique_ptr<clang::CompilerInvocation> CI;

// Set up a temporary diagnostic client to report errors from parsing the
// command line, which may be important for Swift clients if, for example,
Expand All @@ -1098,24 +1083,64 @@ std::optional<std::vector<std::string>> ClangImporter::getClangCC1Arguments(
// clang::CompilerInstance is created.
llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> tempDiagOpts{
new clang::DiagnosticOptions};

auto *tempDiagClient =
new ClangDiagnosticConsumer(importer->Impl, *tempDiagOpts,
ctx.ClangImporterOpts.DumpClangDiagnostics);

auto clangDiags = clang::CompilerInstance::createDiagnostics(
tempDiagOpts.get(), tempDiagClient,
/*owned*/ true);

clang::CreateInvocationOptions CIOpts;
CIOpts.VFS = VFS;
CIOpts.Diags = clangDiags;
CIOpts.RecoverOnError = false;
CIOpts.ProbePrecompiled = true;
auto CI = clang::createInvocation(invocationArgs, std::move(CIOpts));
// If using direct cc1 module build, use extra args to setup ClangImporter.
if (ctx.ClangImporterOpts.DirectClangCC1ModuleBuild) {
llvm::SmallVector<const char *> clangArgs;
clangArgs.reserve(ctx.ClangImporterOpts.ExtraArgs.size());
llvm::for_each(
ctx.ClangImporterOpts.ExtraArgs,
[&](const std::string &Arg) { clangArgs.push_back(Arg.c_str()); });

// Try parse extra args, if failed, return nullopt.
CI = std::make_unique<clang::CompilerInvocation>();
if (!clang::CompilerInvocation::CreateFromArgs(*CI, clangArgs,
*clangDiags))
return std::nullopt;

if (!CI)
return std::nullopt;
// Forwards some options from swift to clang even using direct mode. This is
// to reduce the number of argument passing on the command-line and swift
// compiler can be more efficient to compute swift cache key without having
// the knowledge about clang command-line options.
if (ctx.CASOpts.EnableCaching)
CI->getCASOpts() = ctx.CASOpts.CASOpts;

// Forward the index store path. That information is not passed to scanner
// and it is cached invariant so we don't want to re-scan if that changed.
CI->getFrontendOpts().IndexStorePath = ctx.ClangImporterOpts.IndexStorePath;
} else {
// Otherwise, create cc1 arguments from driver args.
auto driverArgs = getClangDriverArguments(ctx, ignoreClangTarget);

llvm::SmallVector<const char *> invocationArgs;
invocationArgs.reserve(driverArgs.size());
llvm::for_each(driverArgs, [&](const std::string &Arg) {
invocationArgs.push_back(Arg.c_str());
});

if (ctx.ClangImporterOpts.DumpClangDiagnostics) {
llvm::errs() << "clang importer driver args: '";
llvm::interleave(
invocationArgs, [](StringRef arg) { llvm::errs() << arg; },
[] { llvm::errs() << "' '"; });
llvm::errs() << "'\n";
}

clang::CreateInvocationOptions CIOpts;
CIOpts.VFS = VFS;
CIOpts.Diags = clangDiags;
CIOpts.RecoverOnError = false;
CIOpts.ProbePrecompiled = true;
CI = clang::createInvocation(invocationArgs, std::move(CIOpts));
if (!CI)
return std::nullopt;
}

// FIXME: clang fails to generate a module if there is a `-fmodule-map-file`
// argument pointing to a missing file.
Expand Down Expand Up @@ -3919,6 +3944,66 @@ std::string ClangImporter::getClangModuleHash() const {
return Impl.Invocation->getModuleHash(Impl.Instance->getDiagnostics());
}

std::vector<std::string>
ClangImporter::getSwiftExplicitModuleDirectCC1Args() const {
llvm::SmallVector<const char*> clangArgs;
clangArgs.reserve(Impl.ClangArgs.size());
llvm::for_each(Impl.ClangArgs, [&](const std::string &Arg) {
clangArgs.push_back(Arg.c_str());
});

clang::CompilerInvocation instance;
clang::DiagnosticsEngine clangDiags(new clang::DiagnosticIDs(),
new clang::DiagnosticOptions(),
new clang::IgnoringDiagConsumer());
bool success = clang::CompilerInvocation::CreateFromArgs(instance, clangArgs,
clangDiags);
(void)success;
assert(success && "clang options from clangImporter failed to parse");

if (!Impl.SwiftContext.CASOpts.EnableCaching)
return instance.getCC1CommandLine();

// Clear some options that are not needed.
instance.clearImplicitModuleBuildOptions();

// CASOpts are forwarded from swift arguments.
instance.getCASOpts() = clang::CASOptions();

// HeaderSearchOptions.
// Clang search options are only used by scanner and clang importer from main
// module should not using search paths to find modules.
auto &HSOpts = instance.getHeaderSearchOpts();
HSOpts.VFSOverlayFiles.clear();
HSOpts.UserEntries.clear();
HSOpts.SystemHeaderPrefixes.clear();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we switch this to use tooling::dependencies::configureInvocationForCaching by passing in the include-tree root ID to this function (optionally, if caching is enabled)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is the eventual goal. But note following for current setup. This is creating a ClangImporter that is not using include-tree even when caching is enabled, but a regular translation unit that imports modules that are built with include tree. It needs a different set of options from an include tree build, thus it has a customized option clearing function and may need some other tweaking.
In the future, we should run a dependency scanning of the clang importer instance then let clang scanner return the arguments.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we can't move completely to configureInvocationForCaching, would it make sense to take a similar approach to that function for how to handle HeaderSearchOptions? In clang we clear the whole HSOpts, and only preserve a few specific settings. That makes it much easier to know what is intentionally being kept.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that makes sense if we have depscanning. Right now, it is matching the behavior in
ClangImporterOptions::getReducedExtraArgsForSwiftModuleDependency, just in a more elegant way.


// FrontendOptions.
auto &FEOpts = instance.getFrontendOpts();
FEOpts.IncludeTimestamps = false;
FEOpts.ModuleMapFiles.clear();

// IndexStorePath is forwarded from swift.
FEOpts.IndexStorePath.clear();

// PreprocessorOptions.
// Cannot clear macros as the main module clang importer doesn't have clang
// include tree created and it has to be created from command-line. However,
// include files are no collected into CASFS so they will not be found so
// clear them to avoid problem.
auto &PPOpts = instance.getPreprocessorOpts();
PPOpts.MacroIncludes.clear();
PPOpts.Includes.clear();

if (Impl.SwiftContext.ClangImporterOpts.UseClangIncludeTree) {
// FileSystemOptions.
auto &FSOpts = instance.getFileSystemOpts();
FSOpts.WorkingDir.clear();
}

return instance.getCC1CommandLine();
}

std::optional<Decl *>
ClangImporter::importDeclCached(const clang::NamedDecl *ClangDecl) {
return Impl.importDeclCached(ClangDecl, Impl.CurrentVersion);
Expand Down
23 changes: 19 additions & 4 deletions lib/DependencyScan/ModuleDependencyScanner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,9 @@ ModuleDependencyScanner::getMainModuleDependencyInfo(
{"-Xcc", "-target", "-Xcc", ScanASTContext.LangOpts.Target.str()});

std::string rootID;
std::vector<std::string> buildArgs;
auto clangImporter =
static_cast<ClangImporter *>(ScanASTContext.getClangModuleLoader());
if (tracker) {
tracker->startTracking();
for (auto fileUnit : mainModule->getFiles()) {
Expand All @@ -358,8 +361,6 @@ ModuleDependencyScanner::getMainModuleDependencyInfo(
ScanCompilerInvocation.getSearchPathOptions());
// Fetch some dependency files from clang importer.
std::vector<std::string> clangDependencyFiles;
auto clangImporter =
static_cast<ClangImporter *>(ScanASTContext.getClangModuleLoader());
clangImporter->addClangInvovcationDependencies(clangDependencyFiles);
llvm::for_each(clangDependencyFiles,
[&](std::string &file) { tracker->trackFile(file); });
Expand All @@ -373,8 +374,22 @@ ModuleDependencyScanner::getMainModuleDependencyInfo(
rootID = root->getID().toString();
}

auto mainDependencies =
ModuleDependencyInfo::forSwiftSourceModule(rootID, {}, {}, ExtraPCMArgs);
if (ScanASTContext.ClangImporterOpts.ClangImporterDirectCC1Scan) {
buildArgs.push_back("-direct-clang-cc1-module-build");
for (auto &arg : clangImporter->getSwiftExplicitModuleDirectCC1Args()) {
buildArgs.push_back("-Xcc");
buildArgs.push_back(arg);
}
}

llvm::SmallVector<StringRef> buildCommands;
buildCommands.reserve(buildArgs.size());
llvm::for_each(buildArgs, [&](const std::string &arg) {
buildCommands.emplace_back(arg);
});

auto mainDependencies = ModuleDependencyInfo::forSwiftSourceModule(
rootID, buildCommands, {}, ExtraPCMArgs);

llvm::StringSet<> alreadyAddedModules;
// Compute Implicit dependencies of the main module
Expand Down
14 changes: 3 additions & 11 deletions lib/DependencyScan/ScanDependencies.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -290,19 +290,11 @@ static llvm::Error resolveExplicitModuleInputs(
}
}
if (!clangDepDetails->moduleCacheKey.empty()) {
auto appendXclang = [&]() {
if (!resolvingDepInfo.isClangModule()) {
// clang module build using cc1 arg so this is not needed.
commandLine.push_back("-Xcc");
commandLine.push_back("-Xclang");
}
commandLine.push_back("-Xcc");
};
appendXclang();
commandLine.push_back("-Xcc");
commandLine.push_back("-fmodule-file-cache-key");
appendXclang();
commandLine.push_back("-Xcc");
commandLine.push_back(clangDepDetails->mappedPCMPath);
appendXclang();
commandLine.push_back("-Xcc");
commandLine.push_back(clangDepDetails->moduleCacheKey);
}

Expand Down
Loading