jhuber6 created this revision. jhuber6 added reviewers: jdoerfert, gregrodgers, JonChesterfield, ronlieb. Herald added a subscriber: mgorny. jhuber6 requested review of this revision. Herald added subscribers: cfe-commits, sstefan1. Herald added a project: clang.
This patch introduces a linker wrapper tool that allows us to preprocess files before they are sent to the linker. This adds a dummy action and job to the driver stage that builds the linker command as usual and then replaces the command line with the wrapper tool. Depends on D116543 <https://reviews.llvm.org/D116543> Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D116544 Files: clang/include/clang/Driver/Action.h clang/include/clang/Driver/Job.h clang/include/clang/Driver/ToolChain.h clang/lib/Driver/Action.cpp clang/lib/Driver/Driver.cpp clang/lib/Driver/ToolChain.cpp clang/lib/Driver/ToolChains/Clang.cpp clang/lib/Driver/ToolChains/Clang.h clang/tools/CMakeLists.txt clang/tools/clang-linker-wrapper/CMakeLists.txt clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
Index: clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp =================================================================== --- /dev/null +++ clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp @@ -0,0 +1,91 @@ +//===-- clang-linker-wrapper/ClangLinkerWrapper.cpp - wrapper over linker-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// +/// +//===---------------------------------------------------------------------===// + +#include "clang/Basic/Version.h" +#include "llvm/Object/Archive.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/StringSaver.h" +#include "llvm/Support/WithColor.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden); + +// Mark all our options with this category, everything else (except for -help) +// will be hidden. +static cl::OptionCategory + ClangLinkerWrapperCategory("clang-linker-wrapper options"); + +static cl::opt<std::string> LinkerUserPath("linker-path", + cl::desc("Path of linker binary"), + cl::cat(ClangLinkerWrapperCategory)); + +// Do not parse linker options +static cl::list<std::string> + LinkerArgs(cl::Sink, cl::desc("<options to be passed to linker>...")); + +static Error runLinker(std::string LinkerPath, + SmallVectorImpl<std::string> &Args) { + std::vector<StringRef> LinkerArgs; + LinkerArgs.push_back(LinkerPath); + for (auto &Arg : Args) + LinkerArgs.push_back(Arg); + + if (sys::ExecuteAndWait(LinkerPath, LinkerArgs)) + return createStringError(inconvertibleErrorCode(), "'linker' failed"); + return Error::success(); +} + +static void PrintVersion(raw_ostream &OS) { + OS << clang::getClangToolFullVersion("clang-linker-wrapper") << '\n'; +} + +int main(int argc, const char **argv) { + sys::PrintStackTraceOnErrorSignal(argv[0]); + cl::SetVersionPrinter(PrintVersion); + cl::HideUnrelatedOptions(ClangLinkerWrapperCategory); + cl::ParseCommandLineOptions( + argc, argv, + "A wrapper utility over the host linker. It scans the input files for\n" + "sections that require additional processing prior to linking. The tool\n" + "will then transparently pass all arguments and input to the specified\n" + "host linker to create the final binary.\n"); + + if (Help) { + cl::PrintHelpMessage(); + return EXIT_SUCCESS; + } + + auto reportError = [argv](Error E) { + logAllUnhandledErrors(std::move(E), WithColor::error(errs(), argv[0])); + exit(EXIT_FAILURE); + }; + + // TODO: Scan input object files for offloading sections and extract them. + // TODO: Perform appropriate device linking action. + // TODO: Wrap device image in a host binary and pass it to the linker. + WithColor::warning(errs(), argv[0]) << "Offload linking not yet supported.\n"; + + SmallVector<std::string, 0> Argv; + for (const std::string &Arg : LinkerArgs) + Argv.push_back(Arg); + + if (Error Err = runLinker(LinkerUserPath, Argv)) + reportError(std::move(Err)); + + return EXIT_SUCCESS; +} Index: clang/tools/clang-linker-wrapper/CMakeLists.txt =================================================================== --- /dev/null +++ clang/tools/clang-linker-wrapper/CMakeLists.txt @@ -0,0 +1,25 @@ +set(LLVM_LINK_COMPONENTS BitWriter Core Object Support) + +if(NOT CLANG_BUILT_STANDALONE) + set(tablegen_deps intrinsics_gen) +endif() + +add_clang_executable(clang-linker-wrapper + ClangLinkerWrapper.cpp + + DEPENDS + ${tablegen_deps} + ) + +set(CLANG_LINKER_WRAPPER_LIB_DEPS + clangBasic + ) + +add_dependencies(clang clang-linker-wrapper) + +target_link_libraries(clang-linker-wrapper + PRIVATE + ${CLANG_LINKER_WRAPPER_LIB_DEPS} + ) + +install(TARGETS clang-linker-wrapper RUNTIME DESTINATION bin) Index: clang/tools/CMakeLists.txt =================================================================== --- clang/tools/CMakeLists.txt +++ clang/tools/CMakeLists.txt @@ -9,6 +9,7 @@ add_clang_subdirectory(clang-fuzzer) add_clang_subdirectory(clang-import-test) add_clang_subdirectory(clang-nvlink-wrapper) +add_clang_subdirectory(clang-linker-wrapper) add_clang_subdirectory(clang-offload-bundler) add_clang_subdirectory(clang-offload-wrapper) add_clang_subdirectory(clang-scan-deps) Index: clang/lib/Driver/ToolChains/Clang.h =================================================================== --- clang/lib/Driver/ToolChains/Clang.h +++ clang/lib/Driver/ToolChains/Clang.h @@ -170,6 +170,21 @@ const char *LinkingOutput) const override; }; +/// Linker wrapper tool. +class LLVM_LIBRARY_VISIBILITY LinkerWrapper final : public Tool { + const Tool *Linker; + +public: + LinkerWrapper(const ToolChain &TC, const Tool *Linker) + : Tool("Offload::Linker", "linker", TC), Linker(Linker) {} + + bool hasIntegratedCPP() const override { return false; } + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + } // end namespace tools } // end namespace driver Index: clang/lib/Driver/ToolChains/Clang.cpp =================================================================== --- clang/lib/Driver/ToolChains/Clang.cpp +++ clang/lib/Driver/ToolChains/Clang.cpp @@ -8122,3 +8122,28 @@ Args.MakeArgString(getToolChain().GetProgramPath(getShortName())), CmdArgs, Inputs, Output)); } + +void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + ArgStringList CmdArgs; + + // Construct the link job so we can wrap around it. + Linker->ConstructJob(C, JA, Output, Inputs, Args, LinkingOutput); + const auto &LinkCommand = C.getJobs().getJobs().back(); + + CmdArgs.push_back("-linker-path"); + CmdArgs.push_back(LinkCommand->getExecutable()); + for (const char *LinkArg : LinkCommand->getArguments()) + CmdArgs.push_back(LinkArg); + + const char *Exec = + Args.MakeArgString(getToolChain().GetProgramPath("clang-linker-wrapper")); + + // Replace the executable and arguments associated with the link job to the + // wrapper. + LinkCommand->replaceExecutable(Exec); + LinkCommand->replaceArguments(CmdArgs); +} Index: clang/lib/Driver/ToolChain.cpp =================================================================== --- clang/lib/Driver/ToolChain.cpp +++ clang/lib/Driver/ToolChain.cpp @@ -324,6 +324,12 @@ return OffloadWrapper.get(); } +Tool *ToolChain::getLinkerWrapper() const { + if (!LinkerWrapper) + LinkerWrapper.reset(new tools::LinkerWrapper(*this, getLink())); + return LinkerWrapper.get(); +} + Tool *ToolChain::getTool(Action::ActionClass AC) const { switch (AC) { case Action::AssembleJobClass: @@ -362,6 +368,8 @@ case Action::OffloadWrapperJobClass: return getOffloadWrapper(); + case Action::LinkerWrapperJobClass: + return getLinkerWrapper(); } llvm_unreachable("Invalid tool kind."); Index: clang/lib/Driver/Driver.cpp =================================================================== --- clang/lib/Driver/Driver.cpp +++ clang/lib/Driver/Driver.cpp @@ -3913,14 +3913,16 @@ // Check if this Linker Job should emit a static library. if (ShouldEmitStaticLibrary(Args)) { LA = C.MakeAction<StaticLibJobAction>(LinkerInputs, types::TY_Image); + } else if (Args.hasArg(options::OPT_fopenmp_new_driver) && + OffloadKinds != Action::OFK_None) { + LA = C.MakeAction<LinkerWrapperJobAction>(LinkerInputs, types::TY_Image); + LA->propagateHostOffloadInfo(OffloadKinds, + /*BoundArch=*/nullptr); } else { LA = C.MakeAction<LinkJobAction>(LinkerInputs, types::TY_Image); } if (!Args.hasArg(options::OPT_fopenmp_new_driver)) LA = OffloadBuilder.processHostLinkAction(LA); - if (Args.hasArg(options::OPT_fopenmp_new_driver)) - LA->propagateHostOffloadInfo(OffloadKinds, - /*BoundArch=*/nullptr); Actions.push_back(LA); } Index: clang/lib/Driver/Action.cpp =================================================================== --- clang/lib/Driver/Action.cpp +++ clang/lib/Driver/Action.cpp @@ -43,6 +43,8 @@ return "clang-offload-unbundler"; case OffloadWrapperJobClass: return "clang-offload-wrapper"; + case LinkerWrapperJobClass: + return "clang-linker-wrapper"; case StaticLibJobClass: return "static-lib-linker"; } @@ -418,6 +420,12 @@ types::ID Type) : JobAction(OffloadWrapperJobClass, Inputs, Type) {} +void LinkerWrapperJobAction::anchor() {} + +LinkerWrapperJobAction::LinkerWrapperJobAction(ActionList &Inputs, + types::ID Type) + : JobAction(LinkerWrapperJobClass, Inputs, Type) {} + void StaticLibJobAction::anchor() {} StaticLibJobAction::StaticLibJobAction(ActionList &Inputs, types::ID Type) Index: clang/include/clang/Driver/ToolChain.h =================================================================== --- clang/include/clang/Driver/ToolChain.h +++ clang/include/clang/Driver/ToolChain.h @@ -151,6 +151,7 @@ mutable std::unique_ptr<Tool> IfsMerge; mutable std::unique_ptr<Tool> OffloadBundler; mutable std::unique_ptr<Tool> OffloadWrapper; + mutable std::unique_ptr<Tool> LinkerWrapper; Tool *getClang() const; Tool *getFlang() const; @@ -161,6 +162,7 @@ Tool *getClangAs() const; Tool *getOffloadBundler() const; Tool *getOffloadWrapper() const; + Tool *getLinkerWrapper() const; mutable bool SanitizerArgsChecked = false; mutable std::unique_ptr<XRayArgs> XRayArguments; Index: clang/include/clang/Driver/Job.h =================================================================== --- clang/include/clang/Driver/Job.h +++ clang/include/clang/Driver/Job.h @@ -208,6 +208,8 @@ Arguments = std::move(List); } + void replaceExecutable(const char *Exe) { Executable = Exe; } + const char *getExecutable() const { return Executable; } const llvm::opt::ArgStringList &getArguments() const { return Arguments; } Index: clang/include/clang/Driver/Action.h =================================================================== --- clang/include/clang/Driver/Action.h +++ clang/include/clang/Driver/Action.h @@ -73,6 +73,7 @@ OffloadBundlingJobClass, OffloadUnbundlingJobClass, OffloadWrapperJobClass, + LinkerWrapperJobClass, StaticLibJobClass, JobClassFirst = PreprocessJobClass, @@ -642,6 +643,17 @@ } }; +class LinkerWrapperJobAction : public JobAction { + void anchor() override; + +public: + LinkerWrapperJobAction(ActionList &Inputs, types::ID Type); + + static bool classof(const Action *A) { + return A->getKind() == LinkerWrapperJobClass; + } +}; + class StaticLibJobAction : public JobAction { void anchor() override;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits