Driver: Implement majority tool binding logic.
- Still need code for determining proper output location. - Doesn't work yet, of course, as the host isn't providing real tool chains. - Interface still has a few warts, but has gotten a nice bit of polish during the rewrite. llvm-svn: 67038
This commit is contained in:
parent
3ce436d229
commit
e75d834c7c
6 changed files with 229 additions and 2 deletions
|
|
@ -28,8 +28,12 @@ DIAG(err_drv_no_input_files, ERROR,
|
|||
"no input files")
|
||||
DIAG(err_drv_use_of_Z_option, ERROR,
|
||||
"unsupported use of internal gcc -Z option '%0'")
|
||||
DIAG(err_drv_output_argument_with_multiple_files, ERROR,
|
||||
"cannot specify -o when generating multiple output files")
|
||||
|
||||
DIAG(warn_drv_input_file_unused, WARNING,
|
||||
"%0: '%1' input file unused when '%2' is present")
|
||||
DIAG(warn_drv_unused_argument, WARNING,
|
||||
"argument unused during compilation: '%0'")
|
||||
DIAG(warn_drv_pipe_ignored_with_save_temps, WARNING,
|
||||
"-pipe ignored because -save-temps specified")
|
||||
|
|
|
|||
|
|
@ -21,10 +21,14 @@ def err_drv_invalid_output_with_multiple_archs : Error<
|
|||
def err_drv_no_input_files : Error<"no input files">;
|
||||
def err_drv_use_of_Z_option : Error<
|
||||
"unsupported use of internal gcc -Z option '%0'">;
|
||||
def err_drv_output_argument_with_multiple_files : Error<
|
||||
"cannot specify -o when generating multiple output files">;
|
||||
|
||||
def warn_drv_input_file_unused : Warning<
|
||||
"%0: '%1' input file unused when '%2' is present">;
|
||||
def warn_drv_unused_argument : Warning<
|
||||
"argument unused during compilation: '%0'">;
|
||||
def warn_drv_pipe_ignored_with_save_temps : Warning<
|
||||
"-pipe ignored because -save-temps specified">;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,9 @@ namespace driver {
|
|||
class ArgList;
|
||||
class Compilation;
|
||||
class HostInfo;
|
||||
class InputInfo;
|
||||
class OptTable;
|
||||
class PipedJob;
|
||||
class ToolChain;
|
||||
|
||||
/// Driver - Encapsulate logic for constructing compilation processes
|
||||
|
|
@ -54,6 +56,9 @@ public:
|
|||
/// Default host triple.
|
||||
std::string DefaultHostTriple;
|
||||
|
||||
/// Default name for linked images (e.g., "a.out").
|
||||
std::string DefaultImageName;
|
||||
|
||||
/// Host information for the platform the driver is running as. This
|
||||
/// will generally be the actual host platform, but not always.
|
||||
HostInfo *Host;
|
||||
|
|
@ -95,6 +100,7 @@ public:
|
|||
public:
|
||||
Driver(const char *_Name, const char *_Dir,
|
||||
const char *_DefaultHostTriple,
|
||||
const char *_DefaultImageName,
|
||||
Diagnostic &_Diags);
|
||||
~Driver();
|
||||
|
||||
|
|
@ -186,6 +192,17 @@ public:
|
|||
Action *ConstructPhaseAction(const ArgList &Args, phases::ID Phase,
|
||||
Action *Input) const;
|
||||
|
||||
|
||||
/// BuildJobsForAction - Construct the jobs to perform for the
|
||||
/// action \arg A.
|
||||
void BuildJobsForAction(Compilation &C,
|
||||
const Action *A,
|
||||
const ToolChain *TC,
|
||||
bool CanAcceptPipe,
|
||||
bool AtTopLevel,
|
||||
const char *LinkingOutput,
|
||||
InputInfo &Result) const;
|
||||
|
||||
/// GetHostInfo - Construct a new host info object for the given
|
||||
/// host triple.
|
||||
static HostInfo *GetHostInfo(const char *HostTriple);
|
||||
|
|
|
|||
|
|
@ -15,23 +15,30 @@
|
|||
#include "clang/Driver/Compilation.h"
|
||||
#include "clang/Driver/DriverDiagnostic.h"
|
||||
#include "clang/Driver/HostInfo.h"
|
||||
#include "clang/Driver/Job.h"
|
||||
#include "clang/Driver/Option.h"
|
||||
#include "clang/Driver/Options.h"
|
||||
#include "clang/Driver/Tool.h"
|
||||
#include "clang/Driver/ToolChain.h"
|
||||
#include "clang/Driver/Types.h"
|
||||
|
||||
#include "llvm/ADT/StringSet.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/System/Path.h"
|
||||
|
||||
#include "InputInfo.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
using namespace clang::driver;
|
||||
|
||||
Driver::Driver(const char *_Name, const char *_Dir,
|
||||
const char *_DefaultHostTriple,
|
||||
const char *_DefaultImageName,
|
||||
Diagnostic &_Diags)
|
||||
: Opts(new OptTable()), Diags(_Diags),
|
||||
Name(_Name), Dir(_Dir), DefaultHostTriple(_DefaultHostTriple),
|
||||
DefaultImageName(_DefaultImageName),
|
||||
Host(0),
|
||||
CCCIsCXX(false), CCCEcho(false),
|
||||
CCCNoClang(false), CCCNoClangCXX(false), CCCNoClangCPP(false),
|
||||
|
|
@ -567,8 +574,60 @@ Action *Driver::ConstructPhaseAction(const ArgList &Args, phases::ID Phase,
|
|||
return 0;
|
||||
}
|
||||
|
||||
void Driver::BuildJobs(Compilation &C,
|
||||
const ActionList &Actions) const {
|
||||
void Driver::BuildJobs(Compilation &C, const ActionList &Actions) const {
|
||||
bool SaveTemps = C.getArgs().hasArg(options::OPT_save_temps);
|
||||
bool UsePipes = C.getArgs().hasArg(options::OPT_pipe);
|
||||
|
||||
// -save-temps inhibits pipes.
|
||||
if (SaveTemps && UsePipes) {
|
||||
Diag(clang::diag::warn_drv_pipe_ignored_with_save_temps);
|
||||
UsePipes = true;
|
||||
}
|
||||
|
||||
Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o);
|
||||
|
||||
// It is an error to provide a -o option if we are making multiple
|
||||
// output files.
|
||||
if (FinalOutput) {
|
||||
unsigned NumOutputs = 0;
|
||||
for (ActionList::const_iterator it = Actions.begin(), ie = Actions.end();
|
||||
it != ie; ++it)
|
||||
if ((*it)->getType() != types::TY_Nothing)
|
||||
++NumOutputs;
|
||||
|
||||
if (NumOutputs > 1) {
|
||||
Diag(clang::diag::err_drv_output_argument_with_multiple_files);
|
||||
FinalOutput = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (ActionList::const_iterator it = Actions.begin(), ie = Actions.end();
|
||||
it != ie; ++it) {
|
||||
Action *A = *it;
|
||||
|
||||
// If we are linking an image for multiple archs then the linker
|
||||
// wants -arch_multiple and -final_output <final image
|
||||
// name>. Unfortunately, this doesn't fit in cleanly because we
|
||||
// have to pass this information down.
|
||||
//
|
||||
// FIXME: This is a hack; find a cleaner way to integrate this
|
||||
// into the process.
|
||||
const char *LinkingOutput = 0;
|
||||
if (isa<LinkJobAction>(A)) {
|
||||
if (FinalOutput)
|
||||
LinkingOutput = FinalOutput->getValue(C.getArgs());
|
||||
else
|
||||
LinkingOutput = DefaultImageName.c_str();
|
||||
}
|
||||
|
||||
InputInfo II;
|
||||
BuildJobsForAction(C,
|
||||
A, DefaultToolChain,
|
||||
/*CanAcceptPipe*/ true,
|
||||
/*AtTopLevel*/ true,
|
||||
/*LinkingOutput*/ LinkingOutput,
|
||||
II);
|
||||
}
|
||||
|
||||
// If there were no errors, warn about any unused arguments.
|
||||
for (ArgList::const_iterator it = C.getArgs().begin(), ie = C.getArgs().end();
|
||||
|
|
@ -584,6 +643,91 @@ void Driver::BuildJobs(Compilation &C,
|
|||
}
|
||||
}
|
||||
|
||||
void Driver::BuildJobsForAction(Compilation &C,
|
||||
const Action *A,
|
||||
const ToolChain *TC,
|
||||
bool CanAcceptPipe,
|
||||
bool AtTopLevel,
|
||||
const char *LinkingOutput,
|
||||
InputInfo &Result) const {
|
||||
if (const InputAction *IA = dyn_cast<InputAction>(A)) {
|
||||
const char *Name = IA->getInputArg().getValue(C.getArgs());
|
||||
Result = InputInfo(Name, A->getType(), Name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (const BindArchAction *BAA = dyn_cast<BindArchAction>(A)) {
|
||||
const char *ArchName = BAA->getArchName();
|
||||
BuildJobsForAction(C,
|
||||
*BAA->begin(),
|
||||
Host->getToolChain(C.getArgs(), ArchName),
|
||||
CanAcceptPipe,
|
||||
AtTopLevel,
|
||||
LinkingOutput,
|
||||
Result);
|
||||
return;
|
||||
}
|
||||
|
||||
const JobAction *JA = cast<JobAction>(A);
|
||||
const Tool &T = TC->SelectTool(C, *JA);
|
||||
|
||||
// See if we should use an integrated preprocessor. We do so when we
|
||||
// have exactly one input, since this is the only use case we care
|
||||
// about (irrelevant since we don't support combine yet).
|
||||
bool UseIntegratedCPP = false;
|
||||
const ActionList *Inputs = &A->getInputs();
|
||||
if (Inputs->size() == 1 && isa<PreprocessJobAction>(*Inputs->begin())) {
|
||||
if (!C.getArgs().hasArg(options::OPT_no_integrated_cpp) &&
|
||||
!C.getArgs().hasArg(options::OPT_traditional_cpp) &&
|
||||
!C.getArgs().hasArg(options::OPT_save_temps) &&
|
||||
T.hasIntegratedCPP()) {
|
||||
UseIntegratedCPP = true;
|
||||
Inputs = &(*Inputs)[0]->getInputs();
|
||||
}
|
||||
}
|
||||
|
||||
// Only use pipes when there is exactly one input.
|
||||
bool TryToUsePipeInput = Inputs->size() == 1 && T.acceptsPipedInput();
|
||||
llvm::SmallVector<InputInfo, 4> InputInfos;
|
||||
for (ActionList::const_iterator it = Inputs->begin(), ie = Inputs->end();
|
||||
it != ie; ++it) {
|
||||
InputInfo II;
|
||||
BuildJobsForAction(C, *it, TC, TryToUsePipeInput,
|
||||
/*AtTopLevel*/false,
|
||||
LinkingOutput,
|
||||
II);
|
||||
InputInfos.push_back(II);
|
||||
}
|
||||
|
||||
// Determine if we should output to a pipe.
|
||||
bool OutputToPipe = false;
|
||||
if (CanAcceptPipe && T.canPipeOutput()) {
|
||||
// Some actions default to writing to a pipe if they are the top
|
||||
// level phase and there was no user override.
|
||||
//
|
||||
// FIXME: Is there a better way to handle this?
|
||||
if (AtTopLevel) {
|
||||
if (isa<PreprocessJobAction>(A) && !C.getArgs().hasArg(options::OPT_o))
|
||||
OutputToPipe = true;
|
||||
} else if (C.getArgs().hasArg(options::OPT_pipe))
|
||||
OutputToPipe = true;
|
||||
}
|
||||
|
||||
// Figure out where to put the job (pipes).
|
||||
Job *Dest = &C.getJobs();
|
||||
if (InputInfos[0].isPipe()) {
|
||||
assert(InputInfos.size() == 1 && "Unexpected pipe with multiple inputs.");
|
||||
Dest = &InputInfos[0].getPipe();
|
||||
}
|
||||
|
||||
// Always use the first input as the base input.
|
||||
const char *BaseInput = InputInfos[0].getBaseInput();
|
||||
const char *Output = "foo";
|
||||
// FIXME: Make the job.
|
||||
|
||||
Result = InputInfo(Output, A->getType(), BaseInput);
|
||||
}
|
||||
|
||||
llvm::sys::Path Driver::GetFilePath(const char *Name,
|
||||
const ToolChain *TC) const {
|
||||
// FIXME: Implement.
|
||||
|
|
|
|||
57
clang/lib/Driver/InputInfo.h
Normal file
57
clang/lib/Driver/InputInfo.h
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
//===--- InputInfo.h - Input Source & Type Information ----------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef CLANG_LIB_DRIVER_INPUTINFO_H_
|
||||
#define CLANG_LIB_DRIVER_INPUTINFO_H_
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace clang {
|
||||
namespace driver {
|
||||
class PipedJob;
|
||||
|
||||
/// InputInfo - Wrapper for information about an input source.
|
||||
class InputInfo {
|
||||
union {
|
||||
const char *Filename;
|
||||
PipedJob *Pipe;
|
||||
} Data;
|
||||
bool IsPipe;
|
||||
types::ID Type;
|
||||
const char *BaseInput;
|
||||
|
||||
public:
|
||||
InputInfo() {}
|
||||
InputInfo(const char *Filename, types::ID _Type, const char *_BaseInput)
|
||||
: IsPipe(false), Type(_Type), BaseInput(_BaseInput) {
|
||||
Data.Filename = Filename;
|
||||
}
|
||||
InputInfo(PipedJob *Pipe, types::ID _Type, const char *_BaseInput)
|
||||
: IsPipe(true), Type(_Type), BaseInput(_BaseInput) {
|
||||
Data.Pipe = Pipe;
|
||||
}
|
||||
|
||||
bool isPipe() const { return IsPipe; }
|
||||
types::ID getType() const { return Type; }
|
||||
const char *getBaseInput() const { return BaseInput; }
|
||||
|
||||
const char *getInputFilename() const {
|
||||
assert(!isPipe() && "Invalid accessor.");
|
||||
return Data.Filename;
|
||||
}
|
||||
PipedJob &getPipe() const {
|
||||
assert(isPipe() && "Invalid accessor.");
|
||||
return *Data.Pipe;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace driver
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
|
|
@ -45,6 +45,7 @@ int main(int argc, const char **argv) {
|
|||
llvm::OwningPtr<Driver> TheDriver(new Driver(Path.getBasename().c_str(),
|
||||
Path.getDirname().c_str(),
|
||||
LLVM_HOSTTRIPLE,
|
||||
"a.out",
|
||||
Diags));
|
||||
|
||||
llvm::OwningPtr<Compilation> C(TheDriver->BuildCompilation(argc, argv));
|
||||
|
|
|
|||
Loading…
Reference in a new issue