blob: 0e8589ba5bb5da41476111d85f14cf67c5b25450 [file] [log] [blame]
Zonr Changc383a502010-10-12 01:52:08 +08001/*
Stephen Hines0a813a32012-08-03 16:52:40 -07002 * Copyright 2010-2012, The Android Open Source Project
Zonr Changc383a502010-10-12 01:52:08 +08003 *
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 Hines8b5c5c62014-06-06 18:03:18 -070017#include "clang/Basic/DiagnosticOptions.h"
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070018#include "clang/Driver/DriverDiagnostic.h"
Stephen Hinesa1f95ee2013-08-09 01:26:08 -070019#include "clang/Driver/Options.h"
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070020#include "clang/Frontend/TextDiagnosticPrinter.h"
Stephen Hines8f4d9722011-12-05 14:14:42 -080021#include "clang/Frontend/Utils.h"
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070022
Stephen Hinese639eb52010-11-08 19:27:20 -080023#include "llvm/ADT/SmallVector.h"
Loganbe274822011-02-16 22:02:54 +080024#include "llvm/ADT/IntrusiveRefCntPtr.h"
25#include "llvm/ADT/OwningPtr.h"
Stephen Hinese639eb52010-11-08 19:27:20 -080026
Stephen Hinesa1f95ee2013-08-09 01:26:08 -070027#include "llvm/Option/OptTable.h"
Stephen Hinese639eb52010-11-08 19:27:20 -080028#include "llvm/Support/CommandLine.h"
29#include "llvm/Support/ManagedStatic.h"
30#include "llvm/Support/MemoryBuffer.h"
Loganbe274822011-02-16 22:02:54 +080031#include "llvm/Support/Path.h"
Stephen Hinesba7c6dc2011-09-07 19:57:04 -070032#include "llvm/Support/raw_ostream.h"
Loganbe274822011-02-16 22:02:54 +080033#include "llvm/Support/system_error.h"
mkopec1c460b372012-01-09 11:21:50 -050034#include "llvm/Target/TargetMachine.h"
Stephen Hinese639eb52010-11-08 19:27:20 -080035
Stephen Hines8b5c5c62014-06-06 18:03:18 -070036#include "rs_cc_options.h"
Stephen Hinese639eb52010-11-08 19:27:20 -080037#include "slang.h"
Stephen Hines6e6578a2011-02-07 18:05:48 -080038#include "slang_assert.h"
Stephen Hines8f4d9722011-12-05 14:14:42 -080039#include "slang_diagnostic_buffer.h"
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070040#include "slang_rs.h"
41#include "slang_rs_reflect_utils.h"
42
Stephen Hines8b5c5c62014-06-06 18:03:18 -070043#include <list>
44#include <set>
45#include <string>
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070046
47// SaveStringInSet, ExpandArgsFromBuf and ExpandArgv are all copied from
48// $(CLANG_ROOT)/tools/driver/driver.cpp for processing argc/argv passed in
49// main().
50static inline const char *SaveStringInSet(std::set<std::string> &SavedStrings,
51 llvm::StringRef S) {
52 return SavedStrings.insert(S).first->c_str();
53}
54static void ExpandArgsFromBuf(const char *Arg,
55 llvm::SmallVectorImpl<const char*> &ArgVector,
56 std::set<std::string> &SavedStrings);
57static void ExpandArgv(int argc, const char **argv,
58 llvm::SmallVectorImpl<const char*> &ArgVector,
59 std::set<std::string> &SavedStrings);
60
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070061static const char *DetermineOutputFile(const std::string &OutputDir,
62 const char *InputFile,
Stephen Hinese639eb52010-11-08 19:27:20 -080063 slang::Slang::OutputType OutputType,
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070064 std::set<std::string> &SavedStrings) {
Stephen Hinese639eb52010-11-08 19:27:20 -080065 if (OutputType == slang::Slang::OT_Nothing)
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070066 return "/dev/null";
67
68 std::string OutputFile(OutputDir);
69
Stephen Hines7f5704e2014-06-10 18:06:50 -070070 // Append '/' to Opts.mBitcodeOutputDir if not presents
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070071 if (!OutputFile.empty() &&
Raphael8d5a2f62011-02-08 00:15:05 -080072 (OutputFile[OutputFile.size() - 1]) != OS_PATH_SEPARATOR)
73 OutputFile.append(1, OS_PATH_SEPARATOR);
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070074
Stephen Hinese639eb52010-11-08 19:27:20 -080075 if (OutputType == slang::Slang::OT_Dependency) {
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070076 // The build system wants the .d file name stem to be exactly the same as
77 // the source .rs file, instead of the .bc file.
Stephen Hinese639eb52010-11-08 19:27:20 -080078 OutputFile.append(slang::RSSlangReflectUtils::GetFileNameStem(InputFile));
79 } else {
80 OutputFile.append(
81 slang::RSSlangReflectUtils::BCFileNameFromRSFileName(InputFile));
82 }
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070083
Stephen Hinese639eb52010-11-08 19:27:20 -080084 switch (OutputType) {
85 case slang::Slang::OT_Dependency: {
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070086 OutputFile.append(".d");
87 break;
88 }
Stephen Hinese639eb52010-11-08 19:27:20 -080089 case slang::Slang::OT_Assembly: {
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070090 OutputFile.append(".S");
91 break;
92 }
Stephen Hinese639eb52010-11-08 19:27:20 -080093 case slang::Slang::OT_LLVMAssembly: {
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070094 OutputFile.append(".ll");
95 break;
96 }
Stephen Hinese639eb52010-11-08 19:27:20 -080097 case slang::Slang::OT_Object: {
Shih-wei Liaob81c6a42010-10-10 14:15:00 -070098 OutputFile.append(".o");
99 break;
100 }
Stephen Hinese639eb52010-11-08 19:27:20 -0800101 case slang::Slang::OT_Bitcode: {
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700102 OutputFile.append(".bc");
103 break;
104 }
Stephen Hinese639eb52010-11-08 19:27:20 -0800105 case slang::Slang::OT_Nothing:
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700106 default: {
Stephen Hines6e6578a2011-02-07 18:05:48 -0800107 slangAssert(false && "Invalid output type!");
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700108 }
109 }
110
111 return SaveStringInSet(SavedStrings, OutputFile);
112}
113
Stephen Hinesba7c6dc2011-09-07 19:57:04 -0700114#define str(s) #s
115#define wrap_str(s) str(s)
116static void llvm_rs_cc_VersionPrinter() {
117 llvm::raw_ostream &OS = llvm::outs();
118 OS << "llvm-rs-cc: Renderscript compiler\n"
119 << " (http://developer.android.com/guide/topics/renderscript)\n"
120 << " based on LLVM (http://llvm.org):\n";
121 OS << " Built " << __DATE__ << " (" << __TIME__ ").\n";
122 OS << " Target APIs: " << SLANG_MINIMUM_TARGET_API << " - "
123 << SLANG_MAXIMUM_TARGET_API;
124 OS << "\n Build type: " << wrap_str(TARGET_BUILD_VARIANT);
125#ifndef __DISABLE_ASSERTS
126 OS << " with assertions";
127#endif
128 OS << ".\n";
Stephen Hinesba7c6dc2011-09-07 19:57:04 -0700129}
Stephen Hines8f4d9722011-12-05 14:14:42 -0800130#undef wrap_str
131#undef str
Stephen Hinesba7c6dc2011-09-07 19:57:04 -0700132
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700133int main(int argc, const char **argv) {
134 std::set<std::string> SavedStrings;
135 llvm::SmallVector<const char*, 256> ArgVector;
Stephen Hines8b5c5c62014-06-06 18:03:18 -0700136 slang::RSCCOptions Opts;
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700137 llvm::SmallVector<const char*, 16> Inputs;
138 std::string Argv0;
139
140 atexit(llvm::llvm_shutdown);
141
142 ExpandArgv(argc, argv, ArgVector, SavedStrings);
143
144 // Argv0
Logan Chien6f4e0a92011-03-10 01:10:25 +0800145 Argv0 = llvm::sys::path::stem(ArgVector[0]);
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700146
147 // Setup diagnostic engine
Stephen Hines8f4d9722011-12-05 14:14:42 -0800148 slang::DiagnosticBuffer *DiagClient = new slang::DiagnosticBuffer();
Loganbe274822011-02-16 22:02:54 +0800149
150 llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagIDs(
151 new clang::DiagnosticIDs());
152
Stephen Hines23c43582013-01-09 20:02:04 -0800153 llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagOpts(
154 new clang::DiagnosticOptions());
155 clang::DiagnosticsEngine DiagEngine(DiagIDs, &*DiagOpts, DiagClient, true);
Logan Chien9207a2e2011-10-21 15:39:28 +0800156
Stephen Hinese639eb52010-11-08 19:27:20 -0800157 slang::Slang::GlobalInitialization();
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700158
Stephen Hines8b5c5c62014-06-06 18:03:18 -0700159 slang::ParseArguments(ArgVector, Inputs, Opts, DiagEngine);
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700160
161 // Exits when there's any error occurred during parsing the arguments
Stephen Hines8f4d9722011-12-05 14:14:42 -0800162 if (DiagEngine.hasErrorOccurred()) {
163 llvm::errs() << DiagClient->str();
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700164 return 1;
Stephen Hines8f4d9722011-12-05 14:14:42 -0800165 }
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700166
167 if (Opts.mShowHelp) {
Stephen Hines8b5c5c62014-06-06 18:03:18 -0700168 llvm::OwningPtr<llvm::opt::OptTable> OptTbl(slang::createRSCCOptTable());
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700169 OptTbl->PrintHelp(llvm::outs(), Argv0.c_str(),
Stephen Hinesb7d12692011-09-02 18:16:19 -0700170 "Renderscript source compiler");
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700171 return 0;
172 }
173
174 if (Opts.mShowVersion) {
Stephen Hinesba7c6dc2011-09-07 19:57:04 -0700175 llvm_rs_cc_VersionPrinter();
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700176 return 0;
177 }
178
179 // No input file
180 if (Inputs.empty()) {
Logan Chien9207a2e2011-10-21 15:39:28 +0800181 DiagEngine.Report(clang::diag::err_drv_no_input_files);
Stephen Hines8f4d9722011-12-05 14:14:42 -0800182 llvm::errs() << DiagClient->str();
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700183 return 1;
184 }
185
Zonr Changcf6af6a2010-10-12 12:38:51 +0800186 // Prepare input data for RS compiler.
187 std::list<std::pair<const char*, const char*> > IOFiles;
188 std::list<std::pair<const char*, const char*> > DepFiles;
189
Stephen Hinese639eb52010-11-08 19:27:20 -0800190 llvm::OwningPtr<slang::SlangRS> Compiler(new slang::SlangRS());
Zonr Chang641558f2010-10-12 21:07:06 +0800191
Stephen Hines8f4d9722011-12-05 14:14:42 -0800192 Compiler->init(Opts.mTriple, Opts.mCPU, Opts.mFeatures, &DiagEngine,
193 DiagClient);
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700194
195 for (int i = 0, e = Inputs.size(); i != e; i++) {
Zonr Changcf6af6a2010-10-12 12:38:51 +0800196 const char *InputFile = Inputs[i];
197 const char *OutputFile =
Stephen Hines7f5704e2014-06-10 18:06:50 -0700198 DetermineOutputFile(Opts.mBitcodeOutputDir, InputFile,
Zonr Changcf6af6a2010-10-12 12:38:51 +0800199 Opts.mOutputType, SavedStrings);
200
Stephen Hines7f5704e2014-06-10 18:06:50 -0700201 if (Opts.mEmitDependency) {
Zonr Changcf6af6a2010-10-12 12:38:51 +0800202 const char *BCOutputFile, *DepOutputFile;
Zonr Change8c263a2010-10-12 00:35:29 +0800203
Stephen Hinese639eb52010-11-08 19:27:20 -0800204 if (Opts.mOutputType == slang::Slang::OT_Bitcode)
Zonr Change8c263a2010-10-12 00:35:29 +0800205 BCOutputFile = OutputFile;
206 else
Stephen Hines7f5704e2014-06-10 18:06:50 -0700207 BCOutputFile = DetermineOutputFile(Opts.mDependencyOutputDir,
Stephen Hinese639eb52010-11-08 19:27:20 -0800208 InputFile,
209 slang::Slang::OT_Bitcode,
210 SavedStrings);
Zonr Changcf6af6a2010-10-12 12:38:51 +0800211
Stephen Hinese639eb52010-11-08 19:27:20 -0800212 if (Opts.mOutputType == slang::Slang::OT_Dependency)
Zonr Changcf6af6a2010-10-12 12:38:51 +0800213 DepOutputFile = OutputFile;
214 else
Stephen Hines7f5704e2014-06-10 18:06:50 -0700215 DepOutputFile = DetermineOutputFile(Opts.mDependencyOutputDir,
Stephen Hinese639eb52010-11-08 19:27:20 -0800216 InputFile,
217 slang::Slang::OT_Dependency,
218 SavedStrings);
Zonr Changcf6af6a2010-10-12 12:38:51 +0800219
220 DepFiles.push_back(std::make_pair(BCOutputFile, DepOutputFile));
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700221 }
Zonr Changcf6af6a2010-10-12 12:38:51 +0800222
223 IOFiles.push_back(std::make_pair(InputFile, OutputFile));
224 }
225
226 // Let's rock!
Stephen Hinesd7f0ea22011-02-22 17:45:19 -0800227 int CompileFailed = !Compiler->compile(IOFiles,
228 DepFiles,
Stephen Hines7f5704e2014-06-10 18:06:50 -0700229 Opts);
Stephen Hines5c25c512012-02-27 12:58:17 -0800230
Stephen Hinesc632be22011-09-23 15:53:16 -0700231 Compiler->reset();
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700232
Stephen Hinesd7f0ea22011-02-22 17:45:19 -0800233 return CompileFailed;
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700234}
235
236///////////////////////////////////////////////////////////////////////////////
237
238// ExpandArgsFromBuf -
239static void ExpandArgsFromBuf(const char *Arg,
240 llvm::SmallVectorImpl<const char*> &ArgVector,
241 std::set<std::string> &SavedStrings) {
242 const char *FName = Arg + 1;
Stephen Hines75d47182014-05-28 09:43:18 -0700243 std::unique_ptr<llvm::MemoryBuffer> MemBuf;
Loganbe274822011-02-16 22:02:54 +0800244 if (llvm::MemoryBuffer::getFile(FName, MemBuf)) {
245 // Unable to open the file
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700246 ArgVector.push_back(SaveStringInSet(SavedStrings, Arg));
247 return;
248 }
249
250 const char *Buf = MemBuf->getBufferStart();
251 char InQuote = ' ';
252 std::string CurArg;
253
254 for (const char *P = Buf; ; ++P) {
255 if (*P == '\0' || (isspace(*P) && InQuote == ' ')) {
256 if (!CurArg.empty()) {
257 if (CurArg[0] != '@') {
258 ArgVector.push_back(SaveStringInSet(SavedStrings, CurArg));
259 } else {
260 ExpandArgsFromBuf(CurArg.c_str(), ArgVector, SavedStrings);
261 }
262
263 CurArg = "";
264 }
265 if (*P == '\0')
266 break;
267 else
268 continue;
269 }
270
271 if (isspace(*P)) {
272 if (InQuote != ' ')
273 CurArg.push_back(*P);
274 continue;
275 }
276
277 if (*P == '"' || *P == '\'') {
278 if (InQuote == *P)
279 InQuote = ' ';
280 else if (InQuote == ' ')
281 InQuote = *P;
282 else
283 CurArg.push_back(*P);
284 continue;
285 }
286
287 if (*P == '\\') {
288 ++P;
289 if (*P != '\0')
290 CurArg.push_back(*P);
291 continue;
292 }
293 CurArg.push_back(*P);
294 }
Shih-wei Liaob81c6a42010-10-10 14:15:00 -0700295}
296
297// ExpandArgsFromBuf -
298static void ExpandArgv(int argc, const char **argv,
299 llvm::SmallVectorImpl<const char*> &ArgVector,
300 std::set<std::string> &SavedStrings) {
301 for (int i = 0; i < argc; ++i) {
302 const char *Arg = argv[i];
303 if (Arg[0] != '@') {
304 ArgVector.push_back(SaveStringInSet(SavedStrings, std::string(Arg)));
305 continue;
306 }
307
308 ExpandArgsFromBuf(Arg, ArgVector, SavedStrings);
309 }
310}