blob: ec6362eab289811fa1ce905065134aaee6153ca0 [file] [log] [blame]
Shih-wei Liaob81c6a42010-10-10 14:15:00 -07001#include "slang.h"
2
3#include <set>
4#include <string>
5#include <cstdlib>
6
7#include "llvm/ADT/SmallVector.h"
8
9#include "llvm/Support/CommandLine.h"
10#include "llvm/Support/ManagedStatic.h"
11#include "llvm/Support/MemoryBuffer.h"
12
13#include "llvm/System/Path.h"
14
15#include "clang/Driver/Arg.h"
16#include "clang/Driver/ArgList.h"
17#include "clang/Driver/DriverDiagnostic.h"
18#include "clang/Driver/Option.h"
19#include "clang/Driver/OptTable.h"
20
21#include "clang/Frontend/DiagnosticOptions.h"
22#include "clang/Frontend/TextDiagnosticPrinter.h"
23
24#include "slang_rs.h"
25#include "slang_rs_reflect_utils.h"
26
27using namespace slang;
28
29using namespace clang::driver::options;
30
31// Class under clang::driver used are enumerated here.
32using clang::driver::Arg;
33using clang::driver::ArgList;
34using clang::driver::InputArgList;
35using clang::driver::Option;
36using clang::driver::OptTable;
37using clang::driver::arg_iterator;
38
39// SaveStringInSet, ExpandArgsFromBuf and ExpandArgv are all copied from
40// $(CLANG_ROOT)/tools/driver/driver.cpp for processing argc/argv passed in
41// main().
42static inline const char *SaveStringInSet(std::set<std::string> &SavedStrings,
43 llvm::StringRef S) {
44 return SavedStrings.insert(S).first->c_str();
45}
46static void ExpandArgsFromBuf(const char *Arg,
47 llvm::SmallVectorImpl<const char*> &ArgVector,
48 std::set<std::string> &SavedStrings);
49static void ExpandArgv(int argc, const char **argv,
50 llvm::SmallVectorImpl<const char*> &ArgVector,
51 std::set<std::string> &SavedStrings);
52
53enum {
54 OPT_INVALID = 0, // This is not an option ID.
55#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
56 HELPTEXT, METAVAR) OPT_##ID,
57#include "RSCCOptions.inc"
58 LastOption
59#undef OPTION
60};
61
62static const OptTable::Info RSCCInfoTable[] = {
63#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
64 HELPTEXT, METAVAR) \
65 { NAME, HELPTEXT, METAVAR, Option::KIND##Class, FLAGS, PARAM, \
66 OPT_##GROUP, OPT_##ALIAS },
67#include "RSCCOptions.inc"
68};
69
70class RSCCOptTable : public OptTable {
71 public:
72 RSCCOptTable()
73 : OptTable(RSCCInfoTable,
74 sizeof(RSCCInfoTable) / sizeof(RSCCInfoTable[0])) {
75 }
76};
77
78OptTable *createRSCCOptTable() {
79 return new RSCCOptTable();
80}
81
82///////////////////////////////////////////////////////////////////////////////
83
84class RSCCOptions {
85 public:
86 // The include search paths
87 std::vector<std::string> mIncludePaths;
88
89 // The output directory, if any.
90 std::string mOutputDir;
91
92 // The output type
93 Slang::OutputType mOutputType;
94
95 unsigned mAllowRSPrefix : 1;
96
97 // If given, the name of the target triple to compile for. If not given the
98 // target will be selected to match the host.
99 std::string mTriple;
100
101 // If given, the name of the target CPU to generate code for.
102 std::string mCPU;
103
104 // The list of target specific features to enable or disable -- this should
105 // be a list of strings starting with by '+' or '-'.
106 std::vector<std::string> mFeatures;
107
108 std::string mJavaReflectionPathBase;
109
110 std::string mJavaReflectionPackageName;
111
112 BitCodeStorageType mBitcodeStorage;
113
114 unsigned mOutputDep : 1;
115
116 std::string mOutputDepDir;
117
118 std::vector<std::string> mAdditionalDepTargets;
119
120 unsigned mShowHelp : 1; // Show the -help text.
121 unsigned mShowVersion : 1; // Show the -version text.
122
123 RSCCOptions() {
124 mOutputType = Slang::OT_Bitcode;
125 mBitcodeStorage = BCST_APK_RESOURCE;
126 mOutputDep = 0;
127 mShowHelp = 0;
128 mShowVersion = 0;
129 }
130};
131
132// ParseArguments -
133static void ParseArguments(llvm::SmallVectorImpl<const char*> &ArgVector,
134 llvm::SmallVectorImpl<const char*> &Inputs,
135 RSCCOptions &Opts,
136 clang::Diagnostic &Diags) {
137 if (ArgVector.size() > 1) {
138 const char **ArgBegin = ArgVector.data() + 1;
139 const char **ArgEnd = ArgVector.data() + ArgVector.size();
140 unsigned MissingArgIndex, MissingArgCount;
141 llvm::OwningPtr<OptTable> OptParser(createRSCCOptTable());
142 llvm::OwningPtr<InputArgList> Args(
143 OptParser->ParseArgs(ArgBegin, ArgEnd, MissingArgIndex, MissingArgCount));
144
145 // Check for missing argument error.
146 if (MissingArgCount)
147 Diags.Report(clang::diag::err_drv_missing_argument)
148 << Args->getArgString(MissingArgIndex) << MissingArgCount;
149
150 // Issue errors on unknown arguments.
151 for (arg_iterator it = Args->filtered_begin(OPT_UNKNOWN),
152 ie = Args->filtered_end(); it != ie; ++it)
153 Diags.Report(clang::diag::err_drv_unknown_argument)
154 << (*it)->getAsString(*Args);
155
156 for (ArgList::const_iterator it = Args->begin(), ie = Args->end();
157 it != ie; ++it) {
158 const Arg *A = *it;
159 if (A->getOption().getKind() == Option::InputClass)
160 Inputs.push_back(A->getValue(*Args));
161 }
162
163 Opts.mIncludePaths = Args->getAllArgValues(OPT_I);
164
165 Opts.mOutputDir = Args->getLastArgValue(OPT_o);
166
167 if (const Arg *A = Args->getLastArg(OPT_M_Group)) {
168 switch (A->getOption().getID()) {
169 case OPT_M: {
170 Opts.mOutputDep = 1;
171 Opts.mOutputType = Slang::OT_Dependency;
172 break;
173 }
174 case OPT_MD: {
175 Opts.mOutputDep = 1;
176 Opts.mOutputType = Slang::OT_Bitcode;
177 }
178 default: {
179 assert(false && "Invalid option in M group!");
180 }
181 }
182 }
183
184 if (const Arg *A = Args->getLastArg(OPT_Output_Type_Group)) {
185 switch (A->getOption().getID()) {
186 case OPT_emit_asm: {
187 Opts.mOutputType = Slang::OT_Assembly;
188 break;
189 }
190 case OPT_emit_llvm: {
191 Opts.mOutputType = Slang::OT_LLVMAssembly;
192 break;
193 }
194 case OPT_emit_bc: {
195 Opts.mOutputType = Slang::OT_Bitcode;
196 break;
197 }
198 case OPT_emit_nothing: {
199 Opts.mOutputType = Slang::OT_Nothing;
200 break;
201 }
202 default: {
203 assert(false && "Invalid option in output type group!");
204 }
205 }
206 }
207
Zonr Change8c263a2010-10-12 00:35:29 +0800208 if (Opts.mOutputDep &&
209 ((Opts.mOutputType != Slang::OT_Bitcode) &&
210 (Opts.mOutputType != Slang::OT_Dependency)))
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700211 Diags.Report(clang::diag::err_drv_argument_not_allowed_with)
212 << Args->getLastArg(OPT_M_Group)->getAsString(*Args)
213 << Args->getLastArg(OPT_Output_Type_Group)->getAsString(*Args);
214
215 Opts.mAllowRSPrefix = Args->hasArg(OPT_allow_rs_prefix);
216
Shih-wei Liao603217c2010-10-11 00:00:52 -0700217 Opts.mTriple = Args->getLastArgValue(OPT_triple,
218 "armv7-none-linux-gnueabi");
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700219 Opts.mCPU = Args->getLastArgValue(OPT_target_cpu);
220 Opts.mFeatures = Args->getAllArgValues(OPT_target_feature);
221
222 Opts.mJavaReflectionPathBase =
223 Args->getLastArgValue(OPT_java_reflection_path_base);
224 Opts.mJavaReflectionPackageName =
225 Args->getLastArgValue(OPT_java_reflection_package_name);
226
227 llvm::StringRef BitcodeStorageValue =
228 Args->getLastArgValue(OPT_bitcode_storage);
229 if (BitcodeStorageValue == "ar")
230 Opts.mBitcodeStorage = BCST_APK_RESOURCE;
231 else if (BitcodeStorageValue == "jc")
232 Opts.mBitcodeStorage = BCST_JAVA_CODE;
233 else if (!BitcodeStorageValue.empty())
234 Diags.Report(clang::diag::err_drv_invalid_value)
235 << OptParser->getOptionName(OPT_bitcode_storage)
236 << BitcodeStorageValue;
237
238 Opts.mOutputDepDir =
239 Args->getLastArgValue(OPT_output_dep_dir, Opts.mOutputDir);
240 Opts.mAdditionalDepTargets =
241 Args->getAllArgValues(OPT_additional_dep_target);
242
243 Opts.mShowHelp = Args->hasArg(OPT_help);
244 Opts.mShowVersion = Args->hasArg(OPT_version);
245 }
246
247 return;
248}
249
250static const char *DetermineOutputFile(const std::string &OutputDir,
251 const char *InputFile,
252 Slang::OutputType OutputTyupe,
253 std::set<std::string> &SavedStrings) {
254 if (OutputTyupe == Slang::OT_Nothing)
255 return "/dev/null";
256
257 std::string OutputFile(OutputDir);
258
259 // Append '/' to Opts.mOutputDir if not presents
260 if (!OutputFile.empty() &&
261 (OutputFile[OutputFile.size() - 1]) != '/')
262 OutputFile.append(1, '/');
263
264 if (OutputTyupe == Slang::OT_Dependency)
265 // The build system wants the .d file name stem to be exactly the same as
266 // the source .rs file, instead of the .bc file.
267 OutputFile.append(RSSlangReflectUtils::GetFileNameStem(InputFile));
268 else
269 OutputFile.append(RSSlangReflectUtils::BCFileNameFromRSFileName(InputFile));
270
271 switch (OutputTyupe) {
272 case Slang::OT_Dependency: {
273 OutputFile.append(".d");
274 break;
275 }
276 case Slang::OT_Assembly: {
277 OutputFile.append(".S");
278 break;
279 }
280 case Slang::OT_LLVMAssembly: {
281 OutputFile.append(".ll");
282 break;
283 }
284 case Slang::OT_Object: {
285 OutputFile.append(".o");
286 break;
287 }
288 case Slang::OT_Bitcode: {
289 OutputFile.append(".bc");
290 break;
291 }
292 case Slang::OT_Nothing:
293 default: {
294 assert(false && "Invalid output type!");
295 }
296 }
297
298 return SaveStringInSet(SavedStrings, OutputFile);
299}
300
301static bool GenerateBitcodeAccessor(const char *InputFile,
302 const char *OutputFile,
303 const char *PackageName,
304 const RSCCOptions &Opts) {
305 if ((Opts.mOutputType != Slang::OT_Bitcode) ||
306 (Opts.mBitcodeStorage != BCST_JAVA_CODE))
307 return true;
308
309 RSSlangReflectUtils::BitCodeAccessorContext BCAccessorContext;
310 BCAccessorContext.rsFileName = InputFile;
311 BCAccessorContext.bcFileName = OutputFile;
312 BCAccessorContext.reflectPath = Opts.mJavaReflectionPathBase.c_str();
313 BCAccessorContext.packageName = PackageName;
314 BCAccessorContext.bcStorage = Opts.mBitcodeStorage;
315
316 return RSSlangReflectUtils::GenerateBitCodeAccessor(BCAccessorContext);
317}
318
319// ExecuteCompilation -
320static bool ExecuteCompilation(SlangRS &Compiler,
321 const char *InputFile,
322 const char *OutputFile,
Zonr Change8c263a2010-10-12 00:35:29 +0800323 const char *BCOutputFile,
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700324 const char *DepOutputFile,
325 const RSCCOptions &Opts) {
326 std::string RealPackageName;
327
328 Compiler.reset();
329
330 Compiler.setIncludePaths(Opts.mIncludePaths);
331 Compiler.setOutputType(Opts.mOutputType);
332 Compiler.allowRSPrefix(Opts.mAllowRSPrefix);
333
334 if (!Compiler.setInputSource(InputFile))
335 return false;
336
337 if (!Compiler.setOutput(OutputFile))
338 return false;
339
340 if (Opts.mOutputDep) {
341 if (!Compiler.setDepOutput(DepOutputFile))
342 return false;
343
Zonr Change8c263a2010-10-12 00:35:29 +0800344 Compiler.setDepTargetBC(BCOutputFile);
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700345 Compiler.setAdditionalDepTargets(Opts.mAdditionalDepTargets);
346
347 if (Compiler.generateDepFile() > 0)
348 return false;
349 }
350
351 if (Compiler.compile() > 0)
352 return false;
353
354 if (Opts.mOutputType != Slang::OT_Dependency) {
355 if (!Compiler.reflectToJava(Opts.mJavaReflectionPathBase,
356 Opts.mJavaReflectionPackageName,
357 &RealPackageName))
358 return false;
359
360 if (!GenerateBitcodeAccessor(InputFile,
361 OutputFile,
362 RealPackageName.c_str(),
363 Opts))
364 return false;
365 }
366
367 return true;
368}
369
370int main(int argc, const char **argv) {
371 std::set<std::string> SavedStrings;
372 llvm::SmallVector<const char*, 256> ArgVector;
373 RSCCOptions Opts;
374 llvm::SmallVector<const char*, 16> Inputs;
375 std::string Argv0;
376
377 atexit(llvm::llvm_shutdown);
378
379 ExpandArgv(argc, argv, ArgVector, SavedStrings);
380
381 // Argv0
382 llvm::sys::Path Path = llvm::sys::Path(ArgVector[0]);
383 Argv0 = Path.getBasename();
384
385 // Setup diagnostic engine
386 clang::TextDiagnosticPrinter *DiagClient =
387 new clang::TextDiagnosticPrinter(llvm::errs(), clang::DiagnosticOptions());
388 DiagClient->setPrefix(Argv0);
389 clang::Diagnostic Diags(DiagClient);
390
391 Slang::GlobalInitialization();
392
393 ParseArguments(ArgVector, Inputs, Opts, Diags);
394
395 // Exits when there's any error occurred during parsing the arguments
396 if (Diags.getNumErrors() > 0)
397 return 1;
398
399 if (Opts.mShowHelp) {
400 llvm::OwningPtr<OptTable> OptTbl(createRSCCOptTable());
401 OptTbl->PrintHelp(llvm::outs(), Argv0.c_str(),
402 "RenderScript source compiler");
403 return 0;
404 }
405
406 if (Opts.mShowVersion) {
407 llvm::cl::PrintVersionMessage();
408 return 0;
409 }
410
411 // No input file
412 if (Inputs.empty()) {
413 Diags.Report(clang::diag::err_drv_no_input_files);
414 return 1;
415 }
416
Zonr Change8c263a2010-10-12 00:35:29 +0800417 const char *InputFile, *OutputFile, *BCOutputFile = NULL,
418 *DepOutputFile = NULL;
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700419 llvm::OwningPtr<SlangRS> Compiler(new SlangRS(Opts.mTriple, Opts.mCPU,
420 Opts.mFeatures));
421
422 for (int i = 0, e = Inputs.size(); i != e; i++) {
423 InputFile = Inputs[i];
424 OutputFile = DetermineOutputFile(Opts.mOutputDir, InputFile,
425 Opts.mOutputType, SavedStrings);
426 if (Opts.mOutputDep) {
427 if (Opts.mOutputType == Slang::OT_Dependency)
428 DepOutputFile = OutputFile;
429 else
430 DepOutputFile = DetermineOutputFile(Opts.mOutputDepDir, InputFile,
431 Slang::OT_Dependency, SavedStrings);
Zonr Change8c263a2010-10-12 00:35:29 +0800432
433 if (Opts.mOutputType == Slang::OT_Bitcode)
434 BCOutputFile = OutputFile;
435 else
436 BCOutputFile = DetermineOutputFile(Opts.mOutputDepDir, InputFile,
437 Slang::OT_Bitcode, SavedStrings);
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700438 }
439 if (!ExecuteCompilation(*Compiler,
440 InputFile,
441 OutputFile,
Zonr Change8c263a2010-10-12 00:35:29 +0800442 BCOutputFile,
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700443 DepOutputFile,
444 Opts)) {
Shih-wei Liaoc6d19a12010-10-11 00:34:01 -0700445 llvm::errs() << Compiler->getErrorMessage();
446 return 1;
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700447 }
448 }
449
450 return 0;
451}
452
453///////////////////////////////////////////////////////////////////////////////
454
455// ExpandArgsFromBuf -
456static void ExpandArgsFromBuf(const char *Arg,
457 llvm::SmallVectorImpl<const char*> &ArgVector,
458 std::set<std::string> &SavedStrings) {
459 const char *FName = Arg + 1;
460 llvm::MemoryBuffer *MemBuf = llvm::MemoryBuffer::getFile(FName);
461 if (!MemBuf) {
462 ArgVector.push_back(SaveStringInSet(SavedStrings, Arg));
463 return;
464 }
465
466 const char *Buf = MemBuf->getBufferStart();
467 char InQuote = ' ';
468 std::string CurArg;
469
470 for (const char *P = Buf; ; ++P) {
471 if (*P == '\0' || (isspace(*P) && InQuote == ' ')) {
472 if (!CurArg.empty()) {
473 if (CurArg[0] != '@') {
474 ArgVector.push_back(SaveStringInSet(SavedStrings, CurArg));
475 } else {
476 ExpandArgsFromBuf(CurArg.c_str(), ArgVector, SavedStrings);
477 }
478
479 CurArg = "";
480 }
481 if (*P == '\0')
482 break;
483 else
484 continue;
485 }
486
487 if (isspace(*P)) {
488 if (InQuote != ' ')
489 CurArg.push_back(*P);
490 continue;
491 }
492
493 if (*P == '"' || *P == '\'') {
494 if (InQuote == *P)
495 InQuote = ' ';
496 else if (InQuote == ' ')
497 InQuote = *P;
498 else
499 CurArg.push_back(*P);
500 continue;
501 }
502
503 if (*P == '\\') {
504 ++P;
505 if (*P != '\0')
506 CurArg.push_back(*P);
507 continue;
508 }
509 CurArg.push_back(*P);
510 }
511 delete MemBuf;
512}
513
514// ExpandArgsFromBuf -
515static void ExpandArgv(int argc, const char **argv,
516 llvm::SmallVectorImpl<const char*> &ArgVector,
517 std::set<std::string> &SavedStrings) {
518 for (int i = 0; i < argc; ++i) {
519 const char *Arg = argv[i];
520 if (Arg[0] != '@') {
521 ArgVector.push_back(SaveStringInSet(SavedStrings, std::string(Arg)));
522 continue;
523 }
524
525 ExpandArgsFromBuf(Arg, ArgVector, SavedStrings);
526 }
527}