From 93be5aca05c995a6c05990d17c26957b364aadc1 Mon Sep 17 00:00:00 2001 From: Braden Obrzut Date: Sun, 13 Mar 2016 00:34:35 -0500 Subject: [PATCH] - Fixed: Modern versions of GCC on PowerPC inserted padding to the end of pragma packed structures. - Worked aorund modern GCC bug where C++ exceptions in Objective-C++ code would result in an ICE (bug is already on their tracker, but I doubt it will be fixed unless I decide to dig into the issue myself). - Turn off fused floating point instructions since these can cause slight deviations in floating point code. - Use -static-libgcc when compiling on the Mac with GCC since we need to use a custom version of GCC to do so now. - Note: ZDoom will currently still crash on exit on PowerPC since it seems to be deciding that NameManager needs to be destructed before the console commands. --- CMakeLists.txt | 7 ++- src/CMakeLists.txt | 22 ++++---- src/doomtype.h | 12 +++++ src/posix/cocoa/i_common.h | 2 + src/posix/cocoa/i_main.mm | 90 ++++++++++++++----------------- src/posix/cocoa/i_main_except.cpp | 34 ++++++++++++ src/sound/music_dumb.cpp | 4 +- src/textures/pcxtexture.cpp | 2 +- src/w_zip.h | 6 +-- tools/zipdir/zipdir.c | 17 ++++-- 10 files changed, 125 insertions(+), 71 deletions(-) create mode 100644 src/posix/cocoa/i_main_except.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 2e0bf8b77..5d0447963 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -167,6 +167,11 @@ else() set( ALL_C_FLAGS "" ) set( REL_C_FLAGS "" ) set( DEB_C_FLAGS "" ) + + # If we're compiling with a custom GCC on the Mac (which we know since g++-4.2 doesn't support C++11) statically link libgcc. + if( APPLE AND "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" ) + set( ALL_C_FLAGS "-static-libgcc" ) + endif() endif() set( CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${REL_LINKER_FLAGS}" ) @@ -193,7 +198,7 @@ option(FORCE_INTERNAL_GME "Use internal gme" ON) # Fast math flags, required by some subprojects set( ZD_FASTMATH_FLAG "" ) if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) - set( ZD_FASTMATH_FLAG "-ffast-math" ) + set( ZD_FASTMATH_FLAG "-ffast-math -ffp-contract=fast" ) elseif( MSVC ) set( ZD_FASTMATH_FLAG "/fp:fast" ) endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 94ac6fb32..797e76139 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -465,28 +465,28 @@ if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) set( CMAKE_C_FLAGS "-Wno-unused-result ${CMAKE_C_FLAGS}" ) set( CMAKE_CXX_FLAGS "-Wno-unused-result ${CMAKE_CXX_FLAGS}" ) endif() - set( CMAKE_C_FLAGS "-Wall -Wextra -Wno-unused -Wno-unused-parameter -Wno-missing-field-initializers ${CMAKE_C_FLAGS}" ) - set( CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-unused -Wno-unused-parameter -Wno-missing-field-initializers ${CMAKE_CXX_FLAGS}" ) + set( CMAKE_C_FLAGS "-Wall -Wextra -Wno-unused -Wno-unused-parameter -Wno-missing-field-initializers -ffp-contract=off ${CMAKE_C_FLAGS}" ) + set( CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-unused -Wno-unused-parameter -Wno-missing-field-initializers -ffp-contract=off ${CMAKE_CXX_FLAGS}" ) # Use the highest C++ standard available since VS2015 compiles with C++14 # but we only require C++11. The recommended way to do this in CMake is to # probably to use target_compile_features, but I don't feel like maintaining # a list of features we use. - CHECK_CXX_COMPILER_FLAG( "-std=c++14" CAN_DO_CPP14 ) + CHECK_CXX_COMPILER_FLAG( "-std=gnu++14" CAN_DO_CPP14 ) if ( CAN_DO_CPP14 ) - set ( CMAKE_CXX_FLAGS "-std=c++14 ${CMAKE_CXX_FLAGS}" ) + set ( CMAKE_CXX_FLAGS "-std=gnu++14 ${CMAKE_CXX_FLAGS}" ) else () - CHECK_CXX_COMPILER_FLAG( "-std=c++1y" CAN_DO_CPP1Y ) + CHECK_CXX_COMPILER_FLAG( "-std=gnu++1y" CAN_DO_CPP1Y ) if ( CAN_DO_CPP1Y ) - set ( CMAKE_CXX_FLAGS "-std=c++1y ${CMAKE_CXX_FLAGS}" ) + set ( CMAKE_CXX_FLAGS "-std=gnu++1y ${CMAKE_CXX_FLAGS}" ) else () - CHECK_CXX_COMPILER_FLAG( "-std=c++11" CAN_DO_CPP11 ) + CHECK_CXX_COMPILER_FLAG( "-std=gnu++11" CAN_DO_CPP11 ) if ( CAN_DO_CPP11 ) - set ( CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}" ) + set ( CMAKE_CXX_FLAGS "-std=gnu++11 ${CMAKE_CXX_FLAGS}" ) else () - CHECK_CXX_COMPILER_FLAG( "-std=c++0x" CAN_DO_CPP0X ) + CHECK_CXX_COMPILER_FLAG( "-std=gnu++0x" CAN_DO_CPP0X ) if ( CAN_DO_CPP0X ) - set ( CMAKE_CXX_FLAGS "-std=c++0x ${CMAKE_CXX_FLAGS}" ) + set ( CMAKE_CXX_FLAGS "-std=gnu++0x ${CMAKE_CXX_FLAGS}" ) endif () endif () endif () @@ -645,6 +645,7 @@ set( PLAT_COCOA_SOURCES posix/cocoa/i_input.mm posix/cocoa/i_joystick.cpp posix/cocoa/i_main.mm + posix/cocoa/i_main_except.cpp posix/cocoa/i_system.mm posix/cocoa/i_timer.cpp posix/cocoa/i_video.mm @@ -681,6 +682,7 @@ elseif( APPLE ) set_source_files_properties( posix/osx/zdoom.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources ) set_source_files_properties( "${FMOD_LIBRARY}" PROPERTIES MACOSX_PACKAGE_LOCATION Frameworks ) + set_source_files_properties( posix/osx/iwadpicker_cocoa.mm PROPERTIES COMPILE_FLAGS -fobjc-exceptions ) else() set( SYSTEM_SOURCES_DIR posix posix/sdl ) set( SYSTEM_SOURCES ${PLAT_POSIX_SOURCES} ${PLAT_SDL_SOURCES} ) diff --git a/src/doomtype.h b/src/doomtype.h index 22a4d6ffd..db4bc7e5d 100644 --- a/src/doomtype.h +++ b/src/doomtype.h @@ -123,6 +123,18 @@ typedef TMap FClassMap; #define NO_SANITIZE #endif +#if defined(__GNUC__) +// With versions of GCC newer than 4.2, it appears it was determined that the +// cost of an unaligned pointer on PPC was high enough to add padding to the +// end of packed structs. For whatever reason __packed__ and pragma pack are +// handled differently in this regard. Note that this only needs to be applied +// to types which are used in arrays or sizeof is needed. This also prevents +// code from taking references to the struct members. +#define FORCE_PACKED __attribute__((__packed__)) +#else +#define FORCE_PACKED +#endif + #include "basictypes.h" extern bool batchrun; diff --git a/src/posix/cocoa/i_common.h b/src/posix/cocoa/i_common.h index beff4a33d..4a558cf24 100644 --- a/src/posix/cocoa/i_common.h +++ b/src/posix/cocoa/i_common.h @@ -149,6 +149,8 @@ static const NSOpenGLPixelFormatAttribute NSOpenGLPFAAllowOfflineRenderers = NSO - (void)setCollectionBehavior:(NSUInteger)collectionBehavior; @end +typedef NSUInteger NSWindowCollectionBehavior; + #endif // prior to 10.5 diff --git a/src/posix/cocoa/i_main.mm b/src/posix/cocoa/i_main.mm index 2f65254a9..5729a3716 100644 --- a/src/posix/cocoa/i_main.mm +++ b/src/posix/cocoa/i_main.mm @@ -67,7 +67,6 @@ EXTERN_CVAR(Bool, fullscreen ) // --------------------------------------------------------------------------- - namespace { @@ -78,6 +77,9 @@ void (*TermFuncs[MAX_TERMS])(); const char *TermNames[MAX_TERMS]; size_t NumTerms; +} // unnamed namespace + +// Expose this for i_main_except.cpp void call_terms() { while (NumTerms > 0) @@ -86,8 +88,6 @@ void call_terms() } } -} // unnamed namespace - void addterm(void (*func)(), const char *name) { @@ -133,6 +133,41 @@ void Mac_I_FatalError(const char* const message) DArgs* Args; // command line arguments +// Newer versions of GCC than 4.2 have a bug with C++ exceptions in Objective-C++ code. +// To work around we'll implement the try and catch in standard C++. +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61759 +void OriginalMainExcept(int argc, char** argv); +void OriginalMainTry(int argc, char** argv) +{ + Args = new DArgs(argc, argv); + + /* + killough 1/98: + + This fixes some problems with exit handling + during abnormal situations. + + The old code called I_Quit() to end program, + while now I_Quit() is installed as an exit + handler and exit() is called to exit, either + normally or abnormally. Seg faults are caught + and the error handler is used, to prevent + being left in graphics mode or having very + loud SFX noise because the sound card is + left in an unstable state. + */ + + atexit(call_terms); + atterm(I_Quit); + + NSString* exePath = [[NSBundle mainBundle] executablePath]; + progdir = [[exePath stringByDeletingLastPathComponent] UTF8String]; + progdir += "/"; + + C_InitConsole(80 * 8, 25 * 8, false); + D_DoomMain(); +} + namespace { @@ -151,7 +186,6 @@ void NewFailure() I_FatalError("Failed to allocate memory from system heap"); } - int OriginalMain(int argc, char** argv) { printf(GAMENAME" %s - %s - Cocoa version\nCompiled on %s\n\n", @@ -174,53 +208,7 @@ int OriginalMain(int argc, char** argv) vid_vsync = true; fullscreen = true; - try - { - Args = new DArgs(argc, argv); - - /* - killough 1/98: - - This fixes some problems with exit handling - during abnormal situations. - - The old code called I_Quit() to end program, - while now I_Quit() is installed as an exit - handler and exit() is called to exit, either - normally or abnormally. Seg faults are caught - and the error handler is used, to prevent - being left in graphics mode or having very - loud SFX noise because the sound card is - left in an unstable state. - */ - - atexit(call_terms); - atterm(I_Quit); - - NSString* exePath = [[NSBundle mainBundle] executablePath]; - progdir = [[exePath stringByDeletingLastPathComponent] UTF8String]; - progdir += "/"; - - C_InitConsole(80 * 8, 25 * 8, false); - D_DoomMain(); - } - catch(const CDoomError& error) - { - const char* const message = error.GetMessage(); - - if (NULL != message) - { - fprintf(stderr, "%s\n", message); - Mac_I_FatalError(message); - } - - exit(-1); - } - catch(...) - { - call_terms(); - throw; - } + OriginalMainExcept(argc, argv); return 0; } diff --git a/src/posix/cocoa/i_main_except.cpp b/src/posix/cocoa/i_main_except.cpp new file mode 100644 index 000000000..8a095f2a0 --- /dev/null +++ b/src/posix/cocoa/i_main_except.cpp @@ -0,0 +1,34 @@ +// Workaround for GCC Objective-C++ with C++ exceptions bug. + +#include "doomerrors.h" +#include + +// Import some functions from i_main.mm +void call_terms(); +void Mac_I_FatalError(const char* const message); +void OriginalMainTry(int argc, char** argv); + +void OriginalMainExcept(int argc, char** argv) +{ + try + { + OriginalMainTry(argc, argv); + } + catch(const CDoomError& error) + { + const char* const message = error.GetMessage(); + + if (NULL != message) + { + fprintf(stderr, "%s\n", message); + Mac_I_FatalError(message); + } + + exit(-1); + } + catch(...) + { + call_terms(); + throw; + } +} diff --git a/src/sound/music_dumb.cpp b/src/sound/music_dumb.cpp index 31f42b319..fe1fbbb76 100644 --- a/src/sound/music_dumb.cpp +++ b/src/sound/music_dumb.cpp @@ -100,14 +100,14 @@ typedef struct tagITFILEHEADER DWORD reserved2; BYTE chnpan[64]; BYTE chnvol[64]; -} ITFILEHEADER, *PITFILEHEADER; +} FORCE_PACKED ITFILEHEADER, *PITFILEHEADER; typedef struct MODMIDICFG { char szMidiGlb[9*32]; // changed from CHAR char szMidiSFXExt[16*32]; // changed from CHAR char szMidiZXXExt[128*32]; // changed from CHAR -} MODMIDICFG, *LPMODMIDICFG; +} FORCE_PACKED MODMIDICFG, *LPMODMIDICFG; #pragma pack() diff --git a/src/textures/pcxtexture.cpp b/src/textures/pcxtexture.cpp index 125898cce..0ec5d2933 100644 --- a/src/textures/pcxtexture.cpp +++ b/src/textures/pcxtexture.cpp @@ -72,7 +72,7 @@ struct PCXHeader BYTE padding[54]; -}; +} FORCE_PACKED; #pragma pack() //========================================================================== diff --git a/src/w_zip.h b/src/w_zip.h index 16fb7acc7..4f51a13cc 100644 --- a/src/w_zip.h +++ b/src/w_zip.h @@ -13,7 +13,7 @@ struct FZipEndOfCentralDirectory DWORD DirectorySize; DWORD DirectoryOffset; WORD ZipCommentLength; -}; +} FORCE_PACKED; // FZipFileInfo struct FZipCentralDirectoryInfo @@ -36,7 +36,7 @@ struct FZipCentralDirectoryInfo DWORD ExternalAttributes; DWORD LocalHeaderOffset; // file name and other variable length info follows -}; +} FORCE_PACKED; // FZipLocalHeader struct FZipLocalFileHeader @@ -53,7 +53,7 @@ struct FZipLocalFileHeader WORD NameLength; WORD ExtraLength; // file name and other variable length info follows -}; +} FORCE_PACKED; #pragma pack() diff --git a/tools/zipdir/zipdir.c b/tools/zipdir/zipdir.c index cb43f5f82..e21b9ba13 100644 --- a/tools/zipdir/zipdir.c +++ b/tools/zipdir/zipdir.c @@ -60,6 +60,17 @@ #define __cdecl #endif +#ifdef __GNUC__ +// With versions of GCC newer than 4.2, it appears it was determined that the +// cost of an unaligned pointer on PPC was high enough to add padding to the +// end of packed structs. For whatever reason __packed__ and pragma pack are +// handled differently in this regard. Note that this only needs to be applied +// to types which are used in arrays. +#define FORCE_PACKED __attribute__((__packed__)) +#else +#define FORCE_PACKED +#endif + #ifndef __BIG_ENDIAN__ #define MAKE_ID(a,b,c,d) ((a)|((b)<<8)|((c)<<16)|((d)<<24)) #define LittleShort(x) (x) @@ -150,7 +161,7 @@ typedef struct UINT32 UncompressedSize; // 22 WORD NameLength; // 26 WORD ExtraLength; // 28 -} LocalFileHeader; +} FORCE_PACKED LocalFileHeader; typedef struct { @@ -171,7 +182,7 @@ typedef struct WORD InternalAttributes; UINT32 ExternalAttributes; UINT32 LocalHeaderOffset; -} CentralDirectoryEntry; +} FORCE_PACKED CentralDirectoryEntry; typedef struct { @@ -183,7 +194,7 @@ typedef struct UINT32 DirectorySize; UINT32 DirectoryOffset; WORD ZipCommentLength; -} EndOfCentralDirectory; +} FORCE_PACKED EndOfCentralDirectory; //#pragma pack(pop) // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------