1221339Sdim//===--- CreateInvocationFromCommandLine.cpp - CompilerInvocation from Args ==//
2221339Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6221339Sdim//
7221339Sdim//===----------------------------------------------------------------------===//
8221339Sdim//
9221339Sdim// Construct a compiler invocation object for command line driver arguments
10221339Sdim//
11221339Sdim//===----------------------------------------------------------------------===//
12221339Sdim
13249423Sdim#include "clang/Frontend/Utils.h"
14243830Sdim#include "clang/Basic/DiagnosticOptions.h"
15221339Sdim#include "clang/Driver/Compilation.h"
16221339Sdim#include "clang/Driver/Driver.h"
17288943Sdim#include "clang/Driver/Action.h"
18221339Sdim#include "clang/Driver/Options.h"
19221339Sdim#include "clang/Driver/Tool.h"
20249423Sdim#include "clang/Frontend/CompilerInstance.h"
21249423Sdim#include "clang/Frontend/FrontendDiagnostic.h"
22261991Sdim#include "llvm/Option/ArgList.h"
23221339Sdim#include "llvm/Support/Host.h"
24221339Sdimusing namespace clang;
25261991Sdimusing namespace llvm::opt;
26221339Sdim
27314564Sdimstd::unique_ptr<CompilerInvocation> clang::createInvocationFromCommandLine(
28321369Sdim    ArrayRef<const char *> ArgList, IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
29360784Sdim    IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, bool ShouldRecoverOnErorrs,
30360784Sdim    std::vector<std::string> *CC1Args) {
31276479Sdim  if (!Diags.get()) {
32221339Sdim    // No diagnostics engine was provided, so create our own diagnostics object
33221339Sdim    // with the default options.
34249423Sdim    Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions);
35221339Sdim  }
36221339Sdim
37296417Sdim  SmallVector<const char *, 16> Args(ArgList.begin(), ArgList.end());
38221339Sdim
39239462Sdim  // FIXME: Find a cleaner way to force the driver into restricted modes.
40221339Sdim  Args.push_back("-fsyntax-only");
41221339Sdim
42221339Sdim  // FIXME: We shouldn't have to pass in the path info.
43296417Sdim  driver::Driver TheDriver(Args[0], llvm::sys::getDefaultTargetTriple(),
44321369Sdim                           *Diags, VFS);
45221339Sdim
46221339Sdim  // Don't check that inputs exist, they may have been remapped.
47221339Sdim  TheDriver.setCheckInputsExist(false);
48221339Sdim
49276479Sdim  std::unique_ptr<driver::Compilation> C(TheDriver.BuildCompilation(Args));
50321369Sdim  if (!C)
51321369Sdim    return nullptr;
52221339Sdim
53221339Sdim  // Just print the cc1 options if -### was present.
54221339Sdim  if (C->getArgs().hasArg(driver::options::OPT__HASH_HASH_HASH)) {
55261991Sdim    C->getJobs().Print(llvm::errs(), "\n", true);
56276479Sdim    return nullptr;
57221339Sdim  }
58221339Sdim
59221339Sdim  // We expect to get back exactly one command job, if we didn't something
60309124Sdim  // failed. Offload compilation is an exception as it creates multiple jobs. If
61309124Sdim  // that's the case, we proceed with the first job. If caller needs a
62309124Sdim  // particular job, it should be controlled via options (e.g.
63309124Sdim  // --cuda-{host|device}-only for CUDA) passed to the driver.
64221339Sdim  const driver::JobList &Jobs = C->getJobs();
65309124Sdim  bool OffloadCompilation = false;
66288943Sdim  if (Jobs.size() > 1) {
67288943Sdim    for (auto &A : C->getActions()){
68288943Sdim      // On MacOSX real actions may end up being wrapped in BindArchAction
69288943Sdim      if (isa<driver::BindArchAction>(A))
70309124Sdim        A = *A->input_begin();
71309124Sdim      if (isa<driver::OffloadAction>(A)) {
72309124Sdim        OffloadCompilation = true;
73288943Sdim        break;
74288943Sdim      }
75288943Sdim    }
76288943Sdim  }
77288943Sdim  if (Jobs.size() == 0 || !isa<driver::Command>(*Jobs.begin()) ||
78309124Sdim      (Jobs.size() > 1 && !OffloadCompilation)) {
79234353Sdim    SmallString<256> Msg;
80221339Sdim    llvm::raw_svector_ostream OS(Msg);
81261991Sdim    Jobs.Print(OS, "; ", true);
82221339Sdim    Diags->Report(diag::err_fe_expected_compiler_job) << OS.str();
83276479Sdim    return nullptr;
84221339Sdim  }
85221339Sdim
86280031Sdim  const driver::Command &Cmd = cast<driver::Command>(*Jobs.begin());
87280031Sdim  if (StringRef(Cmd.getCreator().getName()) != "clang") {
88221339Sdim    Diags->Report(diag::err_fe_expected_clang_command);
89276479Sdim    return nullptr;
90221339Sdim  }
91221339Sdim
92280031Sdim  const ArgStringList &CCArgs = Cmd.getArguments();
93360784Sdim  if (CC1Args)
94360784Sdim    *CC1Args = {CCArgs.begin(), CCArgs.end()};
95360784Sdim  auto CI = std::make_unique<CompilerInvocation>();
96360784Sdim  if (!CompilerInvocation::CreateFromArgs(*CI, CCArgs, *Diags) &&
97360784Sdim      !ShouldRecoverOnErorrs)
98276479Sdim    return nullptr;
99314564Sdim  return CI;
100221339Sdim}
101