blob: eb18e97b2ae2d5fc363173740658e44f9bc3ee06 [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
Stephen Hinese639eb52010-11-08 19:27:20 -080017#include <cstdlib>
18#include <list>
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070019#include <set>
20#include <string>
Stephen Hinese639eb52010-11-08 19:27:20 -080021#include <utility>
22#include <vector>
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070023
24#include "clang/Driver/Arg.h"
25#include "clang/Driver/ArgList.h"
26#include "clang/Driver/DriverDiagnostic.h"
27#include "clang/Driver/Option.h"
28#include "clang/Driver/OptTable.h"
29
30#include "clang/Frontend/DiagnosticOptions.h"
31#include "clang/Frontend/TextDiagnosticPrinter.h"
32
Stephen Hinese639eb52010-11-08 19:27:20 -080033#include "llvm/ADT/SmallVector.h"
34
35#include "llvm/Support/CommandLine.h"
36#include "llvm/Support/ManagedStatic.h"
37#include "llvm/Support/MemoryBuffer.h"
38
39#include "llvm/System/Path.h"
40
41#include "slang.h"
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070042#include "slang_rs.h"
43#include "slang_rs_reflect_utils.h"
44
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070045// Class under clang::driver used are enumerated here.
Stephen Hinese639eb52010-11-08 19:27:20 -080046using clang::driver::arg_iterator;
47using clang::driver::options::DriverOption;
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070048using clang::driver::Arg;
49using clang::driver::ArgList;
50using clang::driver::InputArgList;
51using clang::driver::Option;
52using clang::driver::OptTable;
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070053
54// SaveStringInSet, ExpandArgsFromBuf and ExpandArgv are all copied from
55// $(CLANG_ROOT)/tools/driver/driver.cpp for processing argc/argv passed in
56// main().
57static inline const char *SaveStringInSet(std::set<std::string> &SavedStrings,
58 llvm::StringRef S) {
59 return SavedStrings.insert(S).first->c_str();
60}
61static void ExpandArgsFromBuf(const char *Arg,
62 llvm::SmallVectorImpl<const char*> &ArgVector,
63 std::set<std::string> &SavedStrings);
64static void ExpandArgv(int argc, const char **argv,
65 llvm::SmallVectorImpl<const char*> &ArgVector,
66 std::set<std::string> &SavedStrings);
67
68enum {
69 OPT_INVALID = 0, // This is not an option ID.
70#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
71 HELPTEXT, METAVAR) OPT_##ID,
72#include "RSCCOptions.inc"
73 LastOption
74#undef OPTION
75};
76
77static const OptTable::Info RSCCInfoTable[] = {
78#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
79 HELPTEXT, METAVAR) \
80 { NAME, HELPTEXT, METAVAR, Option::KIND##Class, FLAGS, PARAM, \
81 OPT_##GROUP, OPT_##ALIAS },
82#include "RSCCOptions.inc"
83};
84
85class RSCCOptTable : public OptTable {
86 public:
87 RSCCOptTable()
88 : OptTable(RSCCInfoTable,
89 sizeof(RSCCInfoTable) / sizeof(RSCCInfoTable[0])) {
90 }
91};
92
93OptTable *createRSCCOptTable() {
94 return new RSCCOptTable();
95}
96
97///////////////////////////////////////////////////////////////////////////////
98
99class RSCCOptions {
100 public:
101 // The include search paths
102 std::vector<std::string> mIncludePaths;
103
104 // The output directory, if any.
105 std::string mOutputDir;
106
107 // The output type
Stephen Hinese639eb52010-11-08 19:27:20 -0800108 slang::Slang::OutputType mOutputType;
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700109
110 unsigned mAllowRSPrefix : 1;
111
112 // If given, the name of the target triple to compile for. If not given the
113 // target will be selected to match the host.
114 std::string mTriple;
115
116 // If given, the name of the target CPU to generate code for.
117 std::string mCPU;
118
119 // The list of target specific features to enable or disable -- this should
120 // be a list of strings starting with by '+' or '-'.
121 std::vector<std::string> mFeatures;
122
123 std::string mJavaReflectionPathBase;
124
125 std::string mJavaReflectionPackageName;
126
Stephen Hinese639eb52010-11-08 19:27:20 -0800127 slang::BitCodeStorageType mBitcodeStorage;
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700128
129 unsigned mOutputDep : 1;
130
131 std::string mOutputDepDir;
132
133 std::vector<std::string> mAdditionalDepTargets;
134
135 unsigned mShowHelp : 1; // Show the -help text.
136 unsigned mShowVersion : 1; // Show the -version text.
137
138 RSCCOptions() {
Stephen Hinese639eb52010-11-08 19:27:20 -0800139 mOutputType = slang::Slang::OT_Bitcode;
140 mBitcodeStorage = slang::BCST_APK_RESOURCE;
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700141 mOutputDep = 0;
142 mShowHelp = 0;
143 mShowVersion = 0;
144 }
145};
146
147// ParseArguments -
148static void ParseArguments(llvm::SmallVectorImpl<const char*> &ArgVector,
149 llvm::SmallVectorImpl<const char*> &Inputs,
150 RSCCOptions &Opts,
151 clang::Diagnostic &Diags) {
152 if (ArgVector.size() > 1) {
153 const char **ArgBegin = ArgVector.data() + 1;
154 const char **ArgEnd = ArgVector.data() + ArgVector.size();
155 unsigned MissingArgIndex, MissingArgCount;
156 llvm::OwningPtr<OptTable> OptParser(createRSCCOptTable());
157 llvm::OwningPtr<InputArgList> Args(
158 OptParser->ParseArgs(ArgBegin, ArgEnd, MissingArgIndex, MissingArgCount));
159
160 // Check for missing argument error.
161 if (MissingArgCount)
162 Diags.Report(clang::diag::err_drv_missing_argument)
163 << Args->getArgString(MissingArgIndex) << MissingArgCount;
164
165 // Issue errors on unknown arguments.
166 for (arg_iterator it = Args->filtered_begin(OPT_UNKNOWN),
167 ie = Args->filtered_end(); it != ie; ++it)
168 Diags.Report(clang::diag::err_drv_unknown_argument)
169 << (*it)->getAsString(*Args);
170
171 for (ArgList::const_iterator it = Args->begin(), ie = Args->end();
172 it != ie; ++it) {
173 const Arg *A = *it;
174 if (A->getOption().getKind() == Option::InputClass)
175 Inputs.push_back(A->getValue(*Args));
176 }
177
178 Opts.mIncludePaths = Args->getAllArgValues(OPT_I);
179
180 Opts.mOutputDir = Args->getLastArgValue(OPT_o);
181
182 if (const Arg *A = Args->getLastArg(OPT_M_Group)) {
183 switch (A->getOption().getID()) {
184 case OPT_M: {
185 Opts.mOutputDep = 1;
Stephen Hinese639eb52010-11-08 19:27:20 -0800186 Opts.mOutputType = slang::Slang::OT_Dependency;
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700187 break;
188 }
189 case OPT_MD: {
190 Opts.mOutputDep = 1;
Stephen Hinese639eb52010-11-08 19:27:20 -0800191 Opts.mOutputType = slang::Slang::OT_Bitcode;
Patrick Scott190ac892010-10-21 14:47:31 -0400192 break;
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700193 }
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: {
Stephen Hinese639eb52010-11-08 19:27:20 -0800203 Opts.mOutputType = slang::Slang::OT_Assembly;
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700204 break;
205 }
206 case OPT_emit_llvm: {
Stephen Hinese639eb52010-11-08 19:27:20 -0800207 Opts.mOutputType = slang::Slang::OT_LLVMAssembly;
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700208 break;
209 }
210 case OPT_emit_bc: {
Stephen Hinese639eb52010-11-08 19:27:20 -0800211 Opts.mOutputType = slang::Slang::OT_Bitcode;
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700212 break;
213 }
214 case OPT_emit_nothing: {
Stephen Hinese639eb52010-11-08 19:27:20 -0800215 Opts.mOutputType = slang::Slang::OT_Nothing;
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700216 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 &&
Stephen Hinese639eb52010-11-08 19:27:20 -0800225 ((Opts.mOutputType != slang::Slang::OT_Bitcode) &&
226 (Opts.mOutputType != slang::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")
Stephen Hinese639eb52010-11-08 19:27:20 -0800246 Opts.mBitcodeStorage = slang::BCST_APK_RESOURCE;
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700247 else if (BitcodeStorageValue == "jc")
Stephen Hinese639eb52010-11-08 19:27:20 -0800248 Opts.mBitcodeStorage = slang::BCST_JAVA_CODE;
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700249 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,
Stephen Hinese639eb52010-11-08 19:27:20 -0800268 slang::Slang::OutputType OutputType,
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700269 std::set<std::string> &SavedStrings) {
Stephen Hinese639eb52010-11-08 19:27:20 -0800270 if (OutputType == slang::Slang::OT_Nothing)
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700271 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
Stephen Hinese639eb52010-11-08 19:27:20 -0800280 if (OutputType == slang::Slang::OT_Dependency) {
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700281 // 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.
Stephen Hinese639eb52010-11-08 19:27:20 -0800283 OutputFile.append(slang::RSSlangReflectUtils::GetFileNameStem(InputFile));
284 } else {
285 OutputFile.append(
286 slang::RSSlangReflectUtils::BCFileNameFromRSFileName(InputFile));
287 }
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700288
Stephen Hinese639eb52010-11-08 19:27:20 -0800289 switch (OutputType) {
290 case slang::Slang::OT_Dependency: {
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700291 OutputFile.append(".d");
292 break;
293 }
Stephen Hinese639eb52010-11-08 19:27:20 -0800294 case slang::Slang::OT_Assembly: {
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700295 OutputFile.append(".S");
296 break;
297 }
Stephen Hinese639eb52010-11-08 19:27:20 -0800298 case slang::Slang::OT_LLVMAssembly: {
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700299 OutputFile.append(".ll");
300 break;
301 }
Stephen Hinese639eb52010-11-08 19:27:20 -0800302 case slang::Slang::OT_Object: {
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700303 OutputFile.append(".o");
304 break;
305 }
Stephen Hinese639eb52010-11-08 19:27:20 -0800306 case slang::Slang::OT_Bitcode: {
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700307 OutputFile.append(".bc");
308 break;
309 }
Stephen Hinese639eb52010-11-08 19:27:20 -0800310 case slang::Slang::OT_Nothing:
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700311 default: {
312 assert(false && "Invalid output type!");
313 }
314 }
315
316 return SaveStringInSet(SavedStrings, OutputFile);
317}
318
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700319int main(int argc, const char **argv) {
320 std::set<std::string> SavedStrings;
321 llvm::SmallVector<const char*, 256> ArgVector;
322 RSCCOptions Opts;
323 llvm::SmallVector<const char*, 16> Inputs;
324 std::string Argv0;
325
326 atexit(llvm::llvm_shutdown);
327
328 ExpandArgv(argc, argv, ArgVector, SavedStrings);
329
330 // Argv0
331 llvm::sys::Path Path = llvm::sys::Path(ArgVector[0]);
332 Argv0 = Path.getBasename();
333
334 // Setup diagnostic engine
335 clang::TextDiagnosticPrinter *DiagClient =
336 new clang::TextDiagnosticPrinter(llvm::errs(), clang::DiagnosticOptions());
337 DiagClient->setPrefix(Argv0);
338 clang::Diagnostic Diags(DiagClient);
339
Stephen Hinese639eb52010-11-08 19:27:20 -0800340 slang::Slang::GlobalInitialization();
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700341
342 ParseArguments(ArgVector, Inputs, Opts, Diags);
343
344 // Exits when there's any error occurred during parsing the arguments
345 if (Diags.getNumErrors() > 0)
346 return 1;
347
348 if (Opts.mShowHelp) {
349 llvm::OwningPtr<OptTable> OptTbl(createRSCCOptTable());
350 OptTbl->PrintHelp(llvm::outs(), Argv0.c_str(),
351 "RenderScript source compiler");
352 return 0;
353 }
354
355 if (Opts.mShowVersion) {
356 llvm::cl::PrintVersionMessage();
357 return 0;
358 }
359
360 // No input file
361 if (Inputs.empty()) {
362 Diags.Report(clang::diag::err_drv_no_input_files);
363 return 1;
364 }
365
Zonr Changcf6af6a2010-10-12 12:38:51 +0800366 // Prepare input data for RS compiler.
367 std::list<std::pair<const char*, const char*> > IOFiles;
368 std::list<std::pair<const char*, const char*> > DepFiles;
369
Stephen Hinese639eb52010-11-08 19:27:20 -0800370 llvm::OwningPtr<slang::SlangRS> Compiler(new slang::SlangRS());
Zonr Chang641558f2010-10-12 21:07:06 +0800371
372 Compiler->init(Opts.mTriple, Opts.mCPU, Opts.mFeatures);
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700373
374 for (int i = 0, e = Inputs.size(); i != e; i++) {
Zonr Changcf6af6a2010-10-12 12:38:51 +0800375 const char *InputFile = Inputs[i];
376 const char *OutputFile =
377 DetermineOutputFile(Opts.mOutputDir, InputFile,
378 Opts.mOutputType, SavedStrings);
379
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700380 if (Opts.mOutputDep) {
Zonr Changcf6af6a2010-10-12 12:38:51 +0800381 const char *BCOutputFile, *DepOutputFile;
Zonr Change8c263a2010-10-12 00:35:29 +0800382
Stephen Hinese639eb52010-11-08 19:27:20 -0800383 if (Opts.mOutputType == slang::Slang::OT_Bitcode)
Zonr Change8c263a2010-10-12 00:35:29 +0800384 BCOutputFile = OutputFile;
385 else
Stephen Hinese639eb52010-11-08 19:27:20 -0800386 BCOutputFile = DetermineOutputFile(Opts.mOutputDepDir,
387 InputFile,
388 slang::Slang::OT_Bitcode,
389 SavedStrings);
Zonr Changcf6af6a2010-10-12 12:38:51 +0800390
Stephen Hinese639eb52010-11-08 19:27:20 -0800391 if (Opts.mOutputType == slang::Slang::OT_Dependency)
Zonr Changcf6af6a2010-10-12 12:38:51 +0800392 DepOutputFile = OutputFile;
393 else
Stephen Hinese639eb52010-11-08 19:27:20 -0800394 DepOutputFile = DetermineOutputFile(Opts.mOutputDepDir,
395 InputFile,
396 slang::Slang::OT_Dependency,
397 SavedStrings);
Zonr Changcf6af6a2010-10-12 12:38:51 +0800398
399 DepFiles.push_back(std::make_pair(BCOutputFile, DepOutputFile));
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700400 }
Zonr Changcf6af6a2010-10-12 12:38:51 +0800401
402 IOFiles.push_back(std::make_pair(InputFile, OutputFile));
403 }
404
405 // Let's rock!
406 if (!Compiler->compile(IOFiles,
407 DepFiles,
408 Opts.mIncludePaths,
409 Opts.mAdditionalDepTargets,
410 Opts.mOutputType,
411 Opts.mBitcodeStorage,
412 Opts.mAllowRSPrefix,
413 Opts.mOutputDep,
414 Opts.mJavaReflectionPathBase,
415 Opts.mJavaReflectionPackageName)) {
416 llvm::errs() << Compiler->getErrorMessage();
417 return 1;
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700418 }
419
420 return 0;
421}
422
423///////////////////////////////////////////////////////////////////////////////
424
425// ExpandArgsFromBuf -
426static void ExpandArgsFromBuf(const char *Arg,
427 llvm::SmallVectorImpl<const char*> &ArgVector,
428 std::set<std::string> &SavedStrings) {
429 const char *FName = Arg + 1;
430 llvm::MemoryBuffer *MemBuf = llvm::MemoryBuffer::getFile(FName);
431 if (!MemBuf) {
432 ArgVector.push_back(SaveStringInSet(SavedStrings, Arg));
433 return;
434 }
435
436 const char *Buf = MemBuf->getBufferStart();
437 char InQuote = ' ';
438 std::string CurArg;
439
440 for (const char *P = Buf; ; ++P) {
441 if (*P == '\0' || (isspace(*P) && InQuote == ' ')) {
442 if (!CurArg.empty()) {
443 if (CurArg[0] != '@') {
444 ArgVector.push_back(SaveStringInSet(SavedStrings, CurArg));
445 } else {
446 ExpandArgsFromBuf(CurArg.c_str(), ArgVector, SavedStrings);
447 }
448
449 CurArg = "";
450 }
451 if (*P == '\0')
452 break;
453 else
454 continue;
455 }
456
457 if (isspace(*P)) {
458 if (InQuote != ' ')
459 CurArg.push_back(*P);
460 continue;
461 }
462
463 if (*P == '"' || *P == '\'') {
464 if (InQuote == *P)
465 InQuote = ' ';
466 else if (InQuote == ' ')
467 InQuote = *P;
468 else
469 CurArg.push_back(*P);
470 continue;
471 }
472
473 if (*P == '\\') {
474 ++P;
475 if (*P != '\0')
476 CurArg.push_back(*P);
477 continue;
478 }
479 CurArg.push_back(*P);
480 }
481 delete MemBuf;
482}
483
484// ExpandArgsFromBuf -
485static void ExpandArgv(int argc, const char **argv,
486 llvm::SmallVectorImpl<const char*> &ArgVector,
487 std::set<std::string> &SavedStrings) {
488 for (int i = 0; i < argc; ++i) {
489 const char *Arg = argv[i];
490 if (Arg[0] != '@') {
491 ArgVector.push_back(SaveStringInSet(SavedStrings, std::string(Arg)));
492 continue;
493 }
494
495 ExpandArgsFromBuf(Arg, ArgVector, SavedStrings);
496 }
497}