Skip to content

Commit d9a9192

Browse files
committed
[llvm-libtool-darwin] Add support for -filelist option
Add support for `-filelist` option for llvm-libtool-darwin. `-filelist` option allows for passing in a file containing a list of filenames. Reviewed by jhenderson, smeenai Differential Revision: https://reviews.llvm.org/D84206
1 parent 38b419e commit d9a9192

File tree

4 files changed

+170
-3
lines changed

4 files changed

+170
-3
lines changed

llvm/docs/CommandGuide/llvm-libtool-darwin.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,13 @@ OPTIONS
4646

4747
Produces a static library from the input files.
4848

49+
.. option:: -filelist <listfile[,dirname]>
50+
51+
Read input file names from `<listfile>`. File names are specified in `<listfile>`
52+
one per line, separated only by newlines. Whitespace on a line is assumed
53+
to be part of the filename. If the directory name, `dirname`, is also
54+
specified then it is prepended to each file name in the `<listfile>`.
55+
4956
EXIT STATUS
5057
-----------
5158

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
## This test checks that the -filelist option works correctly.
2+
3+
# RUN: yaml2obj %S/Inputs/input1.yaml -o %t-input1.o
4+
# RUN: yaml2obj %S/Inputs/input2.yaml -o %t-input2.o
5+
6+
## Passing files in a listfile:
7+
# RUN: echo %t-input1.o > %t.files.txt
8+
# RUN: echo %t-input2.o >> %t.files.txt
9+
# RUN: llvm-libtool-darwin -static -o %t.lib -filelist %t.files.txt
10+
11+
## Check that binaries are present:
12+
# RUN: llvm-ar t %t.lib | \
13+
# RUN: FileCheck %s --check-prefix=CHECK-NAMES --implicit-check-not={{.}} -DPREFIX=%basename_t.tmp
14+
15+
# CHECK-NAMES: [[PREFIX]]-input1.o
16+
# CHECK-NAMES-NEXT: [[PREFIX]]-input2.o
17+
18+
## Check that symbols are present:
19+
# RUN: llvm-nm --print-armap %t.lib | \
20+
# RUN: FileCheck %s --check-prefix=CHECK-SYMBOLS -DPREFIX=%basename_t.tmp --match-full-lines
21+
22+
# CHECK-SYMBOLS: Archive map
23+
# CHECK-SYMBOLS-NEXT: _symbol1 in [[PREFIX]]-input1.o
24+
# CHECK-SYMBOLS-NEXT: _symbol2 in [[PREFIX]]-input2.o
25+
# CHECK-SYMBOLS-EMPTY:
26+
27+
# RUN: rm -rf %t/dirname && mkdir -p %t/dirname
28+
# RUN: yaml2obj %S/Inputs/input1.yaml -o %t/dirname/%basename_t.tmp-input1.o
29+
# RUN: echo %basename_t.tmp-input1.o > %t.files.txt
30+
31+
## Passing in dirname:
32+
# RUN: llvm-libtool-darwin -static -o %t.lib -filelist %t.files.txt,%t/dirname
33+
# RUN: llvm-ar t %t.lib | \
34+
# RUN: FileCheck %s --check-prefix=DIRNAME-NAMES --implicit-check-not={{.}} -DPREFIX=%basename_t.tmp
35+
# RUN: llvm-nm --print-armap %t.lib | \
36+
# RUN: FileCheck %s --check-prefix=DIRNAME-SYMBOLS -DPREFIX=%basename_t.tmp --match-full-lines
37+
38+
# DIRNAME-NAMES: [[PREFIX]]-input1.o
39+
40+
# DIRNAME-SYMBOLS: Archive map
41+
# DIRNAME-SYMBOLS-NEXT: _symbol1 in [[PREFIX]]-input1.o
42+
# DIRNAME-SYMBOLS-EMPTY:
43+
44+
## Passing both -filelist option and object file as input:
45+
# RUN: llvm-libtool-darwin -static -o %t.lib -filelist %t.files.txt,%t/dirname %t-input2.o
46+
# RUN: llvm-ar t %t.lib | \
47+
# RUN: FileCheck %s --check-prefix=REVERSE-NAMES --implicit-check-not={{.}} -DPREFIX=%basename_t.tmp
48+
# RUN: llvm-nm --print-armap %t.lib | \
49+
# RUN: FileCheck %s --check-prefix=REVERSE-SYMBOLS -DPREFIX=%basename_t.tmp --match-full-lines
50+
51+
# REVERSE-NAMES: [[PREFIX]]-input2.o
52+
# REVERSE-NAMES-NEXT: [[PREFIX]]-input1.o
53+
54+
# REVERSE-SYMBOLS: Archive map
55+
# REVERSE-SYMBOLS-NEXT: _symbol2 in [[PREFIX]]-input2.o
56+
# REVERSE-SYMBOLS-NEXT: _symbol1 in [[PREFIX]]-input1.o
57+
# REVERSE-SYMBOLS-EMPTY:
58+
59+
## Check that an error is thrown when a file in the filelist doesn't exist in the cwd and no dirname is specified:
60+
# RUN: echo 'no-such-file' > %t.invalid-list.txt
61+
# RUN: not llvm-libtool-darwin -static -o %t.lib -filelist %t.invalid-list.txt 2>&1 | \
62+
# RUN: FileCheck %s --check-prefix=FILE-ERROR -DFILE=no-such-file
63+
64+
# FILE-ERROR: error: '[[FILE]]': {{[nN]}}o such file or directory
65+
66+
## Check that an error is thrown when the directory exists but does not contain the requested file:
67+
# RUN: not llvm-libtool-darwin -static -o %t.lib -filelist %t.invalid-list.txt,%t/dirname 2>&1 | \
68+
# RUN: FileCheck %s --check-prefix=DIR-ERROR -DDIR=%t/dirname -DFILE=no-such-file
69+
70+
# DIR-ERROR: error: '[[DIR]]{{[/\\]}}[[FILE]]': {{[nN]}}o such file or directory
71+
72+
## Check that an error is thrown when a file is in the cwd but dirname is specified:
73+
# RUN: yaml2obj %S/Inputs/input2.yaml -o %basename_t.tmp-input2.o
74+
# RUN: echo %basename_t.tmp-input2.o > %t.files-cwd.txt
75+
# RUN: not llvm-libtool-darwin -static -o %t.lib -filelist %t.files-cwd.txt,%t/dirname 2>&1 | \
76+
# RUN: FileCheck %s --check-prefix=DIR-ERROR -DDIR=%t/dirname -DFILE=%basename_t.tmp-input2.o
77+
78+
## Check that an error is thrown when the directory doesn't exist:
79+
# RUN: not llvm-libtool-darwin -static -o %t.lib -filelist %t.files-cwd.txt,%t/Invalid-Dir 2>&1 | \
80+
# RUN: FileCheck %s --check-prefix=DIR-ERROR -DDIR=%t/Invalid-Dir -DFILE=%basename_t.tmp-input2.o
81+
82+
## Check that an error is thrown when the filelist is empty:
83+
# RUN: touch %t.empty-list
84+
# RUN: not llvm-libtool-darwin -static -o %t.lib -filelist %t.empty-list 2>&1 | \
85+
# RUN: FileCheck %s --check-prefix=EMPTY-ERROR -DFILE=%t.empty-list
86+
87+
# EMPTY-ERROR: error: file list file: '[[FILE]]' is empty
88+
89+
## Check that an error is thrown when the filelist contains a blank line:
90+
# RUN: echo %t-input2.o > %t.blank-line.txt
91+
# RUN: echo '' >> %t.blank-line.txt
92+
# RUN: not llvm-libtool-darwin -static -o %t.lib -filelist %t.blank-line.txt 2>&1 | \
93+
# RUN: FileCheck %s --check-prefix=EMPTY-FILENAME -DFILE=%t.blank-line.txt
94+
95+
# EMPTY-FILENAME: error: file list file: '[[FILE]]': filename cannot be empty
96+
97+
## Check that an error is thrown when the filelist contains a line with only spaces:
98+
# RUN: echo %t-input2.o > %t.space-line.txt
99+
# RUN: echo " " >> %t.space-line.txt
100+
# RUN: not llvm-libtool-darwin -static -o %t.lib -filelist %t.space-line.txt 2>&1 | \
101+
# RUN: FileCheck %s --check-prefix=FILE-ERROR -DFILE=' ' --strict-whitespace
102+
103+
## Filelist option specified more than once:
104+
# RUN: touch %t.list1.txt and %t.list2.txt
105+
# RUN: not llvm-libtool-darwin -static -o %t.lib -filelist %t.list1.txt -filelist %t.list2.txt 2>&1 | \
106+
# RUN: FileCheck %s --check-prefix=DUPLICATE-ERROR
107+
108+
# DUPLICATE-ERROR: for the --filelist option: may only occur zero or one times!

llvm/test/tools/llvm-libtool-darwin/invalid-input-output-args.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# RUN: not llvm-libtool-darwin -static -o %t.lib 2>&1 | \
55
# RUN: FileCheck %s --check-prefix=NO-INPUT
66

7-
# NO-INPUT: Must specify at least 1 positional argument
7+
# NO-INPUT: error: no input files specified
88

99
## Missing output file:
1010
# RUN: not llvm-libtool-darwin -static %t.input 2>&1 | \

llvm/tools/llvm-libtool-darwin/llvm-libtool-darwin.cpp

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "llvm/Object/ObjectFile.h"
1717
#include "llvm/Support/CommandLine.h"
1818
#include "llvm/Support/InitLLVM.h"
19+
#include "llvm/Support/LineIterator.h"
1920
#include "llvm/Support/WithColor.h"
2021

2122
using namespace llvm;
@@ -29,7 +30,7 @@ static cl::opt<std::string> OutputFile("o", cl::desc("Specify output filename"),
2930

3031
static cl::list<std::string> InputFiles(cl::Positional,
3132
cl::desc("<input files>"),
32-
cl::OneOrMore,
33+
cl::ZeroOrMore,
3334
cl::cat(LibtoolCategory));
3435

3536
enum class Operation { Static };
@@ -41,6 +42,44 @@ static cl::opt<Operation> LibraryOperation(
4142
"Produce a statically linked library from the input files")),
4243
cl::Required, cl::cat(LibtoolCategory));
4344

45+
static cl::opt<std::string>
46+
FileList("filelist",
47+
cl::desc("Pass in file containing a list of filenames"),
48+
cl::value_desc("listfile[,dirname]"), cl::cat(LibtoolCategory));
49+
50+
static Error processFileList() {
51+
StringRef FileName, DirName;
52+
std::tie(FileName, DirName) = StringRef(FileList).rsplit(",");
53+
54+
ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr =
55+
MemoryBuffer::getFileOrSTDIN(FileName, /*FileSize=*/-1,
56+
/*RequiresNullTerminator=*/false);
57+
if (std::error_code EC = FileOrErr.getError())
58+
return createFileError(FileName, errorCodeToError(EC));
59+
const MemoryBuffer &Ref = *FileOrErr.get();
60+
61+
line_iterator I(Ref, /*SkipBlanks=*/false);
62+
if (I.is_at_eof())
63+
return createStringError(std::errc::invalid_argument,
64+
"file list file: '%s' is empty",
65+
FileName.str().c_str());
66+
for (; !I.is_at_eof(); ++I) {
67+
StringRef Line = *I;
68+
if (Line.empty())
69+
return createStringError(std::errc::invalid_argument,
70+
"file list file: '%s': filename cannot be empty",
71+
FileName.str().c_str());
72+
73+
SmallString<128> Path;
74+
if (!DirName.empty())
75+
sys::path::append(Path, DirName, Line);
76+
else
77+
sys::path::append(Path, Line);
78+
InputFiles.push_back(static_cast<std::string>(Path));
79+
}
80+
return Error::success();
81+
}
82+
4483
static Error verifyMachOObject(const NewArchiveMember &Member) {
4584
auto MBRef = Member.Buf->getMemBufferRef();
4685
Expected<std::unique_ptr<object::ObjectFile>> ObjOrErr =
@@ -135,12 +174,25 @@ int main(int Argc, char **Argv) {
135174
InitLLVM X(Argc, Argv);
136175
cl::HideUnrelatedOptions({&LibtoolCategory, &ColorCategory});
137176
cl::ParseCommandLineOptions(Argc, Argv, "llvm-libtool-darwin\n");
177+
if (!FileList.empty()) {
178+
if (Error E = processFileList()) {
179+
WithColor::defaultErrorHandler(std::move(E));
180+
return EXIT_FAILURE;
181+
}
182+
}
183+
184+
if (InputFiles.empty()) {
185+
Error E = createStringError(std::errc::invalid_argument,
186+
"no input files specified");
187+
WithColor::defaultErrorHandler(std::move(E));
188+
return EXIT_FAILURE;
189+
}
138190

139191
switch (LibraryOperation) {
140192
case Operation::Static:
141193
if (Error E = createStaticLibrary()) {
142194
WithColor::defaultErrorHandler(std::move(E));
143-
exit(EXIT_FAILURE);
195+
return EXIT_FAILURE;
144196
}
145197
break;
146198
}

0 commit comments

Comments
 (0)