From c0c13a8d1b987ff64ea8621eb5f6b1b8e9ad149d Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Thu, 27 Apr 2023 13:24:35 -0700 Subject: [PATCH] [Driver] Derive '-external-plugin-path' When the current toolchain is not a Xcode toolchain, derive '-external-plugin-path' poinintng Xcode plugins paths, so we can use plugins in Xcode. rdar://108624128 (cherry picked from commit b0f5c3977f5ff606ea413620c7ccd50ffdddead7) --- lib/Driver/DarwinToolChains.cpp | 95 ++++++++++++++++++++++++++ lib/Driver/ToolChains.cpp | 2 - test/Driver/external-plugin-path.swift | 39 +++++++++++ 3 files changed, 134 insertions(+), 2 deletions(-) create mode 100644 test/Driver/external-plugin-path.swift diff --git a/lib/Driver/DarwinToolChains.cpp b/lib/Driver/DarwinToolChains.cpp index 2dc483ec85de7..f3969819de929 100644 --- a/lib/Driver/DarwinToolChains.cpp +++ b/lib/Driver/DarwinToolChains.cpp @@ -212,6 +212,61 @@ static bool findXcodeClangLibPath(const Twine &libName, return true; } +static bool findXcodeExecutableDir(llvm::SmallVectorImpl &path) { + assert(path.empty()); + + auto xcrunPath = llvm::sys::findProgramByName("xcrun"); + if (!xcrunPath.getError()) { + // Explicitly ask for the default toolchain so that we don't find a swiftc + // included with an open-source toolchain. + const char *args[] = {"-toolchain", "default", "-f", "swiftc", nullptr}; + sys::TaskQueue queue; + queue.addTask(xcrunPath->c_str(), args, /*Env=*/llvm::None, + /*Context=*/nullptr, + /*SeparateErrors=*/true); + queue.execute(nullptr, + [&path](sys::ProcessId PID, int returnCode, StringRef output, + StringRef errors, + sys::TaskProcessInformation ProcInfo, + void *unused) -> sys::TaskFinishedResponse { + if (returnCode == 0) { + output = output.rtrim(); + path.append(output.begin(), output.end()); + llvm::sys::path::remove_filename(path); // 'swiftc' + } + return sys::TaskFinishedResponse::ContinueExecution; + }); + } + + return !path.empty(); +} + +static bool findCurrentSelectedXcodeDir(llvm::SmallVectorImpl &path) { + assert(path.empty()); + + auto xcodeSelectPath = llvm::sys::findProgramByName("xcode-select"); + if (!xcodeSelectPath.getError()) { + const char *args[] = {"-p", nullptr}; + sys::TaskQueue queue; + queue.addTask(xcodeSelectPath->c_str(), args, /*Env=*/llvm::None, + /*Context=*/nullptr, + /*SeparateErrors=*/true); + queue.execute(nullptr, + [&path](sys::ProcessId PID, int returnCode, StringRef output, + StringRef errors, + sys::TaskProcessInformation ProcInfo, + void *unused) -> sys::TaskFinishedResponse { + if (returnCode == 0) { + output = output.rtrim(); + path.append(output.begin(), output.end()); + } + return sys::TaskFinishedResponse::ContinueExecution; + }); + } + + return !path.empty(); +} + static void addVersionString(const ArgList &inputArgs, ArgStringList &arguments, llvm::VersionTuple version) { llvm::SmallString<8> buf; @@ -601,6 +656,46 @@ void toolchains::Darwin::addCommonFrontendArgs( llvm::opt::ArgStringList &arguments) const { ToolChain::addCommonFrontendArgs(OI, output, inputArgs, arguments); + // Pass -external-plugin-path if the current toolchain is not a Xcode default + // toolchain. + { + // 'xcode-select -p' + SmallString<256> xcodeDir; + if (findCurrentSelectedXcodeDir(xcodeDir) && + !StringRef(getDriver().getSwiftProgramPath()).starts_with(xcodeDir)) { + + // 'xcrun -f swiftc' + SmallString<256> xcodeExecutableDir; + if (findXcodeExecutableDir(xcodeExecutableDir)) { + using namespace llvm::sys; + + // '${toolchain}/usr/bin/swift-plugin-server' + SmallString<256> xcodePluginServerPath(xcodeExecutableDir); + path::append(xcodePluginServerPath, "swift-plugin-server"); + if (fs::can_execute(xcodePluginServerPath)) { + + // '${toolchain}/usr/lib/swift/host/plugins' + SmallString<256> xcodePluginPath(xcodeExecutableDir); + path::remove_filename(xcodePluginPath); // 'bin' + path::append(xcodePluginPath, "lib", "swift", "host", "plugins"); + + // '${toolchain}/usr/local/lib/swift/host/plugins' + SmallString<256> xcodeLocalPluginPath(xcodeExecutableDir); + path::remove_filename(xcodeLocalPluginPath); // 'bin' + path::append(xcodeLocalPluginPath, "local"); + path::append(xcodeLocalPluginPath, "lib", "swift", "host", "plugins"); + + arguments.push_back("-external-plugin-path"); + arguments.push_back(inputArgs.MakeArgString(xcodePluginPath + "#" + + xcodePluginServerPath)); + arguments.push_back("-external-plugin-path"); + arguments.push_back(inputArgs.MakeArgString( + xcodeLocalPluginPath + "#" + xcodePluginServerPath)); + } + } + } + } + if (auto sdkVersion = getTargetSDKVersion(getTriple())) { arguments.push_back("-target-sdk-version"); arguments.push_back(inputArgs.MakeArgString(sdkVersion->getAsString())); diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index 23823632051e1..341506cd0293c 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -377,8 +377,6 @@ void ToolChain::addCommonFrontendArgs(const OutputInfo &OI, } // Add plugin path options. - inputArgs.AddAllArgs(arguments, options::OPT_plugin_path); - { SmallString<64> pluginPath; auto programPath = getDriver().getSwiftProgramPath(); diff --git a/test/Driver/external-plugin-path.swift b/test/Driver/external-plugin-path.swift new file mode 100644 index 0000000000000..5cbe62ba815a9 --- /dev/null +++ b/test/Driver/external-plugin-path.swift @@ -0,0 +1,39 @@ +// REQUIRES: OS=macosx + +// RUN: %empty-directory(%t) +// RUN: split-file %s %t + +//# Prepare dummy Xcode.app +// RUN: mkdir -p %t/Xcode.app/Contents/Develoer +// RUN: mkdir -p %t/Xcode.app/Contents/Developer/usr/bin +// RUN: mkdir -p %t/Xcode.app/Contents/Developer/usr/lib/swift/host/plugins +// RUN: mkdir -p %t/Xcode.app/Contents/Developer/usr/local/lib/swift/host/plugins +// RUN: touch %t/Xcode.app/Contents/Developer/usr/bin/swiftc +// RUN: touch %t/Xcode.app/Contents/Developer/usr/bin/swift-plugin-server +// RUN: chmod +x %t/Xcode.app/Contents/Developer/usr/bin/swiftc +// RUN: chmod +x %t/Xcode.app/Contents/Developer/usr/bin/swift-plugin-server + +//# Prepare dummy 'xcode-select' and 'xcrun' +// RUN: mkdir -p %t/usr/bin +// RUN: sed 's;TMPDIR;%t;' %t/xcode-select > %t/usr/bin/xcode-select +// RUN: sed 's;TMPDIR;%t;' %t/xcrun > %t/usr/bin/xcrun +// RUN: chmod +x %t/usr/bin/xcode-select +// RUN: chmod +x %t/usr/bin/xcrun + +// RUN: env PATH=%t/usr/bin %swift_driver_plain -### %t/test.swift | %FileCheck %s + +// CHECK: -plugin-path BUILD_DIR/lib/swift/host/plugins +// CHECK-SAME: -plugin-path BUILD_DIR/local/lib/swift/host/plugins +// CHECK-SAME: -external-plugin-path BUILD_DIR/{{[^#]+}}/Xcode.app/Contents/Developer/usr/lib/swift/host/plugins#BUILD_DIR/{{[^#]+}}/Xcode.app/Contents/Developer/usr/bin/swift-plugin-server +// CHECK-SAME: -external-plugin-path BUILD_DIR/{{[^#]+}}/Xcode.app/Contents/Developer/usr/local/lib/swift/host/plugins#BUILD_DIR/{{[^#]+}}/Xcode.app/Contents/Developer/usr/bin/swift-plugin-server + +//--- xcrun +#!/bin/sh +echo TMPDIR/Xcode.app/Contents/Developer/usr/bin/swiftc + +//--- xcode-select +#!/bin/sh +echo TMPDIR/Xcode.app/Contents/Developer + +//--- test.swift +print(1)