llvm-lib: Implement /machine: argument

And share some code with lld-link.

While here, also add a FIXME about PR42180 and merge r360150 to llvm-lib.

Differential Revision: https://reviews.llvm.org/D63021

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@363016 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Nico Weber 2019-06-11 01:13:41 +00:00
parent ef35a12044
commit d9d0bb7e78
4 changed files with 65 additions and 13 deletions

View File

@ -18,6 +18,21 @@ namespace llvm {
template <typename T> class ArrayRef; template <typename T> class ArrayRef;
int libDriverMain(ArrayRef<const char *> ARgs); int libDriverMain(ArrayRef<const char *> ARgs);
class StringRef;
namespace COFF {
enum MachineTypes : unsigned;
}
// Returns a user-readable string for ARMNT, ARM64, AMD64, I386.
// Other MachineTypes values must not be pased in.
StringRef machineToStr(COFF::MachineTypes MT);
// Maps /machine: arguments to a MachineTypes value.
// Only returns ARMNT, ARM64, AMD64, I386, or IMAGE_FILE_MACHINE_UNKNOWN.
COFF::MachineTypes getMachineType(StringRef S);
} }
#endif #endif

View File

@ -140,7 +140,17 @@ static void doList(opt::InputArgList& Args) {
fatalOpenError(std::move(Err), B->getBufferIdentifier()); fatalOpenError(std::move(Err), B->getBufferIdentifier());
} }
static StringRef machineToStr(COFF::MachineTypes MT) { // Returns /machine's value.
COFF::MachineTypes llvm::getMachineType(StringRef S) {
return StringSwitch<COFF::MachineTypes>(S.lower())
.Cases("x64", "amd64", COFF::IMAGE_FILE_MACHINE_AMD64)
.Cases("x86", "i386", COFF::IMAGE_FILE_MACHINE_I386)
.Case("arm", COFF::IMAGE_FILE_MACHINE_ARMNT)
.Case("arm64", COFF::IMAGE_FILE_MACHINE_ARM64)
.Default(COFF::IMAGE_FILE_MACHINE_UNKNOWN);
}
StringRef llvm::machineToStr(COFF::MachineTypes MT) {
switch (MT) { switch (MT) {
case COFF::IMAGE_FILE_MACHINE_ARMNT: case COFF::IMAGE_FILE_MACHINE_ARMNT:
return "arm"; return "arm";
@ -196,9 +206,20 @@ int llvm::libDriverMain(ArrayRef<const char *> ArgsArr) {
std::vector<StringRef> SearchPaths = getSearchPaths(&Args, Saver); std::vector<StringRef> SearchPaths = getSearchPaths(&Args, Saver);
COFF::MachineTypes LibMachine = COFF::IMAGE_FILE_MACHINE_UNKNOWN;
std::string LibMachineSource;
if (auto *Arg = Args.getLastArg(OPT_machine)) {
LibMachine = getMachineType(Arg->getValue());
if (LibMachine == COFF::IMAGE_FILE_MACHINE_UNKNOWN) {
llvm::errs() << "unknown /machine: arg " << Arg->getValue() << '\n';
return 1;
}
LibMachineSource =
std::string(" (from '/machine:") + Arg->getValue() + "' flag)";
}
// Create a NewArchiveMember for each input file. // Create a NewArchiveMember for each input file.
std::vector<NewArchiveMember> Members; std::vector<NewArchiveMember> Members;
COFF::MachineTypes LibMachine = COFF::IMAGE_FILE_MACHINE_UNKNOWN;
for (auto *Arg : Args.filtered(OPT_INPUT)) { for (auto *Arg : Args.filtered(OPT_INPUT)) {
std::string Path = findInputFile(Arg->getValue(), SearchPaths); std::string Path = findInputFile(Arg->getValue(), SearchPaths);
if (Path.empty()) { if (Path.empty()) {
@ -276,14 +297,20 @@ int llvm::libDriverMain(ArrayRef<const char *> ArgsArr) {
} }
} }
// FIXME: Once lld-link rejects multiple resource .obj files:
// Call convertResToCOFF() on .res files and add the resulting
// COFF file to the .lib output instead of adding the .res file, and remove
// this check. See PR42180.
if (FileMachine != COFF::IMAGE_FILE_MACHINE_UNKNOWN) { if (FileMachine != COFF::IMAGE_FILE_MACHINE_UNKNOWN) {
if (LibMachine == COFF::IMAGE_FILE_MACHINE_UNKNOWN) if (LibMachine == COFF::IMAGE_FILE_MACHINE_UNKNOWN) {
LibMachine = FileMachine; LibMachine = FileMachine;
else if (LibMachine != FileMachine) { LibMachineSource = std::string(" (inferred from earlier file '") +
Arg->getValue() + "')";
} else if (LibMachine != FileMachine) {
llvm::errs() << Arg->getValue() << ": file machine type " llvm::errs() << Arg->getValue() << ": file machine type "
<< machineToStr(FileMachine) << machineToStr(FileMachine)
<< " conflicts with library machine type " << " conflicts with library machine type "
<< machineToStr(LibMachine) << '\n'; << machineToStr(LibMachine) << LibMachineSource << '\n';
return 1; return 1;
} }
} }

View File

@ -3,11 +3,11 @@ include "llvm/Option/OptParser.td"
// lib.exe accepts options starting with either a dash or a slash. // lib.exe accepts options starting with either a dash or a slash.
// Flag that takes no arguments. // Flag that takes no arguments.
class F<string name> : Flag<["/", "-", "-?"], name>; class F<string name> : Flag<["/", "-", "/?", "-?"], name>;
// Flag that takes one argument after ":". // Flag that takes one argument after ":".
class P<string name, string help> : class P<string name, string help> :
Joined<["/", "-", "-?"], name#":">, HelpText<help>; Joined<["/", "-", "/?", "-?"], name#":">, HelpText<help>;
def libpath: P<"libpath", "Object file search path">; def libpath: P<"libpath", "Object file search path">;
@ -18,15 +18,18 @@ def out : P<"out", "Path to file to write output">;
def llvmlibthin : F<"llvmlibthin">, def llvmlibthin : F<"llvmlibthin">,
HelpText<"Make .lib point to .obj files instead of copying their contents">; HelpText<"Make .lib point to .obj files instead of copying their contents">;
def machine: P<"machine", "Specify target platform">;
def help : F<"help">; def help : F<"help">;
def help_q : Flag<["/?", "-?"], "">, Alias<help>;
// /?? and -?? must be before /? and -? to not confuse lib/Options.
def help_q : Flag<["/??", "-??", "/?", "-?"], "">, Alias<help>;
//============================================================================== //==============================================================================
// The flags below do nothing. They are defined only for lib.exe compatibility. // The flags below do nothing. They are defined only for lib.exe compatibility.
//============================================================================== //==============================================================================
class QF<string name> : Joined<["/", "-", "-?"], name#":">; class QF<string name> : Joined<["/", "-", "/?", "-?"], name#":">;
def ignore : QF<"ignore">; def ignore : QF<"ignore">;
def machine: QF<"machine">;
def nologo : F<"nologo">; def nologo : F<"nologo">;

View File

@ -24,15 +24,22 @@ Mixing object files with different machine type is not ok:
RUN: not llvm-lib %t/x86_64.obj %t/i386.obj 2>&1 | \ RUN: not llvm-lib %t/x86_64.obj %t/i386.obj 2>&1 | \
RUN: FileCheck --check-prefix=OBJ32 %s RUN: FileCheck --check-prefix=OBJ32 %s
OBJ32: i386.obj: file machine type x86 conflicts with library machine type x64 OBJ32: i386.obj: file machine type x86 conflicts with library machine type x64 (inferred from earlier file '{{.*}}x86_64.obj')
Neither is mixing object and bitcode files with different machine type: Neither is mixing object and bitcode files with different machine type:
RUN: not llvm-lib %t/x86_64.obj %t/i386.bc 2>&1 | \ RUN: not llvm-lib %t/x86_64.obj %t/i386.bc 2>&1 | \
RUN: FileCheck --check-prefix=BC32 %s RUN: FileCheck --check-prefix=BC32 %s
BC32: i386.bc: file machine type x86 conflicts with library machine type x64 BC32: i386.bc: file machine type x86 conflicts with library machine type x64 (inferred from earlier file '{{.*}}x86_64.obj')
RUN: not llvm-lib %t/arm64.bc %t/x86_64.bc 2>&1 | \ RUN: not llvm-lib %t/arm64.bc %t/x86_64.bc 2>&1 | \
RUN: FileCheck --check-prefix=BC64 %s RUN: FileCheck --check-prefix=BC64 %s
BC64: x86_64.bc: file machine type x64 conflicts with library machine type arm64 BC64: x86_64.bc: file machine type x64 conflicts with library machine type arm64 (inferred from earlier file '{{.*}}arm64.bc')
If /machine: is passed, its value is authoritative.
RUN: not llvm-lib /machine:X86 %t/x86_64.obj %t/i386.obj 2>&1 | \
RUN: FileCheck --check-prefix=OBJ64 %s
OBJ64: x86_64.obj: file machine type x64 conflicts with library machine type x86 (from '/machine:X86' flag)