| /* |
| * Copyright 2012, The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <cerrno> |
| #include <cstdio> |
| #include <cstdlib> |
| #include <cstring> |
| |
| #include <fcntl.h> |
| |
| #include "bcc/Config/Config.h" |
| #include "bcc/Support/Initialization.h" |
| #include "bcc/Support/Log.h" |
| #include "bcc/AndroidBitcode/ABCCompilerDriver.h" |
| |
| #include <cutils/process_name.h> |
| |
| using namespace bcc; |
| |
| static void usage() { |
| fprintf(stderr, "usage: abcc [--fd output_fd|--file output_filename]\n" |
| #ifndef TARGET_BUILD |
| " [--triple triple]\n" |
| " [--android-sysroot sysroot]\n" |
| #endif |
| " input_filename(s) or input_fd(s)...\n"); |
| return; |
| } |
| |
| static inline bool GetIntArg(const char *arg, int &result) { |
| char *endptr; |
| |
| result = ::strtol(arg, &endptr, 0); |
| if (*endptr != '\0') { |
| return false; |
| } else { |
| return true; |
| } |
| } |
| |
| enum Mode { |
| kUnknownMode, |
| kFdMode, |
| kFileMode |
| }; |
| |
| static inline bool ParseArguments(int argc, const char *const *argv, Mode &mode, |
| const char *&input, const char *&output, |
| const char *&triple, const char *&sysroot) { |
| if (argc < 4) { |
| return false; |
| } |
| |
| // Parse the mode in argv[1]. |
| if (::strcmp(argv[1], "--fd") == 0) { |
| mode = kFdMode; |
| } else if (::strcmp(argv[1], "--file") == 0) { |
| mode = kFileMode; |
| } else { |
| ALOGE("Unknown mode '%s'!", argv[1]); |
| return false; |
| } |
| |
| // output is always in argv[2]. |
| output = argv[2]; |
| |
| // On-device version cannot configure the triple and sysroot. |
| int arg_idx = 3; |
| #ifndef TARGET_BUILD |
| if (::strcmp(argv[arg_idx], "--triple") == 0) { |
| if ((arg_idx + 2 /* --triple [triple] input */) >= argc) { |
| ALOGE("Too few arguments when --triple was given!"); |
| return false; |
| } |
| |
| triple = argv[arg_idx + 1]; |
| arg_idx += 2; |
| } |
| |
| if (::strcmp(argv[arg_idx], "--android-sysroot") == 0) { |
| if ((arg_idx + 2 /* --android-sysroot [sysroot] input */) >= argc) { |
| ALOGE("Too few arguments when --android-sysroot was given!"); |
| return false; |
| } |
| |
| sysroot = argv[arg_idx + 1]; |
| arg_idx += 2; |
| } |
| #endif |
| |
| if (triple == NULL) { |
| #ifdef DEFAULT_ARM_CODEGEN |
| // Generate Thumb instead of ARM. |
| triple = DEFAULT_THUMB_TRIPLE_STRING; |
| #else |
| triple = DEFAULT_TARGET_TRIPLE_STRING; |
| #endif |
| } |
| |
| if (sysroot == NULL) { |
| sysroot = "/"; |
| } |
| |
| ALOGD("Triple: %s, Android sysroot: %s", triple, sysroot); |
| |
| // input is in argv[arg_idx] |
| // TODO: Support multiple input files. |
| input = argv[arg_idx]; |
| |
| return true; |
| } |
| |
| static bool Build(int input_fd, int output_fd, |
| const char *triple, const char *sysroot) { |
| ABCCompilerDriver *driver = ABCCompilerDriver::Create(triple); |
| |
| if (driver == NULL) { |
| return false; |
| } |
| |
| driver->setAndroidSysroot(sysroot); |
| |
| bool build_result = driver->build(input_fd, output_fd);; |
| |
| delete driver; |
| |
| return build_result; |
| } |
| |
| static int ProcessFromFd(const char *input, const char *output, |
| const char *triple, const char *sysroot) { |
| int output_fd, input_fd; |
| |
| if (!GetIntArg(output, output_fd)) { |
| ALOGE("Bad output fd '%s'", output); |
| return EXIT_FAILURE; |
| } |
| |
| if (!GetIntArg(input, input_fd)) { |
| ALOGE("Bad input fd '%s'", input); |
| return EXIT_FAILURE; |
| } |
| |
| if (!Build(input_fd, output_fd, triple, sysroot)) { |
| return EXIT_FAILURE; |
| } |
| |
| return EXIT_SUCCESS; |
| } |
| |
| static int ProcessFromFile(const char *input, const char *output, |
| const char *triple, const char *sysroot) { |
| // TODO: Support multiple input files. |
| int output_fd = -1, input_fd = -1; |
| |
| // Open the output file. |
| output_fd = ::open(output, O_RDWR | O_CREAT | O_TRUNC, 0755); |
| |
| if (output_fd < 0) { |
| ALOGE("Failed to open %s for output! (%s)", output, strerror(errno)); |
| return EXIT_FAILURE; |
| } |
| |
| // Open the input file. |
| input_fd = ::open(input, O_RDONLY); |
| |
| if (input_fd < 0) { |
| ALOGE("Failed to open %s for input! (%s)", input, strerror(errno)); |
| ::close(output_fd); |
| return EXIT_FAILURE; |
| } |
| |
| if (!Build(input_fd, output_fd, triple, sysroot)) { |
| ::close(output_fd); |
| ::close(input_fd); |
| return EXIT_FAILURE; |
| } |
| |
| ::close(output_fd); |
| ::close(input_fd); |
| |
| return EXIT_SUCCESS; |
| } |
| |
| int main(int argc, char **argv) { |
| Mode mode = kUnknownMode; |
| const char *input, *output, *triple = NULL, *sysroot = NULL; |
| |
| set_process_name("abcc"); |
| |
| setvbuf(stdout, NULL, _IONBF, 0); |
| |
| init::Initialize(); |
| |
| if (ParseArguments(argc, argv, mode, input, output, triple, sysroot)) { |
| switch (mode) { |
| case kFdMode: { |
| return ProcessFromFd(input, output, triple, sysroot); |
| } |
| case kFileMode: { |
| return ProcessFromFile(input, output, triple, sysroot); |
| } |
| default: { |
| // Unknown mode encountered. Fall-through to print usage and return |
| // error. |
| break; |
| } |
| } |
| // fall-through |
| } |
| |
| usage(); |
| |
| return EXIT_FAILURE; |
| } |