diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt --- a/llvm/CMakeLists.txt +++ b/llvm/CMakeLists.txt @@ -431,6 +431,8 @@ option(LLVM_ENABLE_EXPENSIVE_CHECKS "Enable expensive checks" OFF) +option(LLVM_ENABLE_EXPERIMENTAL_BUSYBOX "Enable usage of llvm tools through a single binary" OFF) + # While adding scalable vector support to LLVM, we temporarily want to # allow an implicit conversion of TypeSize to uint64_t, and to allow # code to get the fixed number of elements from a possibly scalable vector. diff --git a/llvm/cmake/modules/AddLLVM.cmake b/llvm/cmake/modules/AddLLVM.cmake --- a/llvm/cmake/modules/AddLLVM.cmake +++ b/llvm/cmake/modules/AddLLVM.cmake @@ -1214,6 +1214,10 @@ strings strip ) + + if (${LLVM_ENABLE_EXPERIMENTAL_BUSYBOX}) + set(LLVM_TOOLCHAIN_TOOLS "${LLVM_TOOLCHAIN_TOOLS} llvm") + endif() endif() macro(add_llvm_tool name) diff --git a/llvm/tools/llvm-busybox/CMakeLists.txt b/llvm/tools/llvm-busybox/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-busybox/CMakeLists.txt @@ -0,0 +1,58 @@ +if(NOT ${LLVM_ENABLE_EXPERIMENTAL_BUSYBOX}) + return() +endif() + + +set(LLVM_LINK_COMPONENTS + ObjCopy + ObjDump + ) + +add_llvm_tool(llvm + main.cpp + + DEPENDS + LLVMObjCopy + LLVMObjDump + ) + +# llvm-objdump +# +# FIXME: One initial idea was to wrap any post-processing cmake code that did +# stuff like make symlinks into either (1) a function that we can call from this +# cmake file after building this tool, or (2) a subdirectory within that tool +# that we can just `add_subdirectory` into to invoke the build rules for symlinks. +# The problem with (1) is that I can't figure out how to change the scope of a +# function() to the parent scope so it's callable from here. The problem with +# (2) is that I get a cmake build error relating to not being able to find the +# build directory for the subdir that I created (despite it existing). So for +# now, there's nothing I can think of that prevents duplicating these +# "post-processing" build steps without maybe moving them into a parent +# directory outside of the tools's directory. +add_llvm_tool_symlink(llvm-objdump llvm) + +# NOTE that this was originally a symlink to llvm-objdump, but using +# `add_llvm_tool_symlink` doesn't seem to generate the new symlink. Ideally, +# we could just keep all this in its tool's directory and not need to change +# it at all. +add_llvm_tool_symlink(llvm-otool llvm) + +if(LLVM_INSTALL_BINUTILS_SYMLINKS) + add_llvm_tool_symlink(objdump llvm) +endif() + +# llvm-objcopy +add_llvm_tool_symlink(llvm-objcopy llvm) +add_llvm_tool_symlink(llvm-install-name-tool llvm) +add_llvm_tool_symlink(llvm-bitcode-strip llvm) +add_llvm_tool_symlink(llvm-strip llvm) + +if(LLVM_INSTALL_BINUTILS_SYMLINKS) + add_llvm_tool_symlink(objcopy llvm) + add_llvm_tool_symlink(strip llvm) +endif() + +if(LLVM_INSTALL_CCTOOLS_SYMLINKS) + add_llvm_tool_symlink(install_name_tool llvm) + add_llvm_tool_symlink(bitcode_strip llvm) +endif() diff --git a/llvm/tools/llvm-busybox/Tools.def b/llvm/tools/llvm-busybox/Tools.def new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-busybox/Tools.def @@ -0,0 +1,27 @@ +#ifndef TOOL +#define TOOL(BusyboxName, LLVMName, MainFunc) +#endif + +#ifndef OBJDUMP_TOOL +#define OBJDUMP_TOOL(BusyboxName, LLVMName) \ + TOOL(BusyboxName, LLVMName, llvm_objdump_main) +#endif + +#ifndef OBJCOPY_TOOL +#define OBJCOPY_TOOL(BusyboxName, LLVMName) \ + TOOL(BusyboxName, LLVMName, llvm_objcopy_main) +#endif + +OBJDUMP_TOOL("objdump", "llvm-objdump") +OBJDUMP_TOOL("otool", "llvm-otool") + +OBJCOPY_TOOL("objcopy", "llvm-objcopy") +OBJCOPY_TOOL("strip", "llvm-strip") +OBJCOPY_TOOL("bitcode-strip", "llvm-bitcode-strip") +OBJCOPY_TOOL("bitcode_strip", "llvm-bitcode-strip") +OBJCOPY_TOOL("install-name-tool", "llvm-install-name-tool") +OBJCOPY_TOOL("install_name_tool", "llvm-install-name-tool") + +#undef TOOL +#undef OBJDUMP_TOOL +#undef OBJCOPY_TOOL diff --git a/llvm/tools/llvm-busybox/main.cpp b/llvm/tools/llvm-busybox/main.cpp new file mode 100644 --- /dev/null +++ b/llvm/tools/llvm-busybox/main.cpp @@ -0,0 +1,142 @@ +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/OptTable.h" +#include "llvm/Option/Option.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/WithColor.h" +#include "llvm/Support/raw_ostream.h" + +#include + +using namespace llvm; + +#define TOOL(BusyboxName, LLVMName, MainFunc) int MainFunc(int, char **); +#include "Tools.def" + +namespace { + +using MainFunc = int (*)(int, char **); +using ToolFuncPair = std::pair; + +constexpr char BusyboxToolName[] = "llvm"; +constexpr char DescriptiveToolName[] = "llvm (busybox)"; + +StringRef OriginalToolName; + +int InvalidMain(int, char **argv) { + SmallString<32> ErrMsg; + ErrMsg.append("invalid tool '"); + ErrMsg.append(OriginalToolName); + ErrMsg.append( + "' specified. See `llvm --help` for a list of supported llvm tools."); + logAllUnhandledErrors( + createStringError(std::errc::invalid_argument, ErrMsg.data()), + WithColor::error(errs(), BusyboxToolName)); + return 1; +} + +struct ToolConfig { + const char *BusyboxName; + const char *LLVMName; + MainFunc ToolMainFunc; +}; + +constexpr ToolConfig BusyboxTools[] = { +#define TOOL(BusyboxName, LLVMName, MainFunc) {BusyboxName, LLVMName, MainFunc}, +#include "Tools.def" +}; + +bool Is(StringRef Stem, StringRef Tool) { + // We need to recognize the following filenames: + // + // llvm-objdump -> objdump + // llvm-otool-10.exe -> otool + // powerpc64-unknown-freebsd13-objdump -> objdump + // + // llvm-objcopy -> objcopy + // strip-10.exe -> strip + // powerpc64-unknown-freebsd13-objcopy -> objcopy + // llvm-install-name-tool -> install-name-tool + auto I = Stem.rfind_lower(Tool); + return I != StringRef::npos && + (I + Tool.size() == Stem.size() || !isAlnum(Stem[I + Tool.size()])); +} + +ToolFuncPair GetToolFuncPair(StringRef BusyboxName) { + StringRef Stem = sys::path::stem(BusyboxName); + for (const ToolConfig &Config : BusyboxTools) { + if (Is(Stem, Config.BusyboxName)) + return std::make_pair(Config.LLVMName, Config.ToolMainFunc); + } + return std::make_pair("", InvalidMain); +} + +MainFunc GetMainFunc(StringRef RawName) { + StringRef Stem = sys::path::stem(RawName); + for (const ToolConfig &Config : BusyboxTools) { + if (Is(Stem, Config.BusyboxName)) + return Config.ToolMainFunc; + } + return InvalidMain; +} + +} // namespace + +int main(int argc, char **argv) { + OriginalToolName = argv[0]; + StringRef ToolName = sys::path::stem(argv[0]); + MainFunc ToolMainFunc; + MutableArrayRef RawToolArgs; + + if (ToolName == BusyboxToolName) { + // We are invoking busybox via `llvm [toolname] ...`. + if (argc < 2) { + logAllUnhandledErrors( + createStringError( + std::errc::invalid_argument, + "no tool specified. See `llvm --help` for a list of " + "supported llvm tools."), + WithColor::error(errs(), DescriptiveToolName)); + return 1; + } + + StringRef Tool(argv[1]); + + if (Tool == "--help" || Tool == "-h") { + outs() << DescriptiveToolName << "\n\n" + << "USAGE: llvm tool ...\n\n" + << "`tool` can be one of:\n" +#define TOOL(BusyboxName, LLVMName, MainFunc) << " " BusyboxName "\n" +#include "Tools.def" + ; + return 0; + } + + RawToolArgs = makeMutableArrayRef(argv + 2, argc - 2); + ToolFuncPair Pair = GetToolFuncPair(Tool); + + ToolName = Pair.first; + ToolMainFunc = Pair.second; + } else { + // We are invoking busybox via a symlink (`llvm-objdump ...`). + ToolMainFunc = GetMainFunc(ToolName); + RawToolArgs = makeMutableArrayRef(argv + 1, argc - 1); + } + + SmallVector MainArgv; + + // Create the new mutable argv[0]. We must do this because argv contains + // mutable strings. + size_t NewArgv0Len = ToolName.size(); + std::unique_ptr NewArgv0(new char[NewArgv0Len + 1]); + strncpy(NewArgv0.get(), ToolName.data(), NewArgv0Len); + NewArgv0.get()[NewArgv0Len] = 0; + MainArgv.append(1, NewArgv0.get()); + MainArgv.append(RawToolArgs.begin(), RawToolArgs.end()); + return ToolMainFunc(MainArgv.size(), + MutableArrayRef(MainArgv).data()); +} diff --git a/llvm/tools/llvm-objcopy/CMakeLists.txt b/llvm/tools/llvm-objcopy/CMakeLists.txt --- a/llvm/tools/llvm-objcopy/CMakeLists.txt +++ b/llvm/tools/llvm-objcopy/CMakeLists.txt @@ -21,7 +21,7 @@ tablegen(LLVM StripOpts.inc -gen-opt-parser-defs) add_public_tablegen_target(StripOptsTableGen) -add_llvm_tool(llvm-objcopy +set(TOOL_ARGS ConfigManager.cpp llvm-objcopy.cpp COFF/COFFObjcopy.cpp @@ -45,16 +45,23 @@ StripOptsTableGen ) -add_llvm_tool_symlink(llvm-install-name-tool llvm-objcopy) -add_llvm_tool_symlink(llvm-bitcode-strip llvm-objcopy) -add_llvm_tool_symlink(llvm-strip llvm-objcopy) +if(${LLVM_ENABLE_EXPERIMENTAL_BUSYBOX}) + add_llvm_library(LLVMObjCopy ${TOOL_ARGS}) + target_compile_definitions(LLVMObjCopy PRIVATE LLVM_ENABLE_EXPERIMENTAL_BUSYBOX) +else() + add_llvm_tool(llvm-objcopy ${TOOL_ARGS}) -if(LLVM_INSTALL_BINUTILS_SYMLINKS) - add_llvm_tool_symlink(objcopy llvm-objcopy) - add_llvm_tool_symlink(strip llvm-objcopy) -endif() + add_llvm_tool_symlink(llvm-install-name-tool llvm-objcopy) + add_llvm_tool_symlink(llvm-bitcode-strip llvm-objcopy) + add_llvm_tool_symlink(llvm-strip llvm-objcopy) + + if(LLVM_INSTALL_BINUTILS_SYMLINKS) + add_llvm_tool_symlink(objcopy llvm-objcopy) + add_llvm_tool_symlink(strip llvm-objcopy) + endif() -if(LLVM_INSTALL_CCTOOLS_SYMLINKS) - add_llvm_tool_symlink(install_name_tool llvm-install-name-tool) - add_llvm_tool_symlink(bitcode_strip llvm-bitcode-strip) + if(LLVM_INSTALL_CCTOOLS_SYMLINKS) + add_llvm_tool_symlink(install_name_tool llvm-install-name-tool) + add_llvm_tool_symlink(bitcode_strip llvm-bitcode-strip) + endif() endif() diff --git a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp --- a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp +++ b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp @@ -411,7 +411,11 @@ } // anonymous namespace +#ifdef LLVM_ENABLE_EXPERIMENTAL_BUSYBOX +int llvm_objcopy_main(int argc, char **argv) { +#else int main(int argc, char **argv) { +#endif InitLLVM X(argc, argv); ToolName = argv[0]; diff --git a/llvm/tools/llvm-objdump/CMakeLists.txt b/llvm/tools/llvm-objdump/CMakeLists.txt --- a/llvm/tools/llvm-objdump/CMakeLists.txt +++ b/llvm/tools/llvm-objdump/CMakeLists.txt @@ -22,7 +22,7 @@ tablegen(LLVM OtoolOpts.inc -gen-opt-parser-defs) add_public_tablegen_target(OtoolOptsTableGen) -add_llvm_tool(llvm-objdump +set(TOOL_ARGS llvm-objdump.cpp SourcePrinter.cpp COFFDump.cpp @@ -35,12 +35,19 @@ OtoolOptsTableGen ) -if(LLVM_HAVE_LIBXAR) - target_link_libraries(llvm-objdump PRIVATE ${XAR_LIB}) -endif() +if(${LLVM_ENABLE_EXPERIMENTAL_BUSYBOX}) + add_llvm_library(LLVMObjDump ${TOOL_ARGS}) + target_compile_definitions(LLVMObjDump PRIVATE LLVM_ENABLE_EXPERIMENTAL_BUSYBOX) +else() + add_llvm_tool(llvm-objdump ${TOOL_ARGS}) + + if(LLVM_HAVE_LIBXAR) + target_link_libraries(llvm-objdump PRIVATE ${XAR_LIB}) + endif() -add_llvm_tool_symlink(llvm-otool llvm-objdump) + add_llvm_tool_symlink(llvm-otool llvm-objdump) -if(LLVM_INSTALL_BINUTILS_SYMLINKS) - add_llvm_tool_symlink(objdump llvm-objdump) + if(LLVM_INSTALL_BINUTILS_SYMLINKS) + add_llvm_tool_symlink(objdump llvm-objdump) + endif() endif() diff --git a/llvm/tools/llvm-objdump/llvm-objdump.cpp b/llvm/tools/llvm-objdump/llvm-objdump.cpp --- a/llvm/tools/llvm-objdump/llvm-objdump.cpp +++ b/llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -2512,7 +2512,11 @@ InputFilenames.push_back("a.out"); } +#ifdef LLVM_ENABLE_EXPERIMENTAL_BUSYBOX +int llvm_objdump_main(int argc, char **argv) { +#else int main(int argc, char **argv) { +#endif using namespace llvm; InitLLVM X(argc, argv);