diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 40cada744d05d4..cdf4a579f431ef 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -292,6 +292,10 @@ 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; @@ -3498,68 +3502,6 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, Actions.push_back( C.MakeAction(MergerInputs, types::TY_Image)); - if (Arg *A = Args.getLastArg(options::OPT_emit_interface_stubs)) { - llvm::SmallVector PhaseList; - if (Args.hasArg(options::OPT_c)) { - llvm::SmallVector 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(*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(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(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)) { @@ -3661,6 +3603,8 @@ Action *Driver::ConstructPhaseAction( return C.MakeAction(Input, types::TY_ModuleFile); if (Args.hasArg(options::OPT_verify_pch)) return C.MakeAction(Input, types::TY_Nothing); + if (Args.hasArg(options::OPT_emit_interface_stubs)) + return C.MakeAction(Input, types::TY_IFS_CPP); return C.MakeAction(Input, types::TY_LLVM_BC); } case phases::Backend: { @@ -3689,16 +3633,11 @@ 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. 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. + // files. if (FinalOutput) { unsigned NumOutputs = 0; for (const Action *A : C.getActions()) - if (A->getType() != types::TY_Nothing && - A->getKind() != Action::IfsMergeJobClass) + if (A->getType() != types::TY_Nothing) ++NumOutputs; if (NumOutputs > 1) { diff --git a/clang/lib/Driver/ToolChains/InterfaceStubs.cpp b/clang/lib/Driver/ToolChains/InterfaceStubs.cpp index b57602cd3624fc..6677843b2c5330 100644 --- a/clang/lib/Driver/ToolChains/InterfaceStubs.cpp +++ b/clang/lib/Driver/ToolChains/InterfaceStubs.cpp @@ -9,7 +9,6 @@ #include "InterfaceStubs.h" #include "CommonArgs.h" #include "clang/Driver/Compilation.h" -#include "llvm/Support/Path.h" namespace clang { namespace driver { @@ -22,36 +21,13 @@ void Merger::ConstructJob(Compilation &C, const JobAction &JA, std::string Merger = getToolChain().GetProgramPath(getShortName()); llvm::opt::ArgStringList CmdArgs; CmdArgs.push_back("-action"); - const bool WriteBin = !Args.getLastArg(options::OPT_emit_merged_ifs); - CmdArgs.push_back(WriteBin ? "write-bin" : "write-ifs"); + CmdArgs.push_back(Args.getLastArg(options::OPT_emit_merged_ifs) + ? "write-ifs" + : "write-bin"); CmdArgs.push_back("-o"); - - // 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())); - } - + CmdArgs.push_back(Output.getFilename()); + for (const auto &Input : Inputs) + CmdArgs.push_back(Input.getFilename()); C.addCommand(std::make_unique(JA, *this, Args.MakeArgString(Merger), CmdArgs, Inputs)); } diff --git a/clang/lib/Driver/Types.cpp b/clang/lib/Driver/Types.cpp index 7d83be2521e73f..0e14e3d63fab26 100644 --- a/clang/lib/Driver/Types.cpp +++ b/clang/lib/Driver/Types.cpp @@ -330,6 +330,22 @@ 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 IfsModePhaseList; + llvm::SmallVector &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) || diff --git a/clang/test/InterfaceStubs/driver-test.c b/clang/test/InterfaceStubs/driver-test.c index bb2868f6df03e7..d4e50295411ad9 100644 --- a/clang/test/InterfaceStubs/driver-test.c +++ b/clang/test/InterfaceStubs/driver-test.c @@ -1,13 +1,11 @@ // REQUIRES: x86-registered-target -// RUN: %clang -target x86_64-unknown-linux-gnu -x c -o %t1 -emit-interface-stubs %s %S/object.c %S/weak.cpp -// RUN: llvm-nm %t1 2>&1 | FileCheck %s -// RUN: llvm-nm %t1.ifso 2>&1 | FileCheck %s +// RUN: %clang -target x86_64-unknown-linux-gnu -x c -o %t1.so -emit-interface-stubs %s %S/object.c %S/weak.cpp && \ +// RUN: llvm-nm %t1.so 2>&1 | FileCheck --check-prefix=CHECK-IFS %s -// CHECK-DAG: data -// CHECK-DAG: foo -// CHECK-DAG: strongFunc -// CHECK-DAG: weakFunc +// CHECK-IFS-DAG: data +// CHECK-IFS-DAG: foo +// CHECK-IFS-DAG: strongFunc +// CHECK-IFS-DAG: weakFunc int foo(int bar) { return 42 + 1844; } -int main() { return foo(23); } diff --git a/clang/test/InterfaceStubs/driver-test2.c b/clang/test/InterfaceStubs/driver-test2.c deleted file mode 100644 index f0f889a799ddcb..00000000000000 --- a/clang/test/InterfaceStubs/driver-test2.c +++ /dev/null @@ -1,14 +0,0 @@ -// REQUIRES: x86-registered-target - -// RUN: %clang -target x86_64-unknown-linux-gnu -c -emit-interface-stubs \ -// RUN: %s %S/object.c %S/weak.cpp -// RUN: %clang -emit-interface-stubs -emit-merged-ifs \ -// RUN: driver-test2.o object.o weak.o -S -o - | FileCheck %s - -// CHECK-DAG: data -// CHECK-DAG: bar -// CHECK-DAG: strongFunc -// CHECK-DAG: weakFunc - -int bar(int a) { return a; } -int main() { return 0; } diff --git a/clang/test/InterfaceStubs/windows.cpp b/clang/test/InterfaceStubs/windows.cpp index c81c702861e4cb..9ccb771a2f399d 100644 --- a/clang/test/InterfaceStubs/windows.cpp +++ b/clang/test/InterfaceStubs/windows.cpp @@ -1,7 +1,6 @@ // REQUIRES: x86-registered-target // RUN: %clang_cc1 -triple x86_64-windows-msvc -o - %s -emit-interface-stubs | FileCheck -check-prefix=CHECK-CC1 %s -// RUN: %clang -target x86_64-windows-msvc -o - %s -emit-interface-stubs -emit-merged-ifs -S | FileCheck -check-prefix=CHECK-IFS %s -// note: -S is added here to prevent clang from invoking link.exe +// RUN: %clang -target x86_64-windows-msvc -o - %s -emit-interface-stubs -emit-merged-ifs | FileCheck -check-prefix=CHECK-IFS %s // CHECK-CC1: Symbols: // CHECK-CC1-NEXT: ?helloWindowsMsvc@@YAHXZ