13b0f4066SDimitry Andric //===--- CreateInvocationFromCommandLine.cpp - CompilerInvocation from Args ==//
23b0f4066SDimitry Andric //
33b0f4066SDimitry Andric // The LLVM Compiler Infrastructure
43b0f4066SDimitry Andric //
53b0f4066SDimitry Andric // This file is distributed under the University of Illinois Open Source
63b0f4066SDimitry Andric // License. See LICENSE.TXT for details.
73b0f4066SDimitry Andric //
83b0f4066SDimitry Andric //===----------------------------------------------------------------------===//
93b0f4066SDimitry Andric //
103b0f4066SDimitry Andric // Construct a compiler invocation object for command line driver arguments
113b0f4066SDimitry Andric //
123b0f4066SDimitry Andric //===----------------------------------------------------------------------===//
133b0f4066SDimitry Andric
143b0f4066SDimitry Andric #include "clang/Frontend/Utils.h"
15139f7f9bSDimitry Andric #include "clang/Basic/DiagnosticOptions.h"
163b0f4066SDimitry Andric #include "clang/Driver/Compilation.h"
173b0f4066SDimitry Andric #include "clang/Driver/Driver.h"
18875ed548SDimitry Andric #include "clang/Driver/Action.h"
193b0f4066SDimitry Andric #include "clang/Driver/Options.h"
203b0f4066SDimitry Andric #include "clang/Driver/Tool.h"
21139f7f9bSDimitry Andric #include "clang/Frontend/CompilerInstance.h"
22139f7f9bSDimitry Andric #include "clang/Frontend/FrontendDiagnostic.h"
23f785676fSDimitry Andric #include "llvm/Option/ArgList.h"
243b0f4066SDimitry Andric #include "llvm/Support/Host.h"
253b0f4066SDimitry Andric using namespace clang;
26f785676fSDimitry Andric using namespace llvm::opt;
273b0f4066SDimitry Andric
283b0f4066SDimitry Andric /// createInvocationFromCommandLine - Construct a compiler invocation object for
293b0f4066SDimitry Andric /// a command line argument vector.
303b0f4066SDimitry Andric ///
313b0f4066SDimitry Andric /// \return A CompilerInvocation, or 0 if none was built for the given
323b0f4066SDimitry Andric /// argument vector.
createInvocationFromCommandLine(ArrayRef<const char * > ArgList,IntrusiveRefCntPtr<DiagnosticsEngine> Diags,IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS)3395ec533aSDimitry Andric std::unique_ptr<CompilerInvocation> clang::createInvocationFromCommandLine(
34a580b014SDimitry Andric ArrayRef<const char *> ArgList, IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
35*b5893f02SDimitry Andric IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) {
3659d1ed5bSDimitry Andric if (!Diags.get()) {
373b0f4066SDimitry Andric // No diagnostics engine was provided, so create our own diagnostics object
383b0f4066SDimitry Andric // with the default options.
39139f7f9bSDimitry Andric Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions);
403b0f4066SDimitry Andric }
413b0f4066SDimitry Andric
420623d748SDimitry Andric SmallVector<const char *, 16> Args(ArgList.begin(), ArgList.end());
433b0f4066SDimitry Andric
447ae0e2c9SDimitry Andric // FIXME: Find a cleaner way to force the driver into restricted modes.
453b0f4066SDimitry Andric Args.push_back("-fsyntax-only");
463b0f4066SDimitry Andric
473b0f4066SDimitry Andric // FIXME: We shouldn't have to pass in the path info.
480623d748SDimitry Andric driver::Driver TheDriver(Args[0], llvm::sys::getDefaultTargetTriple(),
49a580b014SDimitry Andric *Diags, VFS);
503b0f4066SDimitry Andric
513b0f4066SDimitry Andric // Don't check that inputs exist, they may have been remapped.
523b0f4066SDimitry Andric TheDriver.setCheckInputsExist(false);
533b0f4066SDimitry Andric
5459d1ed5bSDimitry Andric std::unique_ptr<driver::Compilation> C(TheDriver.BuildCompilation(Args));
55302affcbSDimitry Andric if (!C)
56302affcbSDimitry Andric return nullptr;
573b0f4066SDimitry Andric
583b0f4066SDimitry Andric // Just print the cc1 options if -### was present.
593b0f4066SDimitry Andric if (C->getArgs().hasArg(driver::options::OPT__HASH_HASH_HASH)) {
60f785676fSDimitry Andric C->getJobs().Print(llvm::errs(), "\n", true);
6159d1ed5bSDimitry Andric return nullptr;
623b0f4066SDimitry Andric }
633b0f4066SDimitry Andric
643b0f4066SDimitry Andric // We expect to get back exactly one command job, if we didn't something
65e7145dcbSDimitry Andric // failed. Offload compilation is an exception as it creates multiple jobs. If
66e7145dcbSDimitry Andric // that's the case, we proceed with the first job. If caller needs a
67e7145dcbSDimitry Andric // particular job, it should be controlled via options (e.g.
68e7145dcbSDimitry Andric // --cuda-{host|device}-only for CUDA) passed to the driver.
693b0f4066SDimitry Andric const driver::JobList &Jobs = C->getJobs();
70e7145dcbSDimitry Andric bool OffloadCompilation = false;
71875ed548SDimitry Andric if (Jobs.size() > 1) {
72875ed548SDimitry Andric for (auto &A : C->getActions()){
73875ed548SDimitry Andric // On MacOSX real actions may end up being wrapped in BindArchAction
74875ed548SDimitry Andric if (isa<driver::BindArchAction>(A))
75e7145dcbSDimitry Andric A = *A->input_begin();
76e7145dcbSDimitry Andric if (isa<driver::OffloadAction>(A)) {
77e7145dcbSDimitry Andric OffloadCompilation = true;
78875ed548SDimitry Andric break;
79875ed548SDimitry Andric }
80875ed548SDimitry Andric }
81875ed548SDimitry Andric }
82875ed548SDimitry Andric if (Jobs.size() == 0 || !isa<driver::Command>(*Jobs.begin()) ||
83e7145dcbSDimitry Andric (Jobs.size() > 1 && !OffloadCompilation)) {
84dff0c46cSDimitry Andric SmallString<256> Msg;
853b0f4066SDimitry Andric llvm::raw_svector_ostream OS(Msg);
86f785676fSDimitry Andric Jobs.Print(OS, "; ", true);
873b0f4066SDimitry Andric Diags->Report(diag::err_fe_expected_compiler_job) << OS.str();
8859d1ed5bSDimitry Andric return nullptr;
893b0f4066SDimitry Andric }
903b0f4066SDimitry Andric
9139d628a0SDimitry Andric const driver::Command &Cmd = cast<driver::Command>(*Jobs.begin());
9239d628a0SDimitry Andric if (StringRef(Cmd.getCreator().getName()) != "clang") {
933b0f4066SDimitry Andric Diags->Report(diag::err_fe_expected_clang_command);
9459d1ed5bSDimitry Andric return nullptr;
953b0f4066SDimitry Andric }
963b0f4066SDimitry Andric
9739d628a0SDimitry Andric const ArgStringList &CCArgs = Cmd.getArguments();
9895ec533aSDimitry Andric auto CI = llvm::make_unique<CompilerInvocation>();
99dff0c46cSDimitry Andric if (!CompilerInvocation::CreateFromArgs(*CI,
1003b0f4066SDimitry Andric const_cast<const char **>(CCArgs.data()),
1013b0f4066SDimitry Andric const_cast<const char **>(CCArgs.data()) +
1023b0f4066SDimitry Andric CCArgs.size(),
103dff0c46cSDimitry Andric *Diags))
10459d1ed5bSDimitry Andric return nullptr;
10595ec533aSDimitry Andric return CI;
1063b0f4066SDimitry Andric }
107