(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;
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(CompilePhaseList, std::back_inserter(PhaseList),
+ [&](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)) {
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: {
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) {
#include "InterfaceStubs.h"
#include "CommonArgs.h"
#include "clang/Driver/Compilation.h"
+#include "llvm/Support/Path.h"
namespace clang {
namespace driver {
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 += (WriteBin ? ".ifso" : ".ifs");
+ }
+
+ 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));
}
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) ||
// REQUIRES: x86-registered-target
+// REQUIRES: shell
-// 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: mkdir -p %t; cd %t
+// RUN: %clang -target x86_64-unknown-linux-gnu -x c -S -emit-interface-stubs %s %S/object.c %S/weak.cpp && \
+// RUN: llvm-nm %t/a.out.ifso 2>&1 | FileCheck --check-prefix=CHECK-IFS %s
// CHECK-IFS-DAG: data
// CHECK-IFS-DAG: foo
--- /dev/null
+// REQUIRES: x86-registered-target
+// REQUIRES: shell
+
+// RUN: mkdir -p %t; cd %t
+// 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: %t/driver-test2.o %t/object.o %t/weak.o -S -o - 2>&1 | FileCheck %s
+
+// CHECK-DAG: data
+// CHECK-DAG: bar
+// CHECK-DAG: strongFunc
+// CHECK-DAG: weakFunc
+
+int bar(int a) { return a; }
+int main() { return 0; }
--- /dev/null
+// REQUIRES: powerpc-registered-target
+
+// RUN: %clang -x c++ -target powerpc64le-unknown-linux-gnu -o - %s \
+// RUN: -emit-interface-stubs -emit-merged-ifs -S | \
+// RUN: FileCheck -check-prefix=CHECK-IFS %s
+
+ // CHECK-IFS: --- !experimental-ifs-v1
+ // CHECK-IFS: IfsVersion: 1.0
+ // CHECK-IFS: Triple: powerpc64le
+ // CHECK-IFS: Symbols:
+ // CHECK-IFS: _Z8helloPPCv: { Type: Func }
+ // CHECK-IFS: ...
+
+int helloPPC();
// 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 -S | FileCheck -check-prefix=CHECK-IFS %s
+// note: -S is added here to prevent clang from invoking link.exe
// CHECK-CC1: Symbols:
// CHECK-CC1-NEXT: ?helloWindowsMsvc@@YAHXZ