diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index 535496dcfa23e..e63e7952ca3a4 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -99,6 +99,16 @@ namespace swift { /// performed. llvm::Optional TargetVariant; + /// The target triple to instantiate the internal clang instance. + /// When not specified, the compiler will use the value of -target to + /// instantiate the clang instance. + /// This is mainly used to avoid lowering the target triple to use for clang when + /// importing a .swiftinterface whose -target value may be different from + /// the loading module. + /// The lowering triple may result in multiple versions of the same Clang + /// modules being built. + llvm::Optional ClangTarget; + /// The SDK version, if known. Optional SDKVersion; diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index 4a87750912a9f..fbb178fff226d 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -1082,6 +1082,10 @@ def target_variant : Separate<["-"], "target-variant">, HelpText<"Generate 'zippered' code for macCatalyst that can run on the specified" " variant target triple in addition to the main -target triple">; +def clang_target : Separate<["-"], "clang-target">, + Flags<[FrontendOption, SwiftAPIExtractOption, SwiftSymbolGraphExtractOption, SwiftAPIDigesterOption]>, + HelpText<"Separately set the target we should use for internal Clang instance">; + def profile_generate : Flag<["-"], "profile-generate">, Flags<[FrontendOption, NoInteractiveOption]>, HelpText<"Generate instrumented code to collect execution counts">; diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index 2c968fdea1947..7e5f3a10f6225 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -730,7 +730,11 @@ importer::addCommonInvocationArguments( std::vector &invocationArgStrs, ASTContext &ctx) { using ImporterImpl = ClangImporter::Implementation; - const llvm::Triple &triple = ctx.LangOpts.Target; + llvm::Triple triple = ctx.LangOpts.Target; + // Use clang specific target triple if given. + if (ctx.LangOpts.ClangTarget.hasValue()) { + triple = ctx.LangOpts.ClangTarget.getValue(); + } SearchPathOptions &searchPathOpts = ctx.SearchPathOpts; const ClangImporterOptions &importerOpts = ctx.ClangImporterOpts; diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 0f69ea7926dab..bcc19ee54eb26 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -686,6 +686,20 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.TargetVariant = llvm::Triple(A->getValue()); } + // Collect -clang-target value if specified in the front-end invocation. + // Usually, the driver will pass down a clang target with the + // exactly same value as the main target, so we could dignose the usage of + // unavailable APIs. + // The reason we cannot infer clang target from -target is that not all + // front-end invocation will include a -target to start with. For instance, + // when compiling a Swift module from a textual interface, -target isn't + // necessary because the textual interface hardcoded the proper target triple + // to use. Inferring -clang-target there will always give us the default + // target triple. + if (const Arg *A = Args.getLastArg(OPT_clang_target)) { + Opts.ClangTarget = llvm::Triple(A->getValue()); + } + Opts.EnableCXXInterop |= Args.hasArg(OPT_enable_cxx_interop); Opts.EnableObjCInterop = Args.hasFlag(OPT_enable_objc_interop, OPT_disable_objc_interop, diff --git a/lib/Frontend/ModuleInterfaceLoader.cpp b/lib/Frontend/ModuleInterfaceLoader.cpp index 173fab534b2c1..27352cdd08970 100644 --- a/lib/Frontend/ModuleInterfaceLoader.cpp +++ b/lib/Frontend/ModuleInterfaceLoader.cpp @@ -1269,6 +1269,17 @@ void InterfaceSubContextDelegateImpl::inheritOptionsForBuildingInterface( GenericArgs.push_back(triple); } + if (LangOpts.ClangTarget.hasValue()) { + genericSubInvocation.getLangOptions().ClangTarget = LangOpts.ClangTarget; + auto triple = ArgSaver.save(genericSubInvocation.getLangOptions() + .ClangTarget->getTriple()); + assert(!triple.empty()); + // In explicit module build, all PCMs will be built using the given clang target. + // So the Swift interface should know that as well to load these PCMs properly. + GenericArgs.push_back("-clang-target"); + GenericArgs.push_back(triple); + } + // Inherit the Swift language version genericSubInvocation.getLangOptions().EffectiveLanguageVersion = LangOpts.EffectiveLanguageVersion; diff --git a/test/ScanDependencies/Inputs/Swift/XWithTarget.swiftinterface b/test/ScanDependencies/Inputs/Swift/XWithTarget.swiftinterface new file mode 100644 index 0000000000000..dbffe1bbdeb2f --- /dev/null +++ b/test/ScanDependencies/Inputs/Swift/XWithTarget.swiftinterface @@ -0,0 +1,5 @@ +// swift-interface-format-version: 1.0 +// swift-module-flags: -module-name XWithTarget -target x86_64-apple-macosx10.9 +import Swift +@_exported import X +public func overlayFuncX() { } diff --git a/test/ScanDependencies/clang-target.swift b/test/ScanDependencies/clang-target.swift new file mode 100644 index 0000000000000..82b2b5a156a0c --- /dev/null +++ b/test/ScanDependencies/clang-target.swift @@ -0,0 +1,21 @@ +// REQUIRES: VENDOR=apple +// RUN: %empty-directory(%t.module-cache) +// RUN: %target-swift-frontend -emit-module -o %t.foo.swiftmodule -module-cache-path %t.module-cache -I %S/Inputs/CHeaders -I %S/Inputs/Swift %s -target x86_64-apple-macosx10.14 + +// Without -clang-target, we build two X.pcm +// RUN: find %t.module-cache -name "X-*.pcm" | count 2 + +// RUN: %empty-directory(%t.module-cache) +// RUN: %target-swift-frontend -emit-module -o %t.foo.swiftmodule -module-cache-path %t.module-cache -I %S/Inputs/CHeaders -I %S/Inputs/Swift %s -target x86_64-apple-macosx10.14 -clang-target x86_64-apple-macosx10.14 + +// With -clang-target, we build one X.pcm +// RUN: find %t.module-cache -name "X-*.pcm" | count 1 + +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t.module-cache %s -o %t.deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -target x86_64-apple-macosx10.14 -clang-target x86_64-apple-macosx10.14 +// RUN: %FileCheck %s < %t.deps.json + +// CHECK: "-clang-target" +// CHECK-NEXT: "x86_64-apple-macosx10.14" + +import X +import XWithTarget