1 /*
2 * Copyright 2012, 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 <cerrno>
18 #include <cstdio>
19 #include <cstdlib>
20 #include <cstring>
21
22 #include <fcntl.h>
23
24 #include "bcc/Config/Config.h"
25 #include "bcc/Support/Initialization.h"
26 #include "bcc/Support/Log.h"
27 #include "bcc/AndroidBitcode/ABCCompilerDriver.h"
28
29 #include <cutils/process_name.h>
30
31 using namespace bcc;
32
usage()33 static void usage() {
34 fprintf(stderr, "usage: abcc [--fd output_fd|--file output_filename]\n"
35 #ifndef TARGET_BUILD
36 " [--triple triple]\n"
37 " [--android-sysroot sysroot]\n"
38 #endif
39 " input_filename(s) or input_fd(s)...\n");
40 return;
41 }
42
GetIntArg(const char * arg,int & result)43 static inline bool GetIntArg(const char *arg, int &result) {
44 char *endptr;
45
46 result = ::strtol(arg, &endptr, 0);
47 if (*endptr != '\0') {
48 return false;
49 } else {
50 return true;
51 }
52 }
53
54 enum Mode {
55 kUnknownMode,
56 kFdMode,
57 kFileMode
58 };
59
ParseArguments(int argc,const char * const * argv,Mode & mode,const char * & input,const char * & output,const char * & triple,const char * & sysroot)60 static inline bool ParseArguments(int argc, const char *const *argv, Mode &mode,
61 const char *&input, const char *&output,
62 const char *&triple, const char *&sysroot) {
63 if (argc < 4) {
64 return false;
65 }
66
67 // Parse the mode in argv[1].
68 if (::strcmp(argv[1], "--fd") == 0) {
69 mode = kFdMode;
70 } else if (::strcmp(argv[1], "--file") == 0) {
71 mode = kFileMode;
72 } else {
73 ALOGE("Unknown mode '%s'!", argv[1]);
74 return false;
75 }
76
77 // output is always in argv[2].
78 output = argv[2];
79
80 // On-device version cannot configure the triple and sysroot.
81 int arg_idx = 3;
82 #ifndef TARGET_BUILD
83 if (::strcmp(argv[arg_idx], "--triple") == 0) {
84 if ((arg_idx + 2 /* --triple [triple] input */) >= argc) {
85 ALOGE("Too few arguments when --triple was given!");
86 return false;
87 }
88
89 triple = argv[arg_idx + 1];
90 arg_idx += 2;
91 }
92
93 if (::strcmp(argv[arg_idx], "--android-sysroot") == 0) {
94 if ((arg_idx + 2 /* --android-sysroot [sysroot] input */) >= argc) {
95 ALOGE("Too few arguments when --android-sysroot was given!");
96 return false;
97 }
98
99 sysroot = argv[arg_idx + 1];
100 arg_idx += 2;
101 }
102 #endif
103
104 if (triple == NULL) {
105 #ifdef DEFAULT_ARM_CODEGEN
106 // Generate Thumb instead of ARM.
107 triple = DEFAULT_THUMB_TRIPLE_STRING;
108 #else
109 triple = DEFAULT_TARGET_TRIPLE_STRING;
110 #endif
111 }
112
113 if (sysroot == NULL) {
114 sysroot = "/";
115 }
116
117 ALOGD("Triple: %s, Android sysroot: %s", triple, sysroot);
118
119 // input is in argv[arg_idx]
120 // TODO: Support multiple input files.
121 input = argv[arg_idx];
122
123 return true;
124 }
125
Build(int input_fd,int output_fd,const char * triple,const char * sysroot)126 static bool Build(int input_fd, int output_fd,
127 const char *triple, const char *sysroot) {
128 ABCCompilerDriver *driver = ABCCompilerDriver::Create(triple);
129
130 if (driver == NULL) {
131 return false;
132 }
133
134 driver->setAndroidSysroot(sysroot);
135
136 bool build_result = driver->build(input_fd, output_fd);;
137
138 delete driver;
139
140 return build_result;
141 }
142
ProcessFromFd(const char * input,const char * output,const char * triple,const char * sysroot)143 static int ProcessFromFd(const char *input, const char *output,
144 const char *triple, const char *sysroot) {
145 int output_fd, input_fd;
146
147 if (!GetIntArg(output, output_fd)) {
148 ALOGE("Bad output fd '%s'", output);
149 return EXIT_FAILURE;
150 }
151
152 if (!GetIntArg(input, input_fd)) {
153 ALOGE("Bad input fd '%s'", input);
154 return EXIT_FAILURE;
155 }
156
157 if (!Build(input_fd, output_fd, triple, sysroot)) {
158 return EXIT_FAILURE;
159 }
160
161 return EXIT_SUCCESS;
162 }
163
ProcessFromFile(const char * input,const char * output,const char * triple,const char * sysroot)164 static int ProcessFromFile(const char *input, const char *output,
165 const char *triple, const char *sysroot) {
166 // TODO: Support multiple input files.
167 int output_fd = -1, input_fd = -1;
168
169 // Open the output file.
170 output_fd = ::open(output, O_RDWR | O_CREAT | O_TRUNC, 0755);
171
172 if (output_fd < 0) {
173 ALOGE("Failed to open %s for output! (%s)", output, strerror(errno));
174 return EXIT_FAILURE;
175 }
176
177 // Open the input file.
178 input_fd = ::open(input, O_RDONLY);
179
180 if (input_fd < 0) {
181 ALOGE("Failed to open %s for input! (%s)", input, strerror(errno));
182 ::close(output_fd);
183 return EXIT_FAILURE;
184 }
185
186 if (!Build(input_fd, output_fd, triple, sysroot)) {
187 ::close(output_fd);
188 ::close(input_fd);
189 return EXIT_FAILURE;
190 }
191
192 ::close(output_fd);
193 ::close(input_fd);
194
195 return EXIT_SUCCESS;
196 }
197
main(int argc,char ** argv)198 int main(int argc, char **argv) {
199 Mode mode = kUnknownMode;
200 const char *input, *output, *triple = NULL, *sysroot = NULL;
201
202 set_process_name("abcc");
203
204 setvbuf(stdout, NULL, _IONBF, 0);
205
206 init::Initialize();
207
208 if (ParseArguments(argc, argv, mode, input, output, triple, sysroot)) {
209 switch (mode) {
210 case kFdMode: {
211 return ProcessFromFd(input, output, triple, sysroot);
212 }
213 case kFileMode: {
214 return ProcessFromFile(input, output, triple, sysroot);
215 }
216 default: {
217 // Unknown mode encountered. Fall-through to print usage and return
218 // error.
219 break;
220 }
221 }
222 // fall-through
223 }
224
225 usage();
226
227 return EXIT_FAILURE;
228 }
229