diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -3491,6 +3491,51 @@ Actions.push_back( C.MakeAction(MergerInputs, types::TY_Image)); + if (Arg *A = Args.getLastArg(options::OPT_emit_interface_stubs)) { + llvm::SmallVector PhaseList; + llvm::SmallVector &PL = PhaseList; + types::getCompilationPhases(types::TY_IFS_CPP, PL); + + ActionList MergerInputs; + + for (auto &I : Inputs) { + types::ID InputType = I.first; + const Arg *InputArg = I.second; + + if (InputType == types::TY_IFS) + continue; + + Action *Current = C.MakeAction(*InputArg, InputType); + + for (phases::ID Phase : PL) { + if (Phase == phases::IfsMerge) { + assert(Phase == PL.back() && + "merging must be final compilation step."); + MergerInputs.push_back(Current); + Current = nullptr; + break; + } + + if (Phase == phases::Compile) { + Current = C.MakeAction(Current, types::TY_IFS_CPP); + continue; + } + + llvm_unreachable( + "IFS Pipeline can only consist of Compile followed by IfsMerge."); + } + + // 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)) { @@ -3592,8 +3637,6 @@ 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: { @@ -3626,7 +3669,8 @@ 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 --- a/clang/lib/Driver/ToolChains/InterfaceStubs.cpp +++ b/clang/lib/Driver/ToolChains/InterfaceStubs.cpp @@ -21,11 +21,29 @@ 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()); + + std::string OutputFilename = Output.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. + if (OutputFilename != "-") { + std::string DllFileExt = ".so"; + size_t TrimedSize = OutputFilename.size() - DllFileExt.size(); + if (OutputFilename.size() > DllFileExt.size() && + std::equal(OutputFilename.begin() + TrimedSize, OutputFilename.end(), + DllFileExt.begin())) + OutputFilename = OutputFilename.substr(0, TrimedSize); + + OutputFilename += (WriteBin ? ".ifso" : ".ifs"); + } + CmdArgs.push_back(Args.MakeArgString(OutputFilename.c_str())); for (const auto &Input : Inputs) CmdArgs.push_back(Input.getFilename()); C.addCommand(std::make_unique(JA, *this, Args.MakeArgString(Merger), diff --git a/clang/lib/Driver/Types.cpp b/clang/lib/Driver/Types.cpp --- a/clang/lib/Driver/Types.cpp +++ b/clang/lib/Driver/Types.cpp @@ -330,22 +330,6 @@ 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 --- a/clang/test/InterfaceStubs/driver-test.c +++ b/clang/test/InterfaceStubs/driver-test.c @@ -1,11 +1,13 @@ // REQUIRES: x86-registered-target -// 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 +// 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 -// CHECK-IFS-DAG: data -// CHECK-IFS-DAG: foo -// CHECK-IFS-DAG: strongFunc -// CHECK-IFS-DAG: weakFunc +// CHECK-DAG: data +// CHECK-DAG: foo +// CHECK-DAG: strongFunc +// CHECK-DAG: weakFunc int foo(int bar) { return 42 + 1844; } +int main() { return foo(23); } diff --git a/clang/test/InterfaceStubs/windows.cpp b/clang/test/InterfaceStubs/windows.cpp --- a/clang/test/InterfaceStubs/windows.cpp +++ b/clang/test/InterfaceStubs/windows.cpp @@ -1,6 +1,7 @@ // 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 | FileCheck -check-prefix=CHECK-IFS %s +// RUN: %clang -target x86_64-windows-msvc -o - %s -emit-interface-stubs -emit-merged-ifs -c | FileCheck -check-prefix=CHECK-IFS %s +// note: -c is added here to prevent clang from invoking link.exe // CHECK-CC1: Symbols: // CHECK-CC1-NEXT: ?helloWindowsMsvc@@YAHXZ