Skip to content

[ModuleInterface] Look for a prebuilt module by full target name #24402

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 1, 2019
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
52 changes: 50 additions & 2 deletions lib/Frontend/ParseableInterfaceModuleLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "swift/AST/Module.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/Basic/Lazy.h"
#include "swift/Basic/Platform.h"
#include "swift/Basic/STLExtras.h"
#include "swift/Frontend/Frontend.h"
#include "swift/Frontend/ParseableInterfaceSupport.h"
Expand Down Expand Up @@ -826,7 +827,7 @@ class ParseableInterfaceModuleLoaderImpl {
// Assemble the expected path: $PREBUILT_CACHE/Foo.swiftmodule or
// $PREBUILT_CACHE/Foo.swiftmodule/arch.swiftmodule. Note that there's no
// cache key here.
scratch.append(prebuiltCacheDir);
scratch = prebuiltCacheDir;

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

/// Hack to deal with build systems (including the Swift standard library, at
/// the time of this comment) that aren't yet using target-specific names for
/// multi-target swiftmodules, in case the prebuilt cache is.
Optional<StringRef>
computeFallbackPrebuiltModulePath(llvm::SmallString<256> &scratch) {
namespace path = llvm::sys::path;
StringRef sdkPath = ctx.SearchPathOpts.SDKPath;

// Check if the interface file comes from the SDK
if (sdkPath.empty() || !hasPrefix(path::begin(interfacePath),
path::end(interfacePath),
path::begin(sdkPath),
path::end(sdkPath)))
return None;

// If the module isn't target-specific, there's no fallback path.
StringRef inParentDirName =
path::filename(path::parent_path(interfacePath));
if (path::extension(inParentDirName) != ".swiftmodule")
return None;

// If the interface is already using the target-specific name, there's
// nothing else to try.
auto normalizedTarget = getTargetSpecificModuleTriple(ctx.LangOpts.Target);
if (path::stem(modulePath) == normalizedTarget.str())
return None;

// Assemble the expected path:
// $PREBUILT_CACHE/Foo.swiftmodule/target.swiftmodule. Note that there's no
// cache key here.
scratch = prebuiltCacheDir;
path::append(scratch, inParentDirName);
path::append(scratch, normalizedTarget.str());
scratch += ".swiftmodule";

// If there isn't a file at this location, skip returning a path.
if (!fs.exists(scratch))
return None;

return scratch.str();
}

bool isInResourceDir(StringRef path) {
StringRef resourceDir = ctx.SearchPathOpts.RuntimeLibraryPath;
if (resourceDir.empty()) return false;
Expand Down Expand Up @@ -926,7 +969,12 @@ class ParseableInterfaceModuleLoaderImpl {
if (!prebuiltCacheDir.empty()) {
llvm::SmallString<256> scratch;
std::unique_ptr<llvm::MemoryBuffer> moduleBuffer;
auto path = computePrebuiltModulePath(scratch);
Optional<StringRef> path = computePrebuiltModulePath(scratch);
if (!path) {
// Hack: deal with prebuilds of modules that still use the target-based
// names.
path = computeFallbackPrebuiltModulePath(scratch);
}
if (path) {
if (swiftModuleIsUpToDate(*path, deps, moduleBuffer)) {
LLVM_DEBUG(llvm::dbgs() << "Found up-to-date prebuilt module at "
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Like prebuilt-module-cache-archs.swift, but testing the fallback behavior.
// This means we have to know the expected names in advance, so this test only
// runs on macOS.

// REQUIRES: OS=macosx
// REQUIRES: CPU=x86_64

// Use the short name "x86_64.swiftmodule".
// RUN: %empty-directory(%t)
// RUN: %empty-directory(%t/include/Lib.swiftmodule)
// RUN: cp %S/Inputs/prebuilt-module-cache/Lib.swiftinterface %t/include/Lib.swiftmodule/x86_64.swiftinterface

// Do a manual prebuild with the long name "x86_64-apple-macos.swiftmodule",
// and see if it gets picked up.
// RUN: %empty-directory(%t/MCP)
// RUN: %empty-directory(%t/prebuilt-cache/Lib.swiftmodule)
// 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
// 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
// RUN: %{python} %S/Inputs/check-is-forwarding-module.py %t/MCP/Lib-*.swiftmodule

// Prefer a matching name.
// RUN: %empty-directory(%t/MCP)
// 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
// 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
// RUN: %{python} %S/Inputs/check-is-forwarding-module.py %t/MCP/Lib-*.swiftmodule

// Prefer a matching name in the other direction too.
// RUN: %empty-directory(%t/MCP)
// RUN: mv %t/include/Lib.swiftmodule/x86_64.swiftinterface %t/include/Lib.swiftmodule/x86_64-apple-macos.swiftinterface
// 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
// RUN: %{python} %S/Inputs/check-is-forwarding-module.py %t/MCP/Lib-*.swiftmodule

// Don't do the fallback thing for long names to short names.
// RUN: %empty-directory(%t/MCP)
// RUN: rm %t/prebuilt-cache/Lib.swiftmodule/x86_64-apple-macos.swiftmodule
// 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
// RUN: not %{python} %S/Inputs/check-is-forwarding-module.py %t/MCP/Lib-*.swiftmodule

import Lib

struct X {}
let _: X = Lib.testValue
// FROM-INTERFACE: [[@LINE-1]]:16: error: cannot convert value of type 'FromInterface' to specified type 'X'
// FROM-PREBUILT-LONG: [[@LINE-2]]:16: error: cannot convert value of type 'FromPrebuiltLong' to specified type 'X'
// FROM-PREBUILT-SHORT: [[@LINE-3]]:16: error: cannot convert value of type 'FromPrebuiltShort' to specified type 'X'