diff --git a/makefile b/makefile index 5e5b22ff4..50145e321 100644 --- a/makefile +++ b/makefile @@ -342,8 +342,13 @@ ifneq ($(filter 386 486 586 686 i386 i486 i586 i686,$(TARGET_ARCH)),) TARGET_ARCH := x86 endif -# Normalize TARGET_ARCH to arm -ifneq ($(filter arm%,$(TARGET_ARCH)),) +# Normalize TARGET_ARCH to aarch64 (macOS reports arm64) +ifneq ($(filter aarch64 arm64,$(TARGET_ARCH)),) + TARGET_ARCH := aarch64 +endif + +# Normalize TARGET_ARCH to arm (32-bit only, after aarch64 is handled) +ifneq ($(filter armv% arm,$(TARGET_ARCH)),) TARGET_ARCH := arm endif @@ -585,6 +590,10 @@ ifeq ($(TARGET_OS),darwin) ALLFBCFLAGS += -d ENABLE_XQUARTZ else ALLCFLAGS += -DDISABLE_X11 + # FB's OpenGL support lives in the X11 driver, so without XQuartz there is + # no GL driver at all. gfx_opengl.c otherwise still calls the driver hook + # fb_hGL_GetProcAddress(), leaving libfbgfx with an undefined symbol. + ALLCFLAGS += -DDISABLE_OPENGL endif endif diff --git a/src/compiler/ast-node-data.bas b/src/compiler/ast-node-data.bas index 9d3803e57..bd5bfc8c0 100644 --- a/src/compiler/ast-node-data.bas +++ b/src/compiler/ast-node-data.bas @@ -266,9 +266,20 @@ end function private sub hCreateDataDesc( ) static as FBARRAYDIM dTB(0) + dim as integer byalign + + '' Using FIELD = 1, to pack it as done by the rtlib -- except on Darwin, + '' where the linker requires pointer-sized relocations to be aligned to + '' the pointer size. A packed { short, void* } puts the DATA entries' + '' pointers at offset 2 (and every 10 bytes after that), which ld64 + '' rejects ("pointer not aligned ...", fatal on arm64). There the layout + '' must use the natural pointer alignment, matching src/rtlib/fb_data.h. + byalign = 1 + if( fbGetOption( FB_COMPOPT_TARGET ) = FB_COMPTARGET_DARWIN ) then + byalign = env.pointersize + end if - '' Using FIELD = 1, to pack it as done by the rtlib - ast.data.desc = symbStructBegin( NULL, NULL, NULL, "__FB_DATADESC$", NULL, FALSE, 1, FALSE, 0, 0 ) + ast.data.desc = symbStructBegin( NULL, NULL, NULL, "__FB_DATADESC$", NULL, FALSE, byalign, FALSE, 0, 0 ) '' type as short symbAddField( ast.data.desc, "type", 0, dTB(), _ diff --git a/src/compiler/fb.bas b/src/compiler/fb.bas index c050c49c1..23fd1b4a6 100644 --- a/src/compiler/fb.bas +++ b/src/compiler/fb.bas @@ -1768,7 +1768,15 @@ function fbGetBackendValistType _ typedef = FB_CVA_LIST_BUILTIN_ARM case FB_CPUFAMILY_AARCH64 - typedef = FB_CVA_LIST_BUILTIN_AARCH64 + select case env.clopt.target + case FB_COMPTARGET_DARWIN + '' Apple's arm64 ABI uses a plain pointer-like va_list (8 bytes, + '' sizeof(va_list) == sizeof(char*)), not the AAPCS64 + '' __va_list_tag struct that Linux/BSD aarch64 use. + typedef = FB_CVA_LIST_BUILTIN_POINTER + case else + typedef = FB_CVA_LIST_BUILTIN_AARCH64 + end select case FB_CPUFAMILY_PPC typedef = FB_CVA_LIST_BUILTIN_POINTER diff --git a/src/compiler/fbc.bas b/src/compiler/fbc.bas index 61b77df3f..b469e0474 100644 --- a/src/compiler/fbc.bas +++ b/src/compiler/fbc.bas @@ -258,7 +258,13 @@ private sub hSetOutName( ) select case( fbGetOption( FB_COMPOPT_TARGET ) ) case FB_COMPTARGET_CYGWIN, FB_COMPTARGET_WIN32 fbc.outname += ".dll" - case FB_COMPTARGET_LINUX, FB_COMPTARGET_DARWIN, _ + case FB_COMPTARGET_DARWIN + '' Mach-O shared libraries are .dylib; .so is the loadable + '' bundle extension, and fb_DylibLoad() looks for the .dylib + '' name first on Darwin. + fbc.outname = hStripFilename( fbc.outname ) + _ + "lib" + hStripPath( fbc.outname ) + ".dylib" + case FB_COMPTARGET_LINUX, _ FB_COMPTARGET_FREEBSD, FB_COMPTARGET_OPENBSD, _ FB_COMPTARGET_NETBSD, FB_COMPTARGET_DRAGONFLY, _ FB_COMPTARGET_SOLARIS, FB_COMPTARGET_ANDROID @@ -840,6 +846,8 @@ private function hLinkFiles( ) as integer case FB_CPUFAMILY_ARM '' fixme: this is clearly too specific ldcline += "-arch armv6 " + case FB_CPUFAMILY_AARCH64 + ldcline += "-arch arm64 " end select end select @@ -945,7 +953,13 @@ private function hLinkFiles( ) as integer if( fbGetOption( FB_COMPOPT_OUTTYPE ) = FB_OUTTYPE_DYNAMICLIB ) then dllname = hStripPath( hStripExt( fbc.outname ) ) - ldcline += " -shared -h" + hStripPath( fbc.outname ) + if( fbGetOption( FB_COMPOPT_TARGET ) = FB_COMPTARGET_DARWIN ) then + '' Darwin's linker (ld64) has no -shared/-h; it uses -dynamiclib + '' and records the install name via -install_name. + ldcline += " -dynamiclib -install_name " + QUOTE + dllname + QUOTE + else + ldcline += " -shared -h" + hStripPath( fbc.outname ) + end if '' Turn libfoo into foo, so it can be checked against -l foo below if( left( dllname, 3 ) = "lib" ) then @@ -987,7 +1001,13 @@ private function hLinkFiles( ) as integer if( (fbGetOption( FB_COMPOPT_OUTTYPE ) = FB_OUTTYPE_DYNAMICLIB) or _ fbGetOption( FB_COMPOPT_EXPORT ) ) and _ (fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_SOLARIS) then - ldcline += " --export-dynamic" + '' Darwin links through the clang driver, which wants the option + '' spelled with -Wl, rather than passed through as --export-dynamic + if( fbGetOption( FB_COMPOPT_TARGET ) = FB_COMPTARGET_DARWIN ) then + ldcline += " -Wl,-export_dynamic" + else + ldcline += " --export-dynamic" + end if end if case FB_COMPTARGET_XBOX @@ -1166,7 +1186,10 @@ private function hLinkFiles( ) as integer FB_COMPTARGET_FREEBSD, FB_COMPTARGET_OPENBSD, _ FB_COMPTARGET_NETBSD, FB_COMPTARGET_DRAGONFLY, FB_COMPTARGET_SOLARIS - if( fbGetOption( FB_COMPOPT_OUTTYPE ) = FB_OUTTYPE_EXECUTABLE) then + '' Darwin's linker takes no explicit crt1.o; the C compiler driver + '' supplies the startup object (it lives inside libSystem). + if( (fbGetOption( FB_COMPOPT_OUTTYPE ) = FB_OUTTYPE_EXECUTABLE) and _ + (fbGetOption( FB_COMPOPT_TARGET ) <> FB_COMPTARGET_DARWIN) ) then if( fbGetOption( FB_COMPOPT_PROFILE ) ) then select case as const fbGetOption( FB_COMPOPT_TARGET ) case FB_COMPTARGET_OPENBSD, FB_COMPTARGET_NETBSD @@ -1322,18 +1345,17 @@ private function hLinkFiles( ) as integer end select - if( fbGetOption( FB_COMPOPT_TARGET ) = FB_COMPTARGET_DARWIN ) then - ldcline += " -macosx_version_min 10.4" - end if + '' Note: on Darwin the deployment target (-mmacosx-version-min) is supplied + '' by the C compiler driver used for linking, not hard-coded here. '' This is required for 64-bit modules on *nix-y platforms '' for the unwind tables to have any effect '' Windows doesn't need this option + '' (ld64 rejects --eh-frame-hdr; Darwin is handled by clang instead) select case as const fbGetOption( FB_COMPOPT_TARGET ) case FB_COMPTARGET_LINUX, FB_COMPTARGET_FREEBSD, _ FB_COMPTARGET_OPENBSD, FB_COMPTARGET_NETBSD, _ - FB_COMPTARGET_DRAGONFLY, FB_COMPTARGET_SOLARIS, _ - FB_COMPTARGET_DARWIN + FB_COMPTARGET_DRAGONFLY, FB_COMPTARGET_SOLARIS dim as long outtype = fbGetOption( FB_COMPOPT_OUTTYPE ) if outtype = FB_OUTTYPE_EXECUTABLE OrElse outtype = FB_OUTTYPE_DYNAMICLIB Then dim as long cpufamily = fbGetCpuFamily( ) @@ -1408,6 +1430,10 @@ private function hLinkFiles( ) as integer var ld = FBCTOOL_LD if( fbGetOption( FB_COMPOPT_TARGET ) = FB_COMPTARGET_JS ) then ld = FBCTOOL_EMLD + elseif( fbGetOption( FB_COMPOPT_TARGET ) = FB_COMPTARGET_DARWIN ) then + '' ld64 can't be driven like GNU ld (different crt handling, and it + '' rejects several GNU options), so use the C compiler driver to link. + ld = FBCTOOL_CLANG end if if( fbcRunBin( "linking", ld, ldcline ) = FALSE ) then @@ -4308,9 +4334,9 @@ private sub hAddDefaultLibs( ) end if case FB_COMPTARGET_DARWIN - fbcAddDefLib( "gcc" ) - fbcAddDefLib( "System" ) - fbcAddDefLib( "pthread" ) + '' There is no libgcc on macOS unless a GCC toolchain is installed; + '' the clang driver pulls in libSystem (and thus libc/libm/pthread) + '' by itself. libncurses is still needed by the FB runtime. fbcAddDefLib( "ncurses" ) case FB_COMPTARGET_DOS diff --git a/src/compiler/rtl-error.bas b/src/compiler/rtl-error.bas index 17096f555..8931daf95 100644 --- a/src/compiler/rtl-error.bas +++ b/src/compiler/rtl-error.bas @@ -293,7 +293,16 @@ function rtlErrorCheck( byval expr as ASTNODE ptr ) as ASTNODE ptr t = astNewLINK( t, astNewBOP( AST_OP_EQ, expr, astNewCONSTi( 0 ), nxtlabel, AST_OPOPT_NONE ), AST_LINK_RETURN_NONE ) '' fb_ErrorThrow() - t = astNewLINK( t, astNewBRANCH( AST_OP_JUMPPTR, NULL, hErrorThrow( reslabel, nxtlabel ) ), AST_LINK_RETURN_NONE ) + '' Only -ex (-exx) enables RESUME support, and only then is a resume + '' label handed to the throw. Without one the throw can never return + '' a usable jump target, so a plain call is equivalent -- and it keeps + '' the generated C acceptable to clang, which rejects `goto *ptr` in + '' functions that take no label address. + if( env.clopt.resumeerr ) then + t = astNewLINK( t, astNewBRANCH( AST_OP_JUMPPTR, NULL, hErrorThrow( reslabel, nxtlabel ) ), AST_LINK_RETURN_NONE ) + else + t = astNewLINK( t, hErrorThrow( reslabel, nxtlabel ), AST_LINK_RETURN_NONE ) + end if '' end if t = astNewLINK( t, astNewLABEL( nxtlabel ), AST_LINK_RETURN_NONE ) @@ -361,7 +370,13 @@ sub rtlErrorThrow _ end if '' dst - astAdd( astNewBRANCH( AST_OP_JUMPPTR, NULL, proc ) ) + '' As in rtlErrorCheck(): an indirect jump is only meaningful when RESUME + '' support (-ex) is enabled and a resume label was passed along. + if( env.clopt.resumeerr ) then + astAdd( astNewBRANCH( AST_OP_JUMPPTR, NULL, proc ) ) + else + astAdd( proc ) + end if astAdd( astNewLABEL( nxtlabel ) ) end sub diff --git a/src/rtlib/fb_data.h b/src/rtlib/fb_data.h index 2b976807d..22de295a6 100644 --- a/src/rtlib/fb_data.h +++ b/src/rtlib/fb_data.h @@ -1,3 +1,14 @@ +/* Mach-O (Darwin) requires pointer-sized relocations to be aligned; the packed + layout would place the embedded pointers at 2-byte offsets, which ld64 + rejects ("pointer not aligned ...", a hard error on arm64). The compiler + emits the matching naturally-aligned layout for Darwin targets, see + hCreateDataDesc() in src/compiler/ast-node-data.bas. */ +#if defined(__APPLE__) + #define FB_DATADESC_PACKED +#else + #define FB_DATADESC_PACKED FBPACKED +#endif + struct _FB_DATADESC { short len; union { @@ -6,7 +17,7 @@ struct _FB_DATADESC { void *ofs; struct _FB_DATADESC *next; }; -} FBPACKED; +} FB_DATADESC_PACKED; typedef struct _FB_DATADESC FB_DATADESC; diff --git a/src/rtlib/profile_cycles.c b/src/rtlib/profile_cycles.c index c6e2a7327..00f4718fc 100644 --- a/src/rtlib/profile_cycles.c +++ b/src/rtlib/profile_cycles.c @@ -99,10 +99,20 @@ typedef struct _FB_PROFILER_CYCLES */ #if !defined(HOST_DOS) +/* Mach-O section names are limited to 16 characters and, unlike ELF, the + linker does not synthesise __start_/__stop_ boundary symbols, so the + profiler's section scan cannot work the ELF way there; keep the record as a + plain used object instead. */ +#if defined(HOST_DARWIN) + #define FB_PROFILE_SECTION_ATTR __attribute__((used)) +#else + #define FB_PROFILE_SECTION_ATTR __attribute__((section("fb_profilecycledata"), used)) +#endif + /* make sure there is at least one record in the profile data section */ static FB_PROFILE_RECORD_VERSION __attribute__ ((aligned (16))) prof_data_version -__attribute__((section("fb_profilecycledata"), used)) = +FB_PROFILE_SECTION_ATTR = { sizeof( FB_PROFILE_RECORD_VERSION ), FB_PROFILE_RECORD_VERSION_ID, @@ -301,8 +311,15 @@ static void hProfilerWriteReport( FB_PROFILER_CYCLES *prof ) fprintf( f, "Total program execution time: %5.4g seconds\n", fb_Timer() - prof->start_time ); } +#if defined(HOST_DARWIN) + /* No __start_/__stop_ section symbols on Mach-O; fall back to the single + version record so the report is simply empty. */ + data = (unsigned char *)&prof_data_version; + length = sizeof( prof_data_version ); +#else data = (unsigned char *)&__start_fb_profilecycledata[0]; length = (ssize_t)&__stop_fb_profilecycledata - (ssize_t)&__start_fb_profilecycledata[0]; +#endif count = hProfilerCountProcs( data, length ); if( count ) { diff --git a/src/rtlib/unix/fb_private_scancodes_x11.h b/src/rtlib/unix/fb_private_scancodes_x11.h index e76da67d4..bee31cd27 100644 --- a/src/rtlib/unix/fb_private_scancodes_x11.h +++ b/src/rtlib/unix/fb_private_scancodes_x11.h @@ -7,7 +7,16 @@ typedef Display *(*XOPENDISPLAY)(char *); typedef int (*XCLOSEDISPLAY)(Display *); typedef void (*XQUERYKEYMAP)(Display *, unsigned char *); typedef int (*XDISPLAYKEYCODES)(Display *, int *, int *); +/* XGetKeyboardMapping()'s first_keycode parameter is declared as KeyCode + (unsigned char) or as unsigned int depending on NeedWidePrototypes, which + Xfuncproto.h defaults to 1 unless NARROWPROTO is defined. Mirror Xlib's own + declaration, otherwise the function pointers do not match and clang (unlike + GCC, which merely warns) rejects the call. */ +#if defined(NeedWidePrototypes) && NeedWidePrototypes +typedef KeySym* (*XGETKEYBOARDMAPPING)(Display *, unsigned int, int, int *); +#else typedef KeySym* (*XGETKEYBOARDMAPPING)(Display *, KeyCode, int, int *); +#endif typedef int (*XFREE)(void *); extern unsigned char fb_x11keycode_to_scancode[256];