Unified · Split
| @@ -855,6 +855,29 @@ LIBTCCAPI void tcc_delete(TCCState *s1) · 854 unmodified lines | ||
| 855 | 855 | #endif |
| 856 | 856 | } |
| 857 | 857 | |
| 858 | +/* Looks for the active developer SDK set by xcode-select (or the default | |
| 859 | + one set during installation.) */ | |
| 860 | +#define SZPAIR(s) s "", sizeof(s)-1 | |
| 861 | +ST_FUNC int tcc_add_macos_sdkpath(TCCState* s) | |
| 862 | +{ | |
| 863 | + char *sdkroot = NULL, *pos = NULL; | |
| 864 | + void* xcs = dlopen("libxcselect.dylib", RTLD_GLOBAL | RTLD_LAZY); | |
| 865 | + CString path = {}; | |
| 866 | + int (*f)(unsigned int, char**) = dlsym(xcs, "xcselect_host_sdk_path"); | |
| 867 | + | |
| 868 | + if (f) f(1, &sdkroot); | |
| 869 | + if (!sdkroot) return -1; | |
| 870 | + pos = strstr(sdkroot,"SDKs/MacOSX"); | |
| 871 | + if (!pos) return -1; | |
| 872 | + cstr_cat(&path, sdkroot, pos-sdkroot); | |
| 873 | + cstr_cat(&path, SZPAIR("SDKs/MacOSX.sdk/usr/lib\0") ); | |
| 874 | + tcc_add_library_path(s, (char*)path.data); | |
| 875 | + cstr_free(&path); | |
| 876 | + tcc_free(sdkroot); | |
| 877 | + return 0; | |
| 878 | +} | |
| 879 | +#undef SZPAIR | |
| 880 | + | |
| 858 | 881 | LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type) |
| 859 | 882 | { |
| 860 | 883 | s->output_type = output_type; |
| @@ -881,7 +904,11 @@ LIBTCCAPI int tcc_set_output_type(TCCState *s, int output_type) · 20 unmodified lines | ||
| 881 | 904 | } |
| 882 | 905 | |
| 883 | 906 | tcc_add_library_path(s, CONFIG_TCC_LIBPATHS); |
| 884 | − | |
| 907 | +#ifdef TCC_TARGET_MACHO | |
| 908 | + if (tcc_add_macos_sdkpath(s) != 0) { | |
| 909 | + tcc_add_library_path(s, CONFIG_OSX_SDK_FALLBACK); | |
| 910 | + } | |
| 911 | +#endif | |
| 885 | 912 | #ifdef TCC_TARGET_PE |
| 886 | 913 | # ifdef _WIN32 |
| 887 | 914 | if (!s->nostdlib && output_type != TCC_OUTPUT_OBJ) |
| @@ -979,6 +1006,10 @@ static int tcc_glob_so(TCCState *s1, const char *pattern, char *buf, int size) · 91 unmodified lines | ||
| 979 | 1006 | } |
| 980 | 1007 | #endif |
| 981 | 1008 | |
| 1009 | +#ifdef TCC_TARGET_MACHO | |
| 1010 | +ST_FUNC const char* macho_tbd_soname(const char* filename); | |
| 1011 | +#endif | |
| 1012 | + | |
| 982 | 1013 | ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) |
| 983 | 1014 | { |
| 984 | 1015 | int fd, ret = -1; |
| @@ -1006,7 +1037,9 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) · 21 unmodified lines | ||
| 1006 | 1037 | lseek(fd, 0, SEEK_SET); |
| 1007 | 1038 | |
| 1008 | 1039 | #ifdef TCC_TARGET_MACHO |
| 1009 | − if (0 == obj_type && 0 == strcmp(tcc_fileextension(filename), ".dylib")) | |
| 1040 | + if (0 == obj_type | |
| 1041 | + && (0 == strcmp(tcc_fileextension(filename), ".dylib") | |
| 1042 | + || 0 == strcmp(tcc_fileextension(filename), ".tbd"))) | |
| 1010 | 1043 | obj_type = AFF_BINTYPE_DYN; |
| 1011 | 1044 | #endif |
| 1012 | 1045 | |
| @@ -1027,9 +1060,15 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) · 14 unmodified lines | ||
| 1027 | 1060 | case AFF_BINTYPE_DYN: |
| 1028 | 1061 | if (s1->output_type == TCC_OUTPUT_MEMORY) { |
| 1029 | 1062 | #ifdef TCC_IS_NATIVE |
| 1030 | − void *dl = dlopen(filename, RTLD_GLOBAL | RTLD_LAZY); | |
| 1063 | + void* dl; | |
| 1064 | + const char* soname = filename; | |
| 1065 | +# ifdef TCC_TARGET_MACHO | |
| 1066 | + if (!strcmp(tcc_fileextension(filename), ".tbd")) | |
| 1067 | + soname = macho_tbd_soname(filename); | |
| 1068 | +# endif | |
| 1069 | + dl = dlopen(soname, RTLD_GLOBAL | RTLD_LAZY); | |
| 1031 | 1070 | if (dl) { |
| 1032 | − tcc_add_dllref(s1, filename)->handle = dl; | |
| 1071 | + tcc_add_dllref(s1, soname)->handle = dl; | |
| 1033 | 1072 | ret = 0; |
| 1034 | 1073 | } |
| 1035 | 1074 | #endif |
| @@ -1142,8 +1181,8 @@ LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname) · 106 unmodified lines | ||
| 1142 | 1181 | static const char * const libs[] = { "%s/%s.def", "%s/lib%s.def", "%s/%s.dll", "%s/lib%s.dll", "%s/lib%s.a", NULL }; |
| 1143 | 1182 | const char * const *pp = s->static_link ? libs + 4 : libs; |
| 1144 | 1183 | #elif defined TCC_TARGET_MACHO |
| 1145 | − static const char * const libs[] = { "%s/lib%s.dylib", "%s/lib%s.a", NULL }; | |
| 1146 | − const char * const *pp = s->static_link ? libs + 1 : libs; | |
| 1184 | + static const char * const libs[] = { "%s/lib%s.dylib", "%s/lib%s.tbd", "%s/lib%s.a", NULL }; | |
| 1185 | + const char * const *pp = s->static_link ? libs + 2 : libs; | |
| 1147 | 1186 | #elif defined TARGETOS_OpenBSD |
| 1148 | 1187 | static const char * const libs[] = { "%s/lib%s.so.*", "%s/lib%s.a", NULL }; |
| 1149 | 1188 | const char * const *pp = s->static_link ? libs + 1 : libs; |
| @@ -42,6 +42,7 @@ · 41 unmodified lines | ||
| 42 | 42 | #ifndef _WIN32 |
| 43 | 43 | # include <unistd.h> |
| 44 | 44 | # include <sys/time.h> |
| 45 | +# include <sys/stat.h> | |
| 45 | 46 | # ifndef CONFIG_TCC_STATIC |
| 46 | 47 | # include <dlfcn.h> |
| 47 | 48 | # endif |
| @@ -278,6 +279,15 @@ extern long double strtold (const char *__nptr, char **__endptr); · 230 unmodified lines | ||
| 278 | 279 | ALSO_TRIPLET(CONFIG_SYSROOT "/usr/" CONFIG_LDDIR) \ |
| 279 | 280 | ":" ALSO_TRIPLET(CONFIG_SYSROOT "/" CONFIG_LDDIR) \ |
| 280 | 281 | ":" ALSO_TRIPLET(CONFIG_SYSROOT "/usr/local/" CONFIG_LDDIR) |
| 282 | +# ifdef TCC_TARGET_MACHO | |
| 283 | +# define CONFIG_OSX_SDK1 \ | |
| 284 | + "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk" | |
| 285 | +# define CONFIG_OSX_SDK2 \ | |
| 286 | + "/Applications/Xcode.app/Developer/SDKs/MacOSX.sdk" | |
| 287 | +# define CONFIG_OSX_SDK_FALLBACK \ | |
| 288 | + ALSO_TRIPLET(CONFIG_OSX_SDK1 "/usr/" CONFIG_LDDIR) \ | |
| 289 | + ":" ALSO_TRIPLET(CONFIG_OSX_SDK2 "/usr/" CONFIG_LDDIR) | |
| 290 | +# endif | |
| 281 | 291 | # endif |
| 282 | 292 | #endif |
| 283 | 293 | |
| @@ -837,7 +837,102 @@ static uint32_t macho_swap32(uint32_t x) · 836 unmodified lines | ||
| 837 | 837 | } |
| 838 | 838 | #define SWAP(x) (swap ? macho_swap32(x) : (x)) |
| 839 | 839 | |
| 840 | −ST_FUNC int macho_load_dll(TCCState *s1, int fd, const char *filename, int lev) | |
| 840 | +ST_FUNC int macho_add_dllref(TCCState* s1, int lev, const char* soname) | |
| 841 | +{ | |
| 842 | + /* if the dll is already loaded, do not load it */ | |
| 843 | + DLLReference *dllref; | |
| 844 | + int i; | |
| 845 | + for(i = 0; i < s1->nb_loaded_dlls; i++) { | |
| 846 | + dllref = s1->loaded_dlls[i]; | |
| 847 | + if (!strcmp(soname, dllref->name)) { | |
| 848 | + /* but update level if needed */ | |
| 849 | + if (lev < dllref->level) | |
| 850 | + dllref->level = lev; | |
| 851 | + return -1; | |
| 852 | + } | |
| 853 | + } | |
| 854 | + dllref = tcc_mallocz(sizeof(DLLReference) + strlen(soname)); | |
| 855 | + dllref->level = lev; | |
| 856 | + strcpy(dllref->name, soname); | |
| 857 | + dynarray_add(&s1->loaded_dlls, &s1->nb_loaded_dlls, dllref); | |
| 858 | + return 0; | |
| 859 | +} | |
| 860 | + | |
| 861 | +#define tbd_parse_movepast(s) \ | |
| 862 | + (pos = (pos = strstr(pos, s)) ? pos + strlen(s) : NULL) | |
| 863 | +#define tbd_parse_movetoany(cs) (pos = strpbrk(pos, cs)) | |
| 864 | +#define tbd_parse_skipws while (*pos && (*pos==' '||*pos=='\n')) ++pos | |
| 865 | +#define tbd_parse_tramplequote if(*pos=='\''||*pos=='"') tbd_parse_trample | |
| 866 | +#define tbd_parse_tramplespace if(*pos==' ') tbd_parse_trample | |
| 867 | +#define tbd_parse_trample *pos++=0 | |
| 868 | + | |
| 869 | +ST_FUNC const char* macho_tbd_soname(const char* filename) { | |
| 870 | + char *soname, *data, *pos, *ret; | |
| 871 | + struct stat sb; | |
| 872 | + int fd = open(filename,O_RDONLY); | |
| 873 | + if (fd<0) return filename; | |
| 874 | + fstat(fd,&sb); | |
| 875 | + data = load_data(fd, 0, sb.st_size+1); | |
| 876 | + data[sb.st_size]=0; | |
| 877 | + pos = data; | |
| 878 | + | |
| 879 | + if (!tbd_parse_movepast("install-name: ")) return filename; | |
| 880 | + tbd_parse_skipws; | |
| 881 | + tbd_parse_tramplequote; | |
| 882 | + soname = pos; | |
| 883 | + if (!tbd_parse_movetoany("\n \"'")) return filename; | |
| 884 | + tbd_parse_trample; | |
| 885 | + ret = tcc_mallocz(strlen(soname)+1); | |
| 886 | + strcpy(ret, soname); | |
| 887 | + // soname = strdup(soname); | |
| 888 | + tcc_free(data); | |
| 889 | + return ret; | |
| 890 | +} | |
| 891 | + | |
| 892 | +ST_FUNC int macho_load_tbd(TCCState* s1, int fd, const char* filename, int lev) | |
| 893 | +{ | |
| 894 | + char *soname, *data, *pos; | |
| 895 | + | |
| 896 | + struct stat sb; | |
| 897 | + fstat(fd,&sb); | |
| 898 | + data = load_data(fd, 0, sb.st_size+1); | |
| 899 | + data[sb.st_size]=0; | |
| 900 | + pos = data; | |
| 901 | + | |
| 902 | + if (!tbd_parse_movepast("install-name: ")) return -1; | |
| 903 | + tbd_parse_skipws; | |
| 904 | + tbd_parse_tramplequote; | |
| 905 | + soname = pos; | |
| 906 | + if (!tbd_parse_movetoany("\n \"'")) return -1; | |
| 907 | + tbd_parse_trample; | |
| 908 | + if (macho_add_dllref(s1, lev, soname) != 0) goto the_end; | |
| 909 | + | |
| 910 | + while(pos) { | |
| 911 | + char* sym = NULL; | |
| 912 | + int cont = 1; | |
| 913 | + if (!tbd_parse_movepast("symbols: ")) break; | |
| 914 | + if (!tbd_parse_movepast("[")) break; | |
| 915 | + while (cont) { | |
| 916 | + tbd_parse_skipws; | |
| 917 | + tbd_parse_tramplequote; | |
| 918 | + sym = pos; | |
| 919 | + if (!tbd_parse_movetoany(",] \"'")) break; | |
| 920 | + tbd_parse_tramplequote; | |
| 921 | + tbd_parse_tramplespace; | |
| 922 | + tbd_parse_skipws; | |
| 923 | + if (*pos==0||*pos==']') cont=0; | |
| 924 | + tbd_parse_trample; | |
| 925 | + set_elf_sym(s1->dynsymtab_section, 0, 0, | |
| 926 | + ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, SHN_UNDEF, sym); | |
| 927 | + } | |
| 928 | + } | |
| 929 | + | |
| 930 | +the_end: | |
| 931 | + tcc_free(data); | |
| 932 | + return 0; | |
| 933 | +} | |
| 934 | + | |
| 935 | +ST_FUNC int macho_load_dylib(TCCState * s1, int fd, const char* filename, int lev) | |
| 841 | 936 | { |
| 842 | 937 | unsigned char buf[sizeof(struct mach_header_64)]; |
| 843 | 938 | void *buf2; |
| @@ -853,7 +948,6 @@ ST_FUNC int macho_load_dll(TCCState *s1, int fd, const char *filename, int lev) · 9 unmodified lines | ||
| 853 | 948 | uint32_t strsize = 0; |
| 854 | 949 | uint32_t iextdef = 0; |
| 855 | 950 | uint32_t nextdef = 0; |
| 856 | − DLLReference *dllref; | |
| 857 | 951 | |
| 858 | 952 | again: |
| 859 | 953 | if (full_read(fd, buf, sizeof(buf)) != sizeof(buf)) |
| @@ -934,20 +1028,8 @@ ST_FUNC int macho_load_dll(TCCState *s1, int fd, const char *filename, int lev) · 74 unmodified lines | ||
| 934 | 1028 | lc = (struct load_command*) ((char*)lc + lc->cmdsize); |
| 935 | 1029 | } |
| 936 | 1030 | |
| 937 | − /* if the dll is already loaded, do not load it */ | |
| 938 | − for(i = 0; i < s1->nb_loaded_dlls; i++) { | |
| 939 | − dllref = s1->loaded_dlls[i]; | |
| 940 | − if (!strcmp(soname, dllref->name)) { | |
| 941 | − /* but update level if needed */ | |
| 942 | − if (lev < dllref->level) | |
| 943 | − dllref->level = lev; | |
| 944 | − goto the_end; | |
| 945 | − } | |
| 946 | − } | |
| 947 | − dllref = tcc_mallocz(sizeof(DLLReference) + strlen(soname)); | |
| 948 | − dllref->level = lev; | |
| 949 | − strcpy(dllref->name, soname); | |
| 950 | − dynarray_add(&s1->loaded_dlls, &s1->nb_loaded_dlls, dllref); | |
| 1031 | + if (0 != macho_add_dllref(s1, lev, soname)) | |
| 1032 | + goto the_end; | |
| 951 | 1033 | |
| 952 | 1034 | if (!nsyms || !nextdef) |
| 953 | 1035 | tcc_warning("%s doesn't export any symbols?", filename); |
| @@ -972,3 +1054,10 @@ ST_FUNC int macho_load_dll(TCCState *s1, int fd, const char *filename, int lev) · 18 unmodified lines | ||
| 972 | 1054 | tcc_free(buf2); |
| 973 | 1055 | return 0; |
| 974 | 1056 | } |
| 1057 | + | |
| 1058 | +ST_FUNC int macho_load_dll(TCCState * s1, int fd, const char* filename, int lev) | |
| 1059 | +{ | |
| 1060 | + return strcmp(tcc_fileextension(filename), ".tbd") == 0 | |
| 1061 | + ? macho_load_tbd(s1, fd, filename, lev) | |
| 1062 | + : macho_load_dylib(s1, fd, filename, lev); | |
| 1063 | +} | |