xref: /llvm-project/flang/tools/flang-driver/driver.cpp (revision 06eb10dadfaeaadc5d0d95d38bea4bfb5253e077)
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