1257b2971SCaroline Concatto //===-- driver.cpp - Flang Driver -----------------------------------------===// 2257b2971SCaroline Concatto // 3257b2971SCaroline Concatto // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4257b2971SCaroline Concatto // See https://llvm.org/LICENSE.txt for license information. 5257b2971SCaroline Concatto // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6257b2971SCaroline Concatto // 7257b2971SCaroline Concatto //===----------------------------------------------------------------------===// 8257b2971SCaroline Concatto // 9257b2971SCaroline Concatto // This is the entry point to the flang driver; it is a thin wrapper 10257b2971SCaroline Concatto // for functionality in the Driver flang library. 11257b2971SCaroline Concatto // 12257b2971SCaroline Concatto //===----------------------------------------------------------------------===// 131e462fafSAndrzej Warzynski // 141e462fafSAndrzej Warzynski // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ 151e462fafSAndrzej Warzynski // 161e462fafSAndrzej Warzynski //===----------------------------------------------------------------------===// 171e462fafSAndrzej Warzynski 18257b2971SCaroline Concatto #include "clang/Driver/Driver.h" 198d51d37eSAndrzej Warzynski #include "flang/Frontend/CompilerInvocation.h" 208d51d37eSAndrzej Warzynski #include "flang/Frontend/TextDiagnosticPrinter.h" 21257b2971SCaroline Concatto #include "clang/Basic/Diagnostic.h" 22257b2971SCaroline Concatto #include "clang/Basic/DiagnosticIDs.h" 23257b2971SCaroline Concatto #include "clang/Basic/DiagnosticOptions.h" 24257b2971SCaroline Concatto #include "clang/Driver/Compilation.h" 25257b2971SCaroline Concatto #include "llvm/ADT/ArrayRef.h" 26257b2971SCaroline Concatto #include "llvm/ADT/IntrusiveRefCntPtr.h" 27257b2971SCaroline Concatto #include "llvm/Option/ArgList.h" 281c0b03f6SDiana Picus #include "llvm/Support/CommandLine.h" 29257b2971SCaroline Concatto #include "llvm/Support/InitLLVM.h" 30257b2971SCaroline Concatto #include "llvm/Support/VirtualFileSystem.h" 31541f5c4aSHussain Kadhem #include "llvm/Support/raw_ostream.h" 32d768bf99SArchibald Elliott #include "llvm/TargetParser/Host.h" 33541f5c4aSHussain Kadhem #include <stdlib.h> 34257b2971SCaroline Concatto 35257b2971SCaroline Concatto // main frontend method. Lives inside fc1_main.cpp 36257b2971SCaroline Concatto extern int fc1_main(llvm::ArrayRef<const char *> argv, const char *argv0); 37257b2971SCaroline Concatto 381e462fafSAndrzej Warzynski std::string getExecutablePath(const char *argv0) { 39257b2971SCaroline Concatto // This just needs to be some symbol in the binary 401e462fafSAndrzej Warzynski void *p = (void *)(intptr_t)getExecutablePath; 41257b2971SCaroline Concatto return llvm::sys::fs::getMainExecutable(argv0, p); 42257b2971SCaroline Concatto } 43257b2971SCaroline Concatto 44257b2971SCaroline Concatto // This lets us create the DiagnosticsEngine with a properly-filled-out 45257b2971SCaroline Concatto // DiagnosticOptions instance 461e462fafSAndrzej Warzynski static clang::DiagnosticOptions * 471e462fafSAndrzej Warzynski createAndPopulateDiagOpts(llvm::ArrayRef<const char *> argv) { 48257b2971SCaroline Concatto auto *diagOpts = new clang::DiagnosticOptions; 498d51d37eSAndrzej Warzynski 508d51d37eSAndrzej Warzynski // Ignore missingArgCount and the return value of ParseDiagnosticArgs. 518d51d37eSAndrzej Warzynski // Any errors that would be diagnosed here will also be diagnosed later, 528d51d37eSAndrzej Warzynski // when the DiagnosticsEngine actually exists. 538d51d37eSAndrzej Warzynski unsigned missingArgIndex, missingArgCount; 548d51d37eSAndrzej Warzynski llvm::opt::InputArgList args = clang::driver::getDriverOptTable().ParseArgs( 558d51d37eSAndrzej Warzynski argv.slice(1), missingArgIndex, missingArgCount, 569478f661SJustin Bogner llvm::opt::Visibility(clang::driver::options::FlangOption)); 578d51d37eSAndrzej Warzynski 581e462fafSAndrzej Warzynski (void)Fortran::frontend::parseDiagnosticArgs(*diagOpts, args); 598d51d37eSAndrzej Warzynski 60257b2971SCaroline Concatto return diagOpts; 61257b2971SCaroline Concatto } 62257b2971SCaroline Concatto 631e462fafSAndrzej Warzynski static int executeFC1Tool(llvm::SmallVectorImpl<const char *> &argV) { 64257b2971SCaroline Concatto llvm::StringRef tool = argV[1]; 65257b2971SCaroline Concatto if (tool == "-fc1") 66984b800aSserge-sans-paille return fc1_main(llvm::ArrayRef(argV).slice(2), argV[0]); 67257b2971SCaroline Concatto 68257b2971SCaroline Concatto // Reject unknown tools. 69257b2971SCaroline Concatto // ATM it only supports fc1. Any fc1[*] is rejected. 70257b2971SCaroline Concatto llvm::errs() << "error: unknown integrated tool '" << tool << "'. " 71257b2971SCaroline Concatto << "Valid tools include '-fc1'.\n"; 72257b2971SCaroline Concatto return 1; 73257b2971SCaroline Concatto } 74257b2971SCaroline Concatto 7574d5c3c0SPeter Steinfeld static void ExpandResponseFiles(llvm::StringSaver &saver, 7674d5c3c0SPeter Steinfeld llvm::SmallVectorImpl<const char *> &args) { 771c0b03f6SDiana Picus // We're defaulting to the GNU syntax, since we don't have a CL mode. 781c0b03f6SDiana Picus llvm::cl::TokenizerCallback tokenizer = &llvm::cl::TokenizeGNUCommandLine; 79b934be2cSSerge Pavlov llvm::cl::ExpansionContext ExpCtx(saver.getAllocator(), tokenizer); 80fd3d7a9fSSerge Pavlov if (llvm::Error Err = ExpCtx.expandResponseFiles(args)) { 81fd3d7a9fSSerge Pavlov llvm::errs() << toString(std::move(Err)) << '\n'; 82fd3d7a9fSSerge Pavlov } 831c0b03f6SDiana Picus } 841c0b03f6SDiana Picus 85ad14ccc8SShao-Ce Sun int main(int argc, const char **argv) { 86257b2971SCaroline Concatto 87257b2971SCaroline Concatto // Initialize variables to call the driver 88ad14ccc8SShao-Ce Sun llvm::InitLLVM x(argc, argv); 89ad14ccc8SShao-Ce Sun llvm::SmallVector<const char *, 256> args(argv, argv + argc); 90257b2971SCaroline Concatto 91*06eb10daSBrad Richardson clang::driver::ParsedClangName targetandMode = 92*06eb10daSBrad Richardson clang::driver::ToolChain::getTargetAndModeFromProgramName(argv[0]); 931e462fafSAndrzej Warzynski std::string driverPath = getExecutablePath(args[0]); 94257b2971SCaroline Concatto 951c0b03f6SDiana Picus llvm::BumpPtrAllocator a; 961c0b03f6SDiana Picus llvm::StringSaver saver(a); 971c0b03f6SDiana Picus ExpandResponseFiles(saver, args); 981c0b03f6SDiana Picus 99*06eb10daSBrad Richardson // Check if flang is in the frontend mode 10074d5c3c0SPeter Steinfeld auto firstArg = std::find_if(args.begin() + 1, args.end(), 10174d5c3c0SPeter Steinfeld [](const char *a) { return a != nullptr; }); 102ad14ccc8SShao-Ce Sun if (firstArg != args.end()) { 10311efcceaSKazu Hirata if (llvm::StringRef(args[1]).starts_with("-cc1")) { 104ad14ccc8SShao-Ce Sun llvm::errs() << "error: unknown integrated tool '" << args[1] << "'. " 105257b2971SCaroline Concatto << "Valid tools include '-fc1'.\n"; 106257b2971SCaroline Concatto return 1; 107257b2971SCaroline Concatto } 108*06eb10daSBrad Richardson // Call flang frontend 10911efcceaSKazu Hirata if (llvm::StringRef(args[1]).starts_with("-fc1")) { 1101e462fafSAndrzej Warzynski return executeFC1Tool(args); 111257b2971SCaroline Concatto } 112257b2971SCaroline Concatto } 113257b2971SCaroline Concatto 114257b2971SCaroline Concatto // Not in the frontend mode - continue in the compiler driver mode. 115257b2971SCaroline Concatto 116257b2971SCaroline Concatto // Create DiagnosticsEngine for the compiler driver 117257b2971SCaroline Concatto llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> diagOpts = 1181e462fafSAndrzej Warzynski createAndPopulateDiagOpts(args); 119257b2971SCaroline Concatto llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> diagID( 120257b2971SCaroline Concatto new clang::DiagnosticIDs()); 1218d51d37eSAndrzej Warzynski Fortran::frontend::TextDiagnosticPrinter *diagClient = 1228d51d37eSAndrzej Warzynski new Fortran::frontend::TextDiagnosticPrinter(llvm::errs(), &*diagOpts); 1238d51d37eSAndrzej Warzynski 1241e462fafSAndrzej Warzynski diagClient->setPrefix( 1251e462fafSAndrzej Warzynski std::string(llvm::sys::path::stem(getExecutablePath(args[0])))); 1268d51d37eSAndrzej Warzynski 127257b2971SCaroline Concatto clang::DiagnosticsEngine diags(diagID, &*diagOpts, diagClient); 128257b2971SCaroline Concatto 129257b2971SCaroline Concatto // Prepare the driver 130257b2971SCaroline Concatto clang::driver::Driver theDriver(driverPath, 13174d5c3c0SPeter Steinfeld llvm::sys::getDefaultTargetTriple(), diags, 13274d5c3c0SPeter Steinfeld "flang LLVM compiler"); 133257b2971SCaroline Concatto theDriver.setTargetAndMode(targetandMode); 134a468d02fSSlava Zakharin #ifdef FLANG_RUNTIME_F128_MATH_LIB 135a468d02fSSlava Zakharin theDriver.setFlangF128MathLibrary(FLANG_RUNTIME_F128_MATH_LIB); 136a468d02fSSlava Zakharin #endif 137257b2971SCaroline Concatto std::unique_ptr<clang::driver::Compilation> c( 138ad14ccc8SShao-Ce Sun theDriver.BuildCompilation(args)); 139257b2971SCaroline Concatto llvm::SmallVector<std::pair<int, const clang::driver::Command *>, 4> 140257b2971SCaroline Concatto failingCommands; 141257b2971SCaroline Concatto 142541f5c4aSHussain Kadhem // Set the environment variable, FLANG_COMPILER_OPTIONS_STRING, to contain all 143541f5c4aSHussain Kadhem // the compiler options. This is intended for the frontend driver, 144*06eb10daSBrad Richardson // flang -fc1, to enable the implementation of the COMPILER_OPTIONS 145541f5c4aSHussain Kadhem // intrinsic. To this end, the frontend driver requires the list of the 146541f5c4aSHussain Kadhem // original compiler options, which is not available through other means. 147541f5c4aSHussain Kadhem // TODO: This way of passing information between the compiler and frontend 148541f5c4aSHussain Kadhem // drivers is discouraged. We should find a better way not involving env 149541f5c4aSHussain Kadhem // variables. 150541f5c4aSHussain Kadhem std::string compilerOptsGathered; 151541f5c4aSHussain Kadhem llvm::raw_string_ostream os(compilerOptsGathered); 152541f5c4aSHussain Kadhem for (int i = 0; i < argc; ++i) { 153541f5c4aSHussain Kadhem os << argv[i]; 154541f5c4aSHussain Kadhem if (i < argc - 1) { 155541f5c4aSHussain Kadhem os << ' '; 156541f5c4aSHussain Kadhem } 157541f5c4aSHussain Kadhem } 158541f5c4aSHussain Kadhem #ifdef _WIN32 159541f5c4aSHussain Kadhem _putenv_s("FLANG_COMPILER_OPTIONS_STRING", compilerOptsGathered.c_str()); 160541f5c4aSHussain Kadhem #else 161541f5c4aSHussain Kadhem setenv("FLANG_COMPILER_OPTIONS_STRING", compilerOptsGathered.c_str(), 1); 162541f5c4aSHussain Kadhem #endif 163541f5c4aSHussain Kadhem 164257b2971SCaroline Concatto // Run the driver 165257b2971SCaroline Concatto int res = 1; 166257b2971SCaroline Concatto bool isCrash = false; 167257b2971SCaroline Concatto res = theDriver.ExecuteCompilation(*c, failingCommands); 168257b2971SCaroline Concatto 169257b2971SCaroline Concatto for (const auto &p : failingCommands) { 1701e462fafSAndrzej Warzynski int commandRes = p.first; 171257b2971SCaroline Concatto const clang::driver::Command *failingCommand = p.second; 172257b2971SCaroline Concatto if (!res) 1731e462fafSAndrzej Warzynski res = commandRes; 174257b2971SCaroline Concatto 175257b2971SCaroline Concatto // If result status is < 0 (e.g. when sys::ExecuteAndWait returns -1), 176257b2971SCaroline Concatto // then the driver command signalled an error. On Windows, abort will 177257b2971SCaroline Concatto // return an exit code of 3. In these cases, generate additional diagnostic 178257b2971SCaroline Concatto // information if possible. 1791e462fafSAndrzej Warzynski isCrash = commandRes < 0; 180257b2971SCaroline Concatto #ifdef _WIN32 1811e462fafSAndrzej Warzynski isCrash |= commandRes == 3; 182257b2971SCaroline Concatto #endif 183257b2971SCaroline Concatto if (isCrash) { 184257b2971SCaroline Concatto theDriver.generateCompilationDiagnostics(*c, *failingCommand); 185257b2971SCaroline Concatto break; 186257b2971SCaroline Concatto } 187257b2971SCaroline Concatto } 188257b2971SCaroline Concatto 189257b2971SCaroline Concatto diags.getClient()->finish(); 190257b2971SCaroline Concatto 191257b2971SCaroline Concatto // If we have multiple failing commands, we return the result of the first 192257b2971SCaroline Concatto // failing command. 193257b2971SCaroline Concatto return res; 194257b2971SCaroline Concatto } 195