LibDriver, llvm-lib: introduce.

llvm-lib is intended to be a lib.exe compatible utility that also
understands bitcode. The implementation lives in a library so that
lld can use it to implement /lib.

Differential Revision: http://reviews.llvm.org/D10297

llvm-svn: 239434
This commit is contained in:
Peter Collingbourne 2015-06-09 21:50:22 +00:00
parent f12c030f48
commit bc05163f15
16 changed files with 270 additions and 10 deletions

View File

@ -0,0 +1,24 @@
//===- llvm/LibDriver/LibDriver.h - lib.exe-compatible driver ---*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Defines an interface to a lib.exe-compatible driver that also understands
// bitcode files. Used by llvm-lib and lld-link2 /lib.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBDRIVER_LIBDRIVER_H
#define LLVM_LIBDRIVER_LIBDRIVER_H
namespace llvm {
int libDriverMain(int argc, const char **argv);
}
#endif

View File

@ -19,3 +19,4 @@ add_subdirectory(LineEditor)
add_subdirectory(ProfileData)
add_subdirectory(Fuzzer)
add_subdirectory(Passes)
add_subdirectory(LibDriver)

View File

@ -17,8 +17,8 @@
[common]
subdirectories = Analysis AsmParser Bitcode CodeGen DebugInfo ExecutionEngine
LineEditor Linker IR IRReader LTO MC Object Option Passes ProfileData Support
TableGen Target Transforms
LibDriver LineEditor Linker IR IRReader LTO MC Object Option Passes ProfileData
Support TableGen Target Transforms
[component_0]
type = Group

View File

@ -0,0 +1,8 @@
set(LLVM_TARGET_DEFINITIONS Options.td)
tablegen(LLVM Options.inc -gen-opt-parser-defs)
add_public_tablegen_target(LibOptionsTableGen)
add_llvm_library(LLVMLibDriver
LibDriver.cpp
)
add_dependencies(LLVMLibDriver LibOptionsTableGen)

View File

@ -0,0 +1,22 @@
;===- ./lib/LibDriver/LLVMBuild.txt ----------------------------*- Conf -*--===;
;
; The LLVM Compiler Infrastructure
;
; This file is distributed under the University of Illinois Open Source
; License. See LICENSE.TXT for details.
;
;===------------------------------------------------------------------------===;
;
; This is an LLVMBuild description file for the components in this subdirectory.
;
; For more information on the LLVMBuild system, please see:
;
; http://llvm.org/docs/LLVMBuild.html
;
;===------------------------------------------------------------------------===;
[component_0]
type = Library
name = LibDriver
parent = Libraries
required_libraries = Object Option Support

View File

@ -0,0 +1,133 @@
//===- LibDriver.cpp - lib.exe-compatible driver --------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Defines an interface to a lib.exe-compatible driver that also understands
// bitcode files. Used by llvm-lib and lld-link2 /lib.
//
//===----------------------------------------------------------------------===//
#include "llvm/LibDriver/LibDriver.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Object/ArchiveWriter.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
namespace {
enum {
OPT_INVALID = 0,
#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11) OPT_##ID,
#include "Options.inc"
#undef OPTION
};
#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
#include "Options.inc"
#undef PREFIX
static const llvm::opt::OptTable::Info infoTable[] = {
#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X6, X7, X8, X9, X10) \
{ \
X1, X2, X9, X10, OPT_##ID, llvm::opt::Option::KIND##Class, X8, X7, \
OPT_##GROUP, OPT_##ALIAS, X6 \
},
#include "Options.inc"
#undef OPTION
};
class LibOptTable : public llvm::opt::OptTable {
public:
LibOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable), true) {}
};
}
static std::string getOutputPath(llvm::opt::InputArgList *Args) {
if (auto *Arg = Args->getLastArg(OPT_out))
return Arg->getValue();
for (auto *Arg : Args->filtered(OPT_INPUT)) {
if (!StringRef(Arg->getValue()).endswith_lower(".obj"))
continue;
SmallString<128> Val = StringRef(Arg->getValue());
llvm::sys::path::replace_extension(Val, ".lib");
return Val.str();
}
llvm_unreachable("internal error");
}
namespace {
// FIXME: Should re-use StringSaver from lld.
class StrDupSaver : public cl::StringSaver {
std::vector<char *> Dups;
public:
~StrDupSaver() override {
for (std::vector<char *>::iterator I = Dups.begin(), E = Dups.end(); I != E;
++I) {
char *Dup = *I;
free(Dup);
}
}
const char *SaveString(const char *Str) override {
char *Dup = strdup(Str);
Dups.push_back(Dup);
return Dup;
}
};
}
int llvm::libDriverMain(int Argc, const char **Argv) {
SmallVector<const char *, 20> NewArgv(Argv, Argv + Argc);
StrDupSaver Saver;
cl::ExpandResponseFiles(Saver, cl::TokenizeWindowsCommandLine, NewArgv);
Argv = &NewArgv[0];
Argc = static_cast<int>(NewArgv.size());
LibOptTable Table;
unsigned MissingIndex;
unsigned MissingCount;
std::unique_ptr<llvm::opt::InputArgList> Args(
Table.ParseArgs(&Argv[1], &Argv[Argc], MissingIndex, MissingCount));
if (MissingCount) {
llvm::errs() << "missing arg value for \""
<< Args->getArgString(MissingIndex)
<< "\", expected " << MissingCount
<< (MissingCount == 1 ? " argument.\n" : " arguments.\n");
return 1;
}
for (auto *Arg : Args->filtered(OPT_UNKNOWN))
llvm::errs() << "ignoring unknown argument: " << Arg->getSpelling() << "\n";
if (Args->filtered_begin(OPT_INPUT) == Args->filtered_end()) {
llvm::errs() << "no input files.\n";
return 1;
}
std::vector<llvm::NewArchiveIterator> Members;
for (auto *Arg : Args->filtered(OPT_INPUT))
Members.emplace_back(Arg->getValue(),
llvm::sys::path::filename(Arg->getValue()));
std::pair<StringRef, std::error_code> Result = llvm::writeArchive(
getOutputPath(Args.get()), Members, /*WriteSymtab=*/true);
if (Result.second) {
if (Result.first.empty())
Result.first = Argv[0];
llvm::errs() << Result.first << ": " << Result.second.message() << "\n";
return 1;
}
return 0;
}

View File

@ -0,0 +1,20 @@
##===- lib/LibDriver/Makefile ------------------------------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
LEVEL = ../..
LIBRARYNAME = LLVMLibDriver
BUILD_ARCHIVE := 1
BUILT_SOURCES = Options.inc
TABLEGEN_INC_FILES_COMMON = 1
include $(LEVEL)/Makefile.common
$(ObjDir)/Options.inc.tmp : Options.td $(LLVM_TBLGEN) $(ObjDir)/.dir
$(Echo) "Building lib Driver Option tables with tblgen"
$(Verb) $(LLVMTableGen) -gen-opt-parser-defs -o $(call SYSPATH, $@) $<

View File

@ -0,0 +1,17 @@
include "llvm/Option/OptParser.td"
// lib.exe accepts options starting with either a dash or a slash.
// Flag that takes no arguments.
class F<string name> : Flag<["/", "-", "-?"], name>;
// Flag that takes one argument after ":".
class P<string name, string help> :
Joined<["/", "-", "-?"], name#":">, HelpText<help>;
def out : P<"out", "Path to file to write output">;
//==============================================================================
// The flags below do nothing. They are defined only for lib.exe compatibility.
//==============================================================================
def nologo : F<"nologo">;

View File

@ -12,6 +12,6 @@ include $(LEVEL)/Makefile.config
PARALLEL_DIRS := IR AsmParser Bitcode Analysis Transforms CodeGen Target \
ExecutionEngine Linker LTO MC Object Option DebugInfo \
IRReader LineEditor ProfileData Passes
IRReader LineEditor ProfileData Passes LibDriver
include $(LEVEL)/Makefile.common

View File

@ -34,6 +34,7 @@ set(LLVM_TEST_DEPENDS
llvm-dsymutil
llvm-dwarfdump
llvm-extract
llvm-lib
llvm-link
llvm-lto
llvm-mc

View File

@ -24,6 +24,15 @@ RUN: rm -f %t2
RUN: llvm-ar rcs %t2 %t1
RUN: llvm-nm %t2 | FileCheck %s -check-prefix BITCODE
RUN: rm -f %t2
RUN: llvm-lib /out:%t2 %t1
RUN: llvm-nm %t2 | FileCheck %s -check-prefix BITCODE
RUN: rm -f %t2
RUN: echo /out:%t2 %t1 > %t.rsp
RUN: llvm-lib @%t.rsp
RUN: llvm-nm %t2 | FileCheck %s -check-prefix BITCODE
BITCODE: U SomeOtherFunction
BITCODE-NEXT: T main
BITCODE-NEXT: U puts

View File

@ -236,6 +236,7 @@ for pattern in [r"\bbugpoint\b(?!-)",
r"\bllvm-dwarfdump\b",
r"\bllvm-extract\b",
r"\bllvm-go\b",
r"\bllvm-lib\b",
r"\bllvm-link\b",
r"\bllvm-lto\b",
r"\bllvm-mc\b",

View File

@ -1,6 +1,7 @@
set(LLVM_LINK_COMPONENTS
${LLVM_TARGETS_TO_BUILD}
Core
LibDriver
Object
Support
)
@ -26,4 +27,13 @@ add_custom_command(OUTPUT ${llvm_ranlib}
add_custom_target(llvm-ranlib ALL DEPENDS ${llvm_ranlib})
set_target_properties(llvm-ranlib PROPERTIES FOLDER Tools)
set(llvm_lib "${LLVM_RUNTIME_OUTPUT_INTDIR}/llvm-lib${CMAKE_EXECUTABLE_SUFFIX}")
add_custom_command(OUTPUT ${llvm_lib}
COMMAND ${CMAKE_COMMAND} -E ${LLVM_LINK_OR_COPY} "${llvm_ar_binary}" "${llvm_lib}"
DEPENDS llvm-ar)
add_custom_target(llvm-lib ALL DEPENDS ${llvm_lib})
set_target_properties(llvm-lib PROPERTIES FOLDER Tools)
install(SCRIPT install_symlink.cmake -DCMAKE_INSTALL_PREFIX=\"${CMAKE_INSTALL_PREFIX}\")

View File

@ -10,9 +10,12 @@
LEVEL := ../..
TOOLNAME := llvm-ar
TOOLALIAS = llvm-ranlib
LINK_COMPONENTS := all-targets bitreader support object
LINK_COMPONENTS := all-targets bitreader libdriver support object
# This tool has no plugins, optimize startup time.
TOOL_NO_EXPORTS := 1
include $(LEVEL)/Makefile.common
all-local::
$(Verb) $(AliasTool) $(notdir $(ToolBuildPath)) $(ToolDir)/llvm-lib$(EXEEXT)

View File

@ -23,3 +23,9 @@ message("Creating llvm-ranlib")
execute_process(
COMMAND "${CMAKE_COMMAND}" -E ${LINK_OR_COPY} "llvm-ar${EXECUTABLE_SUFFIX}" "llvm-ranlib${EXECUTABLE_SUFFIX}"
WORKING_DIRECTORY "${bindir}")
message("Creating llvm-lib")
execute_process(
COMMAND "${CMAKE_COMMAND}" -E ${LINK_OR_COPY} "llvm-ar${EXECUTABLE_SUFFIX}" "llvm-lib${EXECUTABLE_SUFFIX}"
WORKING_DIRECTORY "${bindir}")

View File

@ -15,6 +15,7 @@
#include "llvm/ADT/StringSwitch.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/LibDriver/LibDriver.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/ArchiveWriter.h"
#include "llvm/Object/ObjectFile.h"
@ -716,6 +717,15 @@ int main(int argc, char **argv) {
PrettyStackTraceProgram X(argc, argv);
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
llvm::InitializeAllTargetInfos();
llvm::InitializeAllTargetMCs();
llvm::InitializeAllAsmParsers();
StringRef Stem = sys::path::stem(ToolName);
if (Stem.find("ranlib") == StringRef::npos &&
Stem.find("lib") != StringRef::npos)
return libDriverMain(argc, const_cast<const char **>(argv));
// Have the command line options parsed and handle things
// like --help and --version.
cl::ParseCommandLineOptions(argc, argv,
@ -723,14 +733,9 @@ int main(int argc, char **argv) {
" This program archives bitcode files into single libraries\n"
);
llvm::InitializeAllTargetInfos();
llvm::InitializeAllTargetMCs();
llvm::InitializeAllAsmParsers();
StringRef Stem = sys::path::stem(ToolName);
if (Stem.find("ar") != StringRef::npos)
return ar_main();
if (Stem.find("ranlib") != StringRef::npos)
return ranlib_main();
fail("Not ranlib or ar!");
fail("Not ranlib, ar or lib!");
}