5757#include " clang/Basic/TargetOptions.h"
5858#include " clang/Driver/Driver.h"
5959#include " clang/Frontend/CompilerInstance.h"
60+ #include " clang/Frontend/TextDiagnosticPrinter.h"
6061#include " clang/Lex/Preprocessor.h"
6162
6263#include " clang/Lex/PreprocessorOptions.h"
@@ -1573,21 +1574,7 @@ bool ShouldUnique(StringRef arg) {
15731574
15741575// static
15751576void SwiftASTContext::AddExtraClangArgs (const std::vector<std::string> &source,
1576- std::vector<std::string> &dest,
1577- bool cc1) {
1578- // FIXME: Support for cc1 flags isn't complete. The uniquing
1579- // algortihm below does not work for cc1 flags. Since cc1 flags are
1580- // not stable it's not feasible to keep a list of all multi-arg
1581- // flags, for example. It also makes it difficult to correctly
1582- // identify where workng directories and path remappings should
1583- // applied. For all these reasons, using cc1 flags for anything but
1584- // a local build with explicit modules and precise compiler
1585- // invocations isn't supported yet.
1586- if (cc1) {
1587- dest.insert (dest.end (), source.begin (), source.end ());
1588- return ;
1589- }
1590-
1577+ std::vector<std::string> &dest) {
15911578 llvm::StringSet<> unique_flags;
15921579 for (auto &arg : dest)
15931580 unique_flags.insert (arg);
@@ -1764,23 +1751,37 @@ static void applyOverrideOptions(std::vector<std::string> &args,
17641751
17651752void SwiftASTContext::AddExtraClangArgs (
17661753 const std::vector<std::string> &ExtraArgs, StringRef overrideOpts) {
1754+ if (ExtraArgs.empty ())
1755+ return ;
1756+
17671757 swift::ClangImporterOptions &importer_options = GetClangImporterOptions ();
17681758
17691759 // Detect cc1 flags. When DirectClangCC1ModuleBuild is on then the
17701760 // clang arguments in the serialized invocation are clang cc1 flags,
17711761 // which are very specific to one compiler version and cannot
17721762 // be merged with driver options.
17731763 bool fresh_invocation = importer_options.ExtraArgs .empty ();
1774- if (fresh_invocation && !ExtraArgs.empty () && ExtraArgs.front () == " -cc1" )
1775- importer_options.DirectClangCC1ModuleBuild = true ;
1776- if (!importer_options.DirectClangCC1ModuleBuild && !ExtraArgs.empty () &&
1777- ExtraArgs.front () == " -cc1" )
1764+ bool invocation_direct_cc1 = ExtraArgs.front () == " -cc1" ;
1765+
1766+ // If it is not a fresh invocation, make sure the cc1 option matches.
1767+ if (!fresh_invocation &&
1768+ (importer_options.DirectClangCC1ModuleBuild != invocation_direct_cc1))
17781769 AddDiagnostic (
17791770 eSeverityWarning,
17801771 " Mixing and matching of driver and cc1 Clang options detected" );
17811772
1782- AddExtraClangArgs (ExtraArgs, importer_options.ExtraArgs ,
1783- importer_options.DirectClangCC1ModuleBuild );
1773+ importer_options.DirectClangCC1ModuleBuild = invocation_direct_cc1;
1774+
1775+ // If using direct cc1 flags, compute the arguments and return.
1776+ // Since this is cc1 flags, override options are driver flags and don't apply.
1777+ if (importer_options.DirectClangCC1ModuleBuild ) {
1778+ if (!fresh_invocation)
1779+ importer_options.ExtraArgs .clear ();
1780+ AddExtraClangCC1Args (ExtraArgs, importer_options.ExtraArgs );
1781+ return ;
1782+ }
1783+
1784+ AddExtraClangArgs (ExtraArgs, importer_options.ExtraArgs );
17841785 applyOverrideOptions (importer_options.ExtraArgs , overrideOpts);
17851786 if (HasNonexistentExplicitModule (importer_options.ExtraArgs ))
17861787 RemoveExplicitModules (importer_options.ExtraArgs );
@@ -1792,6 +1793,78 @@ void SwiftASTContext::AddExtraClangArgs(
17921793 });
17931794}
17941795
1796+ void SwiftASTContext::AddExtraClangCC1Args (
1797+ const std::vector<std::string> &source, std::vector<std::string> &dest) {
1798+ clang::CompilerInvocation invocation;
1799+ llvm::SmallVector<const char *> clangArgs;
1800+ clangArgs.reserve (source.size ());
1801+ llvm::for_each (source, [&](const std::string &Arg) {
1802+ // Workaround for the extra driver argument embedded in the swiftmodule by
1803+ // some swift compiler version. It always starts with `--target=` and it is
1804+ // not a valid cc1 option.
1805+ if (!StringRef (Arg).starts_with (" --target=" ))
1806+ clangArgs.push_back (Arg.c_str ());
1807+ });
1808+
1809+ std::string diags;
1810+ llvm::raw_string_ostream os (diags);
1811+ auto diagOpts = llvm::makeIntrusiveRefCnt<clang::DiagnosticOptions>();
1812+ clang::DiagnosticsEngine clangDiags (
1813+ new clang::DiagnosticIDs (), diagOpts,
1814+ new clang::TextDiagnosticPrinter (os, diagOpts.get ()));
1815+
1816+ if (!clang::CompilerInvocation::CreateFromArgs (invocation, clangArgs,
1817+ clangDiags)) {
1818+ // If cc1 arguments failed to parse, report diagnostics and return
1819+ // immediately.
1820+ AddDiagnostic (eSeverityError, diags);
1821+ // Disable direct-cc1 build as fallback.
1822+ GetClangImporterOptions ().DirectClangCC1ModuleBuild = false ;
1823+ return ;
1824+ }
1825+
1826+ // Clear module cache key and other CAS options to load modules from disk
1827+ // directly.
1828+ invocation.getFrontendOpts ().ModuleCacheKeys .clear ();
1829+ invocation.getCASOpts () = clang::CASOptions ();
1830+
1831+ // Ignore CAS info inside modules when loading.
1832+ invocation.getFrontendOpts ().ModuleLoadIgnoreCAS = true ;
1833+
1834+ // Remove non-existing modules in a systematic way.
1835+ bool module_missing = false ;
1836+ auto CheckFileExists = [&](const char *file) {
1837+ if (!llvm::sys::fs::exists (file)) {
1838+ std::string warn;
1839+ llvm::raw_string_ostream (warn)
1840+ << " Nonexistent explicit module file " << file;
1841+ AddDiagnostic (eSeverityWarning, warn);
1842+ module_missing = true ;
1843+ }
1844+ };
1845+ llvm::for_each (invocation.getHeaderSearchOpts ().PrebuiltModuleFiles ,
1846+ [&](const auto &mod) { CheckFileExists (mod.second .c_str ()); });
1847+ llvm::for_each (invocation.getFrontendOpts ().ModuleFiles ,
1848+ [&](const auto &mod) { CheckFileExists (mod.c_str ()); });
1849+
1850+ // If missing, clear all the prebuilt module options and switch to implicit
1851+ // modules build.
1852+ if (module_missing) {
1853+ invocation.getHeaderSearchOpts ().PrebuiltModuleFiles .clear ();
1854+ invocation.getFrontendOpts ().ModuleFiles .clear ();
1855+ invocation.getLangOpts ().ImplicitModules = true ;
1856+ invocation.getHeaderSearchOpts ().ImplicitModuleMaps = true ;
1857+ }
1858+
1859+ invocation.generateCC1CommandLine (
1860+ [&](const llvm::Twine &arg) { dest.push_back (arg.str ()); });
1861+
1862+ // If cc1 arguments are parsed and generated correctly, set explicitly-built
1863+ // module since only explicit module build can use direct cc1 mode.
1864+ m_has_explicit_modules = true ;
1865+ return ;
1866+ }
1867+
17951868void SwiftASTContext::AddUserClangArgs (TargetProperties &props) {
17961869 Args args (props.GetSwiftExtraClangFlags ());
17971870 std::vector<std::string> user_clang_flags;
@@ -1883,6 +1956,10 @@ void SwiftASTContext::RemapClangImporterOptions(
18831956
18841957void SwiftASTContext::FilterClangImporterOptions (
18851958 std::vector<std::string> &extra_args, SwiftASTContext *ctx) {
1959+ // The direct cc1 mode do not need any extra audit.
1960+ if (ctx && ctx->GetClangImporterOptions ().DirectClangCC1ModuleBuild )
1961+ return ;
1962+
18861963 std::string ivfs_arg;
18871964 // Copy back a filtered version of ExtraArgs.
18881965 std::vector<std::string> orig_args (std::move (extra_args));
@@ -1893,11 +1970,6 @@ void SwiftASTContext::FilterClangImporterOptions(
18931970 arg_sr == " -fno-implicit-module-maps" )
18941971 continue ;
18951972
1896- // This is not a cc1 option.
1897- if (arg_sr.starts_with (" --target=" ) && ctx &&
1898- ctx->GetClangImporterOptions ().DirectClangCC1ModuleBuild )
1899- continue ;
1900-
19011973 // The VFS options turn into fatal errors when the referenced file
19021974 // is not found. Since the Xcode build system tends to create a
19031975 // lot of VFS overlays by default, stat them and emit a warning if
@@ -2184,6 +2256,11 @@ ProcessModule(Module &module, std::string m_description,
21842256 for (auto path : opts.getFrameworkSearchPaths ())
21852257 framework_search_paths.push_back ({path.Path , path.IsSystem });
21862258 auto &clang_opts = invocation.getClangImporterOptions ().ExtraArgs ;
2259+ // If the args embedded are cc1 args, they are not compatible with existing
2260+ // setting. Clear the previous args.
2261+ if (!clang_opts.empty () && clang_opts.front () == " -cc1" )
2262+ extra_clang_args.clear ();
2263+
21872264 for (const std::string &arg : clang_opts) {
21882265 extra_clang_args.push_back (arg);
21892266 LOG_VERBOSE_PRINTF (GetLog (LLDBLog::Types), " adding Clang argument \" %s\" ." ,
0 commit comments