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 31using namespace bcc; 32 33static 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 43static 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 54enum Mode { 55 kUnknownMode, 56 kFdMode, 57 kFileMode 58}; 59 60static 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 126static 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 143static 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 164static 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 198int 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