#include #include #include #ifdef _WIN32 #include // for _spawnvp on Windows #endif #define BRUTAL_MAX_FILES 1000 int backend_main(int argc, char** argv); int system(const char* cmd); char* strdup(const char* str); void brutal_string_append(char** buffer, char* str) { //fprintf(stderr, "appending '%s' to '%s'\n", str, buffer[0]); int len1 = (buffer[0] == NULL) ? 0 : strlen(buffer[0]); //fprintf(stderr, "len1=%d\n", len1); int len2 = strlen(str); //fprintf(stderr, "len2=%d\n", len2); char* nbuf = calloc(len1 + len2 + 1, 1); if (nbuf == NULL) { fprintf(stderr, "ERROR: Out of memory!\n"); exit(1); } int i; for (i = 0; i < len1+len2; i++) { if (i < len1) { nbuf[i] = buffer[0][i]; } else { nbuf[i] = str[i-len1]; } } if (buffer[0] != NULL) { free(buffer[0]); } buffer[0] = nbuf; } int brutal_args_count(char** argv) { if (argv==NULL) { return 0; } int i; for (i = 0; argv[i] != NULL; i++) { // Just count... } return i; } void brutal_args_append(char*** buffer, char* str) { int len = brutal_args_count(buffer[0]); char** nbuf = calloc(len + 2, sizeof(void*)); if (nbuf == NULL) { fprintf(stderr, "ERROR: Out of memory!\n"); exit(1); } int i; for (i = 0; i < len+1; i++) { if (i < len) { nbuf[i] = buffer[0][i]; } else { nbuf[i] = str; } } if (buffer[0] != NULL) { free(buffer[0]); } buffer[0] = nbuf; } void brutal_args_append_all(char*** buffer, char** moreargs) { int i; for (i = 0; moreargs[i] != NULL; i++) { brutal_args_append(buffer, moreargs[i]); } } int brutal_needs_quotes(char* arg) { int i; for (i = 0; arg[i] != 0; i++) { char c = arg[i]; if (c == ' ') { return 1; } } return 0; } int brutal_setenv(char* name, char* value, int replace, int echo, int fake) { if (echo) { fprintf(stderr, "SETENV: Using (%s) environment variable '%s' to '%s'\n", replace ? "replacing" : "if unset", name, value); } if (!fake) { return setenv(name, value, replace); } return 0; } int brutal_exec(char** argv, int echo, int fake) { char* cmd = NULL; int i; for (i = 0; argv[i] != NULL; i++) { int q = brutal_needs_quotes(argv[i]); if (q) { brutal_string_append(&cmd, i == 0 ? "\"" : " \""); } else if (i != 0) { brutal_string_append(&cmd, " "); } brutal_string_append(&cmd, argv[i]); if (q) brutal_string_append(&cmd, "\""); } if (echo) { fprintf(stderr, "%s command: '%s'\n", fake ? "NOT executing" : "executing", cmd); } return fake ? 0 : system(cmd); } int brutal_startswith(const char* start, char* str) { int i = 0; while (start[i] != 0) { if (str[i] != start[i]) { return 0; } i++; } return 1; } int brutal_endswith(char* str, const char* end) { size_t len1 = strlen(str); size_t len2 = strlen(end); if (len1 < len2) { return 0; } int i = (len1-len2); int j = 0; while (str[i] != 0) { if (str[i] != end[j]) { return 0; } i++; j++; } return 1; } typedef struct compilerjob compilerjob_t; struct compilerjob { char* selfcmd; char** inputs; char** incdirs; char** defines; int numinputs; int numincdirs; int numdefines; int skipcompiler; int skiplinker; int skipassembler; int echocmd; int fakecmd; int keeptmp; int useyasm; int usefasm; int usenasm; int usezasm; int useas; int nasmsyntax; int gc; int thread; int mm; int riscv; int linkstatic; int usemold; int use101; char* output; char* tmpdir; char** tmpfiles; char* modinitfile; // If not null, should be added as an input char* modinitfunc; // Name of function in modinit char* sym_prefix; }; char* brutal_path_end(compilerjob_t* job, char* path) { char* lastpart = path; int i; for (i = 0; path[i] != 0; i++) { if (path[i] == '/' || path[i] == '\\') { lastpart = path+i+1; } } return lastpart; } char* brutal_path_sanitise(compilerjob_t* job, char* path) { path = strdup(brutal_path_end(job, path)); int i = 0; while (path[i] != 0) { char c = path[i]; if (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) || ((c >= '0') && (c <= '9'))) { // Keep it. } else { path[i] = '_'; } i++; } return path; } /* I guess the most portable way of checking if a file "exists" is trying to open it for reading * (If it exists but we can't open it for reading, then it's unlikely that we'll be able to accidentally overwrite it either!) */ int brutal_exists(char* fname) { FILE* f = fopen(fname, "rb"); if (f == NULL) { return 0; } else { fclose(f); return 1; } } char* brutal_tmp(compilerjob_t* job, char* namehint1, char* namehint2); char* brutal_tmp(compilerjob_t* job, char* namehint1, char* namehint2) { char* result = NULL; namehint1 = brutal_path_end(job, namehint1); namehint2 = brutal_path_end(job, namehint2); brutal_string_append(&result, job->tmpdir); brutal_string_append(&result, "/"); if (!brutal_startswith("brutal-", namehint1)) { brutal_string_append(&result, "brutal-"); } brutal_string_append(&result, namehint1); brutal_string_append(&result, ".tmp"); brutal_string_append(&result, namehint2); // If the file already exists, we'll print a notice that you've probably got temporary files hanging around and try a new name if (brutal_exists(result)) { char* newhint1 = NULL; fprintf(stderr, "WARNING: File '%s' already exists, you probably have temporary files laying around. I'll try a new name just in case it's a user-modified file!.\n", result); brutal_string_append(&newhint1, namehint1); brutal_string_append(&newhint1, "2"); return brutal_tmp(job, newhint1, namehint2); } // Slight workaround while compiler bugs are being fixed, create a temporary copy of the tmpfiles pointer... char** tmpfiles = job->tmpfiles; // Add the result to tmpfiles brutal_args_append(&tmpfiles, result); // Other end of workaround... job->tmpfiles = tmpfiles; // And we're done! return result; } int brutal_exec_cp(compilerjob_t* job, char* input, char* output) { char** args = NULL; brutal_args_append(&args, "cp"); brutal_args_append(&args, input); brutal_args_append(&args, output); return brutal_exec(args, job->echocmd, job->fakecmd); } int brutal_exec_rm(compilerjob_t* job, char* fname) { char** args = NULL; brutal_args_append(&args, "rm"); brutal_args_append(&args, fname); return brutal_exec(args, job->echocmd, job->fakecmd); } int brutal_exec_preprocessor(compilerjob_t* job, char* input, char* output, int isasm) { char** args = NULL; brutal_args_append(&args, job->selfcmd); brutal_args_append(&args, "-P"); int i; for (i = 0; i < job->numincdirs; i++) { //char* tmp = NULL; //brutal_string_append(&tmp, "-I"); //brutal_string_append(&tmp, job->incdirs[i]); brutal_args_append(&args, "-I"); brutal_args_append(&args, job->incdirs[i]);//tmp); } for (i = 0; i < job->numdefines; i++) { char* tmp = NULL; brutal_string_append(&tmp, "-D"); brutal_string_append(&tmp, job->defines[i]); brutal_args_append(&args, tmp); } if (isasm) { char* tmp = NULL; brutal_string_append(&tmp, "-D"); brutal_string_append(&tmp, "__ASSEMBLER__"); brutal_args_append(&args, tmp); } brutal_args_append(&args, input); brutal_args_append(&args, output); return brutal_exec(args, job->echocmd, job->fakecmd); } int brutal_exec_compiler(compilerjob_t* job, char* input, char* output, char* modname) { char** args = NULL; brutal_args_append(&args, job->selfcmd); brutal_args_append(&args, "-B"); if (job->use101) { brutal_args_append(&args, "--101"); } if (modname != NULL) { brutal_args_append(&args, "--mod"); brutal_args_append(&args, modname); } if (job->sym_prefix != NULL) { brutal_args_append(&args, "--prefix"); brutal_args_append(&args, job->sym_prefix); } brutal_args_append(&args, "--input"); brutal_args_append(&args, input); brutal_args_append(&args, "--output"); brutal_args_append(&args, output); return brutal_exec(args, job->echocmd, job->fakecmd); } int brutal_exec_assembler(compilerjob_t* job, char* input, char* output) { char** args = NULL; if (job->useyasm) { brutal_args_append(&args, "yasm"); if (!job->nasmsyntax) { brutal_args_append(&args, "-p"); brutal_args_append(&args, "gnu"); } brutal_args_append(&args, "-f"); brutal_args_append(&args, "elf64"); } else if (job->usenasm) { brutal_args_append(&args, "nasm"); brutal_args_append(&args, "-f"); brutal_args_append(&args, "elf64"); } else if (job->usefasm) { brutal_args_append(&args, "fasm"); brutal_args_append(&args, "-m"); brutal_args_append(&args, "500000"); // Set a memory limit a bit under 512mb } else if (job->usezasm) { brutal_args_append(&args, "zasm"); brutal_args_append(&args, "--mode"); brutal_args_append(&args, "rv64"); } else if (job->useas) { if (job->riscv) { #ifdef __riscv brutal_args_append(&args, "as"); #else brutal_args_append(&args, "riscv64-linux-gnu-as"); #endif brutal_args_append(&args, "--traditional-format"); brutal_args_append(&args, "-fno-pic"); brutal_args_append(&args, "-march=rv64imafd"); //brutal_args_append(&args, "-march=rv64ifd"); // NOTE: These settings need to be fine-tuned... floating-point ABI is not currently matching the default for Ubuntu cross-compilation brutal_args_append(&args, "-mabi=lp64d"); //-march=rv64ifd -mabi=lp64d } else { brutal_args_append(&args, "as"); brutal_args_append(&args, "--64"); } } else { if (job->riscv) { #ifdef __riscv brutal_args_append(&args, "cc"); #else brutal_args_append(&args, "riscv64-linux-gnu-gcc"); #endif } else { brutal_args_append(&args, "cc"); } brutal_args_append(&args, "-c"); } brutal_args_append(&args, input); if (!job->usefasm) { brutal_args_append(&args, "-o"); } brutal_args_append(&args, output); return brutal_exec(args, job->echocmd, job->fakecmd); } int brutal_exec_linker(compilerjob_t* job, char** inputs, char* output) { char** args = NULL; if (job->usemold) { brutal_args_append(&args, "mold"); brutal_args_append(&args, "-L/usr/lib/x86_64-linux-gnu"); brutal_args_append(&args, "-L/usr/lib/gcc/x86_64-linux-gnu/11"); brutal_args_append(&args, "-lc"); brutal_args_append(&args, "-lgcc"); } else if (job->riscv) { #ifdef __riscv brutal_args_append(&args, "cc"); #else brutal_args_append(&args, "riscv64-linux-gnu-gcc"); #endif } else { brutal_args_append(&args, "cc"); } if (job->linkstatic) { brutal_args_append(&args, "--static"); } if (job->thread) { brutal_args_append(&args, "-pthread"); } brutal_args_append_all(&args, inputs); if (job->gc) { brutal_args_append(&args, "-lgc"); } if (job->mm) { // TODO: It probably makes more sense to dynamically link SOME of this stuff (or, at least, to have more options) // But in any case, it seemed to make sense to have a shortcut to link a multimedia-enabled program brutal_args_append(&args, "-lSDL2"); brutal_args_append(&args, "-lcairo"); } brutal_args_append(&args, "-o"); brutal_args_append(&args, output); return brutal_exec(args, job->echocmd, job->fakecmd); } int brutal_mkmodinit(compilerjob_t* job, char** modnames) { if (job->fakecmd) { return 0; } FILE* o = fopen(job->modinitfile, "w"); if (o == NULL) { return 1; } int i; for (i = 0; modnames[i] != NULL; i++) { fprintf(o, "void __module__%s__init();\n", modnames[i]); } fprintf(o, "void __oop_init_begin();\n"); fprintf(o, "void __oop_init_end();\n"); fprintf(o, "\n"); fprintf(o, "void %s() {\n", job->modinitfunc); fprintf(o, " __oop_init_begin();\n"); for (i = 0; modnames[i] != NULL; i++) { fprintf(o, " __module__%s__init();\n", modnames[i]); } fprintf(o, " __oop_init_end();\n"); fprintf(o, "}\n"); fclose(o); return 0; } int brutal_run(compilerjob_t* job) { char** tolink = NULL; char** toinit = NULL; int result = 0; char* last = NULL; //fprintf(stderr, "Attempting to run...\n"); int i; for (i = 0; i < job->numinputs; i++) { char* input = job->inputs[i]; //fprintf(stderr, "Doing input '%s'\n", input); char* modname = NULL; int isasm = 0; int shouldprep = 1; if (brutal_endswith(input, ".m") || brutal_endswith(input, ".M")) { modname = brutal_path_sanitise(job, input); fprintf(stderr, "NOTE: Using module name '%s'\n", modname); brutal_args_append(&toinit, modname); } else if (brutal_endswith(input, ".s")) { isasm = 1; shouldprep = 0; } else if (brutal_endswith(input, ".S")) { isasm = 1; } /* If this is the modinit file, we need to create it before trying to compile it! */ if (job->modinitfile != NULL && !strcmp(input, job->modinitfile)) { if (brutal_exists(job->modinitfile)) { fprintf(stderr, "ERROR: Module init file already exists, will not overwrite existing file!\n"); exit(1); } if (brutal_mkmodinit(job, toinit) != 0) { fprintf(stderr, "ERROR: Failed to create module init file!\n"); exit(1); } } if (shouldprep) { char* tmp = brutal_tmp(job, input, isasm ? ".preprocessed.s" : ".preprocessed.c"); result = brutal_exec_preprocessor(job, input, tmp, isasm); if (result != 0) goto cleanup; input = tmp; } if (!isasm && !job->skipcompiler) { char* tmp = brutal_tmp(job, input, ".S"); result = brutal_exec_compiler(job, input, tmp, modname); if (result != 0) goto cleanup; input = tmp; } if (!job->skipassembler) { char* tmp = brutal_tmp(job, input, ".o"); result = brutal_exec_assembler(job, input, tmp); if (result != 0) goto cleanup; input = tmp; } brutal_args_append(&tolink, input); last = input; } //fprintf(stderr, "Finished first part...\n"); if (job->skiplinker) { result = brutal_exec_cp(job, last, job->output); if (result != 0) goto cleanup; } else { result = brutal_exec_linker(job, tolink, job->output); if (result != 0) goto cleanup; } cleanup: if (job->tmpfiles != NULL && !job->keeptmp) { for (i = 0; job->tmpfiles[i] != NULL; i++) { result = brutal_exec_rm(job, job->tmpfiles[i]); if (result != 0) { fprintf(stderr, "WARNING: Failed to remove temporary file '%s'\n", job->tmpfiles[i]); } } } return result; } int brutal_usage(int argc, char** argv, int argi, char* problem) { FILE* o = (problem == NULL) ? stdout : stderr; const char* n = argv[0]; fprintf(o, "USAGE:\n"); fprintf(o, " %s [options] input1.c [input2.c ...]\n", n); fprintf(o, "\n"); fprintf(o, "COMMON OPTIONS:\n"); fprintf(o, " -I Add a preprocessor include directory (requires an argument)\n"); fprintf(o, " -D Add a preprocessor definition (requires an argument)\n"); fprintf(o, " -o Set the output filename (requires an argument)\n"); fprintf(o, " -c Skip linker (only produce assembled file, no executable)\n"); fprintf(o, " -S Skip assembler (only produce assembly code, no assembled file)\n"); fprintf(o, " -E Skip compiler (only produce preprocessed code, no compiled code)\n"); fprintf(o, "\n"); fprintf(o, "TARGET/TOOLCHAIN OPTIONS:\n"); fprintf(o, " --static Build with/for static linking\n"); fprintf(o, " --dynamic Build with/for dynamic linking\n"); fprintf(o, " --use-fasm Use FASM assembler (default will pass assembly files to the platform's 'cc')\n"); fprintf(o, " --use-nasm Use NASM assembler (default will pass assembly files to the platform's 'cc')\n"); fprintf(o, " --use-yasm Use YASM assembler (default will pass assembly files to the platform's 'cc')\n"); fprintf(o, " --use-zasm Use ZASM assembler (default will pass assembly files to the platform's 'cc')\n"); fprintf(o, " --use-as Use the 'as' assembler directly (this will usually be the same backend used in the default mode)\n"); fprintf(o, " --nasm-syntax Use NASM syntax in assembly output (this can be used with --use-yasm, otherwise GNU syntax will be default)\n"); fprintf(o, " --RV64 Use RISC-V target (this assumes a suitable GNU toolchain for assembly & linkage)\n"); fprintf(o, " --AMD64 Use AMD64/x86-64 target (this assumes a suitable GNU toolchain for assembly & linkage)\n"); fprintf(o, "\n"); fprintf(o, "SPECIAL CODE GENERATION OPTIONS:\n"); fprintf(o, " --prefix Add a prefix to standard C symbols (requires an argument)\n"); fprintf(o, " --101 Use __classic_call calling convention by default (only for 1337 h4x0r5)\n"); fprintf(o, "\n"); fprintf(o, "BACKEND INVOCATION OPTIONS:\n"); fprintf(o, " --echo Echo command invocations & environment settings to the shell\n"); fprintf(o, " --fake Fake command invocations (can be used in conjunction with --echo to just show which commands would be used to compile something)\n"); fprintf(o, " --keeptmp Keep temporary files\n"); fprintf(o, " --compiler Invoke the internal compiler directly (must be first option, passes all options to backend)\n"); fprintf(o, " --preprocessor Invoke the internal preprocessor directly (must be first option, passes all options to preprocessor)\n"); fprintf(o, "\n"); fprintf(o, "EXTENSION OPTIONS:\n"); fprintf(o, " --gc Enable garbage collection\n"); fprintf(o, " --thread Enable multithreading\n"); fprintf(o, " (aliases: -pthread, --pthread)\n"); fprintf(o, " --mm Enable multimedia (requires SDL2, cairo libraries)\n"); fprintf(o, "\n"); fprintf(o, "TOOLCHAIN INFORMATION:\n"); fprintf(o, " --usage Shows usage information\n"); fprintf(o, " (aliases: --help, -h, -u, -H, -U)\n"); fprintf(o, " --version Shows version information\n"); fprintf(o, "\n"); if (problem != NULL) { fprintf(o, "ERROR:\n"); fprintf(o, " Around arg #%d: %s\n", argi, problem); } return (problem == NULL) ? 0 : 1; } void brutal_xdefine(compilerjob_t* job, const char* def) { if (job->numdefines < BRUTAL_MAX_FILES) { job->defines[job->numdefines] = def; job->numdefines++; } else { fprintf(stderr, "ERROR: Too many defines\n"); exit(1); } } int main(int argc, char** argv, char** envp) { compilerjob_t* job; /* Shortcuts to invoke the backend features directly. */ if (argc > 1) { if (!strcmp(argv[1], "-B") || !strcmp(argv[1], "--compiler") || !strcmp(argv[1], "--backend")) { argv[1] = "-B"; return backend_main(argc, argv); } else if (!strcmp(argv[1], "-P") || !strcmp(argv[1], "--preprocessor")) { argv[1] = "-P"; return backend_main(argc, argv); #ifdef TOOL_MK } else if (!strcmp(argv[1], "-M") || !strcmp(argv[1], "--make")) { argv[1] = "-M"; mk_main(argc, argv, envp); return 0; #endif } } fprintf(stderr, "SecureLang C Compiler Frontend\n"); job = calloc(1, sizeof(compilerjob_t)); if (job == NULL) { fprintf(stderr, "ERROR: Out of memory!\n"); return 1; } job->inputs = calloc(BRUTAL_MAX_FILES, sizeof(void*)); job->incdirs = calloc(BRUTAL_MAX_FILES, sizeof(void*)); job->defines = calloc(BRUTAL_MAX_FILES, sizeof(void*)); if (job->inputs == NULL || job->incdirs == NULL || job->defines == NULL) { fprintf(stderr, "ERROR: Out of memory!\n"); return 1; } job->selfcmd = strdup(argv[0]); job->linkstatic = 0; job->use101 = 0; job->sym_prefix = NULL; #ifdef __riscv job->riscv = 1; #else job->riscv = 0; #endif int specifiedlinkage = 0; int needsmodinit = 0; int argi = 1; while (argi < argc) { char* a = argv[argi]; //fprintf(stderr, "Processing argument '%s'\n", a); if (brutal_startswith("-o", a)) { if (strlen(a) > 2) { job->output = strdup(a+2); } else if (argi+1 < argc) { argi++; job->output = strdup(argv[argi]); } else { return brutal_usage(argc, argv, argi, "Expected output filename following -o"); } } else if (brutal_startswith("--prefix", a)) { if (argi+1 < argc) { argi++; job->sym_prefix = strdup(argv[argi]); } else { return brutal_usage(argc, argv, argi, "Expected symbol prefix following --prefix"); } } else if (brutal_startswith("-I", a)) { char* dir = NULL; if (strlen(a) > 2) { dir = strdup(a+2); } else if (argi+1 < argc) { argi++; dir = strdup(argv[argi]); } else { return brutal_usage(argc, argv, argi, "Expected directory name following -I"); } //fprintf(stderr, "Got include directory '%s'\n", dir); if (job->numincdirs < BRUTAL_MAX_FILES) { job->incdirs[job->numincdirs] = dir; job->numincdirs++; } else { return brutal_usage(argc, argv, argi, "Too many include directories"); } } else if (brutal_startswith("-D", a)) { char* def = NULL; if (strlen(a) > 2) { def = strdup(a+2); } else if (argi+1 < argc) { argi++; def = strdup(argv[argi]); } else { return brutal_usage(argc, argv, argi, "Expected preprocessor definition following -D"); } if (job->numdefines < BRUTAL_MAX_FILES) { job->defines[job->numdefines] = def; job->numdefines++; } else { return brutal_usage(argc, argv, argi, "Too many defines"); } } else if (!strcmp("--static", a)) { job->linkstatic = 1; specifiedlinkage = 1; } else if (!strcmp("--dynamic", a)) { job->linkstatic = 0; specifiedlinkage = 1; } else if (brutal_startswith("--RV", a) || brutal_startswith("--rv", a)) { fprintf(stderr, "WARNING: Current RISC-V backend is being tested for 64-bit with minimal floating-point support\n"); job->riscv = 1; } else if (brutal_startswith("--AMD", a) || brutal_startswith("--amd", a)) { job->riscv = 0; } else if (!strcmp("--use-as", a)) { job->useas = 1; } else if (!strcmp("--use-yasm", a)) { job->useyasm = 1; } else if (!strcmp("--use-fasm", a)) { job->usefasm = 1; } else if (!strcmp("--use-nasm", a)) { job->usenasm = 1; job->nasmsyntax = 1; } else if (!strcmp("--use-zasm", a)) { job->usezasm = 1; } else if (!strcmp("--nasm-syntax", a)) { job->nasmsyntax = 1; } else if (!strcmp("--use-mold", a)) { job->usemold = 1; } else if (!strcmp("--version", a)) { fprintf(stderr, "Too early to tell.\n"); return 0; } else if (!strcmp("--usage", a) || !strcmp("--help", a) || !strcmp("-h", a) || !strcmp("-u", a) || !strcmp("-H", a) || !strcmp("-U", a)) { return brutal_usage(argc, argv, argi, NULL); } else if (!strcmp("--version", a)) { fprintf(stderr, "Too early to tell.\n"); return 0; } else if (!strcmp("-E", a)) { job->skipcompiler = 1; job->skipassembler = 1; job->skiplinker = 1; } else if (!strcmp("-S", a)) { job->skipassembler = 1; job->skiplinker = 1; } else if (!strcmp("-c", a)) { job->skiplinker = 1; } else if (!strcmp("--101", a)) { job->use101 = 1; } else if (!strcmp("--echo", a)) { job->echocmd = 1; } else if (!strcmp("--fake", a)) { job->fakecmd = 1; } else if (!strcmp("--keeptmp", a)) { job->keeptmp = 1; } else if (!strcmp("--gc", a)) { job->gc = 1; } else if (!strcmp("--thread", a) || !strcmp("-pthread", a) || !strcmp("--pthread", a)) { job->thread = 1; } else if (!strcmp("--mm", a)) { job->mm = 1; } else if (brutal_startswith("-", a)) { return brutal_usage(argc, argv, argi, "Bad option"); } else { if (job->numinputs < BRUTAL_MAX_FILES) { char* cp = strdup(a); if (brutal_endswith(cp, ".m") || brutal_endswith(cp, ".M")) { needsmodinit = 1; } //fprintf(stderr, "Got strings '%s' '%s'\n", a, cp); job->inputs[job->numinputs] = cp; job->numinputs = job->numinputs + 1; } else { return brutal_usage(argc, argv, argi, "Too many input files"); } } argi++; } //fprintf(stderr, "Finished processing commands...\n"); if (needsmodinit && (job->skipassembler || job->skiplinker)) { needsmodinit = false; } if (job->numinputs < 1) { return brutal_usage(argc, argv, argi, "Nothing to do (expected input file)"); } else { //fprintf(stderr, "Got %d inputs\n", job->numinputs); } if (job->output == NULL) { if (job->skipcompiler) { job->output = "./a.out.C"; } else if (job->skipassembler) { job->output = "./a.out.S"; } else if (job->skiplinker) { job->output = "./a.out.o"; } else { job->output = "./a.out"; } } if (job->tmpdir == NULL) { job->tmpdir = "."; } if (specifiedlinkage) { if ((job->riscv || job->useyasm || job->usefasm || job->usezasm) && !job->linkstatic) { fprintf(stderr, "WARNING: Dynamic linking using RISC-V or FASM/YASM targets is work-in-progress.\n"); } } else { if ((job->riscv || job->useyasm || job->usefasm)) { fprintf(stderr, "NOTE: Using static linking as default on RISC-V or FASM/YASM targets.\n"); job->linkstatic = 1; } } /* Set any environment variables for current backend. * TODO: Evenutally move the more-stable options into regular command-line arguments. */ if (job->riscv) { brutal_setenv("CCB_FAMILY", "risc-v", 1, job->echocmd, job->fakecmd); } if (job->usefasm) { brutal_setenv("CCB_ASMFMT", "fasm", 1, job->echocmd, job->fakecmd); } if (job->nasmsyntax) { brutal_setenv("CCB_ASMFMT", "nasm", 1, job->echocmd, job->fakecmd); } if (needsmodinit) { if (job->modinitfile == NULL) { job->modinitfile = brutal_tmp(job, "modinit", ".c"); } if (job->modinitfunc == NULL) { job->modinitfunc = "__modinit"; } if (job->numinputs < BRUTAL_MAX_FILES) { job->inputs[job->numinputs] = job->modinitfile; job->numinputs = job->numinputs + 1; } else { return brutal_usage(argc, argv, argi, "Too many input files"); } } //fprintf(stderr, "Ready to run...\n"); brutal_xdefine(job, "__BRUTAL"); brutal_xdefine(job, "_ZCC"); if (job->gc) { brutal_xdefine(job, "__BRUTAL_FEATURE_GC"); } if (job->mm) { brutal_xdefine(job, "__BRUTAL_FEATURE_MM"); } if (job->thread) { brutal_xdefine(job, "__BRUTAL_FEATURE_THREAD"); } if (job->riscv) { brutal_xdefine(job, "__BRUTAL_CPU_RV64"); brutal_xdefine(job, "__riscv"); } else { brutal_xdefine(job, "__BRUTAL_CPU_X64"); brutal_xdefine(job, "__x86_64__"); } brutal_xdefine(job, "__BRUTAL_OS_LINUX"); // TODO: Better/more target flags return brutal_run(job); }