Skip to content

Commit 3d16557

Browse files
authored
[ModuleInterface] Look for a prebuilt module by full target name (#24402)
Although the default cache location separates by platform, a /combined/ cache is still an interesting idea, and in that case we need to use the full platform names.
1 parent f863700 commit 3d16557

File tree

2 files changed

+95
-2
lines changed

2 files changed

+95
-2
lines changed

lib/Frontend/ParseableInterfaceModuleLoader.cpp

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "swift/AST/Module.h"
2020
#include "swift/AST/ProtocolConformance.h"
2121
#include "swift/Basic/Lazy.h"
22+
#include "swift/Basic/Platform.h"
2223
#include "swift/Basic/STLExtras.h"
2324
#include "swift/Frontend/Frontend.h"
2425
#include "swift/Frontend/ParseableInterfaceSupport.h"
@@ -826,7 +827,7 @@ class ParseableInterfaceModuleLoaderImpl {
826827
// Assemble the expected path: $PREBUILT_CACHE/Foo.swiftmodule or
827828
// $PREBUILT_CACHE/Foo.swiftmodule/arch.swiftmodule. Note that there's no
828829
// cache key here.
829-
scratch.append(prebuiltCacheDir);
830+
scratch = prebuiltCacheDir;
830831

831832
// FIXME: Would it be possible to only have architecture-specific names
832833
// here? Then we could skip this check.
@@ -845,6 +846,48 @@ class ParseableInterfaceModuleLoaderImpl {
845846
return scratch.str();
846847
}
847848

849+
/// Hack to deal with build systems (including the Swift standard library, at
850+
/// the time of this comment) that aren't yet using target-specific names for
851+
/// multi-target swiftmodules, in case the prebuilt cache is.
852+
Optional<StringRef>
853+
computeFallbackPrebuiltModulePath(llvm::SmallString<256> &scratch) {
854+
namespace path = llvm::sys::path;
855+
StringRef sdkPath = ctx.SearchPathOpts.SDKPath;
856+
857+
// Check if the interface file comes from the SDK
858+
if (sdkPath.empty() || !hasPrefix(path::begin(interfacePath),
859+
path::end(interfacePath),
860+
path::begin(sdkPath),
861+
path::end(sdkPath)))
862+
return None;
863+
864+
// If the module isn't target-specific, there's no fallback path.
865+
StringRef inParentDirName =
866+
path::filename(path::parent_path(interfacePath));
867+
if (path::extension(inParentDirName) != ".swiftmodule")
868+
return None;
869+
870+
// If the interface is already using the target-specific name, there's
871+
// nothing else to try.
872+
auto normalizedTarget = getTargetSpecificModuleTriple(ctx.LangOpts.Target);
873+
if (path::stem(modulePath) == normalizedTarget.str())
874+
return None;
875+
876+
// Assemble the expected path:
877+
// $PREBUILT_CACHE/Foo.swiftmodule/target.swiftmodule. Note that there's no
878+
// cache key here.
879+
scratch = prebuiltCacheDir;
880+
path::append(scratch, inParentDirName);
881+
path::append(scratch, normalizedTarget.str());
882+
scratch += ".swiftmodule";
883+
884+
// If there isn't a file at this location, skip returning a path.
885+
if (!fs.exists(scratch))
886+
return None;
887+
888+
return scratch.str();
889+
}
890+
848891
bool isInResourceDir(StringRef path) {
849892
StringRef resourceDir = ctx.SearchPathOpts.RuntimeLibraryPath;
850893
if (resourceDir.empty()) return false;
@@ -926,7 +969,12 @@ class ParseableInterfaceModuleLoaderImpl {
926969
if (!prebuiltCacheDir.empty()) {
927970
llvm::SmallString<256> scratch;
928971
std::unique_ptr<llvm::MemoryBuffer> moduleBuffer;
929-
auto path = computePrebuiltModulePath(scratch);
972+
Optional<StringRef> path = computePrebuiltModulePath(scratch);
973+
if (!path) {
974+
// Hack: deal with prebuilds of modules that still use the target-based
975+
// names.
976+
path = computeFallbackPrebuiltModulePath(scratch);
977+
}
930978
if (path) {
931979
if (swiftModuleIsUpToDate(*path, deps, moduleBuffer)) {
932980
LLVM_DEBUG(llvm::dbgs() << "Found up-to-date prebuilt module at "
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Like prebuilt-module-cache-archs.swift, but testing the fallback behavior.
2+
// This means we have to know the expected names in advance, so this test only
3+
// runs on macOS.
4+
5+
// REQUIRES: OS=macosx
6+
// REQUIRES: CPU=x86_64
7+
8+
// Use the short name "x86_64.swiftmodule".
9+
// RUN: %empty-directory(%t)
10+
// RUN: %empty-directory(%t/include/Lib.swiftmodule)
11+
// RUN: cp %S/Inputs/prebuilt-module-cache/Lib.swiftinterface %t/include/Lib.swiftmodule/x86_64.swiftinterface
12+
13+
// Do a manual prebuild with the long name "x86_64-apple-macos.swiftmodule",
14+
// and see if it gets picked up.
15+
// RUN: %empty-directory(%t/MCP)
16+
// RUN: %empty-directory(%t/prebuilt-cache/Lib.swiftmodule)
17+
// RUN: sed -e 's/FromInterface/FromPrebuiltLong/g' %S/Inputs/prebuilt-module-cache/Lib.swiftinterface | %target-swift-frontend -parse-stdlib -module-cache-path %t/MCP -emit-module-path %t/prebuilt-cache/Lib.swiftmodule/x86_64-apple-macos.swiftmodule - -module-name Lib
18+
// RUN: not %target-swift-frontend -typecheck -parse-stdlib -module-cache-path %t/MCP -sdk %t/include -I %t/include/ -prebuilt-module-cache-path %t/prebuilt-cache %s 2>&1 | %FileCheck -check-prefix=FROM-PREBUILT-LONG %s
19+
// RUN: %{python} %S/Inputs/check-is-forwarding-module.py %t/MCP/Lib-*.swiftmodule
20+
21+
// Prefer a matching name.
22+
// RUN: %empty-directory(%t/MCP)
23+
// RUN: sed -e 's/FromInterface/FromPrebuiltShort/g' %S/Inputs/prebuilt-module-cache/Lib.swiftinterface | %target-swift-frontend -parse-stdlib -module-cache-path %t/MCP -emit-module-path %t/prebuilt-cache/Lib.swiftmodule/x86_64.swiftmodule - -module-name Lib
24+
// RUN: not %target-swift-frontend -typecheck -parse-stdlib -module-cache-path %t/MCP -sdk %t/include -I %t/include/ -prebuilt-module-cache-path %t/prebuilt-cache %s 2>&1 | %FileCheck -check-prefix=FROM-PREBUILT-SHORT %s
25+
// RUN: %{python} %S/Inputs/check-is-forwarding-module.py %t/MCP/Lib-*.swiftmodule
26+
27+
// Prefer a matching name in the other direction too.
28+
// RUN: %empty-directory(%t/MCP)
29+
// RUN: mv %t/include/Lib.swiftmodule/x86_64.swiftinterface %t/include/Lib.swiftmodule/x86_64-apple-macos.swiftinterface
30+
// RUN: not %target-swift-frontend -typecheck -parse-stdlib -module-cache-path %t/MCP -sdk %t/include -I %t/include/ -prebuilt-module-cache-path %t/prebuilt-cache %s 2>&1 | %FileCheck -check-prefix=FROM-PREBUILT-LONG %s
31+
// RUN: %{python} %S/Inputs/check-is-forwarding-module.py %t/MCP/Lib-*.swiftmodule
32+
33+
// Don't do the fallback thing for long names to short names.
34+
// RUN: %empty-directory(%t/MCP)
35+
// RUN: rm %t/prebuilt-cache/Lib.swiftmodule/x86_64-apple-macos.swiftmodule
36+
// RUN: not %target-swift-frontend -typecheck -parse-stdlib -module-cache-path %t/MCP -sdk %t/include -I %t/include/ -prebuilt-module-cache-path %t/prebuilt-cache %s 2>&1 | %FileCheck -check-prefix=FROM-INTERFACE %s
37+
// RUN: not %{python} %S/Inputs/check-is-forwarding-module.py %t/MCP/Lib-*.swiftmodule
38+
39+
import Lib
40+
41+
struct X {}
42+
let _: X = Lib.testValue
43+
// FROM-INTERFACE: [[@LINE-1]]:16: error: cannot convert value of type 'FromInterface' to specified type 'X'
44+
// FROM-PREBUILT-LONG: [[@LINE-2]]:16: error: cannot convert value of type 'FromPrebuiltLong' to specified type 'X'
45+
// FROM-PREBUILT-SHORT: [[@LINE-3]]:16: error: cannot convert value of type 'FromPrebuiltShort' to specified type 'X'

0 commit comments

Comments
 (0)