blob: 1f989b2fcc5ad218526dcd9b83234ec83b6e0654 [file] [log] [blame]
Stephen Hines8b5c5c62014-06-06 18:03:18 -07001/*
2 * Copyright 2014, 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
17#include "clang/Basic/DiagnosticOptions.h"
18#include "clang/Driver/DriverDiagnostic.h"
19#include "clang/Driver/Options.h"
20#include "clang/Frontend/Utils.h"
21
Stephen Hines8b5c5c62014-06-06 18:03:18 -070022#include "llvm/Option/Arg.h"
23#include "llvm/Option/ArgList.h"
24#include "llvm/Option/Option.h"
25#include "llvm/Option/OptTable.h"
Jean-Luc Brouillet5309b0c2015-05-01 16:13:11 -070026#include "llvm/Support/CommandLine.h"
Stephen Hines8b5c5c62014-06-06 18:03:18 -070027
28#include "rs_cc_options.h"
29#include "slang.h"
30#include "slang_assert.h"
31
32#include <cstdlib>
33#include <string>
34#include <utility>
35#include <vector>
36
37enum {
38 OPT_INVALID = 0, // This is not an option ID.
39#define PREFIX(NAME, VALUE)
40#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
41 HELPTEXT, METAVAR) \
42 OPT_##ID,
43#include "RSCCOptions.inc"
44 LastOption
45#undef OPTION
46#undef PREFIX
47};
48
49#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
50#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
51 HELPTEXT, METAVAR)
52#include "RSCCOptions.inc"
53#undef OPTION
54#undef PREFIX
55
56static const llvm::opt::OptTable::Info RSCCInfoTable[] = {
57#define PREFIX(NAME, VALUE)
58#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
59 HELPTEXT, METAVAR) \
60 { \
61 PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \
62 PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS \
63 } \
64 ,
65#include "RSCCOptions.inc"
66#undef OPTION
67#undef PREFIX
68};
69
70namespace {
71
72class RSCCOptTable : public llvm::opt::OptTable {
73 public:
74 RSCCOptTable()
75 : OptTable(RSCCInfoTable,
76 sizeof(RSCCInfoTable) / sizeof(RSCCInfoTable[0])) {}
77};
78}
79
Jean-Luc Brouillet5309b0c2015-05-01 16:13:11 -070080namespace slang {
Stephen Hines8b5c5c62014-06-06 18:03:18 -070081
Jean-Luc Brouillet5309b0c2015-05-01 16:13:11 -070082llvm::opt::OptTable *createRSCCOptTable() { return new RSCCOptTable(); }
Stephen Hines8b5c5c62014-06-06 18:03:18 -070083
Jean-Luc Brouillet5309b0c2015-05-01 16:13:11 -070084// This function is similar to
85// clang/lib/Frontend/CompilerInvocation::CreateFromArgs.
86bool ParseArguments(const llvm::ArrayRef<const char *> &ArgsIn,
87 llvm::SmallVectorImpl<const char *> &Inputs,
88 RSCCOptions &Opts, clang::DiagnosticOptions &DiagOpts,
Pirama Arumuga Nainar1906a002015-06-29 10:30:41 -070089 llvm::StringSaver &StringSaver) {
Jean-Luc Brouillet5309b0c2015-05-01 16:13:11 -070090 // We use a different diagnostic engine for argument parsing from the rest of
91 // the work. This mimics what's done in clang. I believe it is so the
92 // argument parsing errors are well formatted while the full errors can be
93 // influenced by command line arguments.
94 llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> ArgumentParseDiagOpts(
95 new clang::DiagnosticOptions());
96 llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagIDs(
97 new clang::DiagnosticIDs());
98 DiagnosticBuffer DiagsBuffer;
99 clang::DiagnosticsEngine DiagEngine(DiagIDs, &*ArgumentParseDiagOpts,
100 &DiagsBuffer, false);
Stephen Hines8b5c5c62014-06-06 18:03:18 -0700101
Jean-Luc Brouillet5309b0c2015-05-01 16:13:11 -0700102 // Populate a vector with the command line arguments, expanding command files
103 // that have been included via the '@' argument.
104 llvm::SmallVector<const char *, 256> ArgVector;
105 ArgVector.append(ArgsIn.begin(), ArgsIn.end());
106 llvm::cl::ExpandResponseFiles(StringSaver, llvm::cl::TokenizeGNUCommandLine,
107 ArgVector, false);
Stephen Hines8b5c5c62014-06-06 18:03:18 -0700108
Jean-Luc Brouillet5309b0c2015-05-01 16:13:11 -0700109 std::unique_ptr<llvm::opt::OptTable> OptParser(createRSCCOptTable());
110 unsigned MissingArgIndex = 0;
111 unsigned MissingArgCount = 0;
112 std::unique_ptr<llvm::opt::InputArgList> Args(
113 OptParser->ParseArgs(ArgVector.begin() + 1, ArgVector.end(),
114 MissingArgIndex, MissingArgCount));
Stephen Hines8b5c5c62014-06-06 18:03:18 -0700115
Jean-Luc Brouillet5309b0c2015-05-01 16:13:11 -0700116 // Check for missing argument error.
117 if (MissingArgCount) {
118 DiagEngine.Report(clang::diag::err_drv_missing_argument)
119 << Args->getArgString(MissingArgIndex) << MissingArgCount;
120 }
121
122 // Issue errors on unknown arguments.
123 for (llvm::opt::arg_iterator it = Args->filtered_begin(OPT_UNKNOWN),
124 ie = Args->filtered_end();
125 it != ie; ++it) {
126 DiagEngine.Report(clang::diag::err_drv_unknown_argument)
127 << (*it)->getAsString(*Args);
128 }
129
130 DiagOpts.IgnoreWarnings = Args->hasArg(OPT_w);
131 DiagOpts.Warnings = Args->getAllArgValues(OPT_W);
132
133 for (llvm::opt::ArgList::const_iterator it = Args->begin(), ie = Args->end();
134 it != ie; ++it) {
135 const llvm::opt::Arg *A = *it;
136 if (A->getOption().getKind() == llvm::opt::Option::InputClass)
137 Inputs.push_back(A->getValue());
138 }
139
140 Opts.mIncludePaths = Args->getAllArgValues(OPT_I);
141
142 Opts.mBitcodeOutputDir = Args->getLastArgValue(OPT_o);
143
144 if (const llvm::opt::Arg *A = Args->getLastArg(OPT_M_Group)) {
145 switch (A->getOption().getID()) {
146 case OPT_M: {
147 Opts.mEmitDependency = true;
148 Opts.mOutputType = Slang::OT_Dependency;
149 break;
Stephen Hines8b5c5c62014-06-06 18:03:18 -0700150 }
Jean-Luc Brouillet5309b0c2015-05-01 16:13:11 -0700151 case OPT_MD: {
152 Opts.mEmitDependency = true;
153 Opts.mOutputType = Slang::OT_Bitcode;
154 break;
Stephen Hines8b5c5c62014-06-06 18:03:18 -0700155 }
Ying Wang21c94c92015-07-22 16:27:14 -0700156 case OPT_MP: {
157 Opts.mEmitDependency = true;
158 Opts.mOutputType = Slang::OT_Bitcode;
159 Opts.mEmitPhonyDependency = true;
160 break;
161 }
Jean-Luc Brouillet5309b0c2015-05-01 16:13:11 -0700162 default: { slangAssert(false && "Invalid option in M group!"); }
Stephen Hinesdd22d5c2014-08-14 16:32:50 -0700163 }
Stephen Hines8b5c5c62014-06-06 18:03:18 -0700164 }
Jean-Luc Brouillet5309b0c2015-05-01 16:13:11 -0700165
166 if (const llvm::opt::Arg *A = Args->getLastArg(OPT_Output_Type_Group)) {
167 switch (A->getOption().getID()) {
168 case OPT_emit_asm: {
169 Opts.mOutputType = Slang::OT_Assembly;
170 break;
171 }
172 case OPT_emit_llvm: {
173 Opts.mOutputType = Slang::OT_LLVMAssembly;
174 break;
175 }
176 case OPT_emit_bc: {
177 Opts.mOutputType = Slang::OT_Bitcode;
178 break;
179 }
180 case OPT_emit_nothing: {
181 Opts.mOutputType = Slang::OT_Nothing;
182 break;
183 }
184 default: { slangAssert(false && "Invalid option in output type group!"); }
185 }
186 }
187
188 if (Opts.mEmitDependency && ((Opts.mOutputType != Slang::OT_Bitcode) &&
189 (Opts.mOutputType != Slang::OT_Dependency)))
190 DiagEngine.Report(clang::diag::err_drv_argument_not_allowed_with)
191 << Args->getLastArg(OPT_M_Group)->getAsString(*Args)
192 << Args->getLastArg(OPT_Output_Type_Group)->getAsString(*Args);
193
194 Opts.mAllowRSPrefix = Args->hasArg(OPT_allow_rs_prefix);
195
196 Opts.mJavaReflectionPathBase =
197 Args->getLastArgValue(OPT_java_reflection_path_base);
198 Opts.mJavaReflectionPackageName =
199 Args->getLastArgValue(OPT_java_reflection_package_name);
200
201 Opts.mRSPackageName = Args->getLastArgValue(OPT_rs_package_name);
202
203 llvm::StringRef BitcodeStorageValue =
204 Args->getLastArgValue(OPT_bitcode_storage);
205 if (BitcodeStorageValue == "ar")
206 Opts.mBitcodeStorage = BCST_APK_RESOURCE;
207 else if (BitcodeStorageValue == "jc")
208 Opts.mBitcodeStorage = BCST_JAVA_CODE;
209 else if (!BitcodeStorageValue.empty())
210 DiagEngine.Report(clang::diag::err_drv_invalid_value)
211 << OptParser->getOptionName(OPT_bitcode_storage) << BitcodeStorageValue;
212
213 llvm::opt::Arg *lastBitwidthArg = Args->getLastArg(OPT_m32, OPT_m64);
214 if (Args->hasArg(OPT_reflect_cpp)) {
215 Opts.mBitcodeStorage = BCST_CPP_CODE;
216 // mJavaReflectionPathBase can be set for C++ reflected builds.
217 // Set it to the standard mBitcodeOutputDir (via -o) by default.
218 if (Opts.mJavaReflectionPathBase.empty()) {
219 Opts.mJavaReflectionPathBase = Opts.mBitcodeOutputDir;
220 }
221
222 // Check for bitwidth arguments.
223 if (lastBitwidthArg) {
224 if (lastBitwidthArg->getOption().matches(OPT_m32)) {
225 Opts.mBitWidth = 32;
226 } else {
227 Opts.mBitWidth = 64;
228 }
229 }
230 } else if (lastBitwidthArg) {
David Gross2770d0e2015-08-03 14:58:59 -0700231 // -m32/-m64 are forbidden for non-C++ reflection paths for non-eng builds
232 // (they would make it too easy for a developer to accidentally create and
233 // release an APK that has 32-bit or 64-bit bitcode but not both).
234#ifdef __ENABLE_INTERNAL_OPTIONS
235 if (lastBitwidthArg->getOption().matches(OPT_m32)) {
236 Opts.mBitWidth = 32;
237 } else {
238 Opts.mBitWidth = 64;
239 }
240 Opts.mEmit3264 = false;
241#else
242 DiagEngine.Report(
243 DiagEngine.getCustomDiagID(clang::DiagnosticsEngine::Error,
244 "cannot use -m32/-m64 without specifying "
245 "C++ reflection (-reflect-c++)"));
246#endif
Jean-Luc Brouillet5309b0c2015-05-01 16:13:11 -0700247 }
248
249 Opts.mDependencyOutputDir =
250 Args->getLastArgValue(OPT_output_dep_dir, Opts.mBitcodeOutputDir);
251 Opts.mAdditionalDepTargets = Args->getAllArgValues(OPT_additional_dep_target);
252
253 Opts.mShowHelp = Args->hasArg(OPT_help);
254 Opts.mShowVersion = Args->hasArg(OPT_version);
255 Opts.mDebugEmission = Args->hasArg(OPT_emit_g);
256 Opts.mVerbose = Args->hasArg(OPT_verbose);
David Gross2770d0e2015-08-03 14:58:59 -0700257 Opts.mASTPrint = Args->hasArg(OPT_ast_print);
258
259 // Delegate options
260
261 std::vector<std::string> DelegatedStrings;
262 for (int Opt : std::vector<unsigned>{OPT_debug, OPT_print_after_all, OPT_print_before_all}) {
263 if (Args->hasArg(Opt)) {
264 // TODO: Don't assume that the option begins with "-"; determine this programmatically instead.
265 DelegatedStrings.push_back(std::string("-") + std::string(OptParser->getOptionName(Opt)));
266 slangAssert(OptParser->getOptionKind(Opt) == llvm::opt::Option::FlagClass);
267 }
268 }
269 if (DelegatedStrings.size()) {
270 std::vector<const char *> DelegatedCStrs;
271 DelegatedCStrs.push_back(*ArgVector.data()); // program name
272 std::for_each(DelegatedStrings.cbegin(), DelegatedStrings.cend(),
273 [&DelegatedCStrs](const std::string &String) { DelegatedCStrs.push_back(String.c_str()); });
274 llvm::cl::ParseCommandLineOptions(DelegatedCStrs.size(), DelegatedCStrs.data());
275 }
Jean-Luc Brouillet5309b0c2015-05-01 16:13:11 -0700276
277 // If we are emitting both 32-bit and 64-bit bitcode, we must embed it.
278
279 size_t OptLevel =
280 clang::getLastArgIntValue(*Args, OPT_optimization_level, 3, DiagEngine);
281
282 Opts.mOptimizationLevel =
283 OptLevel == 0 ? llvm::CodeGenOpt::None : llvm::CodeGenOpt::Aggressive;
284
285 Opts.mTargetAPI =
286 clang::getLastArgIntValue(*Args, OPT_target_api, RS_VERSION, DiagEngine);
287
288 if (Opts.mTargetAPI == 0) {
289 Opts.mTargetAPI = UINT_MAX;
290 }
291
David Gross2770d0e2015-08-03 14:58:59 -0700292 if ((Opts.mTargetAPI < 21) || (Opts.mBitcodeStorage == BCST_CPP_CODE))
293 Opts.mEmit3264 = false;
294 if (Opts.mEmit3264)
Jean-Luc Brouillet5309b0c2015-05-01 16:13:11 -0700295 Opts.mBitcodeStorage = BCST_JAVA_CODE;
Jean-Luc Brouillet5309b0c2015-05-01 16:13:11 -0700296
297 if (DiagEngine.hasErrorOccurred()) {
298 llvm::errs() << DiagsBuffer.str();
299 return false;
300 }
301
302 return true;
303}
Stephen Hines8b5c5c62014-06-06 18:03:18 -0700304}