#include "revision.h"
#include "warning.h"
#include "mangle.h"
+#include "printer.h"
#ifndef PREPROCESSOR
#ifndef __WIN32__
#ifndef ASSEMBLER
#ifdef __APPLE__
-#define ASSEMBLER "gcc -c -xassembler"
+#define ASSEMBLER "gcc -m32 -c -xassembler"
#else
#define ASSEMBLER "as --32"
#endif
#endif
-/** The current c mode/dialect. */
-unsigned int c_mode = _C89 | _ANSI | _C99 | _GNUC;
-
-/** The 'machine size', 16, 32 or 64 bit, 32bit is the default. */
-unsigned int machine_size = 32;
-
-/** true if the char type is signed. */
-bool char_is_signed = true;
-
-/** true for strict language checking. */
-bool strict_mode = false;
-
-/** use builtins for some libc functions */
-bool use_builtins = false;
-
-/** we have extern function with const attribute. */
-bool have_const_functions = false;
-
-atomic_type_kind_t wchar_atomic_kind = ATOMIC_TYPE_INT;
+unsigned int c_mode = _C89 | _ANSI | _C99 | _GNUC;
+unsigned int machine_size = 32;
+bool byte_order_big_endian = false;
+bool char_is_signed = true;
+bool strict_mode = false;
+bool use_builtins = false;
+bool have_const_functions = false;
+atomic_type_kind_t wchar_atomic_kind = ATOMIC_TYPE_INT;
+unsigned force_long_double_size = 0;
+bool enable_main_collect2_hack = false;
+bool freestanding = false;
/* to switch on printing of implicit casts */
extern bool print_implicit_casts;
/* to switch on printing of parenthesis to indicate operator precedence */
extern bool print_parenthesis;
+static const char *target_triple;
static int verbose;
static struct obstack cppflags_obst, ldflags_obst;
static char dep_target[1024];
static file_list_entry_t *temp_files;
-#if defined(_DEBUG) || defined(FIRM_DEBUG)
-/**
- * Debug printf implementation.
- *
- * @param fmt printf style format parameter
- */
-void dbg_printf(const char *fmt, ...)
-{
- va_list list;
-
- if (firm_dump.debug_print) {
- va_start(list, fmt);
- vprintf(fmt, list);
- va_end(list);
- } /* if */
-}
-#endif /* defined(_DEBUG) || defined(FIRM_DEBUG) */
-
static void initialize_firm(void)
{
firm_early_init();
-
- dump_consts_local(1);
- dump_keepalive_edges(1);
}
static void get_output_name(char *buf, size_t buflen, const char *inputname,
panic("filename too long");
}
-#include "builtins.h"
+#include "gen_builtins.h"
static translation_unit_t *do_parsing(FILE *const in, const char *const input_name)
{
add_flag(&cppflags_obst, "-U__VERSION__");
add_flag(&cppflags_obst, "-D__VERSION__=\"%s\"", cparser_REVISION);
- /* TODO hack... */
- add_flag(&cppflags_obst, "-D__builtin_abort=abort");
- add_flag(&cppflags_obst, "-D__builtin_abs=abs");
- add_flag(&cppflags_obst, "-D__builtin_exit=exit");
- add_flag(&cppflags_obst, "-D__builtin_malloc=malloc");
- add_flag(&cppflags_obst, "-D__builtin_memcmp=memcmp");
- add_flag(&cppflags_obst, "-D__builtin_memcpy=memcpy");
- add_flag(&cppflags_obst, "-D__builtin_memset=memset");
- add_flag(&cppflags_obst, "-D__builtin_strlen=strlen");
- add_flag(&cppflags_obst, "-D__builtin_strcmp=strcmp");
- add_flag(&cppflags_obst, "-D__builtin_strcpy=strcpy");
-
if (flags[0] != '\0') {
size_t len = strlen(flags);
obstack_1grow(&cppflags_obst, ' ');
}
assert(obstack_object_size(&cppflags_obst) == 0);
- obstack_printf(&cppflags_obst, "%s ", PREPROCESSOR);
+
+ const char *preprocessor = getenv("CPARSER_PP");
+ if (preprocessor != NULL) {
+ obstack_printf(&cppflags_obst, "%s ", preprocessor);
+ } else {
+ if (target_triple != NULL)
+ obstack_printf(&cppflags_obst, "%s-", target_triple);
+ obstack_printf(&cppflags_obst, PREPROCESSOR);
+ }
+
switch (filetype) {
case FILETYPE_C:
add_flag(&cppflags_obst, "-std=c99");
FILE *f = popen(buf, "r");
if (f == NULL) {
fprintf(stderr, "invoking preprocessor failed\n");
- exit(1);
+ exit(EXIT_FAILURE);
}
/* we don't really need that anymore */
static void assemble(const char *out, const char *in)
{
- char buf[65536];
+ struct obstack asflags_obst;
+ char *buf;
+
+ obstack_init(&asflags_obst);
+
+ const char *assembler = getenv("CPARSER_AS");
+ if (assembler != NULL) {
+ obstack_printf(&asflags_obst, "%s ", assembler);
+ } else {
+ if (target_triple != NULL)
+ obstack_printf(&asflags_obst, "%s-", target_triple);
+ obstack_printf(&asflags_obst, "%s ", ASSEMBLER);
+ }
+
+ obstack_printf(&asflags_obst, "%s -o %s", in, out);
+ obstack_1grow(&asflags_obst, '\0');
+ buf = obstack_finish(&asflags_obst);
- snprintf(buf, sizeof(buf), "%s %s -o %s", ASSEMBLER, in, out);
if (verbose) {
puts(buf);
}
int err = system(buf);
if (err != 0) {
fprintf(stderr, "assembler reported an error\n");
- exit(1);
+ exit(EXIT_FAILURE);
}
+
+ obstack_free(&asflags_obst, NULL);
}
static void print_file_name(const char *file)
const char *flags = obstack_finish(&ldflags_obst);
/* construct commandline */
- obstack_printf(&ldflags_obst, "%s ", LINKER);
+ const char *linker = getenv("CPARSER_LINK");
+ if (linker != NULL) {
+ obstack_printf(&ldflags_obst, "%s ", linker);
+ } else {
+ if (target_triple != NULL)
+ obstack_printf(&ldflags_obst, "%s-", target_triple);
+ obstack_printf(&ldflags_obst, "%s ", LINKER);
+ }
+ obstack_printf(&ldflags_obst, "%s ", linker);
obstack_printf(&ldflags_obst, "%s", flags);
obstack_1grow(&ldflags_obst, '\0');
int err = system(commandline);
if (err != EXIT_SUCCESS) {
fprintf(stderr, "linker reported an error\n");
- exit(1);
+ exit(EXIT_FAILURE);
}
}
if (fd == -1) {
fprintf(stderr, "couldn't create temporary file: %s\n",
strerror(errno));
- exit(1);
+ exit(EXIT_FAILURE);
}
FILE *out = fdopen(fd, "w");
if (out == NULL) {
fprintf(stderr, "couldn't create temporary file FILE*\n");
- exit(1);
+ exit(EXIT_FAILURE);
}
file_list_entry_t *entry = xmalloc(sizeof(*entry));
static void usage(const char *argv0)
{
- fprintf(stderr, "Usage %s input [-o output] [-c]\n", argv0);
+ fprintf(stderr, "Usage %s [options] input [-o output]\n", argv0);
}
static void print_cparser_version(void)
"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
}
+static void print_help(const char *argv0)
+{
+ usage(argv0);
+ puts("");
+ puts("\t-fhelp Display help about firm optimisation options");
+ puts("\t-bhelp Display help about firm backend options");
+ puts("A big number of gcc flags is also supported");
+}
+
static void set_be_option(const char *arg)
{
- int res = firm_be_option(arg);
+ int res = be_parse_arg(arg);
(void) res;
assert(res);
}
if (in == NULL) {
fprintf(stderr, "Couldn't open '%s': %s\n", filename,
strerror(errno));
- exit(1);
+ exit(EXIT_FAILURE);
}
return in;
return FILETYPE_UNKNOWN;
}
-static void init_os_support(void)
+/**
+ * Initialize firm codegeneration for a specific operating system.
+ * The argument is the operating system part of a target-triple */
+static bool set_os_support(const char *os)
{
- /* OS option must be set to the backend */
- switch (firm_opt.os_support) {
- case OS_SUPPORT_MINGW:
- set_be_option("ia32-gasmode=mingw");
- wchar_atomic_kind = ATOMIC_TYPE_USHORT;
- break;
- case OS_SUPPORT_LINUX:
+ wchar_atomic_kind = ATOMIC_TYPE_INT;
+ force_long_double_size = 0;
+ enable_main_collect2_hack = false;
+
+ if (strstr(os, "linux") != NULL || strstr(os, "bsd") != NULL
+ || streq(os, "solaris")) {
set_be_option("ia32-gasmode=elf");
- break;
- case OS_SUPPORT_MACHO:
+ set_create_ld_ident(create_name_linux_elf);
+ } else if (streq(os, "darwin")) {
+ force_long_double_size = 16;
set_be_option("ia32-gasmode=macho");
set_be_option("ia32-stackalign=4");
- set_be_option("pic");
- break;
+ set_be_option("pic=true");
+ set_create_ld_ident(create_name_macho);
+ } else if (strstr(os, "mingw") != NULL || streq(os, "win32")) {
+ wchar_atomic_kind = ATOMIC_TYPE_USHORT;
+ enable_main_collect2_hack = true;
+ set_be_option("ia32-gasmode=mingw");
+ set_create_ld_ident(create_name_win32);
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+static bool parse_target_triple(const char *arg)
+{
+ const char *manufacturer = strchr(arg, '-');
+ if (manufacturer == NULL) {
+ fprintf(stderr, "Target-triple is not in the form 'cpu_type-manufacturer-operating_system'\n");
+ return false;
+ }
+ manufacturer += 1;
+
+ const char *os = strchr(manufacturer, '-');
+ if (os == NULL) {
+ fprintf(stderr, "Target-triple is not in the form 'cpu_type-manufacturer-operating_system'\n");
+ return false;
}
+ os += 1;
+
+ /* Note: Triples are more or less defined by what the config.guess and
+ * config.sub scripts from GNU autoconf emit. We have to lookup there what
+ * triples are possible */
+
+ /* process cpu type */
+ if (strstart(arg, "i386-")) {
+ be_parse_arg("isa=ia32");
+ be_parse_arg("ia32-arch=i386");
+ } else if (strstart(arg, "i486-")) {
+ be_parse_arg("isa=ia32");
+ be_parse_arg("ia32-arch=i486");
+ } else if (strstart(arg, "i586-")) {
+ be_parse_arg("isa=ia32");
+ be_parse_arg("ia32-arch=i586");
+ } else if (strstart(arg, "i686-")) {
+ be_parse_arg("isa=ia32");
+ be_parse_arg("ia32-arch=i686");
+ } else if (strstart(arg, "i786-")) {
+ be_parse_arg("isa=ia32");
+ be_parse_arg("ia32-arch=pentium4");
+ } else if (strstart(arg, "x86_64")) {
+ be_parse_arg("isa=amd64");
+ } else if (strstart(arg, "sparc-")) {
+ be_parse_arg("isa=sparc");
+ } else if (strstart(arg, "arm-")) {
+ be_parse_arg("isa=arm");
+ } else {
+ fprintf(stderr, "Unknown cpu in triple '%s'\n", arg);
+ return false;
+ }
+
+ /* process manufacturer, alot of people incorrectly leave out the
+ * manufacturer instead of using unknown- */
+ if (strstart(manufacturer, "linux")) {
+ os = manufacturer;
+ manufacturer = "unknown-";
+ }
+
+ /* process operating system */
+ if (!set_os_support(os)) {
+ fprintf(stderr, "Unknown operating system '%s' in triple '%s'\n", os, arg);
+ return false;
+ }
+
+ target_triple = arg;
+ return true;
}
int main(int argc, char **argv)
if (option[0] == 'O') {
sscanf(&option[1], "%d", &opt_level);
}
- if (strcmp(arg, "-fwin32") == 0) {
- firm_opt.os_support = OS_SUPPORT_MINGW;
- } else if (strcmp(arg, "-fmac") == 0) {
- firm_opt.os_support = OS_SUPPORT_MACHO;
- } else if (strcmp(arg, "-flinux") == 0) {
- firm_opt.os_support = OS_SUPPORT_LINUX;
- }
}
- /* set target/os specific stuff */
- init_os_support();
+ /* Guess host OS */
+#if defined(_WIN32) || defined(__CYGWIN__)
+ set_os_support("win32");
+#elif defined(__APPLE__)
+ set_os_support("darwin");
+#else
+ set_os_support("linux");
+#endif
/* apply optimisation level */
switch(opt_level) {
/* fallthrough */
case 3:
set_option("thread-jumps");
- set_option("if-conv");
+ set_option("if-conversion");
/* fallthrough */
case 2:
set_option("strict-aliasing");
break;
}
+ const char *target = getenv("TARGET");
+ if (target != NULL)
+ parse_target_triple(target);
+
/* parse rest of options */
- standard = STANDARD_DEFAULT;
- unsigned features_on = 0;
- unsigned features_off = 0;
- filetype_t forced_filetype = FILETYPE_AUTODETECT;
- bool help_displayed = false;
- bool argument_errors = false;
+ standard = STANDARD_DEFAULT;
+ unsigned features_on = 0;
+ unsigned features_off = 0;
+ filetype_t forced_filetype = FILETYPE_AUTODETECT;
+ bool help_displayed = false;
+ bool argument_errors = false;
for (int i = 1; i < argc; ++i) {
const char *arg = argv[i];
if (arg[0] == '-' && arg[1] != '\0') {
char const *orig_opt;
GET_ARG_AFTER(orig_opt, "-f");
- if (strstart(orig_opt, "align-loops=") ||
- strstart(orig_opt, "align-jumps=") ||
- strstart(orig_opt, "align-functions=")) {
- fprintf(stderr, "ignoring gcc option '-f%s'\n", orig_opt);
- } else if (strstart(orig_opt, "input-charset=")) {
+ if (strstart(orig_opt, "input-charset=")) {
char const* const encoding = strchr(orig_opt, '=') + 1;
select_input_encoding(encoding);
} else if (streq(orig_opt, "verbose-asm")) {
mode = truth_value ? ParseOnly : CompileAssembleLink;
} else if (streq(opt, "unsigned-char")) {
char_is_signed = !truth_value;
+ } else if (streq(opt, "freestanding")) {
+ freestanding = true;
+ } else if (streq(opt, "hosted")) {
+ freestanding = false;
+ } else if (truth_value == false &&
+ streq(opt, "asynchronous-unwind-tables")) {
+ /* nothing todo, a gcc feature which we don't support
+ * anyway was deactivated */
+ } else if (strstart(orig_opt, "align-loops=") ||
+ strstart(orig_opt, "align-jumps=") ||
+ strstart(orig_opt, "align-functions=")) {
+ fprintf(stderr, "ignoring gcc option '-f%s'\n", orig_opt);
+ } else if (strstart(orig_opt, "message-length=")) {
+ /* ignore: would only affect error message format */
} else if (streq(opt, "fast-math") ||
streq(opt, "jump-tables") ||
- streq(opt, "unroll-loops") ||
streq(opt, "expensive-optimizations") ||
streq(opt, "common") ||
- streq(opt, "PIC") ||
+ streq(opt, "optimize-sibling-calls") ||
streq(opt, "align-loops") ||
streq(opt, "align-jumps") ||
- streq(opt, "align-functions")) {
+ streq(opt, "align-functions") ||
+ streq(opt, "PIC")) {
fprintf(stderr, "ignoring gcc option '-f%s'\n", orig_opt);
} else {
int res = firm_option(orig_opt);
} else if (option[0] == 'b') {
const char *opt;
GET_ARG_AFTER(opt, "-b");
- int res = firm_be_option(opt);
+ int res = be_parse_arg(opt);
if (res == 0) {
fprintf(stderr, "error: unknown Firm backend option '-b %s'\n",
opt);
strncpy(cpu_arch, opt, sizeof(cpu_arch));
}
} else if (option[0] == 'W') {
- if (strstart(option + 1, "p,")) {
+ if (option[1] == '\0') {
+ /* ignore -W, out defaults are already quiet verbose */
+ } else if (strstart(option + 1, "p,")) {
// pass options directly to the preprocessor
const char *opt;
GET_ARG_AFTER(opt, "-Wp,");
char arch_opt[64];
GET_ARG_AFTER(opt, "-m");
- if (strstart(opt, "arch=")) {
+ if (strstart(opt, "target=")) {
+ GET_ARG_AFTER(opt, "-mtarget=");
+ if (!parse_target_triple(opt))
+ argument_errors = true;
+ } else if (strstart(opt, "triple=")) {
+ GET_ARG_AFTER(opt, "-mtriple=");
+ if (!parse_target_triple(opt))
+ argument_errors = true;
+ } else if (strstart(opt, "arch=")) {
GET_ARG_AFTER(opt, "-march=");
snprintf(arch_opt, sizeof(arch_opt), "%s-arch=%s", cpu_arch, opt);
- int res = firm_be_option(arch_opt);
- if (res == 0)
+ int res = be_parse_arg(arch_opt);
+ if (res == 0) {
+ fprintf(stderr, "Unknown architecture '%s'\n", arch_opt);
argument_errors = true;
- else {
+ } else {
snprintf(arch_opt, sizeof(arch_opt), "%s-opt=%s", cpu_arch, opt);
- int res = firm_be_option(arch_opt);
+ int res = be_parse_arg(arch_opt);
if (res == 0)
argument_errors = true;
}
} else if (strstart(opt, "tune=")) {
GET_ARG_AFTER(opt, "-mtune=");
snprintf(arch_opt, sizeof(arch_opt), "%s-opt=%s", cpu_arch, opt);
- int res = firm_be_option(arch_opt);
+ int res = be_parse_arg(arch_opt);
if (res == 0)
argument_errors = true;
} else if (strstart(opt, "cpu=")) {
GET_ARG_AFTER(opt, "-mcpu=");
snprintf(arch_opt, sizeof(arch_opt), "%s-arch=%s", cpu_arch, opt);
- int res = firm_be_option(arch_opt);
+ int res = be_parse_arg(arch_opt);
if (res == 0)
argument_errors = true;
} else if (strstart(opt, "fpmath=")) {
}
if (!argument_errors) {
snprintf(arch_opt, sizeof(arch_opt), "%s-fpunit=%s", cpu_arch, opt);
- int res = firm_be_option(arch_opt);
+ int res = be_parse_arg(arch_opt);
if (res == 0)
argument_errors = true;
}
} else if (strstart(opt, "preferred-stack-boundary=")) {
GET_ARG_AFTER(opt, "-mpreferred-stack-boundary=");
snprintf(arch_opt, sizeof(arch_opt), "%s-stackalign=%s", cpu_arch, opt);
- int res = firm_be_option(arch_opt);
+ int res = be_parse_arg(arch_opt);
if (res == 0)
argument_errors = true;
} else if (streq(opt, "omit-leaf-frame-pointer")) {
set_be_option("omitleaffp=0");
} else if (streq(opt, "rtd")) {
default_calling_convention = CC_STDCALL;
+ } else if (strstart(opt, "regparm=")) {
+ fprintf(stderr, "error: regparm convention not supported yet\n");
+ argument_errors = true;
+ } else if (streq(opt, "soft-float")) {
+ fprintf(stderr, "error: software floatingpoint not supported yet\n");
+ argument_errors = true;
} else {
char *endptr;
long int value = strtol(opt, &endptr, 10);
mode = PrintCaml;
} else if (streq(option, "print-jna")) {
mode = PrintJna;
+ } else if (streq(option, "jna-limit")) {
+ ++i;
+ if (i >= argc) {
+ fprintf(stderr, "error: "
+ "expected argument after '--jna-limit'\n");
+ argument_errors = true;
+ break;
+ }
+ jna_limit_output(argv[i]);
+ } else if (streq(option, "jna-libname")) {
+ ++i;
+ if (i >= argc) {
+ fprintf(stderr, "error: "
+ "expected argument after '--jna-libname'\n");
+ argument_errors = true;
+ break;
+ }
+ jna_set_libname(argv[i]);
} else if (streq(option, "time")) {
do_timing = true;
} else if (streq(option, "version")) {
print_cparser_version();
- exit(EXIT_SUCCESS);
+ return EXIT_SUCCESS;
+ } else if (streq(option, "help")) {
+ print_help(argv[0]);
+ help_displayed = true;
} else if (streq(option, "dump-function")) {
++i;
if (i >= argc) {
streq(suffix, "S") ? FILETYPE_ASSEMBLER :
streq(suffix, "a") ? FILETYPE_OBJECT :
streq(suffix, "c") ? FILETYPE_C :
+ streq(suffix, "C") ? FILETYPE_CXX :
streq(suffix, "cc") ? FILETYPE_CXX :
+ streq(suffix, "cp") ? FILETYPE_CXX :
streq(suffix, "cpp") ? FILETYPE_CXX :
+ streq(suffix, "CPP") ? FILETYPE_CXX :
streq(suffix, "cxx") ? FILETYPE_CXX :
+ streq(suffix, "c++") ? FILETYPE_CXX :
+ streq(suffix, "ii") ? FILETYPE_CXX :
streq(suffix, "h") ? FILETYPE_C :
streq(suffix, "ir") ? FILETYPE_IR :
streq(suffix, "o") ? FILETYPE_OBJECT :
streq(suffix, "s") ? FILETYPE_PREPROCESSED_ASSEMBLER :
streq(suffix, "so") ? FILETYPE_OBJECT :
- FILETYPE_AUTODETECT;
+ FILETYPE_OBJECT; /* gcc behavior: unknown file extension means object file */
}
}
-
- if (type == FILETYPE_AUTODETECT) {
- fprintf(stderr, "'%s': file format not recognized\n", arg);
- continue;
- }
}
file_list_entry_t *entry
}
}
+ if (help_displayed) {
+ return !argument_errors;
+ }
+
if (print_file_name_file != NULL) {
print_file_name(print_file_name_file);
- return 0;
+ return EXIT_SUCCESS;
}
-
if (files == NULL) {
fprintf(stderr, "error: no input files specified\n");
argument_errors = true;
}
- if (help_displayed) {
- return !argument_errors;
- }
if (argument_errors) {
usage(argv[0]);
- return 1;
+ return EXIT_FAILURE;
}
/* we do the lowering in ast2firm */
c_mode &= ~features_off;
gen_firm_init();
+ byte_order_big_endian = be_get_backend_param()->byte_order_big_endian;
init_symbol_table();
init_types();
init_typehash();
if (out == NULL) {
fprintf(stderr, "Couldn't open '%s' for writing: %s\n", outname,
strerror(errno));
- return 1;
+ return EXIT_FAILURE;
}
}
file_list_entry_t *file;
+ bool already_constructed_firm = false;
for (file = files; file != NULL; file = file->next) {
char asm_tempfile[1024];
const char *filename = file->name;
in = open_file(filename);
lextest(in, filename);
fclose(in);
- exit(EXIT_SUCCESS);
+ return EXIT_SUCCESS;
}
FILE *preprocessed_in = NULL;
c_mode |= features_on;
c_mode &= ~features_off;
- timer_push(TV_PARSING);
+ /* do the actual parsing */
+ ir_timer_t *t_parsing = ir_timer_new();
+ timer_register(t_parsing, "Frontend: Parsing");
+ timer_push(t_parsing);
init_tokens();
translation_unit_t *const unit = do_parsing(in, filename);
- timer_pop();
+ timer_pop(t_parsing);
/* prints the AST even if errors occurred */
if (mode == PrintAst) {
- type_set_output(out);
- ast_set_output(out);
+ print_to_file(out);
print_ast(unit);
}
/* remove output file */
if (out != stdout)
unlink(outname);
- exit(EXIT_FAILURE);
+ return EXIT_FAILURE;
}
}
continue;
}
- timer_push(TV_CONSTRUCT);
+ /* build the firm graph */
+ ir_timer_t *t_construct = ir_timer_new();
+ timer_register(t_construct, "Frontend: Graph construction");
+ timer_push(t_construct);
+ if (already_constructed_firm) {
+ panic("compiling multiple files/translation units not possible");
+ }
translation_unit_to_firm(unit);
- timer_pop();
+ already_constructed_firm = true;
+ timer_pop(t_construct);
graph_built:
if (mode == ParseOnly) {
if (irg == NULL) {
fprintf(stderr, "No graph for function '%s' found\n",
dumpfunction);
- exit(1);
+ return EXIT_FAILURE;
}
- dump_ir_block_graph_file(irg, out);
+ dump_ir_graph_file(out, irg);
fclose(out);
- exit(0);
+ return EXIT_SUCCESS;
}
if (mode == CompileExportIR) {
fclose(out);
ir_export(outname);
- exit(0);
+ return EXIT_SUCCESS;
}
- gen_firm_finish(asm_out, filename, /*c_mode=*/1,
- have_const_functions);
+ gen_firm_finish(asm_out, filename, have_const_functions);
if (asm_out != out) {
fclose(asm_out);
}
const char *flags = obstack_finish(&ldflags_obst);
/* construct commandline */
- obstack_printf(&file_obst, "%s", LINKER);
+ const char *linker = getenv("CPARSER_LINK");
+ if (linker != NULL) {
+ obstack_printf(&file_obst, "%s ", linker);
+ } else {
+ if (target_triple != NULL)
+ obstack_printf(&file_obst, "%s-", target_triple);
+ obstack_printf(&file_obst, "%s ", LINKER);
+ }
+
for (file_list_entry_t *entry = files; entry != NULL;
entry = entry->next) {
if (entry->type != FILETYPE_OBJECT)
int err = system(commandline);
if (err != EXIT_SUCCESS) {
fprintf(stderr, "linker reported an error\n");
- exit(1);
+ return EXIT_FAILURE;
}
}
exit_types();
exit_tokens();
exit_symbol_table();
- return 0;
+ return EXIT_SUCCESS;
}