19
19
#include " llvm/Option/ArgList.h"
20
20
#include " llvm/Support/CommandLine.h"
21
21
#include " llvm/Support/Error.h"
22
+ #include " llvm/Support/FileOutputBuffer.h"
22
23
#include " llvm/Support/InitLLVM.h"
23
24
#include " llvm/Support/WithColor.h"
24
25
@@ -78,23 +79,36 @@ class LipoOptTable : public opt::OptTable {
78
79
enum class LipoAction {
79
80
PrintArchs,
80
81
VerifyArch,
82
+ ThinArch,
81
83
};
82
84
83
85
struct Config {
84
86
SmallVector<std::string, 1 > InputFiles;
85
87
SmallVector<std::string, 1 > VerifyArchList;
88
+ std::string ThinArchType;
89
+ std::string OutputFile;
86
90
LipoAction ActionToPerform;
87
91
};
88
92
89
93
} // end namespace
90
94
95
+ static void validateArchitectureName (StringRef ArchitectureName) {
96
+ if (Triple (ArchitectureName).getArch () == Triple::ArchType::UnknownArch)
97
+ reportError (" Invalid architecture: " + ArchitectureName);
98
+ }
99
+
91
100
static Config parseLipoOptions (ArrayRef<const char *> ArgsArr) {
92
101
Config C;
93
102
LipoOptTable T;
94
103
unsigned MissingArgumentIndex, MissingArgumentCount;
95
104
llvm::opt::InputArgList InputArgs =
96
105
T.ParseArgs (ArgsArr, MissingArgumentIndex, MissingArgumentCount);
97
106
107
+ if (MissingArgumentCount)
108
+ reportError (" missing argument to " +
109
+ StringRef (InputArgs.getArgString (MissingArgumentIndex)) +
110
+ " option" );
111
+
98
112
if (InputArgs.size () == 0 ) {
99
113
// PrintHelp does not accept Twine.
100
114
T.PrintHelp (errs (), " llvm-lipo input[s] option[s]" , " llvm-lipo" );
@@ -121,6 +135,9 @@ static Config parseLipoOptions(ArrayRef<const char *> ArgsArr) {
121
135
if (C.InputFiles .empty ())
122
136
reportError (" at least one input file should be specified" );
123
137
138
+ if (InputArgs.hasArg (LIPO_output))
139
+ C.OutputFile = InputArgs.getLastArgValue (LIPO_output);
140
+
124
141
SmallVector<opt::Arg *, 1 > ActionArgs (InputArgs.filtered (LIPO_action_group));
125
142
if (ActionArgs.empty ())
126
143
reportError (" at least one action should be specified" );
@@ -151,6 +168,17 @@ static Config parseLipoOptions(ArrayRef<const char *> ArgsArr) {
151
168
C.ActionToPerform = LipoAction::PrintArchs;
152
169
return C;
153
170
171
+ case LIPO_thin:
172
+ if (C.InputFiles .size () > 1 )
173
+ reportError (" thin expects a single input file" );
174
+ C.ThinArchType = ActionArgs[0 ]->getValue ();
175
+ validateArchitectureName (C.ThinArchType );
176
+ if (C.OutputFile .empty ())
177
+ reportError (" thin expects a single output file" );
178
+
179
+ C.ActionToPerform = LipoAction::ThinArch;
180
+ return C;
181
+
154
182
default :
155
183
reportError (" llvm-lipo action unspecified" );
156
184
}
@@ -164,8 +192,12 @@ readInputBinaries(ArrayRef<std::string> InputFiles) {
164
192
createBinary (InputFile);
165
193
if (!BinaryOrErr)
166
194
reportError (InputFile, BinaryOrErr.takeError ());
167
- if (!isa<MachOObjectFile>(BinaryOrErr->getBinary ()) &&
168
- !isa<MachOUniversalBinary>(BinaryOrErr->getBinary ()))
195
+ // TODO: Add compatibility for archive files
196
+ if (BinaryOrErr->getBinary ()->isArchive ())
197
+ reportError (" File " + InputFile +
198
+ " is an archive file and is not yet supported." );
199
+ if (!BinaryOrErr->getBinary ()->isMachO () &&
200
+ !BinaryOrErr->getBinary ()->isMachOUniversalBinary ())
169
201
reportError (" File " + InputFile + " has unsupported binary format" );
170
202
InputBinaries.push_back (std::move (*BinaryOrErr));
171
203
}
@@ -180,8 +212,7 @@ static void verifyArch(ArrayRef<OwningBinary<Binary>> InputBinaries,
180
212
assert (InputBinaries.size () == 1 && " Incorrect number of input binaries" );
181
213
182
214
for (StringRef Arch : VerifyArchList)
183
- if (Triple (Arch).getArch () == Triple::ArchType::UnknownArch)
184
- reportError (" Invalid architecture: " + Arch);
215
+ validateArchitectureName (Arch);
185
216
186
217
if (auto UO =
187
218
dyn_cast<MachOUniversalBinary>(InputBinaries.front ().getBinary ())) {
@@ -238,6 +269,44 @@ static void printArchs(ArrayRef<OwningBinary<Binary>> InputBinaries) {
238
269
exit (EXIT_SUCCESS);
239
270
}
240
271
272
+ LLVM_ATTRIBUTE_NORETURN
273
+ static void extractSlice (ArrayRef<OwningBinary<Binary>> InputBinaries,
274
+ StringRef ThinArchType, StringRef OutputFileName) {
275
+ assert (!ThinArchType.empty () && " The architecture type should be non-empty" );
276
+ assert (InputBinaries.size () == 1 && " Incorrect number of input binaries" );
277
+ assert (!OutputFileName.empty () && " Thin expects a single output file" );
278
+
279
+ if (InputBinaries.front ().getBinary ()->isMachO ()) {
280
+ reportError (" input file " +
281
+ InputBinaries.front ().getBinary ()->getFileName () +
282
+ " must be a fat file when the -thin option is specified" );
283
+ exit (EXIT_FAILURE);
284
+ }
285
+
286
+ auto *UO = cast<MachOUniversalBinary>(InputBinaries.front ().getBinary ());
287
+ Expected<std::unique_ptr<MachOObjectFile>> Obj =
288
+ UO->getObjectForArch (ThinArchType);
289
+ if (!Obj)
290
+ reportError (" fat input file " + UO->getFileName () +
291
+ " does not contain the specified architecture " + ThinArchType +
292
+ " to thin it to" );
293
+
294
+ Expected<std::unique_ptr<FileOutputBuffer>> OutFileOrError =
295
+ FileOutputBuffer::create (OutputFileName,
296
+ Obj.get ()->getMemoryBufferRef ().getBufferSize (),
297
+ sys::fs::can_execute (UO->getFileName ())
298
+ ? FileOutputBuffer::F_executable
299
+ : 0 );
300
+ if (!OutFileOrError)
301
+ reportError (OutputFileName, OutFileOrError.takeError ());
302
+ std::copy (Obj.get ()->getMemoryBufferRef ().getBufferStart (),
303
+ Obj.get ()->getMemoryBufferRef ().getBufferEnd (),
304
+ OutFileOrError.get ()->getBufferStart ());
305
+ if (Error E = OutFileOrError.get ()->commit ())
306
+ reportError (OutputFileName, std::move (E));
307
+ exit (EXIT_SUCCESS);
308
+ }
309
+
241
310
int main (int argc, char **argv) {
242
311
InitLLVM X (argc, argv);
243
312
Config C = parseLipoOptions (makeArrayRef (argv + 1 , argc));
@@ -251,6 +320,9 @@ int main(int argc, char **argv) {
251
320
case LipoAction::PrintArchs:
252
321
printArchs (InputBinaries);
253
322
break ;
323
+ case LipoAction::ThinArch:
324
+ extractSlice (InputBinaries, C.ThinArchType , C.OutputFile );
325
+ break ;
254
326
}
255
327
return EXIT_SUCCESS;
256
328
}
0 commit comments