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.
333b0f4066SDimitry Andric CompilerInvocation *
346122f3e6SDimitry Andric clang::createInvocationFromCommandLine(ArrayRef<const char *> ArgList,
35dff0c46cSDimitry Andric                             IntrusiveRefCntPtr<DiagnosticsEngine> Diags) {
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 
426122f3e6SDimitry Andric   SmallVector<const char *, 16> Args;
433b0f4066SDimitry Andric   Args.push_back("<clang>"); // FIXME: Remove dummy argument.
443b0f4066SDimitry Andric   Args.insert(Args.end(), ArgList.begin(), ArgList.end());
453b0f4066SDimitry Andric 
467ae0e2c9SDimitry Andric   // FIXME: Find a cleaner way to force the driver into restricted modes.
473b0f4066SDimitry Andric   Args.push_back("-fsyntax-only");
483b0f4066SDimitry Andric 
493b0f4066SDimitry Andric   // FIXME: We shouldn't have to pass in the path info.
50dff0c46cSDimitry Andric   driver::Driver TheDriver("clang", llvm::sys::getDefaultTargetTriple(),
5159d1ed5bSDimitry Andric                            *Diags);
523b0f4066SDimitry Andric 
533b0f4066SDimitry Andric   // Don't check that inputs exist, they may have been remapped.
543b0f4066SDimitry Andric   TheDriver.setCheckInputsExist(false);
553b0f4066SDimitry Andric 
5659d1ed5bSDimitry Andric   std::unique_ptr<driver::Compilation> C(TheDriver.BuildCompilation(Args));
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
65875ed548SDimitry Andric   // failed. CUDA compilation is an exception as it creates multiple jobs. If
66875ed548SDimitry Andric   // that's the case, we proceed with the first job. If caller needs particular
67875ed548SDimitry Andric   // CUDA job, it should be controlled via --cuda-{host|device}-only option
68875ed548SDimitry Andric   // passed to the driver.
693b0f4066SDimitry Andric   const driver::JobList &Jobs = C->getJobs();
70875ed548SDimitry Andric   bool CudaCompilation = 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))
75875ed548SDimitry Andric         A = *A->begin();
76875ed548SDimitry Andric       if (isa<driver::CudaDeviceAction>(A)) {
77875ed548SDimitry Andric         CudaCompilation = true;
78875ed548SDimitry Andric         break;
79875ed548SDimitry Andric       }
80875ed548SDimitry Andric     }
81875ed548SDimitry Andric   }
82875ed548SDimitry Andric   if (Jobs.size() == 0 || !isa<driver::Command>(*Jobs.begin()) ||
83875ed548SDimitry Andric       (Jobs.size() > 1 && !CudaCompilation)) {
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();
9859d1ed5bSDimitry Andric   std::unique_ptr<CompilerInvocation> CI(new 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;
10559d1ed5bSDimitry Andric   return CI.release();
1063b0f4066SDimitry Andric }
107