/*
* 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;
}