diff --git a/build/embed-asset-path.sh b/build/embed-asset-path.sh index cf7005c..5d3043c 100644 --- a/build/embed-asset-path.sh +++ b/build/embed-asset-path.sh @@ -69,7 +69,7 @@ cat <> src/assets.c snprintf(incpath,511,"%s/%s",CJIT->tmpdir,"${name}"); if(CJIT->fresh) res = muntargz_to_path(CJIT->tmpdir,(const uint8_t*)&${varname},${varname}_len); if(res!=0) { _err("Error extracting %s",incpath); return(false); } -tcc_add_include_path(CJIT->TCC, incpath); +cjit_add_include_path(CJIT, incpath); // ^^ ${name} ^^ EOF diff --git a/build/init.mk b/build/init.mk index 877225d..75d33db 100644 --- a/build/init.mk +++ b/build/init.mk @@ -17,7 +17,7 @@ cflags := ${CFLAGS} ${cflags_includes} SOURCES := src/file.o src/cjit.o \ src/main.o src/assets.o \ - src/cwalk.o src/repl.o \ + src/cwalk.o \ src/muntar.o src/tinflate.o src/tinfgzip.o \ src/embed_libtcc1.a.o src/embed_include.o #src/embed_source.o diff --git a/src/cjit.c b/src/cjit.c index f652bbe..8f8c436 100644 --- a/src/cjit.c +++ b/src/cjit.c @@ -35,6 +35,9 @@ #define MAX_PATH 260 // rather short paths #define MAX_STRING 20480 // max 20KiB strings +#define tcc(cjit) (TCCState*)cjit->TCC +#define setup if(!cjit->done_setup)cjit_setup(cjit) +#define debug(fmt,par) if(!cjit->quiet)_err(fmt,par) // declared at bottom void _out(const char *fmt, ...); void _err(const char *fmt, ...); @@ -117,7 +120,7 @@ CJITState* cjit_new() { } // instantiate TCC before extracting assets because // extract_assets() will also add include paths using TCC - cjit->TCC = tcc_new(); + cjit->TCC = (void*)tcc_new(); if (!cjit->TCC) { _err("CJIT: Could not initialize tinyCC"); free(cjit); @@ -132,65 +135,65 @@ CJITState* cjit_new() { return(NULL); } // error handler callback for TCC - tcc_set_error_func(cjit->TCC, stderr, cjit_tcc_handle_error); + tcc_set_error_func(tcc(cjit), stderr, cjit_tcc_handle_error); return(cjit); } -bool cjit_setup(CJITState *cjit) { +static bool cjit_setup(CJITState *cjit) { // set output in memory for just in time execution if(cjit->done_setup) { _err("Warning: cjit_setup called twice or more times"); return(true); } - tcc_set_output_type(cjit->TCC, cjit->tcc_output); + tcc_set_output_type(tcc(cjit), cjit->tcc_output); #if defined(LIBC_MUSL) - tcc_add_libc_symbols(cjit->TCC); + tcc_add_libc_symbols(tcc(cjit)); #endif if(getenv("CFLAGS")) { char *extra_cflags = NULL; extra_cflags = getenv("CFLAGS"); _err("CFLAGS: %s",extra_cflags); - tcc_set_options(cjit->TCC, extra_cflags); + tcc_set_options(tcc(cjit), extra_cflags); } #if defined(_WIN32) // add symbols for windows compatibility - tcc_add_symbol(cjit->TCC, "usleep", &win_compat_usleep); - tcc_add_symbol(cjit->TCC, "getline", &win_compat_getline); + tcc_add_symbol(tcc(cjit), "usleep", &win_compat_usleep); + tcc_add_symbol(tcc(cjit), "getline", &win_compat_getline); #endif // When using SDL2 these defines are needed - tcc_define_symbol(cjit->TCC,"SDL_DISABLE_IMMINTRIN_H",NULL); - tcc_define_symbol(cjit->TCC,"SDL_MAIN_HANDLED",NULL); + tcc_define_symbol(tcc(cjit),"SDL_DISABLE_IMMINTRIN_H",NULL); + tcc_define_symbol(tcc(cjit),"SDL_MAIN_HANDLED",NULL); // where is libtcc1.a found - tcc_add_library_path(cjit->TCC, cjit->tmpdir); + tcc_add_library_path(tcc(cjit), cjit->tmpdir); // tcc_set_lib_path(TCC,tmpdir); // this overrides all? - tcc_add_sysinclude_path(cjit->TCC, cjit->tmpdir); - tcc_add_sysinclude_path(cjit->TCC, "."); - tcc_add_sysinclude_path(cjit->TCC, "include"); - tcc_add_library_path(cjit->TCC, "."); + tcc_add_sysinclude_path(tcc(cjit), cjit->tmpdir); + tcc_add_sysinclude_path(tcc(cjit), "."); + tcc_add_sysinclude_path(tcc(cjit), "include"); + tcc_add_library_path(tcc(cjit), "."); #if defined(_WIN32) { // windows system32 libraries //tcc_add_library_path(TCC, "C:\\Windows\\System32") // 64bit - tcc_add_library_path(cjit->TCC, "C:\\Windows\\SysWOW64"); + tcc_add_library_path(tcc(cjit), "C:\\Windows\\SysWOW64"); // tinycc win32 headers char *tpath = malloc(strlen(cjit->tmpdir)+32); strcpy(tpath,cjit->tmpdir); strcat(tpath,"/tinycc_win32/winapi"); - tcc_add_sysinclude_path(cjit->TCC, tpath); + tcc_add_sysinclude_path(tcc(cjit), tpath); free(tpath); // windows SDK headers char *sdkpath = malloc(512); if( get_winsdkpath(sdkpath,511) ) { int pathend = strlen(sdkpath); strcpy(&sdkpath[pathend],"\\um"); // um/GL - tcc_add_sysinclude_path(cjit->TCC, sdkpath); + tcc_add_sysinclude_path(tcc(cjit), sdkpath); strcpy(&sdkpath[pathend],"\\shared"); // winapifamili.h etc. - tcc_add_sysinclude_path(cjit->TCC, sdkpath); + tcc_add_sysinclude_path(tcc(cjit), sdkpath); } free(sdkpath); } @@ -290,7 +293,14 @@ static int detect_bom(const char *filename,size_t *filesize) { } } -static bool cjit_add_source(CJITState *cjit, const char *path) { +bool cjit_add_buffer(CJITState *cjit, const char *buffer) { + setup; + tcc_compile_string(tcc(cjit),buffer); + debug("+B %p",buffer); +} + +bool cjit_add_source(CJITState *cjit, const char *path) { + setup; size_t length; int res = detect_bom(path,&length); if(res<0) { @@ -336,38 +346,37 @@ static bool cjit_add_source(CJITState *cjit, const char *path) { char *tmp = malloc(dirname+1); strncpy(tmp,path,dirname); tmp[dirname] = 0x0; - tcc_add_include_path(cjit->TCC,tmp); + tcc_add_include_path(tcc(cjit),tmp); free(tmp); } - tcc_compile_string(cjit->TCC,contents); + tcc_compile_string(tcc(cjit),contents); free(contents); + debug("+S %s",path); return true; } bool cjit_add_file(CJITState *cjit, const char *path) { - // _err("%s",__func__); + setup; int is_source = has_source_extension(path); if(is_source == 0) { // no extension, we still add - cjit_setup(cjit); - if(tcc_add_file(cjit->TCC, path)<0) { + if(tcc_add_file(tcc(cjit), path)<0) { _err("%s: tcc_add_file error: %s",__func__,path); return false; } return true; } if(is_source>0) { - cjit_setup(cjit); if(!cjit_add_source(cjit, path)) { _err("%s: error: %s",__func__,path); return false; } } else { - cjit_setup(cjit); - if(tcc_add_file(cjit->TCC, path)<0) { + if(tcc_add_file(tcc(cjit), path)<0) { _err("%s: tcc_add_file error: %s",__func__,path); return false; } } + debug("+F %s",path); return true; } @@ -384,13 +393,13 @@ bool cjit_compile_file(CJITState *cjit, const char *path) { __func__,path); return false; } - cjit_setup(cjit); - tcc_add_file(cjit->TCC, path); + setup; + tcc_add_file(tcc(cjit), path); if(cjit->output_filename) { if(!cjit->quiet) _err("Compiling: %s -> %s",path, cjit->output_filename); - tcc_output_file(cjit->TCC, + tcc_output_file(tcc(cjit), cjit->output_filename); } else { char *ext; @@ -405,13 +414,30 @@ bool cjit_compile_file(CJITState *cjit, const char *path) { strcpy(ext,".o"); if(!cjit->quiet) _err("Compiling: %s -> %s",path,tmp); - tcc_output_file(cjit->TCC,tmp); + tcc_output_file(tcc(cjit),tmp); free(tmp); } return true; } +// link all setup and create an executable file +int cjit_link(CJITState *cjit) { + if(!cjit->done_setup) { + _err("%s: no source code found",__func__); + return 1; + } + if(!cjit->output_filename) { + _err("%s: no output file configured (-o)",__func__); + return 1; + } + return( tcc_output_file(tcc(cjit),cjit->output_filename)); +} + int cjit_exec(CJITState *cjit, int argc, char **argv) { + if(!cjit->done_setup) { + _err("%s: no source code found",__func__); + return 1; + } if(cjit->done_exec) { _err("%s: CJIT already executed once",__func__); return 1; @@ -419,12 +445,12 @@ int cjit_exec(CJITState *cjit, int argc, char **argv) { int res = 1; int (*_ep)(int, char**); // relocate the code (link symbols) - if (tcc_relocate(cjit->TCC) < 0) { + if (tcc_relocate(tcc(cjit)) < 0) { _err("%s: TCC linker error",__func__); _err("Library functions missing."); return -1; } - _ep = tcc_get_symbol(cjit->TCC, cjit->entry?cjit->entry:"main"); + _ep = tcc_get_symbol(tcc(cjit), cjit->entry?cjit->entry:"main"); if (!_ep) { _err("Symbol not found in source: %s",cjit->entry?cjit->entry:"main"); return -1; @@ -494,11 +520,41 @@ void cjit_free(CJITState *cjit) { if(cjit->write_pid) free(cjit->write_pid); if(cjit->entry) free(cjit->entry); if(cjit->output_filename) free(cjit->output_filename); - if(cjit->TCC) tcc_delete(cjit->TCC); + if(cjit->TCC) tcc_delete(tcc(cjit)); free(cjit); } +// wrappers to make TCC opaque +void cjit_set_output(CJITState *cjit, int output) { + if(output>5 || output<1) + _err("%s: invalid output: %i",__func__,output); + else + cjit->tcc_output = output; +} +void cjit_define_symbol(CJITState *cjit, const char *sym, const char *value) { + tcc_define_symbol(tcc(cjit),sym,value); + if(!cjit->quiet)_err("+D %s",sym,value?value:""); +} +void cjit_add_include_path(CJITState *cjit, const char *path) { + tcc_add_include_path(tcc(cjit), path); + if(!cjit->quiet)_err("+I %s",path); +} +// TODO: temporary, to be reimplemented in linker.c +void cjit_add_library_path(CJITState *cjit, const char *path) { + tcc_add_library_path(tcc(cjit), path); + if(!cjit->quiet)_err("+L %s",path); +} +// TODO: temporary, to be reimplemented in linker.c +void cjit_add_library(CJITState *cjit, const char *path) { + tcc_add_library(tcc(cjit), path); + if(!cjit->quiet)_err("+l %s",path); +} +void cjit_set_tcc_options(CJITState *cjit, const char *opts) { + tcc_set_options(tcc(cjit),opts); + if(!cjit->quiet)_err("+O %s",opts); +} + // stdout message free from context void _out(const char *fmt, ...) { char msg[MAX_STRING+4]; diff --git a/src/cjit.h b/src/cjit.h index 9c8e12d..3d0eeec 100644 --- a/src/cjit.h +++ b/src/cjit.h @@ -22,11 +22,10 @@ #include #include -#include // passed to cjit_exec with CJIT execution parameters struct CJITState { - TCCState *TCC; // the tinyCC context + void *TCC; // the tinyCC context char *tmpdir; // path to execution temporary directory char *write_pid; // filename to write the pid of execution char *entry; // entry point, default "main" if left NULL @@ -47,15 +46,35 @@ struct CJITState { typedef struct CJITState CJITState; extern CJITState* cjit_new(); -extern bool cjit_setup(CJITState *cjit); +// extern bool cjit_setup(CJITState *cjit); extern bool cjit_status(CJITState *cjit); -extern bool cjit_compile_file(CJITState *cjit, const char *_path); + +// setup functions to add source and libs extern bool cjit_add_file(CJITState *cjit, const char *path); +extern bool cjit_add_source(CJITState *cjit, const char *path); +extern bool cjit_add_buffer(CJITState *cjit, const char *buffer); -extern int cjit_exec(CJITState *cjit, int argc, char **argv); +// end game functions +extern int cjit_link(CJITState *cjit); // link and create an executable file +extern int cjit_exec(CJITState *cjit, int argc, char **argv); // exec in mem +extern bool cjit_compile_file(CJITState *cjit, const char *_path); // compile a single file to a bytecode object extern void cjit_free(CJITState *CJIT); + +#define MEM 1 /* output will be run in memory */ +#define EXE 2 /* executable file */ +#define OBJ 3 /* object file */ +#define DLL 4 /* dynamic library */ +#define PRE 5 /* only preprocess */ +void cjit_set_output(CJITState *cjit, int output); + +void cjit_define_symbol(CJITState *cjit, const char *sym, const char *value); +void cjit_add_include_path(CJITState *cjit, const char *path); +void cjit_add_library_path(CJITState *cjit, const char *path); +void cjit_add_library(CJITState *cjit, const char *path); +void cjit_set_tcc_options(CJITState *cjit, const char *opts); + ///////////// // from embedded.c - generated at build time extern bool extract_assets(CJITState *CJIT); diff --git a/src/main.c b/src/main.c index 09168e6..55889d1 100644 --- a/src/main.c +++ b/src/main.c @@ -125,33 +125,33 @@ int main(int argc, char **argv) { int _res; _res = parse_value(opt.arg); if(_res==0) { // -Dsym (no key=value) - tcc_define_symbol(CJIT->TCC, opt.arg, NULL); + cjit_define_symbol(CJIT, opt.arg, NULL); } else if(_res>0) { // -Dkey=value - tcc_define_symbol(CJIT->TCC, opt.arg, &opt.arg[_res]); + cjit_define_symbol(CJIT, opt.arg, &opt.arg[_res]); } else { // invalid char _err("Invalid char used in -D define symbol: %s", opt.arg); cjit_free(CJIT); exit(1); } } else if (c == 'c') { // don't link or execute, just compile to .o - CJIT->tcc_output = TCC_OUTPUT_OBJ; + cjit_set_output(CJIT, OBJ); } else if (c == 'o') { // override output filename if(CJIT->output_filename) free(CJIT->output_filename); CJIT->output_filename = malloc(strlen(opt.arg)+1); strcpy(CJIT->output_filename,opt.arg); - CJIT->tcc_output = TCC_OUTPUT_EXE; + cjit_set_output(CJIT, EXE); } else if (c == 'L') { // library path if(!CJIT->quiet)_err("lib path: %s",opt.arg); - tcc_add_library_path(CJIT->TCC, opt.arg); + cjit_add_library_path(CJIT, opt.arg); } else if (c == 'l') { // library link if(!CJIT->quiet)_err("lib: %s",opt.arg); - tcc_add_library(CJIT->TCC, opt.arg); + cjit_add_library(CJIT, opt.arg); } else if (c == 'C') { // cflags compiler options if(!CJIT->quiet)_err("cflags: %s",opt.arg); - tcc_set_options(CJIT->TCC, opt.arg); + cjit_set_tcc_options(CJIT->TCC, opt.arg); } else if (c == 'I') { // include paths in cflags if(!CJIT->quiet)_err("inc: %s",opt.arg); - tcc_add_include_path(CJIT->TCC, opt.arg); + cjit_add_include_path(CJIT, opt.arg); } else if (c == 'e') { // entry point (default main) if(!CJIT->quiet)_err("entry: %s",opt.arg); if(CJIT->entry) free(CJIT->entry); @@ -194,6 +194,7 @@ int main(int argc, char **argv) { } if(!CJIT->quiet) _err("CJIT %s by Dyne.org",VERSION); +#if 0 // If no arguments then start the REPL if (argc == 0 ) { _err("No input file: interactive mode"); @@ -210,6 +211,7 @@ int main(int argc, char **argv) { } // end of REPL ///////////////////////////////////// +#endif // number of args at the left hand of arg separator, or all of them int left_args = arg_separator? arg_separator: argc; @@ -228,23 +230,22 @@ int main(int argc, char **argv) { _err("Error reading from standard input"); goto endgame; } - cjit_setup(CJIT); - if( tcc_compile_string(CJIT->TCC,stdin_code) < 0) { + if( cjit_add_buffer(CJIT->TCC,stdin_code) < 0) { _err("Code runtime error in stdin"); free(stdin_code); goto endgame; } + free(stdin_code); // end of STDIN //////////////// - } else if(CJIT->tcc_output==3) { + } else if(CJIT->tcc_output==OBJ) { ///////////////////////////// // Compile one .c file to .o if(left_args - opt.ind != 1) { _err("Compiling to object files supports only one file argument"); goto endgame; } - cjit_setup(CJIT); //if(!CJIT->quiet)_err("Compile: %s",argv[opt.ind]); res = cjit_compile_file(CJIT, argv[opt.ind]) ?0:1; // 0 on success goto endgame; @@ -267,8 +268,7 @@ int main(int argc, char **argv) { _err("Error reading from standard input"); goto endgame; } - cjit_setup(CJIT); - if( tcc_compile_string(CJIT->TCC,stdin_code) < 0) { + if( cjit_add_buffer(CJIT,stdin_code) < 0) { _err("Code runtime error in stdin"); free(stdin_code); goto endgame; @@ -283,8 +283,7 @@ int main(int argc, char **argv) { // compile to executable if(CJIT->output_filename) { _err("Create executable: %s", CJIT->output_filename); - cjit_setup(CJIT); - if(tcc_output_file(CJIT->TCC,CJIT->output_filename)<0) { + if(cjit_link(CJIT)<0) { _err("Error in linker compiling to file: %s", CJIT->output_filename); res = 1;