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