diff options
Diffstat (limited to 'clang/lib/Driver')
-rw-r--r-- | clang/lib/Driver/Driver.cpp | 77 | ||||
-rw-r--r-- | clang/lib/Driver/ToolChains/InterfaceStubs.cpp | 36 | ||||
-rw-r--r-- | clang/lib/Driver/Types.cpp | 16 |
3 files changed, 99 insertions, 30 deletions
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index cdf4a579f43..40cada744d0 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -292,10 +292,6 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL, (PhaseArg = DAL.getLastArg(options::OPT_emit_ast))) { FinalPhase = phases::Compile; - // clang interface stubs - } else if ((PhaseArg = DAL.getLastArg(options::OPT_emit_interface_stubs))) { - FinalPhase = phases::IfsMerge; - // -S only runs up to the backend. } else if ((PhaseArg = DAL.getLastArg(options::OPT_S))) { FinalPhase = phases::Backend; @@ -3502,6 +3498,68 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, Actions.push_back( C.MakeAction<IfsMergeJobAction>(MergerInputs, types::TY_Image)); + if (Arg *A = Args.getLastArg(options::OPT_emit_interface_stubs)) { + llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> PhaseList; + if (Args.hasArg(options::OPT_c)) { + llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> CompilePhaseList; + types::getCompilationPhases(types::TY_IFS_CPP, CompilePhaseList); + llvm::copy_if(PhaseList, std::back_inserter(CompilePhaseList), + [&](phases::ID Phase) { return Phase <= phases::Compile; }); + } else { + types::getCompilationPhases(types::TY_IFS_CPP, PhaseList); + } + + ActionList MergerInputs; + + for (auto &I : Inputs) { + types::ID InputType = I.first; + const Arg *InputArg = I.second; + + // Currently clang and the llvm assembler do not support generating symbol + // stubs from assembly, so we skip the input on asm files. For ifs files + // we rely on the normal pipeline setup in the pipeline setup code above. + if (InputType == types::TY_IFS || InputType == types::TY_PP_Asm || + InputType == types::TY_Asm) + continue; + + Action *Current = C.MakeAction<InputAction>(*InputArg, InputType); + + for (auto Phase : PhaseList) { + switch (Phase) { + default: + llvm_unreachable( + "IFS Pipeline can only consist of Compile followed by IfsMerge."); + case phases::Compile: { + // Only IfsMerge (llvm-ifs) can handle .o files by looking for ifs + // files where the .o file is located. The compile action can not + // handle this. + if (InputType == types::TY_Object) + break; + + Current = C.MakeAction<CompileJobAction>(Current, types::TY_IFS_CPP); + break; + } + case phases::IfsMerge: { + assert(Phase == PhaseList.back() && + "merging must be final compilation step."); + MergerInputs.push_back(Current); + Current = nullptr; + break; + } + } + } + + // If we ended with something, add to the output list. + if (Current) + Actions.push_back(Current); + } + + // Add an interface stubs merge action if necessary. + if (!MergerInputs.empty()) + Actions.push_back( + C.MakeAction<IfsMergeJobAction>(MergerInputs, types::TY_Image)); + } + // If --print-supported-cpus, -mcpu=? or -mtune=? is specified, build a custom // Compile phase that prints out supported cpu models and quits. if (Arg *A = Args.getLastArg(options::OPT_print_supported_cpus)) { @@ -3603,8 +3661,6 @@ Action *Driver::ConstructPhaseAction( return C.MakeAction<CompileJobAction>(Input, types::TY_ModuleFile); if (Args.hasArg(options::OPT_verify_pch)) return C.MakeAction<VerifyPCHJobAction>(Input, types::TY_Nothing); - if (Args.hasArg(options::OPT_emit_interface_stubs)) - return C.MakeAction<CompileJobAction>(Input, types::TY_IFS_CPP); return C.MakeAction<CompileJobAction>(Input, types::TY_LLVM_BC); } case phases::Backend: { @@ -3633,11 +3689,16 @@ void Driver::BuildJobs(Compilation &C) const { Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o); // It is an error to provide a -o option if we are making multiple output - // files. + // files. There is one exception, IfsMergeJob: when generating interface stubs + // enabled we want to be able to generate the stub file at the same time that + // we generate the real library/a.out. So when a .o, .so, etc are the output, + // with clang interface stubs there will also be a .ifs and .ifso at the same + // location. if (FinalOutput) { unsigned NumOutputs = 0; for (const Action *A : C.getActions()) - if (A->getType() != types::TY_Nothing) + if (A->getType() != types::TY_Nothing && + A->getKind() != Action::IfsMergeJobClass) ++NumOutputs; if (NumOutputs > 1) { diff --git a/clang/lib/Driver/ToolChains/InterfaceStubs.cpp b/clang/lib/Driver/ToolChains/InterfaceStubs.cpp index 6677843b2c5..b57602cd362 100644 --- a/clang/lib/Driver/ToolChains/InterfaceStubs.cpp +++ b/clang/lib/Driver/ToolChains/InterfaceStubs.cpp @@ -9,6 +9,7 @@ #include "InterfaceStubs.h" #include "CommonArgs.h" #include "clang/Driver/Compilation.h" +#include "llvm/Support/Path.h" namespace clang { namespace driver { @@ -21,13 +22,36 @@ void Merger::ConstructJob(Compilation &C, const JobAction &JA, std::string Merger = getToolChain().GetProgramPath(getShortName()); llvm::opt::ArgStringList CmdArgs; CmdArgs.push_back("-action"); - CmdArgs.push_back(Args.getLastArg(options::OPT_emit_merged_ifs) - ? "write-ifs" - : "write-bin"); + const bool WriteBin = !Args.getLastArg(options::OPT_emit_merged_ifs); + CmdArgs.push_back(WriteBin ? "write-bin" : "write-ifs"); CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - for (const auto &Input : Inputs) - CmdArgs.push_back(Input.getFilename()); + + // Normally we want to write to a side-car file ending in ".ifso" so for + // example if `clang -emit-interface-stubs -shared -o libhello.so` were + // invoked then we would like to get libhello.so and libhello.ifso. If the + // stdout stream is given as the output file (ie `-o -`), that is the one + // exception where we will just append to the same filestream as the normal + // output. + SmallString<128> OutputFilename(Output.getFilename()); + if (OutputFilename != "-") { + if (Args.hasArg(options::OPT_shared)) + llvm::sys::path::replace_extension(OutputFilename, + (WriteBin ? "ifso" : "ifs")); + else + OutputFilename += ".ifso"; + } + + CmdArgs.push_back(Args.MakeArgString(OutputFilename.c_str())); + + // Here we append the input files. If the input files are object files, then + // we look for .ifs files present in the same location as the object files. + for (const auto &Input : Inputs) { + SmallString<128> InputFilename(Input.getFilename()); + if (Input.getType() == types::TY_Object) + llvm::sys::path::replace_extension(InputFilename, ".ifs"); + CmdArgs.push_back(Args.MakeArgString(InputFilename.c_str())); + } + C.addCommand(std::make_unique<Command>(JA, *this, Args.MakeArgString(Merger), CmdArgs, Inputs)); } diff --git a/clang/lib/Driver/Types.cpp b/clang/lib/Driver/Types.cpp index 0e14e3d63fa..7d83be2521e 100644 --- a/clang/lib/Driver/Types.cpp +++ b/clang/lib/Driver/Types.cpp @@ -330,22 +330,6 @@ void types::getCompilationPhases(const clang::driver::Driver &Driver, llvm::copy_if(PhaseList, std::back_inserter(P), [](phases::ID Phase) { return Phase <= phases::Precompile; }); - // Treat Interface Stubs like its own compilation mode. - else if (DAL.getLastArg(options::OPT_emit_interface_stubs)) { - llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> IfsModePhaseList; - llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> &PL = PhaseList; - phases::ID LastPhase = phases::IfsMerge; - if (Id != types::TY_IFS) { - if (DAL.hasArg(options::OPT_c)) - LastPhase = phases::Compile; - PL = IfsModePhaseList; - types::getCompilationPhases(types::TY_IFS_CPP, PL); - } - llvm::copy_if(PL, std::back_inserter(P), [&](phases::ID Phase) { - return Phase <= LastPhase; - }); - } - // -{fsyntax-only,-analyze,emit-ast} only run up to the compiler. else if (DAL.getLastArg(options::OPT_fsyntax_only) || DAL.getLastArg(options::OPT_print_supported_cpus) || |