From d590fdddf6ba938bdc2f59e2c0d2e3fc9713f67a Mon Sep 17 00:00:00 2001 From: Andrew Udvare Date: Tue, 29 Sep 2020 20:39:18 -0400 Subject: [PATCH] macOS support; thanks to @MrYadro This should support ARM64 and x86-64. -target flag based on information from https://developer.apple.com/documentation/xcode/building_a_universal_macos_binary#3618377. --- .travis.yml | 43 ++++++++++++++++++---- premake5.lua | 38 +++++++++++++++++++- src/core/CdStreamPosix.cpp | 73 +++++++++++++++++++++++++------------- src/skel/glfw/glfw.cpp | 25 ++++++++++--- 4 files changed, 143 insertions(+), 36 deletions(-) diff --git a/.travis.yml b/.travis.yml index 51ef58eb..c124a9f0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,15 +1,44 @@ language: cpp -os: linux dist: focal -matrix: +os: linux +jobs: include: - env: TARGET=release_linux-amd64-librw_gl3_glfw-oal + os: linux - env: TARGET=debug_linux-amd64-librw_gl3_glfw-oal + os: linux + - env: TARGET=release_macosx-amd64-librw_gl3_glfw-oal PREMAKE5=premake-5.0.0-alpha15 + compiler: clang + os: osx + osx_image: xcode12u + - env: TARGET=debug_macosx-amd64-librw_gl3_glfw-oal PREMAKE5=premake-5.0.0-alpha15 + compiler: clang + os: osx + osx_image: xcode12u +addons: + apt: + update: true + packages: + - linux-libc-dev + - libopenal-dev + - libglew-dev + - libglfw3-dev + - libsndfile1-dev + - libmpg123-dev + - gcc-8-multilib + - g++-8-multilib + homebrew: + packages: + - libsndfile + - mpg123 + - glew + - glfw + - openal-soft script: - - sudo apt-get update - - sudo apt-get -y install linux-libc-dev libopenal-dev libglew-dev libglfw3-dev libsndfile1-dev libmpg123-dev gcc-8-multilib g++-8-multilib - mkdir -p "$TRAVIS_BUILD_DIR/build" - cd "$TRAVIS_BUILD_DIR" - - ./premake5Linux --with-librw gmake2 - - cd build - - CC=gcc-8 CXX=g++-8 make config=$TARGET -j4 verbose=1 + - if [ "$TRAVIS_OS_NAME" = linux ]; then ./premake5Linux --with-librw gmake2; fi + - if [ "$TRAVIS_OS_NAME" = osx ]; then curl -L -o "${PREMAKE5}.zip" "https://github.com/premake/premake-core/releases/download/v5.0.0-alpha15/${PREMAKE5}-src.zip" && unzip -q "${PREMAKE5}.zip" && cd "$PREMAKE5" && make -f Bootstrap.mak osx && cd .. && "./${PREMAKE5}/bin/release/premake5" --with-librw gmake2; fi + - cd build + - if [ "$TRAVIS_OS_NAME" = linux ]; then env CC=gcc-8 CXX=g++-8 make config=$TARGET -j4 verbose=1; fi + - if [ "$TRAVIS_OS_NAME" = osx ]; then make config=$TARGET -j4 verbose=1; fi diff --git a/premake5.lua b/premake5.lua index b61a9c4c..b38c8ae1 100644 --- a/premake5.lua +++ b/premake5.lua @@ -84,6 +84,12 @@ workspace "reVC" platforms { "bsd-amd64-librw_gl3_glfw-oal" } + + filter { "system:macosx" } + platforms { + "macosx-amd64-librw_gl3_glfw-oal", + "macosx-arm64-librw_gl3_glfw-oal", + } filter "configurations:Debug" defines { "DEBUG" } @@ -100,6 +106,9 @@ workspace "reVC" filter { "platforms:bsd*" } system "bsd" + + filter { "platforms:macosx*" } + system "macosx" filter { "platforms:*x86*" } architecture "x86" @@ -109,6 +118,13 @@ workspace "reVC" filter { "platforms:*arm*" } architecture "ARM" + + filter { "platforms:macosx-arm64-*" } + buildoptions { "-target", "arm64-apple-macos11", "-std=gnu++14" } + + filter { "platforms:macosx-amd64-*" } + buildoptions { "-target", "x86_64-apple-macos10.12", "-std=gnu++14" } + filter { "platforms:*librw_d3d9*" } defines { "RW_D3D9" } @@ -162,7 +178,14 @@ project "librw" filter "platforms:bsd*" includedirs { "/usr/local/include" } libdirs { "/usr/local/lib" } - + + filter "platforms:macosx*" + -- Support MacPorts and Homebrew + includedirs { "/opt/local/include" } + includedirs {"/usr/local/include" } + libdirs { "/opt/local/lib" } + libdirs { "/usr/local/lib" } + filter "platforms:*RW34*" flags { "ExcludeFromBuild" } filter {} @@ -277,6 +300,11 @@ project "reVC" filter "platforms:bsd*oal" links { "openal", "mpg123", "sndfile", "pthread" } + + filter "platforms:macosx*oal" + links { "openal", "mpg123", "sndfile", "pthread" } + includedirs { "/usr/local/opt/openal-soft/include" } + libdirs { "/usr/local/opt/openal-soft/lib" } if _OPTIONS["with-opus"] then filter {} @@ -330,3 +358,11 @@ project "reVC" links { "GL", "GLEW", "glfw", "sysinfo" } includedirs { "/usr/local/include" } libdirs { "/usr/local/lib" } + + filter "platforms:macosx*gl3_glfw*" + links { "GLEW", "glfw" } + linkoptions { "-framework OpenGL" } + includedirs { "/opt/local/include" } + includedirs { "/usr/local/include" } + libdirs { "/opt/local/lib" } + libdirs { "/usr/local/lib" } diff --git a/src/core/CdStreamPosix.cpp b/src/core/CdStreamPosix.cpp index e114a29a..895143a4 100644 --- a/src/core/CdStreamPosix.cpp +++ b/src/core/CdStreamPosix.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -21,6 +22,30 @@ #define CDDEBUG(f, ...) debug ("%s: " f "\n", "cdvd_stream", ## __VA_ARGS__) #define CDTRACE(f, ...) printf("%s: " f "\n", "cdvd_stream", ## __VA_ARGS__) +#ifdef __APPLE__ +#define COMPAT_SEM_T sem_t * +int compat_sem_init(sem_t **ptr, __attribute__((unused)) int x, __attribute__((unused)) int y) { + *ptr = sem_open("/semaphore", O_CREAT, 0644, 1); + return *ptr == SEM_FAILED ? -1 : 0; +} +int compat_sem_post(sem_t **sem) { + return sem_post(*sem); +} +int compat_sem_wait(sem_t **sem) { + return sem_wait(*sem); +} +int compat_sem_destroy(sem_t **sem, const char * name) { + sem_close(*sem); + sem_unlink(name); +} +#else +#define COMPAT_SEM_T sem_t +#define compat_sem_post sem_post +#define compat_sem_destroy(x, y) sem_destroy(x) +#define compat_sem_init sem_init +#define compat_sem_wait sem_wait +#endif + // #define ONE_THREAD_PER_CHANNEL // Don't use if you're not on SSD/Flash. (Also you may want to benefit from this via using all channels in Streaming.cpp) bool flushStream[MAX_CDCHANNELS]; @@ -35,11 +60,11 @@ struct CdReadInfo int32 nStatus; #ifdef ONE_THREAD_PER_CHANNEL int8 nThreadStatus; // 0: created 1:initalized 2:abort now - pthread_t pChannelThread; - sem_t pStartSemaphore; + pthread_t pChannelThread; + COMPAT_SEM_T pStartSemaphore; #endif - sem_t pDoneSemaphore; // used for CdStreamSync - int32 hFile; + COMPAT_SEM_T pDoneSemaphore; // used for CdStreamSync + int32 hFile; }; char gCdImageNames[MAX_CDIMAGES+1][64]; @@ -51,7 +76,7 @@ char *gImgNames[MAX_CDIMAGES]; #ifndef ONE_THREAD_PER_CHANNEL pthread_t _gCdStreamThread; -sem_t gCdStreamSema; // released when we have new thing to read(so channel is set) +COMPAT_SEM_T gCdStreamSema; // released when we have new thing to read(so channel is set) int8 gCdStreamThreadStatus; // 0: created 1:initalized 2:abort now Queue gChannelRequestQ; bool _gbCdStreamOverlapped; @@ -76,7 +101,7 @@ CdStreamInitThread(void) gChannelRequestQ.tail = 0; gChannelRequestQ.size = gNumChannels + 1; ASSERT(gChannelRequestQ.items != nil ); - status = sem_init(&gCdStreamSema, 0, 0); + status = compat_sem_init(&gCdStreamSema, 0, 0); #endif @@ -91,7 +116,7 @@ CdStreamInitThread(void) { for ( int32 i = 0; i < gNumChannels; i++ ) { - status = sem_init(&gpReadInfo[i].pDoneSemaphore, 0, 0); + status = compat_sem_init(&gpReadInfo[i].pDoneSemaphore, 0, 0); if (status == -1) { @@ -100,7 +125,7 @@ CdStreamInitThread(void) return; } #ifdef ONE_THREAD_PER_CHANNEL - status = sem_init(&gpReadInfo[i].pStartSemaphore, 0, 0); + status = compat_sem_init(&gpReadInfo[i].pStartSemaphore, 0, 0); if (status == -1) { @@ -214,13 +239,13 @@ CdStreamShutdown(void) // Destroying semaphores and free(gpReadInfo) will be done at threads #ifndef ONE_THREAD_PER_CHANNEL gCdStreamThreadStatus = 2; - sem_post(&gCdStreamSema); + compat_sem_post(&gCdStreamSema); #endif #ifdef ONE_THREAD_PER_CHANNEL for ( int32 i = 0; i < gNumChannels; i++ ) { gpReadInfo[i].nThreadStatus = 2; - sem_post(&gpReadInfo[i].pStartSemaphore); + compat_sem_post(&gpReadInfo[i].pStartSemaphore); } #endif } @@ -254,10 +279,10 @@ CdStreamRead(int32 channel, void *buffer, uint32 offset, uint32 size) #ifndef ONE_THREAD_PER_CHANNEL AddToQueue(&gChannelRequestQ, channel); - if ( sem_post(&gCdStreamSema) != 0 ) + if ( compat_sem_post(&gCdStreamSema) != 0 ) printf("Signal Sema Error\n"); #else - if ( sem_post(&gpReadInfo[channel].pStartSemaphore) != 0 ) + if ( compat_sem_post(&gpReadInfo[channel].pStartSemaphore) != 0 ) printf("Signal Sema Error\n"); #endif @@ -332,7 +357,7 @@ CdStreamSync(int32 channel) { pChannel->bLocked = true; - sem_wait(&pChannel->pDoneSemaphore); + compat_sem_wait(&pChannel->pDoneSemaphore); } pChannel->bReading = false; @@ -383,12 +408,12 @@ void *CdStreamThread(void *param) #ifndef ONE_THREAD_PER_CHANNEL while (gCdStreamThreadStatus != 2) { - sem_wait(&gCdStreamSema); + compat_sem_wait(&gCdStreamSema); int32 channel = GetFirstInQueue(&gChannelRequestQ); #else int channel = *((int*)param); while (gpReadInfo[channel].nThreadStatus != 2){ - sem_wait(&gpReadInfo[channel].pStartSemaphore); + compat_sem_wait(&gpReadInfo[channel].pStartSemaphore); #endif ASSERT( channel < gNumChannels ); @@ -437,22 +462,22 @@ void *CdStreamThread(void *param) if ( pChannel->bLocked ) { - sem_post(&pChannel->pDoneSemaphore); + compat_sem_post(&pChannel->pDoneSemaphore); } pChannel->bReading = false; } #ifndef ONE_THREAD_PER_CHANNEL - for ( int32 i = 0; i < gNumChannels; i++ ) - { - sem_destroy(&gpReadInfo[i].pDoneSemaphore); - } - sem_destroy(&gCdStreamSema); + for ( int32 i = 0; i < gNumChannels; i++ ) + { + compat_sem_destroy(&gpReadInfo[i].pDoneSemaphore, "/semaphoredone"); + } + compat_sem_destroy(&gCdStreamSema, "/semaphore"); free(gChannelRequestQ.items); #else - sem_destroy(&gpReadInfo[channel].pStartSemaphore); - sem_destroy(&gpReadInfo[channel].pDoneSemaphore); + compat_sem_destroy(&gpReadInfo[channel].pStartSemaphore, "/semaphorestart"); + compat_sem_destroy(&gpReadInfo[channel].pDoneSemaphore, "/semaphoredone"); #endif - free(gpReadInfo); + free(gpReadInfo); pthread_exit(nil); } diff --git a/src/skel/glfw/glfw.cpp b/src/skel/glfw/glfw.cpp index b40130c4..74330141 100644 --- a/src/skel/glfw/glfw.cpp +++ b/src/skel/glfw/glfw.cpp @@ -81,7 +81,12 @@ DWORD _dwOperatingSystemVersion; #include "resource.h" #else long _dwOperatingSystemVersion; +#ifndef __APPLE__ #include +#else +#include +#include +#endif #include #include #include @@ -449,15 +454,27 @@ psInitialize(void) #endif #endif +#ifndef __APPLE__ struct sysinfo systemInfo; sysinfo(&systemInfo); - _dwMemAvailPhys = systemInfo.freeram; - _dwOperatingSystemVersion = OS_WINXP; // To fool other classes - debug("Physical memory size %u\n", systemInfo.totalram); debug("Available physical memory %u\n", systemInfo.freeram); - +#else + uint64_t size = 0; + uint64_t page_size = 0; + size_t uint64_len = sizeof(uint64_t); + size_t ull_len = sizeof(unsigned long long); + sysctl((int[]){CTL_HW, HW_PAGESIZE}, 2, &page_size, &ull_len, NULL, 0); + sysctl((int[]){CTL_HW, HW_MEMSIZE}, 2, &size, &uint64_len, NULL, 0); + vm_statistics_data_t vm_stat; + mach_msg_type_number_t count = HOST_VM_INFO_COUNT; + host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&vm_stat, &count); + _dwMemAvailPhys = (uint64_t)(vm_stat.free_count * page_size); + debug("Physical memory size %llu\n", _dwMemAvailPhys); + debug("Available physical memory %llu\n", size); +#endif + _dwOperatingSystemVersion = OS_WINXP; // To fool other classes #endif TheText.Unload();