diff --git a/Makefile b/Makefile index 2a83a126..5ed0be4b 100644 --- a/Makefile +++ b/Makefile @@ -139,7 +139,7 @@ TCC_X += riscv64 # cross libtcc1.a targets to build LIBTCC1_X = i386 x86_64 i386-win32 x86_64-win32 x86_64-osx arm arm64 arm-wince -LIBTCC1_X += riscv64 +LIBTCC1_X += riscv64 arm64-osx PROGS_CROSS = $(foreach X,$(TCC_X),$X-tcc$(EXESUF)) LIBTCC1_CROSS = $(foreach X,$(LIBTCC1_X),$X-libtcc1.a) diff --git a/configure b/configure index 4c9e51e0..1618570c 100755 --- a/configure +++ b/configure @@ -47,28 +47,22 @@ gcc_major=0 gcc_minor=0 cc_name="gcc" ar_set= - -cpu=`uname -m` +darwin= +cpu= cpuver= # OS specific +cpu_sys=`uname -m` targetos=`uname` + case $targetos in Darwin) + darwin=yes confvars="$confvars OSX dll=no" cc=`which cc` cc=`readlink $cc || echo clang` tcc_usrinclude="`xcrun --show-sdk-path`/usr/include" DLLSUF=".dylib" - case $cpu in - arm64) - # We cannot yet build a native arm64 version, - # Use x86_64 and count on Rosetta to make the job. - cpu=x86_64 - CFLAGS="$CFLAGS -arch $cpu" - LDFLAGS="$LDFLAGS -arch $cpu" - ;; - esac ;; Windows_NT|MINGW*|MSYS*|CYGWIN*) mingw32=yes @@ -169,6 +163,18 @@ done cc="${cross_prefix}${cc}" ar="${cross_prefix}${ar}" +# Checking for CFLAGS +test -z "$CFLAGS" && CFLAGS="-Wall -O2" + +# on OSX M1 with --cpu=x86_64, build a tcc to run under rosetta entirely +if test "$darwin" = "yes" -a "$cpu" = "x86_64" -a "$cpu_sys" = "arm64"; then + CFLAGS="$CFLAGS -arch $cpu" + LDFLAGS="$LDFLAGS -arch $cpu" +fi + +# checking for cpu +test -z "$cpu" && cpu="$cpu_sys" + case "$cpu" in x86|i386|i486|i586|i686|i86pc|BePC|i686-AT386) cpu="i386" @@ -227,11 +233,6 @@ case "$cpu" in ;; esac -# Checking for CFLAGS -if test -z "$CFLAGS"; then - CFLAGS="-Wall -O2" -fi - if test "$mingw32" = "yes" ; then if test "$source_path_used" = "no"; then source_path="." diff --git a/libtcc.c b/libtcc.c index 53f8fe5c..855550d4 100644 --- a/libtcc.c +++ b/libtcc.c @@ -855,53 +855,15 @@ LIBTCCAPI void tcc_delete(TCCState *s1) #endif } -#ifdef TCC_TARGET_MACHO -/* Looks for the active developer SDK set by xcode-select (or the default - one set during installation.) */ -#define SZPAIR(s) s "", sizeof(s)-1 -ST_FUNC int tcc_add_macos_sdkpath(TCCState* s) -{ -#if defined(_WIN32) - (void)s; - return -1; -#else - char *sdkroot = NULL, *pos = NULL; - void* xcs = dlopen("libxcselect.dylib", RTLD_GLOBAL | RTLD_LAZY); - CString path; - int (*f)(unsigned int, char**) = dlsym(xcs, "xcselect_host_sdk_path"); - - if (f) f(1, &sdkroot); - if (!sdkroot) return -1; - pos = strstr(sdkroot,"SDKs/MacOSX"); - if (!pos) return -1; - cstr_new(&path); - cstr_cat(&path, sdkroot, pos-sdkroot); - cstr_cat(&path, SZPAIR("SDKs/MacOSX.sdk/usr/lib\0") ); - tcc_add_library_path(s, (char*)path.data); - cstr_free(&path); -#ifndef MEM_DEBUG /* FIXME: How to use free() instead of tcc_free() */ - tcc_free(sdkroot); -#endif - return 0; -#endif -} -#undef SZPAIR -#endif - LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type) { s->output_type = output_type; - /* always elf for objects */ - if (output_type == TCC_OUTPUT_OBJ) - s->output_format = TCC_OUTPUT_FORMAT_ELF; - if (!s->nostdinc) { /* default include paths */ /* -isystem paths have already been handled */ tcc_add_sysinclude_path(s, CONFIG_TCC_SYSINCLUDEPATHS); } - #ifdef CONFIG_TCC_BCHECK if (s->do_bounds_check) { /* if bound checking, then add corresponding sections */ @@ -912,18 +874,29 @@ LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type) /* add debug sections */ tccelf_stab_new(s); } + if (output_type == TCC_OUTPUT_OBJ) { + /* always elf for objects */ + s->output_format = TCC_OUTPUT_FORMAT_ELF; + return 0; + } tcc_add_library_path(s, CONFIG_TCC_LIBPATHS); -#ifdef TCC_TARGET_MACHO - if (tcc_add_macos_sdkpath(s) != 0) { - tcc_add_library_path(s, CONFIG_OSX_SDK_FALLBACK); - } -#endif + #ifdef TCC_TARGET_PE # ifdef _WIN32 - if (!s->nostdlib && output_type != TCC_OUTPUT_OBJ) - tcc_add_systemdir(s); + /* allow linking with system dll's directly */ + tcc_add_systemdir(s); # endif + /* target PE has its own startup code in libtcc1.a */ + return 0; + +#elif defined TCC_TARGET_MACHO +# ifdef TCC_IS_NATIVE + tcc_add_macos_sdkpath(s); +# endif + /* Mach-O with LC_MAIN doesn't need any crt startup code. */ + return 0; + #else /* paths for crt objects */ tcc_split_path(s, &s->crt_paths, &s->nb_crt_paths, CONFIG_TCC_CRTPREFIX); @@ -957,16 +930,14 @@ LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type) tcc_add_crt(s, "crtbeginS.o"); else tcc_add_crt(s, "crtbegin.o"); -#elif TCC_TARGET_MACHO - /* Mach-O with LC_MAIN doesn't need any crt startup code. */ #else if (output_type != TCC_OUTPUT_DLL) tcc_add_crt(s, "crt1.o"); tcc_add_crt(s, "crti.o"); #endif } -#endif return 0; +#endif } LIBTCCAPI int tcc_add_include_path(TCCState *s, const char *pathname) @@ -981,7 +952,6 @@ LIBTCCAPI int tcc_add_sysinclude_path(TCCState *s, const char *pathname) return 0; } -#if !defined TCC_TARGET_MACHO || defined TCC_IS_NATIVE ST_FUNC DLLReference *tcc_add_dllref(TCCState *s1, const char *dllname) { DLLReference *ref = tcc_mallocz(sizeof(DLLReference) + strlen(dllname)); @@ -989,7 +959,6 @@ ST_FUNC DLLReference *tcc_add_dllref(TCCState *s1, const char *dllname) dynarray_add(&s1->loaded_dlls, &s1->nb_loaded_dlls, ref); return ref; } -#endif /* OpenBSD: choose latest from libxxx.so.x.y versions */ #if defined TARGETOS_OpenBSD && !defined _WIN32 @@ -1016,10 +985,6 @@ static int tcc_glob_so(TCCState *s1, const char *pattern, char *buf, int size) } #endif -#ifdef TCC_TARGET_MACHO -ST_FUNC const char* macho_tbd_soname(const char* filename); -#endif - ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) { int fd, ret = -1; @@ -1046,13 +1011,6 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) obj_type = tcc_object_type(fd, &ehdr); lseek(fd, 0, SEEK_SET); -#ifdef TCC_TARGET_MACHO - if (0 == obj_type - && (0 == strcmp(tcc_fileextension(filename), ".dylib") - || 0 == strcmp(tcc_fileextension(filename), ".tbd"))) - obj_type = AFF_BINTYPE_DYN; -#endif - switch (obj_type) { case AFF_BINTYPE_REL: @@ -1066,35 +1024,63 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) #ifdef TCC_TARGET_PE default: ret = pe_load_file(s1, fd, filename); -#else + goto check_success; + +#elif defined TCC_TARGET_MACHO case AFF_BINTYPE_DYN: + case_dyn_or_tbd: if (s1->output_type == TCC_OUTPUT_MEMORY) { #ifdef TCC_IS_NATIVE void* dl; const char* soname = filename; -# ifdef TCC_TARGET_MACHO - if (!strcmp(tcc_fileextension(filename), ".tbd")) + if (obj_type != AFF_BINTYPE_DYN) soname = macho_tbd_soname(filename); -# endif dl = dlopen(soname, RTLD_GLOBAL | RTLD_LAZY); - if (dl) { - tcc_add_dllref(s1, soname)->handle = dl; - ret = 0; - } -# ifdef TCC_TARGET_MACHO - if (strcmp(filename, soname)) + if (dl) + tcc_add_dllref(s1, soname)->handle = dl, ret = 0; + if (filename != soname) tcc_free((void *)soname); #endif -#endif - break; + } else if (obj_type == AFF_BINTYPE_DYN) { + ret = macho_load_dll(s1, fd, filename, (flags & AFF_REFERENCED_DLL) != 0); + } else { + ret = macho_load_tbd(s1, fd, filename, (flags & AFF_REFERENCED_DLL) != 0); } -#ifdef TCC_TARGET_MACHO - ret = macho_load_dll(s1, fd, filename, - (flags & AFF_REFERENCED_DLL) != 0); -#else - ret = tcc_load_dll(s1, fd, filename, - (flags & AFF_REFERENCED_DLL) != 0); + break; + default: + { + const char *ext = tcc_fileextension(filename); + if (!strcmp(ext, ".tbd")) + goto case_dyn_or_tbd; + if (!strcmp(ext, ".dylib")) { + obj_type = AFF_BINTYPE_DYN; + goto case_dyn_or_tbd; + } + goto check_success; + } + +#else /* unix */ + case AFF_BINTYPE_DYN: + if (s1->output_type == TCC_OUTPUT_MEMORY) { +#ifdef TCC_IS_NATIVE + void* dl = dlopen(filename, RTLD_GLOBAL | RTLD_LAZY); + if (dl) + tcc_add_dllref(s1, filename)->handle = dl, ret = 0; #endif + } else + ret = tcc_load_dll(s1, fd, filename, (flags & AFF_REFERENCED_DLL) != 0); + break; + + default: + /* as GNU ld, consider it is an ld script if not recognized */ + ret = tcc_load_ldscript(s1, fd); + goto check_success; + +#endif /* pe / macos / unix */ + +check_success: + if (ret < 0) + tcc_error_noabort("%s: unrecognized file type", filename); break; #ifdef TCC_TARGET_COFF @@ -1102,16 +1088,6 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) ret = tcc_load_coff(s1, fd); break; #endif - default: -#ifndef TCC_TARGET_MACHO - /* as GNU ld, consider it is an ld script if not recognized */ - ret = tcc_load_ldscript(s1, fd); -#endif - -#endif /* !TCC_TARGET_PE */ - if (ret < 0) - tcc_error_noabort("%s: unrecognized file type", filename); - break; } close(fd); } else { @@ -1708,13 +1684,20 @@ static int args_parser_make_argv(const char *r, int *argc, char ***argv) return ret; } +ST_FUNC char *tcc_load_text(int fd) +{ + int len = lseek(fd, 0, SEEK_END); + char *buf = load_data(fd, 0, len + 1); + buf[len] = 0; + return buf; +} + /* read list file */ static void args_parser_listfile(TCCState *s, const char *filename, int optind, int *pargc, char ***pargv) { TCCState *s1 = s; int fd, i; - size_t len; char *p; int argc = 0; char **argv = NULL; @@ -1723,10 +1706,7 @@ static void args_parser_listfile(TCCState *s, if (fd < 0) tcc_error("listfile '%s' not found", filename); - len = lseek(fd, 0, SEEK_END); - p = tcc_malloc(len + 1), p[len] = 0; - lseek(fd, 0, SEEK_SET), read(fd, p, len), close(fd); - + p = tcc_load_text(fd); for (i = 0; i < *pargc; ++i) if (i == optind) args_parser_make_argv(p, &argc, &argv); diff --git a/tcc.h b/tcc.h index cc8a2f82..890c8db6 100644 --- a/tcc.h +++ b/tcc.h @@ -42,7 +42,6 @@ #ifndef _WIN32 # include # include -# include # ifndef CONFIG_TCC_STATIC # include # endif @@ -183,7 +182,8 @@ extern long double strtold (const char *__nptr, char **__endptr); #endif /* only native compiler supports -run */ -#if defined _WIN32 == defined TCC_TARGET_PE +#if defined _WIN32 == defined TCC_TARGET_PE \ + && defined __APPLE__ == defined TCC_TARGET_MACHO # if defined __i386__ && defined TCC_TARGET_I386 # define TCC_IS_NATIVE # elif defined __x86_64__ && defined TCC_TARGET_X86_64 @@ -223,8 +223,11 @@ extern long double strtold (const char *__nptr, char **__endptr); # define ELF_OBJ_ONLY /* create elf .o but native executables */ #endif -/* No ten-byte long doubles on window except in cross-compilers made by GCC */ -#if defined TCC_TARGET_PE || (defined _WIN32 && !defined __GNUC__) +/* No ten-byte long doubles on window and macos except in + cross-compilers made by a mingw-GCC */ +#if defined TCC_TARGET_PE \ + || (defined TCC_TARGET_MACHO && defined TCC_TARGET_X86_64) \ + || (defined _WIN32 && !defined __GNUC__) # define TCC_USING_DOUBLE_FOR_LDOUBLE 1 #endif @@ -279,15 +282,6 @@ extern long double strtold (const char *__nptr, char **__endptr); ALSO_TRIPLET(CONFIG_SYSROOT "/usr/" CONFIG_LDDIR) \ ":" ALSO_TRIPLET(CONFIG_SYSROOT "/" CONFIG_LDDIR) \ ":" ALSO_TRIPLET(CONFIG_SYSROOT "/usr/local/" CONFIG_LDDIR) -# ifdef TCC_TARGET_MACHO -# define CONFIG_OSX_SDK1 \ - "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk" -# define CONFIG_OSX_SDK2 \ - "/Applications/Xcode.app/Developer/SDKs/MacOSX.sdk" -# define CONFIG_OSX_SDK_FALLBACK \ - ALSO_TRIPLET(CONFIG_OSX_SDK1 "/usr/" CONFIG_LDDIR) \ - ":" ALSO_TRIPLET(CONFIG_OSX_SDK2 "/usr/" CONFIG_LDDIR) -# endif # endif #endif @@ -1351,9 +1345,8 @@ PUB_FUNC int tcc_parse_args(TCCState *s, int *argc, char ***argv, int optind); #ifdef _WIN32 ST_FUNC char *normalize_slashes(char *path); #endif -#if !defined TCC_TARGET_MACHO || defined TCC_IS_NATIVE ST_FUNC DLLReference *tcc_add_dllref(TCCState *s1, const char *dllname); -#endif +ST_FUNC char *tcc_load_text(int fd); /* tcc_parse_args return codes: */ #define OPT_HELP 1 @@ -1814,6 +1807,11 @@ PUB_FUNC int tcc_get_dllexports(const char *filename, char **pp); #ifdef TCC_TARGET_MACHO ST_FUNC int macho_output_file(TCCState * s1, const char *filename); ST_FUNC int macho_load_dll(TCCState *s1, int fd, const char *filename, int lev); +ST_FUNC int macho_load_tbd(TCCState *s1, int fd, const char *filename, int lev); +#ifdef TCC_IS_NATIVE +ST_FUNC void tcc_add_macos_sdkpath(TCCState* s); +ST_FUNC const char* macho_tbd_soname(const char* filename); +#endif #endif /* ------------ tccrun.c ----------------- */ #ifdef TCC_IS_NATIVE diff --git a/tccgen.c b/tccgen.c index 833b7043..c36032ab 100644 --- a/tccgen.c +++ b/tccgen.c @@ -8093,11 +8093,6 @@ static void init_putv(init_params *p, CType *type, unsigned long c) else if (sizeof(double) == LDOUBLE_SIZE) memcpy(ptr, &vtop->c.ld, LDOUBLE_SIZE); #ifndef TCC_CROSS_TEST -#if defined(TCC_TARGET_MACHO) && defined(TCC_TARGET_X86_64) - /* Special case for Rosetta to handle --cpu=x86_64 on macOS */ - else if (sizeof(double) == sizeof(long double)) - memcpy(ptr, &vtop->c.ld, sizeof(double)); -#endif else tcc_error("can't cross compile long double constants"); #endif diff --git a/tccmacho.c b/tccmacho.c index bc0b0937..eb3d9d23 100644 --- a/tccmacho.c +++ b/tccmacho.c @@ -851,10 +851,7 @@ ST_FUNC int macho_add_dllref(TCCState* s1, int lev, const char* soname) return -1; } } - dllref = tcc_mallocz(sizeof(DLLReference) + strlen(soname)); - dllref->level = lev; - strcpy(dllref->name, soname); - dynarray_add(&s1->loaded_dlls, &s1->nb_loaded_dlls, dllref); + tcc_add_dllref(s1, soname)->level = lev; return 0; } @@ -866,47 +863,70 @@ ST_FUNC int macho_add_dllref(TCCState* s1, int lev, const char* soname) #define tbd_parse_tramplespace if(*pos==' ') tbd_parse_trample #define tbd_parse_trample *pos++=0 -ST_FUNC const char* macho_tbd_soname(const char* filename) { - char *soname, *data, *pos, *ret; - struct stat sb; - int fd = open(filename,O_RDONLY); - if (fd<0) return filename; - fstat(fd,&sb); - data = load_data(fd, 0, sb.st_size+1); - data[sb.st_size]=0; - pos = data; +#ifdef TCC_IS_NATIVE +/* Looks for the active developer SDK set by xcode-select (or the default + one set during installation.) */ +ST_FUNC void tcc_add_macos_sdkpath(TCCState* s) +{ + char *sdkroot = NULL, *pos = NULL; + void* xcs = dlopen("libxcselect.dylib", RTLD_GLOBAL | RTLD_LAZY); + CString path; + int (*f)(unsigned int, char**) = dlsym(xcs, "xcselect_host_sdk_path"); + cstr_new(&path); + if (f) f(1, &sdkroot); + if (sdkroot) + pos = strstr(sdkroot,"SDKs/MacOSX"); + if (pos) + cstr_printf(&path, "%.*s.sdk/usr/lib", pos - sdkroot + 11, sdkroot); + /* must use free from libc directly */ +#pragma push_macro("free") +#undef free + free(sdkroot); +#pragma pop_macro("free") + if (path.size) + tcc_add_library_path(s, (char*)path.data); + else + tcc_add_library_path(s, + "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib" + ":" "/Applications/Xcode.app/Developer/SDKs/MacOSX.sdk/usr/lib" + ); + cstr_free(&path); +} - if (!tbd_parse_movepast("install-name: ")) return filename; +ST_FUNC const char* macho_tbd_soname(const char* filename) { + char *soname, *data, *pos; + const char *ret = filename; + + int fd = open(filename,O_RDONLY); + if (fd<0) return ret; + pos = data = tcc_load_text(fd); + if (!tbd_parse_movepast("install-name: ")) goto the_end; tbd_parse_skipws; tbd_parse_tramplequote; soname = pos; - if (!tbd_parse_movetoany("\n \"'")) return filename; + if (!tbd_parse_movetoany("\n \"'")) goto the_end; tbd_parse_trample; - ret = tcc_mallocz(strlen(soname)+1); - strcpy(ret, soname); - // soname = strdup(soname); + ret = tcc_strdup(soname); +the_end: tcc_free(data); return ret; } +#endif /* TCC_IS_NATIVE */ ST_FUNC int macho_load_tbd(TCCState* s1, int fd, const char* filename, int lev) { char *soname, *data, *pos; + int ret = -1; - struct stat sb; - fstat(fd,&sb); - data = load_data(fd, 0, sb.st_size+1); - data[sb.st_size]=0; - pos = data; - - if (!tbd_parse_movepast("install-name: ")) return -1; + pos = data = tcc_load_text(fd); + if (!tbd_parse_movepast("install-name: ")) goto the_end; tbd_parse_skipws; tbd_parse_tramplequote; soname = pos; - if (!tbd_parse_movetoany("\n \"'")) return -1; + if (!tbd_parse_movetoany("\n \"'")) goto the_end; tbd_parse_trample; + ret = 0; if (macho_add_dllref(s1, lev, soname) != 0) goto the_end; - while(pos) { char* sym = NULL; int cont = 1; @@ -929,10 +949,10 @@ ST_FUNC int macho_load_tbd(TCCState* s1, int fd, const char* filename, int lev) the_end: tcc_free(data); - return 0; + return ret; } -ST_FUNC int macho_load_dylib(TCCState * s1, int fd, const char* filename, int lev) +ST_FUNC int macho_load_dll(TCCState * s1, int fd, const char* filename, int lev) { unsigned char buf[sizeof(struct mach_header_64)]; void *buf2; @@ -1054,10 +1074,3 @@ ST_FUNC int macho_load_dylib(TCCState * s1, int fd, const char* filename, int le tcc_free(buf2); return 0; } - -ST_FUNC int macho_load_dll(TCCState * s1, int fd, const char* filename, int lev) -{ - return strcmp(tcc_fileextension(filename), ".tbd") == 0 - ? macho_load_tbd(s1, fd, filename, lev) - : macho_load_dylib(s1, fd, filename, lev); -} diff --git a/tccpp.c b/tccpp.c index e5bff784..cb56781d 100644 --- a/tccpp.c +++ b/tccpp.c @@ -2465,7 +2465,7 @@ static void parse_number(const char *p) tokc.f = (float)d; } else if (t == 'L') { ch = *p++; -#ifdef TCC_TARGET_PE +#ifdef TCC_USING_DOUBLE_FOR_LDOUBLE tok = TOK_CDOUBLE; tokc.d = d; #else @@ -2521,7 +2521,7 @@ static void parse_number(const char *p) tokc.f = strtof(token_buf, NULL); } else if (t == 'L') { ch = *p++; -#ifdef TCC_TARGET_PE +#ifdef TCC_USING_DOUBLE_FOR_LDOUBLE tok = TOK_CDOUBLE; tokc.d = strtod(token_buf, NULL); #else diff --git a/tests/Makefile b/tests/Makefile index 56a2832a..8cc2e36c 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -281,15 +281,13 @@ cross-test : tcctest.c examples/ex3.c @echo ------------ $@ ------------ $(foreach T,$(CROSS-TGTS),$(call CROSS-COMPILE,$T)) -CROSS-MACOS= # x86_64-osx - CROSS-TGTS = \ i386 \ i386-win32 \ i386-OpenBSD \ x86_64 \ x86_64-win32 \ - $(CROSS-MACOS) \ + x86_64-osx \ x86_64-FreeBSD \ x86_64-NetBSD \ x86_64-OpenBSD \ @@ -298,6 +296,7 @@ CROSS-TGTS = \ arm-NetBSD \ arm-wince \ arm64 \ + arm64-osx \ arm64-FreeBSD \ arm64-NetBSD \ arm64-OpenBSD \