From 515cf21ba345fe1ebbdc640ac0f397686dd84597 Mon Sep 17 00:00:00 2001 From: Xi Ge Date: Tue, 13 Jul 2021 10:03:08 -0700 Subject: [PATCH] driver: refactor driver tool logics into a library. NFC --- include/swift/DriverTool/DriverTool.h | 27 ++ lib/CMakeLists.txt | 1 + lib/DriverTool/CMakeLists.txt | 30 ++ .../DriverTool}/autolink_extract_main.cpp | 0 lib/DriverTool/driver.cpp | 404 ++++++++++++++++++ .../DriverTool}/modulewrap_main.cpp | 0 .../DriverTool}/swift_api_digester_main.cpp | 0 .../DriverTool}/swift_api_extract_main.cpp | 0 .../DriverTool}/swift_indent_main.cpp | 0 .../swift_symbolgraph_extract_main.cpp | 0 tools/driver/CMakeLists.txt | 31 +- tools/driver/driver.cpp | 386 +---------------- 12 files changed, 467 insertions(+), 412 deletions(-) create mode 100644 include/swift/DriverTool/DriverTool.h create mode 100644 lib/DriverTool/CMakeLists.txt rename {tools/driver => lib/DriverTool}/autolink_extract_main.cpp (100%) create mode 100644 lib/DriverTool/driver.cpp rename {tools/driver => lib/DriverTool}/modulewrap_main.cpp (100%) rename {tools/driver => lib/DriverTool}/swift_api_digester_main.cpp (100%) rename {tools/driver => lib/DriverTool}/swift_api_extract_main.cpp (100%) rename {tools/driver => lib/DriverTool}/swift_indent_main.cpp (100%) rename {tools/driver => lib/DriverTool}/swift_symbolgraph_extract_main.cpp (100%) diff --git a/include/swift/DriverTool/DriverTool.h b/include/swift/DriverTool/DriverTool.h new file mode 100644 index 00000000000..a387ab3527d --- /dev/null +++ b/include/swift/DriverTool/DriverTool.h @@ -0,0 +1,27 @@ +//===--- DriverTool.h - Driver control ----------------------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This file provides a high-level API for interacting with the basic +// driver operation. +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_DRIVERTOOL_H +#define SWIFT_DRIVERTOOL_H + +#include "swift/Basic/LLVM.h" + +namespace swift { + int mainEntry(int argc_, const char **argv_); +} // namespace swift + +#endif diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 69d6d1a3bcd..6a3ea1e38ff 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -22,6 +22,7 @@ add_subdirectory(ClangImporter) add_subdirectory(Demangling) add_subdirectory(DependencyScan) add_subdirectory(Driver) +add_subdirectory(DriverTool) add_subdirectory(Frontend) add_subdirectory(FrontendTool) add_subdirectory(Index) diff --git a/lib/DriverTool/CMakeLists.txt b/lib/DriverTool/CMakeLists.txt new file mode 100644 index 00000000000..dd06606195b --- /dev/null +++ b/lib/DriverTool/CMakeLists.txt @@ -0,0 +1,30 @@ +set(driver_sources_and_options + driver.cpp + autolink_extract_main.cpp + modulewrap_main.cpp + swift_api_digester_main.cpp + swift_indent_main.cpp + swift_symbolgraph_extract_main.cpp + swift_api_extract_main.cpp) + +set(driver_common_libs + swiftAPIDigester + swiftDriver + swiftFrontendTool + swiftSymbolGraphGen + LLVMBitstreamReader + libswift) + +add_swift_host_library(swiftDriverTool STATIC + ${driver_sources_and_options} +) +target_link_libraries(swiftDriverTool + PUBLIC + ${driver_common_libs}) + +# If building as part of clang, make sure the headers are installed. +if(NOT SWIFT_BUILT_STANDALONE) + add_dependencies(swiftDriverTool clang-resource-headers) +endif() + +set_swift_llvm_is_available(swiftDriverTool) diff --git a/tools/driver/autolink_extract_main.cpp b/lib/DriverTool/autolink_extract_main.cpp similarity index 100% rename from tools/driver/autolink_extract_main.cpp rename to lib/DriverTool/autolink_extract_main.cpp diff --git a/lib/DriverTool/driver.cpp b/lib/DriverTool/driver.cpp new file mode 100644 index 00000000000..825946e161d --- /dev/null +++ b/lib/DriverTool/driver.cpp @@ -0,0 +1,404 @@ +//===--- driver.cpp - Swift Compiler Driver -------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// +// +// This is the entry point to the swift compiler driver. +// +//===----------------------------------------------------------------------===// + +#include "swift/AST/DiagnosticEngine.h" +#include "swift/AST/DiagnosticsDriver.h" +#include "swift/Basic/LLVMInitialize.h" +#include "swift/Basic/InitializeLibSwift.h" +#include "swift/Basic/PrettyStackTrace.h" +#include "swift/Basic/Program.h" +#include "swift/Basic/TaskQueue.h" +#include "swift/Basic/SourceManager.h" +#include "swift/Driver/Compilation.h" +#include "swift/Driver/Driver.h" +#include "swift/Driver/FrontendUtil.h" +#include "swift/Driver/Job.h" +#include "swift/Driver/ToolChain.h" +#include "swift/Frontend/Frontend.h" +#include "swift/Frontend/PrintingDiagnosticConsumer.h" +#include "swift/FrontendTool/FrontendTool.h" +#include "swift/DriverTool/DriverTool.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/Errno.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/StringSaver.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Support/raw_ostream.h" + +#include +#include + +#if defined(_WIN32) +#include +#endif + +using namespace swift; +using namespace swift::driver; + +std::string getExecutablePath(const char *FirstArg) { + void *P = (void *)(intptr_t)getExecutablePath; + return llvm::sys::fs::getMainExecutable(FirstArg, P); +} + +/// Run 'swift-autolink-extract'. +extern int autolink_extract_main(ArrayRef Args, const char *Argv0, + void *MainAddr); + +extern int modulewrap_main(ArrayRef Args, const char *Argv0, + void *MainAddr); + +/// Run 'swift-indent' +extern int swift_indent_main(ArrayRef Args, const char *Argv0, + void *MainAddr); + +/// Run 'swift-symbolgraph-extract' +extern int swift_symbolgraph_extract_main(ArrayRef Args, const char *Argv0, +void *MainAddr); + +/// Run 'swift-api-digester' +extern int swift_api_digester_main(ArrayRef Args, + const char *Argv0, void *MainAddr); + +/// Run 'swift-api-extract' +extern int swift_api_extract_main(ArrayRef Args, + const char *Argv0, void *MainAddr); + +/// Determine if the given invocation should run as a "subcommand". +/// +/// Examples of "subcommands" are 'swift build' or 'swift test', which are +/// usually used to invoke the Swift package manager executables 'swift-build' +/// and 'swift-test', respectively. +/// +/// \param ExecName The name of the argv[0] we were invoked as. +/// \param SubcommandName On success, the full name of the subcommand to invoke. +/// \param Args On return, the adjusted program arguments to use. +/// \returns True if running as a subcommand. +static bool shouldRunAsSubcommand(StringRef ExecName, + SmallString<256> &SubcommandName, + const ArrayRef Args, + bool &isRepl) { + assert(!Args.empty()); + + // If we are not run as 'swift', don't do anything special. This doesn't work + // with symlinks with alternate names, but we can't detect 'swift' vs 'swiftc' + // if we try and resolve using the actual executable path. + if (ExecName != "swift") + return false; + + // If there are no program arguments, always invoke as normal. + if (Args.size() == 1) + return false; + + // Otherwise, we have a program argument. If it looks like an option or a + // path, then invoke in interactive mode with the arguments as given. + StringRef FirstArg(Args[1]); + if (FirstArg.startswith("-") || FirstArg.contains('.') || + FirstArg.contains('/')) + return false; + + // Otherwise, we should have some sort of subcommand. Get the subcommand name + // and remove it from the program arguments. + StringRef Subcommand = Args[1]; + + // If the subcommand is the "built-in" 'repl', then use the + // normal driver. + if (Subcommand == "repl") { + isRepl = true; + return false; + } + + // Form the subcommand name. + SubcommandName.assign("swift-"); + SubcommandName.append(Subcommand); + + return true; +} + +static bool shouldDisallowNewDriver(DiagnosticEngine &diags, + StringRef ExecName, + const ArrayRef argv) { + // We are not invoking the driver, so don't forward. + if (ExecName != "swift" && ExecName != "swiftc") { + return true; + } + StringRef disableArg = "-disallow-use-new-driver"; + StringRef disableEnv = "SWIFT_USE_OLD_DRIVER"; + auto shouldWarn = !llvm::sys::Process:: + GetEnv("SWIFT_AVOID_WARNING_USING_OLD_DRIVER").hasValue(); + // If user specified using the old driver, don't forward. + if (llvm::find_if(argv, [&](const char* arg) { + return StringRef(arg) == disableArg; + }) != argv.end()) { + if (shouldWarn) + diags.diagnose(SourceLoc(), diag::old_driver_deprecated, disableArg); + return true; + } + if (llvm::sys::Process::GetEnv(disableEnv).hasValue()) { + if (shouldWarn) + diags.diagnose(SourceLoc(), diag::old_driver_deprecated, disableEnv); + return true; + } + return false; +} + +static bool appendSwiftDriverName(SmallString<256> &buffer) { + assert(llvm::sys::fs::exists(buffer)); + if (auto driverNameOp = llvm::sys::Process::GetEnv("SWIFT_USE_NEW_DRIVER")) { + llvm::sys::path::append(buffer, *driverNameOp); + return true; + } + + llvm::sys::path::append(buffer, "swift-driver"); + if (llvm::sys::fs::exists(buffer)) { + return true; + } + llvm::sys::path::remove_filename(buffer); + llvm::sys::path::append(buffer, "swift-driver-new"); + if (llvm::sys::fs::exists(buffer)) { + return true; + } + + return false; +} + +static int run_driver(StringRef ExecName, + const ArrayRef argv) { + // This is done here and not done in FrontendTool.cpp, because + // FrontendTool.cpp is linked to tools, which don't use libswift. + initializeLibSwift(); + + // Handle integrated tools. + if (argv.size() > 1) { + StringRef FirstArg(argv[1]); + if (FirstArg == "-frontend") { + return performFrontend(llvm::makeArrayRef(argv.data()+2, + argv.data()+argv.size()), + argv[0], (void *)(intptr_t)getExecutablePath); + } + if (FirstArg == "-modulewrap") { + return modulewrap_main(llvm::makeArrayRef(argv.data()+2, + argv.data()+argv.size()), + argv[0], (void *)(intptr_t)getExecutablePath); + } + + // Run the integrated Swift frontend when called as "swift-frontend" but + // without a leading "-frontend". + if (!FirstArg.startswith("--driver-mode=") + && ExecName == "swift-frontend") { + return performFrontend(llvm::makeArrayRef(argv.data()+1, + argv.data()+argv.size()), + argv[0], (void *)(intptr_t)getExecutablePath); + } + } + + std::string Path = getExecutablePath(argv[0]); + + PrintingDiagnosticConsumer PDC; + + SourceManager SM; + DiagnosticEngine Diags(SM); + Diags.addConsumer(PDC); + + // Forwarding calls to the swift driver if the C++ driver is invoked as `swift` + // or `swiftc`, and an environment variable SWIFT_USE_NEW_DRIVER is defined. + if (!shouldDisallowNewDriver(Diags, ExecName, argv)) { + SmallString<256> NewDriverPath(llvm::sys::path::parent_path(Path)); + if (appendSwiftDriverName(NewDriverPath) && + llvm::sys::fs::exists(NewDriverPath)) { + std::vector subCommandArgs; + // Rewrite the program argument. + subCommandArgs.push_back(NewDriverPath.c_str()); + if (ExecName == "swiftc") { + subCommandArgs.push_back("--driver-mode=swiftc"); + } else { + assert(ExecName == "swift"); + subCommandArgs.push_back("--driver-mode=swift"); + } + // Push these non-op frontend arguments so the build log can indicate + // the new driver is used. + subCommandArgs.push_back("-Xfrontend"); + subCommandArgs.push_back("-new-driver-path"); + subCommandArgs.push_back("-Xfrontend"); + subCommandArgs.push_back(NewDriverPath.c_str()); + + // Push on the source program arguments + subCommandArgs.insert(subCommandArgs.end(), argv.begin() + 1, argv.end()); + + // Execute the subcommand. + subCommandArgs.push_back(nullptr); + ExecuteInPlace(NewDriverPath.c_str(), subCommandArgs.data()); + + // If we reach here then an error occurred (typically a missing path). + std::string ErrorString = llvm::sys::StrError(); + llvm::errs() << "error: unable to invoke subcommand: " << subCommandArgs[0] + << " (" << ErrorString << ")\n"; + return 2; + } + } + + Driver TheDriver(Path, ExecName, argv, Diags); + switch (TheDriver.getDriverKind()) { + case Driver::DriverKind::AutolinkExtract: + return autolink_extract_main( + TheDriver.getArgsWithoutProgramNameAndDriverMode(argv), + argv[0], (void *)(intptr_t)getExecutablePath); + case Driver::DriverKind::SwiftIndent: + return swift_indent_main( + TheDriver.getArgsWithoutProgramNameAndDriverMode(argv), + argv[0], (void *)(intptr_t)getExecutablePath); + case Driver::DriverKind::SymbolGraph: + return swift_symbolgraph_extract_main(TheDriver.getArgsWithoutProgramNameAndDriverMode(argv), argv[0], (void *)(intptr_t)getExecutablePath); + case Driver::DriverKind::APIExtract: + return swift_api_extract_main( + TheDriver.getArgsWithoutProgramNameAndDriverMode(argv), argv[0], + (void *)(intptr_t)getExecutablePath); + case Driver::DriverKind::APIDigester: + return swift_api_digester_main( + TheDriver.getArgsWithoutProgramNameAndDriverMode(argv), argv[0], + (void *)(intptr_t)getExecutablePath); + default: + break; + } + + std::unique_ptr ArgList = + TheDriver.parseArgStrings(ArrayRef(argv).slice(1)); + if (Diags.hadAnyError()) + return 1; + + std::unique_ptr TC = TheDriver.buildToolChain(*ArgList); + if (Diags.hadAnyError()) + return 1; + + for (auto arg: ArgList->getArgs()) { + if (arg->getOption().hasFlag(options::NewDriverOnlyOption)) { + Diags.diagnose(SourceLoc(), diag::warning_unsupported_driver_option, + arg->getSpelling()); + } + } + + std::unique_ptr C = + TheDriver.buildCompilation(*TC, std::move(ArgList)); + + if (Diags.hadAnyError()) + return 1; + + if (C) { + std::unique_ptr TQ = TheDriver.buildTaskQueue(*C); + if (!TQ) + return 1; + return C->performJobs(std::move(TQ)).exitCode; + } + + return 0; +} + +int swift::mainEntry(int argc_, const char **argv_) { +#if defined(_WIN32) + LPWSTR *wargv_ = CommandLineToArgvW(GetCommandLineW(), &argc_); + std::vector utf8Args; + // We use UTF-8 as the internal character encoding. On Windows, + // arguments passed to wmain are encoded in UTF-16 + for (int i = 0; i < argc_; i++) { + const wchar_t *wideArg = wargv_[i]; + int wideArgLen = std::wcslen(wideArg); + utf8Args.push_back(""); + llvm::ArrayRef uRef((const char *)wideArg, + (const char *)(wideArg + wideArgLen)); + llvm::convertUTF16ToUTF8String(uRef, utf8Args[i]); + } + + std::vector utf8CStrs; + llvm::transform(utf8Args, std::back_inserter(utf8CStrs), + std::mem_fn(&std::string::c_str)); + argv_ = utf8CStrs.data(); +#endif + // Expand any response files in the command line argument vector - arguments + // may be passed through response files in the event of command line length + // restrictions. + SmallVector ExpandedArgs(&argv_[0], &argv_[argc_]); + llvm::BumpPtrAllocator Allocator; + llvm::StringSaver Saver(Allocator); + swift::driver::ExpandResponseFilesWithRetry(Saver, ExpandedArgs); + + // Initialize the stack trace using the parsed argument vector with expanded + // response files. + + // PROGRAM_START/InitLLVM overwrites the passed in arguments with UTF-8 + // versions of them on Windows. This also has the effect of overwriting the + // response file expansion. Since we handle the UTF-8 conversion above, we + // pass in a copy and throw away the modifications. + int ThrowawayExpandedArgc = ExpandedArgs.size(); + const char **ThrowawayExpandedArgv = ExpandedArgs.data(); + PROGRAM_START(ThrowawayExpandedArgc, ThrowawayExpandedArgv); + ArrayRef argv(ExpandedArgs); + + PrettyStackTraceSwiftVersion versionStackTrace; + + // Check if this invocation should execute a subcommand. + StringRef ExecName = llvm::sys::path::stem(argv[0]); + SmallString<256> SubcommandName; + bool isRepl = false; + if (shouldRunAsSubcommand(ExecName, SubcommandName, argv, isRepl)) { + // Preserve argv for the stack trace. + SmallVector subCommandArgs(argv.begin(), argv.end()); + subCommandArgs.erase(&subCommandArgs[1]); + // We are running as a subcommand, try to find the subcommand adjacent to + // the executable we are running as. + SmallString<256> SubcommandPath( + llvm::sys::path::parent_path(getExecutablePath(argv[0]))); + llvm::sys::path::append(SubcommandPath, SubcommandName); + + // If we didn't find the tool there, let the OS search for it. + if (!llvm::sys::fs::exists(SubcommandPath)) { + // Search for the program and use the path if found. If there was an + // error, ignore it and just let the exec fail. + auto result = llvm::sys::findProgramByName(SubcommandName); + if (!result.getError()) + SubcommandPath = *result; + } + + // Rewrite the program argument. + subCommandArgs[0] = SubcommandPath.c_str(); + + // Execute the subcommand. + subCommandArgs.push_back(nullptr); + ExecuteInPlace(SubcommandPath.c_str(), subCommandArgs.data()); + + // If we reach here then an error occurred (typically a missing path). + std::string ErrorString = llvm::sys::StrError(); + llvm::errs() << "error: unable to invoke subcommand: " << subCommandArgs[0] + << " (" << ErrorString << ")\n"; + return 2; + } + + if (isRepl) { + // Preserve argv for the stack trace. + SmallVector replArgs(argv.begin(), argv.end()); + replArgs.erase(&replArgs[1]); + return run_driver(ExecName, replArgs); + } else { + return run_driver(ExecName, argv); + } +} diff --git a/tools/driver/modulewrap_main.cpp b/lib/DriverTool/modulewrap_main.cpp similarity index 100% rename from tools/driver/modulewrap_main.cpp rename to lib/DriverTool/modulewrap_main.cpp diff --git a/tools/driver/swift_api_digester_main.cpp b/lib/DriverTool/swift_api_digester_main.cpp similarity index 100% rename from tools/driver/swift_api_digester_main.cpp rename to lib/DriverTool/swift_api_digester_main.cpp diff --git a/tools/driver/swift_api_extract_main.cpp b/lib/DriverTool/swift_api_extract_main.cpp similarity index 100% rename from tools/driver/swift_api_extract_main.cpp rename to lib/DriverTool/swift_api_extract_main.cpp diff --git a/tools/driver/swift_indent_main.cpp b/lib/DriverTool/swift_indent_main.cpp similarity index 100% rename from tools/driver/swift_indent_main.cpp rename to lib/DriverTool/swift_indent_main.cpp diff --git a/tools/driver/swift_symbolgraph_extract_main.cpp b/lib/DriverTool/swift_symbolgraph_extract_main.cpp similarity index 100% rename from tools/driver/swift_symbolgraph_extract_main.cpp rename to lib/DriverTool/swift_symbolgraph_extract_main.cpp diff --git a/tools/driver/CMakeLists.txt b/tools/driver/CMakeLists.txt index e011d56e969..2595a4a1d5f 100644 --- a/tools/driver/CMakeLists.txt +++ b/tools/driver/CMakeLists.txt @@ -1,32 +1,12 @@ - -set(driver_sources_and_options - driver.cpp - autolink_extract_main.cpp - modulewrap_main.cpp - swift_api_digester_main.cpp - swift_indent_main.cpp - swift_symbolgraph_extract_main.cpp - swift_api_extract_main.cpp - ) - -set(driver_common_libs - swiftAPIDigester - swiftDriver - swiftFrontendTool - swiftSymbolGraphGen - LLVMBitstreamReader) - # The swift-frontend tool - add_swift_host_tool(swift-frontend - ${driver_sources_and_options} + driver.cpp SWIFT_COMPONENT compiler HAS_LIBSWIFT ) target_link_libraries(swift-frontend - PRIVATE - ${driver_common_libs} - libswift) + PUBLIC + swiftDriverTool) # Create a `swift-driver` symlinks adjacent to the `swift-frontend` executable # to ensure that `swiftc` forwards to the standalone driver when invoked. @@ -75,11 +55,6 @@ add_swift_tool_symlink(swift-autolink-extract swift-frontend autolink-driver) add_swift_tool_symlink(swift-indent swift-frontend editor-integration) add_swift_tool_symlink(swift-api-digester swift-frontend compiler) -# If building as part of clang, make sure the headers are installed. -if(NOT SWIFT_BUILT_STANDALONE) - add_dependencies(swift-frontend clang-resource-headers) -endif() - add_dependencies(compiler swift-frontend) swift_install_in_component(FILES "${SWIFT_RUNTIME_OUTPUT_INTDIR}/swift${CMAKE_EXECUTABLE_SUFFIX}" DESTINATION "bin" diff --git a/tools/driver/driver.cpp b/tools/driver/driver.cpp index 3114e8361cf..2d836f052e4 100644 --- a/tools/driver/driver.cpp +++ b/tools/driver/driver.cpp @@ -14,390 +14,8 @@ // //===----------------------------------------------------------------------===// -#include "swift/AST/DiagnosticEngine.h" -#include "swift/AST/DiagnosticsDriver.h" -#include "swift/Basic/LLVMInitialize.h" -#include "swift/Basic/InitializeLibSwift.h" -#include "swift/Basic/PrettyStackTrace.h" -#include "swift/Basic/Program.h" -#include "swift/Basic/TaskQueue.h" -#include "swift/Basic/SourceManager.h" -#include "swift/Driver/Compilation.h" -#include "swift/Driver/Driver.h" -#include "swift/Driver/FrontendUtil.h" -#include "swift/Driver/Job.h" -#include "swift/Driver/ToolChain.h" -#include "swift/Frontend/Frontend.h" -#include "swift/Frontend/PrintingDiagnosticConsumer.h" -#include "swift/FrontendTool/FrontendTool.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/ConvertUTF.h" -#include "llvm/Support/Errno.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Host.h" -#include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/Process.h" -#include "llvm/Support/Program.h" -#include "llvm/Support/Signals.h" -#include "llvm/Support/StringSaver.h" -#include "llvm/Support/TargetSelect.h" -#include "llvm/Support/raw_ostream.h" - -#include -#include - -#if defined(_WIN32) -#include -#endif - -using namespace swift; -using namespace swift::driver; - -std::string getExecutablePath(const char *FirstArg) { - void *P = (void *)(intptr_t)getExecutablePath; - return llvm::sys::fs::getMainExecutable(FirstArg, P); -} - -/// Run 'swift-autolink-extract'. -extern int autolink_extract_main(ArrayRef Args, const char *Argv0, - void *MainAddr); - -extern int modulewrap_main(ArrayRef Args, const char *Argv0, - void *MainAddr); - -/// Run 'swift-indent' -extern int swift_indent_main(ArrayRef Args, const char *Argv0, - void *MainAddr); - -/// Run 'swift-symbolgraph-extract' -extern int swift_symbolgraph_extract_main(ArrayRef Args, const char *Argv0, -void *MainAddr); - -/// Run 'swift-api-digester' -extern int swift_api_digester_main(ArrayRef Args, - const char *Argv0, void *MainAddr); - -/// Run 'swift-api-extract' -extern int swift_api_extract_main(ArrayRef Args, - const char *Argv0, void *MainAddr); - -/// Determine if the given invocation should run as a "subcommand". -/// -/// Examples of "subcommands" are 'swift build' or 'swift test', which are -/// usually used to invoke the Swift package manager executables 'swift-build' -/// and 'swift-test', respectively. -/// -/// \param ExecName The name of the argv[0] we were invoked as. -/// \param SubcommandName On success, the full name of the subcommand to invoke. -/// \param Args On return, the adjusted program arguments to use. -/// \returns True if running as a subcommand. -static bool shouldRunAsSubcommand(StringRef ExecName, - SmallString<256> &SubcommandName, - const ArrayRef Args, - bool &isRepl) { - assert(!Args.empty()); - - // If we are not run as 'swift', don't do anything special. This doesn't work - // with symlinks with alternate names, but we can't detect 'swift' vs 'swiftc' - // if we try and resolve using the actual executable path. - if (ExecName != "swift") - return false; - - // If there are no program arguments, always invoke as normal. - if (Args.size() == 1) - return false; - - // Otherwise, we have a program argument. If it looks like an option or a - // path, then invoke in interactive mode with the arguments as given. - StringRef FirstArg(Args[1]); - if (FirstArg.startswith("-") || FirstArg.contains('.') || - FirstArg.contains('/')) - return false; - - // Otherwise, we should have some sort of subcommand. Get the subcommand name - // and remove it from the program arguments. - StringRef Subcommand = Args[1]; - - // If the subcommand is the "built-in" 'repl', then use the - // normal driver. - if (Subcommand == "repl") { - isRepl = true; - return false; - } - - // Form the subcommand name. - SubcommandName.assign("swift-"); - SubcommandName.append(Subcommand); - - return true; -} - -static bool shouldDisallowNewDriver(DiagnosticEngine &diags, - StringRef ExecName, - const ArrayRef argv) { - // We are not invoking the driver, so don't forward. - if (ExecName != "swift" && ExecName != "swiftc") { - return true; - } - StringRef disableArg = "-disallow-use-new-driver"; - StringRef disableEnv = "SWIFT_USE_OLD_DRIVER"; - auto shouldWarn = !llvm::sys::Process:: - GetEnv("SWIFT_AVOID_WARNING_USING_OLD_DRIVER").hasValue(); - // If user specified using the old driver, don't forward. - if (llvm::find_if(argv, [&](const char* arg) { - return StringRef(arg) == disableArg; - }) != argv.end()) { - if (shouldWarn) - diags.diagnose(SourceLoc(), diag::old_driver_deprecated, disableArg); - return true; - } - if (llvm::sys::Process::GetEnv(disableEnv).hasValue()) { - if (shouldWarn) - diags.diagnose(SourceLoc(), diag::old_driver_deprecated, disableEnv); - return true; - } - return false; -} - -static bool appendSwiftDriverName(SmallString<256> &buffer) { - assert(llvm::sys::fs::exists(buffer)); - if (auto driverNameOp = llvm::sys::Process::GetEnv("SWIFT_USE_NEW_DRIVER")) { - llvm::sys::path::append(buffer, *driverNameOp); - return true; - } - - llvm::sys::path::append(buffer, "swift-driver"); - if (llvm::sys::fs::exists(buffer)) { - return true; - } - llvm::sys::path::remove_filename(buffer); - llvm::sys::path::append(buffer, "swift-driver-new"); - if (llvm::sys::fs::exists(buffer)) { - return true; - } - - return false; -} - -static int run_driver(StringRef ExecName, - const ArrayRef argv) { - // This is done here and not done in FrontendTool.cpp, because - // FrontendTool.cpp is linked to tools, which don't use libswift. - initializeLibSwift(); - - // Handle integrated tools. - if (argv.size() > 1) { - StringRef FirstArg(argv[1]); - if (FirstArg == "-frontend") { - return performFrontend(llvm::makeArrayRef(argv.data()+2, - argv.data()+argv.size()), - argv[0], (void *)(intptr_t)getExecutablePath); - } - if (FirstArg == "-modulewrap") { - return modulewrap_main(llvm::makeArrayRef(argv.data()+2, - argv.data()+argv.size()), - argv[0], (void *)(intptr_t)getExecutablePath); - } - - // Run the integrated Swift frontend when called as "swift-frontend" but - // without a leading "-frontend". - if (!FirstArg.startswith("--driver-mode=") - && ExecName == "swift-frontend") { - return performFrontend(llvm::makeArrayRef(argv.data()+1, - argv.data()+argv.size()), - argv[0], (void *)(intptr_t)getExecutablePath); - } - } - - std::string Path = getExecutablePath(argv[0]); - - PrintingDiagnosticConsumer PDC; - - SourceManager SM; - DiagnosticEngine Diags(SM); - Diags.addConsumer(PDC); - - // Forwarding calls to the swift driver if the C++ driver is invoked as `swift` - // or `swiftc`, and an environment variable SWIFT_USE_NEW_DRIVER is defined. - if (!shouldDisallowNewDriver(Diags, ExecName, argv)) { - SmallString<256> NewDriverPath(llvm::sys::path::parent_path(Path)); - if (appendSwiftDriverName(NewDriverPath) && - llvm::sys::fs::exists(NewDriverPath)) { - std::vector subCommandArgs; - // Rewrite the program argument. - subCommandArgs.push_back(NewDriverPath.c_str()); - if (ExecName == "swiftc") { - subCommandArgs.push_back("--driver-mode=swiftc"); - } else { - assert(ExecName == "swift"); - subCommandArgs.push_back("--driver-mode=swift"); - } - // Push these non-op frontend arguments so the build log can indicate - // the new driver is used. - subCommandArgs.push_back("-Xfrontend"); - subCommandArgs.push_back("-new-driver-path"); - subCommandArgs.push_back("-Xfrontend"); - subCommandArgs.push_back(NewDriverPath.c_str()); - - // Push on the source program arguments - subCommandArgs.insert(subCommandArgs.end(), argv.begin() + 1, argv.end()); - - // Execute the subcommand. - subCommandArgs.push_back(nullptr); - ExecuteInPlace(NewDriverPath.c_str(), subCommandArgs.data()); - - // If we reach here then an error occurred (typically a missing path). - std::string ErrorString = llvm::sys::StrError(); - llvm::errs() << "error: unable to invoke subcommand: " << subCommandArgs[0] - << " (" << ErrorString << ")\n"; - return 2; - } - } - - Driver TheDriver(Path, ExecName, argv, Diags); - switch (TheDriver.getDriverKind()) { - case Driver::DriverKind::AutolinkExtract: - return autolink_extract_main( - TheDriver.getArgsWithoutProgramNameAndDriverMode(argv), - argv[0], (void *)(intptr_t)getExecutablePath); - case Driver::DriverKind::SwiftIndent: - return swift_indent_main( - TheDriver.getArgsWithoutProgramNameAndDriverMode(argv), - argv[0], (void *)(intptr_t)getExecutablePath); - case Driver::DriverKind::SymbolGraph: - return swift_symbolgraph_extract_main(TheDriver.getArgsWithoutProgramNameAndDriverMode(argv), argv[0], (void *)(intptr_t)getExecutablePath); - case Driver::DriverKind::APIExtract: - return swift_api_extract_main( - TheDriver.getArgsWithoutProgramNameAndDriverMode(argv), argv[0], - (void *)(intptr_t)getExecutablePath); - case Driver::DriverKind::APIDigester: - return swift_api_digester_main( - TheDriver.getArgsWithoutProgramNameAndDriverMode(argv), argv[0], - (void *)(intptr_t)getExecutablePath); - default: - break; - } - - std::unique_ptr ArgList = - TheDriver.parseArgStrings(ArrayRef(argv).slice(1)); - if (Diags.hadAnyError()) - return 1; - - std::unique_ptr TC = TheDriver.buildToolChain(*ArgList); - if (Diags.hadAnyError()) - return 1; - - for (auto arg: ArgList->getArgs()) { - if (arg->getOption().hasFlag(options::NewDriverOnlyOption)) { - Diags.diagnose(SourceLoc(), diag::warning_unsupported_driver_option, - arg->getSpelling()); - } - } - - std::unique_ptr C = - TheDriver.buildCompilation(*TC, std::move(ArgList)); - - if (Diags.hadAnyError()) - return 1; - - if (C) { - std::unique_ptr TQ = TheDriver.buildTaskQueue(*C); - if (!TQ) - return 1; - return C->performJobs(std::move(TQ)).exitCode; - } - - return 0; -} +#include "swift/DriverTool/DriverTool.h" int main(int argc_, const char **argv_) { -#if defined(_WIN32) - LPWSTR *wargv_ = CommandLineToArgvW(GetCommandLineW(), &argc_); - std::vector utf8Args; - // We use UTF-8 as the internal character encoding. On Windows, - // arguments passed to wmain are encoded in UTF-16 - for (int i = 0; i < argc_; i++) { - const wchar_t *wideArg = wargv_[i]; - int wideArgLen = std::wcslen(wideArg); - utf8Args.push_back(""); - llvm::ArrayRef uRef((const char *)wideArg, - (const char *)(wideArg + wideArgLen)); - llvm::convertUTF16ToUTF8String(uRef, utf8Args[i]); - } - - std::vector utf8CStrs; - llvm::transform(utf8Args, std::back_inserter(utf8CStrs), - std::mem_fn(&std::string::c_str)); - argv_ = utf8CStrs.data(); -#endif - // Expand any response files in the command line argument vector - arguments - // may be passed through response files in the event of command line length - // restrictions. - SmallVector ExpandedArgs(&argv_[0], &argv_[argc_]); - llvm::BumpPtrAllocator Allocator; - llvm::StringSaver Saver(Allocator); - swift::driver::ExpandResponseFilesWithRetry(Saver, ExpandedArgs); - - // Initialize the stack trace using the parsed argument vector with expanded - // response files. - - // PROGRAM_START/InitLLVM overwrites the passed in arguments with UTF-8 - // versions of them on Windows. This also has the effect of overwriting the - // response file expansion. Since we handle the UTF-8 conversion above, we - // pass in a copy and throw away the modifications. - int ThrowawayExpandedArgc = ExpandedArgs.size(); - const char **ThrowawayExpandedArgv = ExpandedArgs.data(); - PROGRAM_START(ThrowawayExpandedArgc, ThrowawayExpandedArgv); - ArrayRef argv(ExpandedArgs); - - PrettyStackTraceSwiftVersion versionStackTrace; - - // Check if this invocation should execute a subcommand. - StringRef ExecName = llvm::sys::path::stem(argv[0]); - SmallString<256> SubcommandName; - bool isRepl = false; - if (shouldRunAsSubcommand(ExecName, SubcommandName, argv, isRepl)) { - // Preserve argv for the stack trace. - SmallVector subCommandArgs(argv.begin(), argv.end()); - subCommandArgs.erase(&subCommandArgs[1]); - // We are running as a subcommand, try to find the subcommand adjacent to - // the executable we are running as. - SmallString<256> SubcommandPath( - llvm::sys::path::parent_path(getExecutablePath(argv[0]))); - llvm::sys::path::append(SubcommandPath, SubcommandName); - - // If we didn't find the tool there, let the OS search for it. - if (!llvm::sys::fs::exists(SubcommandPath)) { - // Search for the program and use the path if found. If there was an - // error, ignore it and just let the exec fail. - auto result = llvm::sys::findProgramByName(SubcommandName); - if (!result.getError()) - SubcommandPath = *result; - } - - // Rewrite the program argument. - subCommandArgs[0] = SubcommandPath.c_str(); - - // Execute the subcommand. - subCommandArgs.push_back(nullptr); - ExecuteInPlace(SubcommandPath.c_str(), subCommandArgs.data()); - - // If we reach here then an error occurred (typically a missing path). - std::string ErrorString = llvm::sys::StrError(); - llvm::errs() << "error: unable to invoke subcommand: " << subCommandArgs[0] - << " (" << ErrorString << ")\n"; - return 2; - } - - if (isRepl) { - // Preserve argv for the stack trace. - SmallVector replArgs(argv.begin(), argv.end()); - replArgs.erase(&replArgs[1]); - return run_driver(ExecName, replArgs); - } else { - return run_driver(ExecName, argv); - } + return swift::mainEntry(argc_, argv_); }