58
58
#include " clang/Basic/Module.h"
59
59
#include " clang/Basic/TargetInfo.h"
60
60
#include " clang/Basic/Version.h"
61
+ #include " clang/CAS/CASOptions.h"
61
62
#include " clang/CodeGen/ObjectFilePCHContainerOperations.h"
63
+ #include " clang/Frontend/CompilerInvocation.h"
62
64
#include " clang/Frontend/FrontendActions.h"
63
65
#include " clang/Frontend/TextDiagnosticPrinter.h"
64
66
#include " clang/Frontend/Utils.h"
73
75
#include " clang/Sema/Sema.h"
74
76
#include " clang/Serialization/ASTReader.h"
75
77
#include " clang/Serialization/ASTWriter.h"
78
+ #include " clang/Tooling/DependencyScanning/ScanAndUpdateArgs.h"
76
79
#include " llvm/ADT/IntrusiveRefCntPtr.h"
77
80
#include " llvm/ADT/STLExtras.h"
81
+ #include " llvm/ADT/SmallVector.h"
78
82
#include " llvm/ADT/StringExtras.h"
79
83
#include " llvm/Support/CrashRecoveryContext.h"
80
84
#include " llvm/Support/FileCollector.h"
@@ -1067,26 +1071,7 @@ std::optional<std::vector<std::string>> ClangImporter::getClangCC1Arguments(
1067
1071
ClangImporter *importer, ASTContext &ctx,
1068
1072
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS,
1069
1073
bool ignoreClangTarget) {
1070
- // If using direct cc1 module build, return extra args only.
1071
- if (ctx.ClangImporterOpts .DirectClangCC1ModuleBuild )
1072
- return ctx.ClangImporterOpts .ExtraArgs ;
1073
-
1074
- // Otherwise, create cc1 arguments from driver args.
1075
- auto driverArgs = getClangDriverArguments (ctx, ignoreClangTarget);
1076
-
1077
- llvm::SmallVector<const char *> invocationArgs;
1078
- invocationArgs.reserve (driverArgs.size ());
1079
- llvm::for_each (driverArgs, [&](const std::string &Arg) {
1080
- invocationArgs.push_back (Arg.c_str ());
1081
- });
1082
-
1083
- if (ctx.ClangImporterOpts .DumpClangDiagnostics ) {
1084
- llvm::errs () << " clang importer driver args: '" ;
1085
- llvm::interleave (
1086
- invocationArgs, [](StringRef arg) { llvm::errs () << arg; },
1087
- [] { llvm::errs () << " ' '" ; });
1088
- llvm::errs () << " '\n " ;
1089
- }
1074
+ std::unique_ptr<clang::CompilerInvocation> CI;
1090
1075
1091
1076
// Set up a temporary diagnostic client to report errors from parsing the
1092
1077
// command line, which may be important for Swift clients if, for example,
@@ -1098,24 +1083,60 @@ std::optional<std::vector<std::string>> ClangImporter::getClangCC1Arguments(
1098
1083
// clang::CompilerInstance is created.
1099
1084
llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> tempDiagOpts{
1100
1085
new clang::DiagnosticOptions};
1101
-
1102
1086
auto *tempDiagClient =
1103
1087
new ClangDiagnosticConsumer (importer->Impl , *tempDiagOpts,
1104
1088
ctx.ClangImporterOpts .DumpClangDiagnostics );
1105
-
1106
1089
auto clangDiags = clang::CompilerInstance::createDiagnostics (
1107
1090
tempDiagOpts.get (), tempDiagClient,
1108
1091
/* owned*/ true );
1109
1092
1110
- clang::CreateInvocationOptions CIOpts;
1111
- CIOpts.VFS = VFS;
1112
- CIOpts.Diags = clangDiags;
1113
- CIOpts.RecoverOnError = false ;
1114
- CIOpts.ProbePrecompiled = true ;
1115
- auto CI = clang::createInvocation (invocationArgs, std::move (CIOpts));
1093
+ // If using direct cc1 module build, use extra args to setup ClangImporter.
1094
+ if (ctx.ClangImporterOpts .DirectClangCC1ModuleBuild ) {
1095
+ llvm::SmallVector<const char *> clangArgs;
1096
+ clangArgs.reserve (ctx.ClangImporterOpts .ExtraArgs .size ());
1097
+ llvm::for_each (
1098
+ ctx.ClangImporterOpts .ExtraArgs ,
1099
+ [&](const std::string &Arg) { clangArgs.push_back (Arg.c_str ()); });
1100
+
1101
+ // Try parse extra args, if failed, return nullopt.
1102
+ CI = std::make_unique<clang::CompilerInvocation>();
1103
+ if (!clang::CompilerInvocation::CreateFromArgs (*CI, clangArgs,
1104
+ *clangDiags))
1105
+ return std::nullopt;
1116
1106
1117
- if (!CI)
1118
- return std::nullopt;
1107
+ // Forwards some options from swift to clang even using direct mode. This is
1108
+ // to reduce the number of argument passing on the command-line and swift
1109
+ // compiler can be more efficient to compute swift cache key without having
1110
+ // the knowledge about clang command-line options.
1111
+ if (ctx.CASOpts .EnableCaching )
1112
+ CI->getCASOpts () = ctx.CASOpts .CASOpts ;
1113
+ } else {
1114
+ // Otherwise, create cc1 arguments from driver args.
1115
+ auto driverArgs = getClangDriverArguments (ctx, ignoreClangTarget);
1116
+
1117
+ llvm::SmallVector<const char *> invocationArgs;
1118
+ invocationArgs.reserve (driverArgs.size ());
1119
+ llvm::for_each (driverArgs, [&](const std::string &Arg) {
1120
+ invocationArgs.push_back (Arg.c_str ());
1121
+ });
1122
+
1123
+ if (ctx.ClangImporterOpts .DumpClangDiagnostics ) {
1124
+ llvm::errs () << " clang importer driver args: '" ;
1125
+ llvm::interleave (
1126
+ invocationArgs, [](StringRef arg) { llvm::errs () << arg; },
1127
+ [] { llvm::errs () << " ' '" ; });
1128
+ llvm::errs () << " '\n " ;
1129
+ }
1130
+
1131
+ clang::CreateInvocationOptions CIOpts;
1132
+ CIOpts.VFS = VFS;
1133
+ CIOpts.Diags = clangDiags;
1134
+ CIOpts.RecoverOnError = false ;
1135
+ CIOpts.ProbePrecompiled = true ;
1136
+ CI = clang::createInvocation (invocationArgs, std::move (CIOpts));
1137
+ if (!CI)
1138
+ return std::nullopt;
1139
+ }
1119
1140
1120
1141
// FIXME: clang fails to generate a module if there is a `-fmodule-map-file`
1121
1142
// argument pointing to a missing file.
@@ -3919,6 +3940,63 @@ std::string ClangImporter::getClangModuleHash() const {
3919
3940
return Impl.Invocation ->getModuleHash (Impl.Instance ->getDiagnostics ());
3920
3941
}
3921
3942
3943
+ std::vector<std::string>
3944
+ ClangImporter::getSwiftExplicitModuleDirectCC1Args () const {
3945
+ llvm::SmallVector<const char *> clangArgs;
3946
+ clangArgs.reserve (Impl.ClangArgs .size ());
3947
+ llvm::for_each (Impl.ClangArgs , [&](const std::string &Arg) {
3948
+ clangArgs.push_back (Arg.c_str ());
3949
+ });
3950
+
3951
+ clang::CompilerInvocation instance;
3952
+ clang::DiagnosticsEngine clangDiags (new clang::DiagnosticIDs (),
3953
+ new clang::DiagnosticOptions (),
3954
+ new clang::IgnoringDiagConsumer ());
3955
+ bool success = clang::CompilerInvocation::CreateFromArgs (instance, clangArgs,
3956
+ clangDiags);
3957
+ (void )success;
3958
+ assert (success && " clang options from clangImporter failed to parse" );
3959
+
3960
+ if (!Impl.SwiftContext .CASOpts .EnableCaching )
3961
+ return instance.getCC1CommandLine ();
3962
+
3963
+ // Clear some options that are not needed.
3964
+ instance.clearImplicitModuleBuildOptions ();
3965
+
3966
+ // CASOpts are forwarded from swift arguments.
3967
+ instance.getCASOpts () = clang::CASOptions ();
3968
+
3969
+ // HeaderSearchOptions.
3970
+ // Clang search options are only used by scanner and clang importer from main
3971
+ // module should not using search paths to find modules.
3972
+ auto &HSOpts = instance.getHeaderSearchOpts ();
3973
+ HSOpts.VFSOverlayFiles .clear ();
3974
+ HSOpts.UserEntries .clear ();
3975
+ HSOpts.SystemHeaderPrefixes .clear ();
3976
+
3977
+ // FrontendOptions.
3978
+ auto &FEOpts = instance.getFrontendOpts ();
3979
+ FEOpts.IncludeTimestamps = false ;
3980
+ FEOpts.ModuleMapFiles .clear ();
3981
+
3982
+ // PreprocessorOptions.
3983
+ // Cannot clear macros as the main module clang importer doesn't have clang
3984
+ // include tree created and it has to be created from command-line. However,
3985
+ // include files are no collected into CASFS so they will not be found so
3986
+ // clear them to avoid problem.
3987
+ auto &PPOpts = instance.getPreprocessorOpts ();
3988
+ PPOpts.MacroIncludes .clear ();
3989
+ PPOpts.Includes .clear ();
3990
+
3991
+ if (Impl.SwiftContext .ClangImporterOpts .UseClangIncludeTree ) {
3992
+ // FileSystemOptions.
3993
+ auto &FSOpts = instance.getFileSystemOpts ();
3994
+ FSOpts.WorkingDir .clear ();
3995
+ }
3996
+
3997
+ return instance.getCC1CommandLine ();
3998
+ }
3999
+
3922
4000
std::optional<Decl *>
3923
4001
ClangImporter::importDeclCached (const clang::NamedDecl *ClangDecl) {
3924
4002
return Impl.importDeclCached (ClangDecl, Impl.CurrentVersion );
0 commit comments