Initial commit of current C compiler sources, partly rebranded but not yet properly cleaned up!
This commit is contained in:
parent
6e217b2669
commit
7f74463109
317
cc.c
Normal file
317
cc.c
Normal file
@ -0,0 +1,317 @@
|
|||||||
|
#define TOOL_CPP
|
||||||
|
|
||||||
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <process.h>
|
||||||
|
#endif
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
//#include "compile.h"
|
||||||
|
#define CCB_IMPLEMENTATION
|
||||||
|
#include "ccb.h"
|
||||||
|
#define CCBGENERIC_IMPLEMENTATION
|
||||||
|
#include "ccbgeneric.h"
|
||||||
|
#ifdef TOOL_CPP
|
||||||
|
#define CPP_IMPLEMENTATION
|
||||||
|
#include "cpp.h"
|
||||||
|
#endif
|
||||||
|
#ifdef TOOL_MK
|
||||||
|
#define MK_IMPLEMENTATION
|
||||||
|
#include "mk.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int sh_main(int argc, char** argv);
|
||||||
|
|
||||||
|
void ccb_compile_error_impl(ccb_t* ccb/*, const char* fmt, ...*/) {
|
||||||
|
fprintf(stderr, "^ Around line %d, column %d of '%s'.\n", ccb->pos.uline, ccb->pos.ucol, ccb->pos.ufile);
|
||||||
|
fprintf(stderr, " [Around line %d, column %d of preprocessed input]\n", ccb->pos.line, ccb->pos.col);
|
||||||
|
/*#ifdef _ZCC
|
||||||
|
fprintf(stderr, "ERROR '%s'\n(TODO: Better formatting!)\n", fmt);
|
||||||
|
((char*)NULL)[0] = 0; // Trigger debugger
|
||||||
|
#else
|
||||||
|
va_list a;
|
||||||
|
va_start(a, fmt);
|
||||||
|
vfprintf(stderr, fmt, a);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
va_end(a);
|
||||||
|
#endif*/
|
||||||
|
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ccb_compile_warn_impl(ccb_t* ccb/*, const char* fmt, ...*/) {
|
||||||
|
fprintf(stderr, "^ Around line %d, column %d of '%s'.\n", ccb->pos.uline, ccb->pos.ucol, ccb->pos.ufile);
|
||||||
|
fprintf(stderr, " [Around line %d, column %d of preprocessed input]\n", ccb->pos.line, ccb->pos.col);
|
||||||
|
/*#ifdef _ZCC
|
||||||
|
fprintf(stderr, "WARNING '%s'\n(TODO: Better formatting!)\n", fmt);
|
||||||
|
#else
|
||||||
|
va_list a;
|
||||||
|
va_start(a, fmt);
|
||||||
|
vfprintf(stderr, fmt, a);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
va_end(a);
|
||||||
|
#endif*/
|
||||||
|
}
|
||||||
|
|
||||||
|
static int startcompile(ccb_t* ccb) {
|
||||||
|
ccb_util_init(ccb);
|
||||||
|
ccb_target_init(ccb);
|
||||||
|
ccb_ast_init(ccb);
|
||||||
|
|
||||||
|
ccb_list_t* block = ccb_parse_run(ccb);
|
||||||
|
if (!ccb->dump_ast) {
|
||||||
|
if (ccb->include_data) {
|
||||||
|
ccb_target_gen_data_section(ccb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* First run is required to gather externs. TODO: This should be done for any extern data elements too! */
|
||||||
|
for (ccb_list_iterator_t* it = ccb_list_iterator(block); !ccb_list_iterator_end(it); ) {
|
||||||
|
if (!ccb->dump_ast) {
|
||||||
|
if (ccb->include_code) {
|
||||||
|
ccb_target_gen_declfunction(ccb, ccb_list_iterator_next(it));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("%s", ccb_ast_string(ccb, ccb_list_iterator_next(it)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ccb->knownexterns != NULL) {
|
||||||
|
for (ccb_list_iterator_t* it = ccb_list_iterator(ccb->knownexterns); !ccb_list_iterator_end(it); ) {
|
||||||
|
if (!ccb->dump_ast) {
|
||||||
|
if (ccb->include_code) {
|
||||||
|
ccb_target_gen_declextern(ccb, ccb_list_iterator_next(it));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("%s", ccb_ast_string(ccb, ccb_list_iterator_next(it)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (ccb_list_iterator_t* it = ccb_list_iterator(block); !ccb_list_iterator_end(it); ) {
|
||||||
|
if (!ccb->dump_ast) {
|
||||||
|
if (ccb->include_code) {
|
||||||
|
ccb_target_gen_function(ccb, ccb_list_iterator_next(it));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("%s", ccb_ast_string(ccb, ccb_list_iterator_next(it)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Original main program from LICE:
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
argc--;
|
||||||
|
argv++;
|
||||||
|
return startcompile(!!(argc && !strcmp(*argv, "--dump-ast")))
|
||||||
|
? EXIT_SUCCESS
|
||||||
|
: EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void usage(int argc, char** argv, int arge) {
|
||||||
|
//fprintf(stderr, "TODO: Usage!\n");
|
||||||
|
char* n = argv[0];
|
||||||
|
|
||||||
|
fprintf(stderr, "USAGE:\n\n");
|
||||||
|
fprintf(stderr, " %s [--silent] [--ast-only|--code-only|--data-only|--usage] [TODO --asmfmt fasm|gas] [TODO --binfmt elf|flat] [--input <fname>] [--output|--append <fname>]\n\n", n);
|
||||||
|
fprintf(stderr, "(This is a simple core compiler designed to be invoked from a more user-friendly frontend.\nArguments must be provided in the above order, defaults to using stdin/stdout.)");
|
||||||
|
}
|
||||||
|
|
||||||
|
int preprocessormain(int argc, char** argv); // Extra definition of the C preprocessor main program
|
||||||
|
//void mk_main(int argc, char** argv); // Extra definition of the "make" tool main program
|
||||||
|
|
||||||
|
/* Zak's new new main program: (frontend) */
|
||||||
|
#include "frontend.c"
|
||||||
|
/* Zak's new main program: (backend) */
|
||||||
|
int backend_main(int argc, char** argv) {
|
||||||
|
/*int x;
|
||||||
|
for(x=0;x<argc;x++) {
|
||||||
|
printf("Got arg '%s'\n", argv[x]);
|
||||||
|
}*/
|
||||||
|
//argc = 3;
|
||||||
|
//argv = (char*[]){"test",/*"--ast-only",*/"--input","C:\\Users\\Zak\\source\\repos\\ZCC\\Debug\\test2.c"};
|
||||||
|
ccb_t ccb;
|
||||||
|
ccb.dump_ast = false;
|
||||||
|
ccb.silent = false;
|
||||||
|
ccb.input = stdin;
|
||||||
|
ccb.output = stdout;
|
||||||
|
ccb.include_code = true;
|
||||||
|
ccb.include_data = true;
|
||||||
|
ccb.pos.line = 1;
|
||||||
|
ccb.pos.col = 1;
|
||||||
|
ccb.pos.uline = 1;
|
||||||
|
ccb.pos.ucol = 1;
|
||||||
|
ccb.pos.ufile = strdup("input");
|
||||||
|
ccb.default_callconv = 0;
|
||||||
|
ccb.func_callconv = 0;
|
||||||
|
ccb.func_name = NULL;
|
||||||
|
ccb.mod_name = NULL;
|
||||||
|
ccb.mod_initstmts = NULL;
|
||||||
|
ccb.sym_prefix = strdup("");
|
||||||
|
ccb.declarednames = NULL;
|
||||||
|
ccb.knownexterns = NULL;
|
||||||
|
ccb.bsscount = 0;
|
||||||
|
|
||||||
|
int argi = 1;
|
||||||
|
if (argc > argi && (!strcmp(argv[argi], "--silent") || !strcmp(argv[argi], "--usage") || !strcmp(argv[argi], "-P") || !strcmp(argv[argi], "-B"))) { // Also skip added notices if using --usage
|
||||||
|
if (!strcmp(argv[argi], "--silent")) {
|
||||||
|
argi++;
|
||||||
|
}
|
||||||
|
ccb.silent = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "SecureLang C Compiler backend (CCb), early version\n");
|
||||||
|
fprintf(stderr, "NOTE: This program generally reads program code from standard input (until EOF) and writes assembly code to standard output.\n");
|
||||||
|
fprintf(stderr, " It would usually be used from a compiler frontend (preprocessing, assembling and linking must be done separately).\n");
|
||||||
|
fprintf(stderr, " Use --silent as the first argument to disable these notices or --usage to learn more.\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ignore -B, used to invoke backend. */
|
||||||
|
if (argc > argi && !strcmp(argv[argi], "-B")) {
|
||||||
|
argi++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc > argi && !strcmp(argv[argi], "--ast-only")) {
|
||||||
|
if (!ccb.silent) {
|
||||||
|
fprintf(stderr, "NOTE: Will dump AST to output instead of assembly code.\n");
|
||||||
|
}
|
||||||
|
ccb.dump_ast = true;
|
||||||
|
argi++;
|
||||||
|
}
|
||||||
|
else if (argc > argi && !strcmp(argv[argi], "--data-only")) {
|
||||||
|
if (!ccb.silent) {
|
||||||
|
fprintf(stderr, "NOTE: Will dump data section only.\n");
|
||||||
|
}
|
||||||
|
ccb.include_code = false;
|
||||||
|
ccb.include_data = true;
|
||||||
|
argi++;
|
||||||
|
}
|
||||||
|
else if (argc > argi && !strcmp(argv[argi], "--code-only")) {
|
||||||
|
if (!ccb.silent) {
|
||||||
|
fprintf(stderr, "NOTE: Will dump code section only.\n");
|
||||||
|
}
|
||||||
|
ccb.include_code = true;
|
||||||
|
ccb.include_data = false;
|
||||||
|
argi++;
|
||||||
|
}
|
||||||
|
#ifdef TOOL_CPP
|
||||||
|
else if (argc > argi && !strcmp(argv[argi], "-P")) { /* Invoke the built-in preprocessor instead of the backend. */
|
||||||
|
if (!ccb.silent) {
|
||||||
|
fprintf(stderr, "NOTE: Invoking the experimental preprocessor.\n");
|
||||||
|
}
|
||||||
|
// NOTE: This will only work for argv == 1, and because cppmain ignores the -P flag!
|
||||||
|
return preprocessormain(argc, argv);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef TOOL_MK
|
||||||
|
else if (argc > argi && !strcmp(argv[argi], "-M")) { /* Invoke the built-in make tool instead of the backend. */
|
||||||
|
if (!ccb.silent) {
|
||||||
|
fprintf(stderr, "NOTE: Invoking the experimental make tool.\n");
|
||||||
|
}
|
||||||
|
// NOTE: This will only work for argv == 1, and because cppmain ignores the -P flag!
|
||||||
|
void* tmp = NULL;
|
||||||
|
mk_main(argc, argv, &tmp);
|
||||||
|
return -1; // TODO: mk_main returns void but also has some exit calls, this behaviour needs to be checked to return error codes properly
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef TOOL_SH
|
||||||
|
else if (argc > argi && !strcmp(argv[argi], "-S")) { /* Invoke the built-in make tool instead of the backend. */
|
||||||
|
if (!ccb.silent) {
|
||||||
|
fprintf(stderr, "NOTE: Invoking the experimental shell tool.\n");
|
||||||
|
}
|
||||||
|
// NOTE: This will only work for argv == 1, and because cppmain ignores the -P flag!
|
||||||
|
void* tmp = NULL;
|
||||||
|
return sh_main(argc, argv);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (argc > argi && !strcmp(argv[argi], "--usage")) {
|
||||||
|
printf("USAGE?\n");
|
||||||
|
usage(argc, argv, -1);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc > argi && !strcmp(argv[argi], "--101")) {
|
||||||
|
if (!ccb.silent) {
|
||||||
|
fprintf(stderr, "NOTE: Using calling convention 101 (__classic_call) by default.\n", argv[argi + 1]);
|
||||||
|
}
|
||||||
|
ccb.default_callconv = 101;
|
||||||
|
argi++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc > argi + 1 && !strcmp(argv[argi], "--mod")) {
|
||||||
|
if (!ccb.silent) {
|
||||||
|
fprintf(stderr, "NOTE: Using module name '%s'.\n", argv[argi + 1]);
|
||||||
|
}
|
||||||
|
ccb.mod_name = strdup(argv[argi + 1]);
|
||||||
|
argi += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc > argi + 1 && !strcmp(argv[argi], "--prefix")) {
|
||||||
|
if (!ccb.silent) {
|
||||||
|
fprintf(stderr, "NOTE: Using symbol prefix '%s'.\n", argv[argi + 1]);
|
||||||
|
}
|
||||||
|
ccb.sym_prefix = strdup(argv[argi + 1]);
|
||||||
|
argi += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc > argi + 1 && !strcmp(argv[argi], "--input")) {
|
||||||
|
if (!ccb.silent) {
|
||||||
|
fprintf(stderr, "NOTE: Using input from '%s'.\n", argv[argi + 1]);
|
||||||
|
}
|
||||||
|
ccb.input = fopen(argv[argi + 1], "r");
|
||||||
|
ccb.pos.ufile = strdup(argv[argi + 1]);
|
||||||
|
argi += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc > argi + 1 && !strcmp(argv[argi], "--output")) {
|
||||||
|
if (!ccb.silent) {
|
||||||
|
fprintf(stderr, "NOTE: Writing output to '%s'.\n", argv[argi + 1]);
|
||||||
|
}
|
||||||
|
ccb.output = fopen(argv[argi + 1], "w");
|
||||||
|
argi += 2;
|
||||||
|
}
|
||||||
|
else if (argc > argi + 1 && !strcmp(argv[argi], "--append")) {
|
||||||
|
if (!ccb.silent) {
|
||||||
|
fprintf(stderr, "NOTE: Appending output from '%s'.\n", argv[argi]);
|
||||||
|
}
|
||||||
|
ccb.output = fopen(argv[argi + 1], "a");
|
||||||
|
argi += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ccb.input == NULL) {
|
||||||
|
fprintf(stderr, "ERROR: Failed to open input file.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ccb.output == NULL) {
|
||||||
|
fprintf(stderr, "ERROR: Failed to open output file.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argi != argc) {
|
||||||
|
usage(argc, argv, argi);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int result = startcompile(&ccb);
|
||||||
|
|
||||||
|
if (ccb.input != stdin) {
|
||||||
|
fclose(ccb.input);
|
||||||
|
}
|
||||||
|
if (ccb.output != stdout) {
|
||||||
|
fclose(ccb.output);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
4256
ccbgeneric.h
Normal file
4256
ccbgeneric.h
Normal file
File diff suppressed because it is too large
Load Diff
6
fakelibc/README
Normal file
6
fakelibc/README
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
The fakelibc directory contains "fake" header files to allow the compiler to
|
||||||
|
self-host on Linux-compatible systems without needing complete C compatibility.
|
||||||
|
|
||||||
|
It can also be used for other small tools built with the compiler, but is not
|
||||||
|
a replacement for a full libc (just a more-portable wrapper over GNU libc or
|
||||||
|
compatible).
|
7
fakelibc/assert.h
Normal file
7
fakelibc/assert.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#ifndef _FAKELIBC_ASSERT_H
|
||||||
|
#define _FAKELIBC_ASSERT_H
|
||||||
|
|
||||||
|
#define assert(...) do {} while(0)
|
||||||
|
|
||||||
|
/* From ifndef at top of file: */
|
||||||
|
#endif
|
74
fakelibc/ctype.h
Normal file
74
fakelibc/ctype.h
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
#ifndef _FAKELIBC_CTYPE_H
|
||||||
|
#define _FAKELIBC_CTYPE_H
|
||||||
|
/*
|
||||||
|
#define isspace fake_isspace
|
||||||
|
#define isdigit fake_isdigit
|
||||||
|
#define isxdigit fake_isxdigit
|
||||||
|
#define isalpha fake_isalpha
|
||||||
|
#define isalnum fake_isalnum
|
||||||
|
#define isprint fake_isprint
|
||||||
|
#define ispunct fake_ispunct
|
||||||
|
|
||||||
|
static int fake_isspace(int ch) {
|
||||||
|
return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fake_isdigit(int ch) {
|
||||||
|
return (ch >= '0') && (ch <= '9');
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fake_isxdigit(int ch) {
|
||||||
|
return isdigit(ch) || ((ch >= 'a') && (ch <= 'f')) || ((ch >= 'A') && (ch <= 'F'));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fake_isalpha(int ch) {
|
||||||
|
return ((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z'));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fake_isalnum(int ch) {
|
||||||
|
return isalpha(ch) || isdigit(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fake_isprint(int ch) {
|
||||||
|
return isalnum(ch) || isspace(ch) || ispunct(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fake_ispunct(int ch) {
|
||||||
|
switch (ch) {
|
||||||
|
case ',':
|
||||||
|
case '<':
|
||||||
|
case '.':
|
||||||
|
case '>':
|
||||||
|
case '/':
|
||||||
|
case '?':
|
||||||
|
case ';':
|
||||||
|
case ':':
|
||||||
|
case '\'':
|
||||||
|
case '\"':
|
||||||
|
case '[':
|
||||||
|
case ']':
|
||||||
|
case '{':
|
||||||
|
case '}':
|
||||||
|
case '`':
|
||||||
|
case '~':
|
||||||
|
case '@':
|
||||||
|
case '#':
|
||||||
|
case '$':
|
||||||
|
case '%':
|
||||||
|
case '^':
|
||||||
|
case '&':
|
||||||
|
case '*':
|
||||||
|
case '(':
|
||||||
|
case ')':
|
||||||
|
case '-':
|
||||||
|
case '_':
|
||||||
|
case '=':
|
||||||
|
case '+':
|
||||||
|
return 1;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
/* From ifndef at top of file: */
|
||||||
|
#endif
|
0
fakelibc/dirent.h
Normal file
0
fakelibc/dirent.h
Normal file
20
fakelibc/errno.h
Normal file
20
fakelibc/errno.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#ifndef _FAKELIBC_ERRNO_H
|
||||||
|
#define _FAKELIBC_ERRNO_H
|
||||||
|
|
||||||
|
//extern int errno;
|
||||||
|
|
||||||
|
/* On modern Linux platforms the errno is simulated. This is presumably so that each
|
||||||
|
* thread can have it's own errno without the ABI becoming a huge mess.
|
||||||
|
*/
|
||||||
|
#ifdef __MAC
|
||||||
|
int errno;
|
||||||
|
#else
|
||||||
|
int* __errno_location();
|
||||||
|
|
||||||
|
#define errno __errno_location()[0]
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ENOENT 2
|
||||||
|
|
||||||
|
/* From ifndef at top of file: */
|
||||||
|
#endif
|
0
fakelibc/fcntl.h
Normal file
0
fakelibc/fcntl.h
Normal file
7
fakelibc/float.h
Normal file
7
fakelibc/float.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#ifndef _FAKELIBC_FLOAT_H
|
||||||
|
#define _FAKELIBC_FLOAT_H
|
||||||
|
|
||||||
|
#define DBL_MAX_EXP 1024
|
||||||
|
#define DBL_MANT_DIG 53
|
||||||
|
|
||||||
|
#endif
|
7
fakelibc/inttypes.h
Normal file
7
fakelibc/inttypes.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#ifndef _FAKELIBC_INTTYPES_H
|
||||||
|
#define _FAKELIBC_INTTYPES_H
|
||||||
|
|
||||||
|
#define PRIx32 "x"
|
||||||
|
|
||||||
|
/* From ifndef at top of file: */
|
||||||
|
#endif
|
8
fakelibc/limits.h
Normal file
8
fakelibc/limits.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#ifndef _FAKELIBC_LIMITS_H
|
||||||
|
#define _FAKELIBC_LIMITS_H
|
||||||
|
|
||||||
|
#define CHAR_BIT 8
|
||||||
|
#define UINT_MAX 0xFFFFFFFFU
|
||||||
|
|
||||||
|
/* From ifndef at top of file: */
|
||||||
|
#endif
|
0
fakelibc/math.h
Normal file
0
fakelibc/math.h
Normal file
5
fakelibc/memory.h
Normal file
5
fakelibc/memory.h
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#ifndef _FAKELIBC_MEMORY_H
|
||||||
|
#define _FAKELIBC_MEMORY_H
|
||||||
|
|
||||||
|
/* From ifndef at top of file: */
|
||||||
|
#endif
|
0
fakelibc/pwd.h
Normal file
0
fakelibc/pwd.h
Normal file
18
fakelibc/setjmp.h
Normal file
18
fakelibc/setjmp.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef _FAKELIBC_SETJMP_H
|
||||||
|
#define _FAKELIBC_SETJMP_H
|
||||||
|
|
||||||
|
/*struct jmp_buf_struct {
|
||||||
|
int todo;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct jmp_buf_struct jmp_buf;*/
|
||||||
|
typedef int jmp_buf;
|
||||||
|
|
||||||
|
#define setjmp(x) \
|
||||||
|
0
|
||||||
|
// (printf("WARNING: Unimplemented: setjmp\n") && 0)
|
||||||
|
#define longjmp(x,y) \
|
||||||
|
printf("WARNING: Unimplemented: longjmp\n")
|
||||||
|
|
||||||
|
/* From ifndef at top of file: */
|
||||||
|
#endif
|
0
fakelibc/signal.h
Normal file
0
fakelibc/signal.h
Normal file
27
fakelibc/stdarg.h
Normal file
27
fakelibc/stdarg.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#ifndef _FAKELIBC_STDARG_H
|
||||||
|
#define _FAKELIBC_STDARG_H
|
||||||
|
|
||||||
|
// TODO: This will basically not work except for the simplest printf-like cases
|
||||||
|
|
||||||
|
typedef long long** va_list;
|
||||||
|
|
||||||
|
#define _VA_CHECK() \
|
||||||
|
if (__builtin_func_callconv != 101) {\
|
||||||
|
printf("ERROR: Unpacking varargs currently only works with __classic_call (#101). Function %s uses convention %d instead.\n", __func__, __builtin_func_callconv);\
|
||||||
|
}
|
||||||
|
|
||||||
|
#define va_start(list,lastarg) \
|
||||||
|
do {\
|
||||||
|
_VA_CHECK();\
|
||||||
|
list = &lastarg;\
|
||||||
|
list++;\
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define va_arg(list,T) \
|
||||||
|
(T)(list++)
|
||||||
|
|
||||||
|
#define va_end(list) \
|
||||||
|
do {list = (void*)0;} while(0)
|
||||||
|
|
||||||
|
/* From ifndef at top of file: */
|
||||||
|
#endif
|
10
fakelibc/stdbool.h
Normal file
10
fakelibc/stdbool.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#ifndef _FAKELIBC_STDBOOL_H
|
||||||
|
#define _FAKELIBC_STDBOOL_H
|
||||||
|
|
||||||
|
typedef int bool;
|
||||||
|
|
||||||
|
#define true 1
|
||||||
|
#define false 0
|
||||||
|
|
||||||
|
/* From ifndef at top of file: */
|
||||||
|
#endif
|
13
fakelibc/stddef.h
Normal file
13
fakelibc/stddef.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#ifndef _FAKELIBC_STDDEF_H
|
||||||
|
#define _FAKELIBC_STDDEF_H
|
||||||
|
|
||||||
|
//#ifndef _FAKELIBC_STDLIB_H
|
||||||
|
typedef long size_t;
|
||||||
|
//#endif
|
||||||
|
|
||||||
|
#ifndef NULL
|
||||||
|
#define NULL ((void*) 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* From ifndef at top of file: */
|
||||||
|
#endif
|
26
fakelibc/stdint.h
Normal file
26
fakelibc/stdint.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#ifndef _FAKELIBC_STDINT_H
|
||||||
|
#define _FAKELIBC_STDINT_H
|
||||||
|
|
||||||
|
typedef char int8_t;
|
||||||
|
typedef short int16_t;
|
||||||
|
typedef int int32_t;
|
||||||
|
typedef long long int64_t;
|
||||||
|
typedef unsigned char uint8_t;
|
||||||
|
typedef unsigned short uint16_t;
|
||||||
|
typedef unsigned int uint32_t;
|
||||||
|
typedef unsigned long long uint64_t;
|
||||||
|
|
||||||
|
typedef int64_t intptr_t;
|
||||||
|
typedef uint64_t uintptr_t;
|
||||||
|
|
||||||
|
typedef uint32_t uint_fast8_t;
|
||||||
|
typedef int32_t int_fast8_t;
|
||||||
|
typedef uint32_t uint_fast16_t;
|
||||||
|
typedef int32_t int_fast16_t;
|
||||||
|
typedef uint32_t uint_fast32_t;
|
||||||
|
typedef int32_t int_fast32_t;
|
||||||
|
typedef uint64_t uint_fast64_t;
|
||||||
|
typedef int64_t int_fast64_t;
|
||||||
|
|
||||||
|
/* From ifndef at top of file: */
|
||||||
|
#endif
|
58
fakelibc/stdio.h
Normal file
58
fakelibc/stdio.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#ifndef _FAKELIBC_STDIO_H
|
||||||
|
#define _FAKELIBC_STDIO_H
|
||||||
|
|
||||||
|
struct FILE_internals {};
|
||||||
|
|
||||||
|
typedef struct FILE_internals FILE;
|
||||||
|
|
||||||
|
#define EXIT_FAILURE 1
|
||||||
|
#define EXIT_SUCCESS 0
|
||||||
|
|
||||||
|
#ifdef __MAC
|
||||||
|
extern FILE* __stderrp;
|
||||||
|
extern FILE* __stdinp;
|
||||||
|
extern FILE* __stdoutp;
|
||||||
|
#define stderr __stderrp
|
||||||
|
#define stdin __stdinp
|
||||||
|
#define stdout __stdoutp
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern FILE* stderr;
|
||||||
|
extern FILE* stdin;
|
||||||
|
extern FILE* stdout;
|
||||||
|
|
||||||
|
#define EOF ((int)-1)
|
||||||
|
|
||||||
|
int printf(const char* fmt, ...);
|
||||||
|
int sprintf(char *buf, const char* fmt, ...);
|
||||||
|
int fprintf(FILE* f, const char* fmt, ...);
|
||||||
|
|
||||||
|
FILE* fopen(const char* name, const char* mode);
|
||||||
|
int fclose(FILE* f);
|
||||||
|
int fflush(FILE* f);
|
||||||
|
|
||||||
|
long fread(void* buffer, long size, long count, FILE* f);
|
||||||
|
long fwrite(void* buffer, long size, long count, FILE* f);
|
||||||
|
|
||||||
|
char* fgets(char*, int, FILE*);
|
||||||
|
|
||||||
|
int fputs(const char*, FILE*);
|
||||||
|
int fputc(int, FILE*);
|
||||||
|
|
||||||
|
void perror(const char*);
|
||||||
|
|
||||||
|
int putc(int c, FILE* f);
|
||||||
|
|
||||||
|
int putchar(int c);
|
||||||
|
|
||||||
|
int fseek(FILE* f, long offset, int wh);
|
||||||
|
#define SEEK_SET 0
|
||||||
|
#define SEEK_CUR 1
|
||||||
|
#define SEEK_END 2
|
||||||
|
|
||||||
|
long ftell(FILE* f);
|
||||||
|
|
||||||
|
long getline(char** linevar, long *nvar, FILE* f);
|
||||||
|
|
||||||
|
/* From ifndef at top of file: */
|
||||||
|
#endif
|
26
fakelibc/stdlib.h
Normal file
26
fakelibc/stdlib.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#ifndef _FAKELIBC_STDLIB_H
|
||||||
|
#define _FAKELIBC_STDLIB_H
|
||||||
|
|
||||||
|
//typedef long size_t;
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
void* malloc(long sz);
|
||||||
|
void* calloc(long n, long sz);
|
||||||
|
void* realloc(void* mem, long sz);
|
||||||
|
void free(void* mem);
|
||||||
|
char* getenv(const char* name);
|
||||||
|
void exit(int x);
|
||||||
|
|
||||||
|
long strtol(const char* str, char**endvar, int base);
|
||||||
|
long long strtoll(const char* str, char**endvar, int base);
|
||||||
|
unsigned long strtoul(const char* str, char**endvar, int base);
|
||||||
|
unsigned long long strtoull(const char* str, char**endvar, int base);
|
||||||
|
|
||||||
|
float strtof(const char* str, char**endvar);
|
||||||
|
double strtod(const char* str, char**endvar);
|
||||||
|
|
||||||
|
double atof(const char* str);
|
||||||
|
int atoi(const char* str);
|
||||||
|
|
||||||
|
/* From ifndef at top of file: */
|
||||||
|
#endif
|
47
fakelibc/string.h
Normal file
47
fakelibc/string.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#ifndef _FAKELIBC_STRING_H
|
||||||
|
#define _FAKELIBC_STRING_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
//size_t strlen(const char* foo);
|
||||||
|
#define strlen fake_strlen
|
||||||
|
static size_t fake_strlen(const char* foo) {
|
||||||
|
if (foo == NULL) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
size_t i = 0;
|
||||||
|
while (foo[i] != 0) i++;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char *strchr(const char* str, int chr);
|
||||||
|
char *strrchr(const char* str, int chr);
|
||||||
|
char* strcat(char* str, const char* cat);
|
||||||
|
char* strcpy(char* buffer, const char* str);
|
||||||
|
char* strncpy(char* buffer, const char* str, size_t n);
|
||||||
|
const char* strpbrk(const char* str, const char* search);
|
||||||
|
int strcmp(const char* a, const char* b);
|
||||||
|
char* strdup(const char* str);
|
||||||
|
char* strndup(const char* str, size_t n);
|
||||||
|
|
||||||
|
//void* memcpy(void* dst, const void* src, size_t nbytes);
|
||||||
|
#define memcpy fake_memcpy
|
||||||
|
static void* fake_memcpy(void* dst, const void* src, size_t nbytes) {
|
||||||
|
// TODO: This was only required because calling libc's version triggered errors, this probably isn't an issue now that more bugs have been fixed.
|
||||||
|
//printf("fake_memcpy(%lx, %lx, %ld)\n", dst, src, nbytes);
|
||||||
|
char* cdst = (char*) dst;
|
||||||
|
const char* csrc = (char*) src;
|
||||||
|
size_t i = 0;
|
||||||
|
for (i = 0; i < nbytes; i++) {
|
||||||
|
//printf("fake_memcpy %ld\n", i);
|
||||||
|
cdst[i] = csrc[i];
|
||||||
|
}
|
||||||
|
//printf("fake_memcpy done!\n");
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* memset(void* mem, int byt, size_t nbytes);
|
||||||
|
|
||||||
|
/* From ifndef at top of file: */
|
||||||
|
#endif
|
0
fakelibc/sys/resource.h
Normal file
0
fakelibc/sys/resource.h
Normal file
50
fakelibc/sys/stat.h
Normal file
50
fakelibc/sys/stat.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#ifndef _FAKELIBC_SYS_STAT_H
|
||||||
|
#define _FAKELIBC_SYS_STAT_H
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
/* This is currently designed to match x86-64 definitions for Linux. They probably don't
|
||||||
|
* differ a lot across architectures (besides differences between 32-/64-bit builds)
|
||||||
|
* but the standard definitions on Linux are unusually cryptic, some of the typedefs
|
||||||
|
* involve 3 or more nested macros spread out across all sorts of includes, so using
|
||||||
|
* them as a reference feels a bit ridiculous.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define st_mtime st_mtim.tv_sec
|
||||||
|
#define st_atime st_atim.tv_sec
|
||||||
|
#define st_ctime st_ctim.tv_sec
|
||||||
|
|
||||||
|
typedef unsigned int ino_t;
|
||||||
|
typedef unsigned int mode_t;
|
||||||
|
typedef unsigned int uid_t;
|
||||||
|
typedef unsigned int gid_t;
|
||||||
|
typedef unsigned long dev_t;
|
||||||
|
typedef unsigned long nlink_t;
|
||||||
|
|
||||||
|
struct stat {
|
||||||
|
dev_t st_dev;
|
||||||
|
ino_t st_ino;
|
||||||
|
|
||||||
|
nlink_t st_nlink;
|
||||||
|
mode_t st_mode;
|
||||||
|
|
||||||
|
uid_t st_uid;
|
||||||
|
gid_t st_gid;
|
||||||
|
int __padding_A;
|
||||||
|
|
||||||
|
dev_t st_rdev;
|
||||||
|
long st_size;
|
||||||
|
long st_blocksize;
|
||||||
|
long st_blocks;
|
||||||
|
|
||||||
|
struct timespec st_atim;
|
||||||
|
struct timespec st_mtim;
|
||||||
|
struct timespec st_ctim;
|
||||||
|
|
||||||
|
long __reserved_A;
|
||||||
|
long __reserved_B;
|
||||||
|
long __reserved_C;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* From ifndef at top of file: */
|
||||||
|
#endif
|
0
fakelibc/sys/time.h
Normal file
0
fakelibc/sys/time.h
Normal file
0
fakelibc/sys/types.h
Normal file
0
fakelibc/sys/types.h
Normal file
29
fakelibc/time.h
Normal file
29
fakelibc/time.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#ifndef _FAKELIBC_TIME_H
|
||||||
|
#define _FAKELIBC_TIME_H
|
||||||
|
|
||||||
|
typedef long time_t;
|
||||||
|
|
||||||
|
char* ctime(const time_t* timevar);
|
||||||
|
|
||||||
|
/* TODO: Check if modern systems add any more fields. */
|
||||||
|
struct tm {
|
||||||
|
int tm_sec;
|
||||||
|
int tm_min;
|
||||||
|
int tm_hour;
|
||||||
|
int tm_mday;
|
||||||
|
int tm_mon;
|
||||||
|
int tm_year;
|
||||||
|
int tm_wday;
|
||||||
|
int tm_yday;
|
||||||
|
int tm_isdst;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct timespec {
|
||||||
|
int tv_sec;
|
||||||
|
long tv_nsec;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tm* localtime(const time_t* timep);
|
||||||
|
|
||||||
|
/* From ifndef at top of file: */
|
||||||
|
#endif
|
0
fakelibc/unistd.h
Normal file
0
fakelibc/unistd.h
Normal file
0
fakelibc/utime.h
Normal file
0
fakelibc/utime.h
Normal file
913
frontend.c
Normal file
913
frontend.c
Normal file
@ -0,0 +1,913 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <process.h> // 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);
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user