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