[macOS] Build infrastructure and portability fixes
Build system: - Enable ObjC++, macOS deployment target, framework linking - Fix AppleClang detection - macOS platform name for output directories - Skip Vulkan on macOS, null graphics without Vulkan dependency - macOS SDL2 framework detection and discord-rpc macOS sources Portability fixes: - mach_absolute_time for macOS tick counting - _NSGetExecutablePath for macOS - guard MAP_FIXED_NOREPLACE, ftruncate64->ftruncate - guard Vulkan include/usage, fix data root for all POSIX
This commit is contained in:
@@ -1,5 +1,11 @@
|
|||||||
cmake_minimum_required(VERSION 3.20)
|
cmake_minimum_required(VERSION 3.20)
|
||||||
project(xenia LANGUAGES C CXX)
|
if(APPLE)
|
||||||
|
project(xenia LANGUAGES C CXX OBJCXX)
|
||||||
|
set(CMAKE_OBJCXX_STANDARD 20)
|
||||||
|
set(CMAKE_OBJCXX_STANDARD_REQUIRED ON)
|
||||||
|
else()
|
||||||
|
project(xenia LANGUAGES C CXX)
|
||||||
|
endif()
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
@@ -52,6 +58,8 @@ set(CMAKE_STATIC_LINKER_FLAGS_CHECKED "${CMAKE_STATIC_LINKER_FLAGS_DEBUG}" CACHE
|
|||||||
# Platform name for output paths
|
# Platform name for output paths
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
set(XE_PLATFORM_NAME "Windows")
|
set(XE_PLATFORM_NAME "Windows")
|
||||||
|
elseif(APPLE)
|
||||||
|
set(XE_PLATFORM_NAME "macOS")
|
||||||
else()
|
else()
|
||||||
set(XE_PLATFORM_NAME "Linux")
|
set(XE_PLATFORM_NAME "Linux")
|
||||||
endif()
|
endif()
|
||||||
@@ -178,7 +186,7 @@ else()
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Clang-specific C++ warnings
|
# Clang-specific C++ warnings
|
||||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||||
add_compile_options(
|
add_compile_options(
|
||||||
$<$<COMPILE_LANGUAGE:CXX>:-Wno-deprecated-register>
|
$<$<COMPILE_LANGUAGE:CXX>:-Wno-deprecated-register>
|
||||||
$<$<COMPILE_LANGUAGE:CXX>:-Wno-deprecated-volatile>
|
$<$<COMPILE_LANGUAGE:CXX>:-Wno-deprecated-volatile>
|
||||||
@@ -216,7 +224,23 @@ else()
|
|||||||
$<$<COMPILE_LANGUAGE:C>:-Wno-implicit-function-declaration>
|
$<$<COMPILE_LANGUAGE:C>:-Wno-implicit-function-declaration>
|
||||||
)
|
)
|
||||||
|
|
||||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
if(APPLE)
|
||||||
|
# macOS-specific settings
|
||||||
|
set(CMAKE_OSX_DEPLOYMENT_TARGET "15.0" CACHE STRING "Minimum macOS version")
|
||||||
|
add_compile_options(
|
||||||
|
$<$<COMPILE_LANGUAGE:CXX>:-Wno-shorten-64-to-32>
|
||||||
|
-Wno-deprecated-declarations
|
||||||
|
-Wno-character-conversion
|
||||||
|
)
|
||||||
|
add_link_options(-Wl,-no_warn_duplicate_libraries)
|
||||||
|
link_libraries(
|
||||||
|
"-framework CoreFoundation"
|
||||||
|
"-framework Foundation"
|
||||||
|
"-framework IOKit"
|
||||||
|
dl
|
||||||
|
pthread
|
||||||
|
)
|
||||||
|
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||||
# GTK3 via pkg-config
|
# GTK3 via pkg-config
|
||||||
find_package(PkgConfig REQUIRED)
|
find_package(PkgConfig REQUIRED)
|
||||||
pkg_check_modules(GTK3 REQUIRED gtk+-x11-3.0)
|
pkg_check_modules(GTK3 REQUIRED gtk+-x11-3.0)
|
||||||
|
|||||||
@@ -48,7 +48,9 @@
|
|||||||
|
|
||||||
// Available graphics systems:
|
// Available graphics systems:
|
||||||
#include "xenia/gpu/null/null_graphics_system.h"
|
#include "xenia/gpu/null/null_graphics_system.h"
|
||||||
|
#if !XE_PLATFORM_MAC
|
||||||
#include "xenia/gpu/vulkan/vulkan_graphics_system.h"
|
#include "xenia/gpu/vulkan/vulkan_graphics_system.h"
|
||||||
|
#endif
|
||||||
#if XE_PLATFORM_WIN32
|
#if XE_PLATFORM_WIN32
|
||||||
#include "xenia/gpu/d3d12/d3d12_graphics_system.h"
|
#include "xenia/gpu/d3d12/d3d12_graphics_system.h"
|
||||||
#endif // XE_PLATFORM_WIN32
|
#endif // XE_PLATFORM_WIN32
|
||||||
@@ -401,7 +403,9 @@ std::unique_ptr<gpu::GraphicsSystem> EmulatorApp::CreateGraphicsSystem() {
|
|||||||
#if XE_PLATFORM_WIN32
|
#if XE_PLATFORM_WIN32
|
||||||
factory.Add<gpu::d3d12::D3D12GraphicsSystem>("d3d12");
|
factory.Add<gpu::d3d12::D3D12GraphicsSystem>("d3d12");
|
||||||
#endif // XE_PLATFORM_WIN32
|
#endif // XE_PLATFORM_WIN32
|
||||||
|
#if !XE_PLATFORM_MAC
|
||||||
factory.Add<gpu::vulkan::VulkanGraphicsSystem>("vulkan");
|
factory.Add<gpu::vulkan::VulkanGraphicsSystem>("vulkan");
|
||||||
|
#endif
|
||||||
std::unique_ptr<gpu::GraphicsSystem> gpu_implementation =
|
std::unique_ptr<gpu::GraphicsSystem> gpu_implementation =
|
||||||
factory.Create(gpu_implementation_name);
|
factory.Create(gpu_implementation_name);
|
||||||
if (!gpu_implementation) {
|
if (!gpu_implementation) {
|
||||||
@@ -475,12 +479,9 @@ bool EmulatorApp::OnInitialize() {
|
|||||||
if (!cvars::portable &&
|
if (!cvars::portable &&
|
||||||
!std::filesystem::exists(storage_root / "portable.txt")) {
|
!std::filesystem::exists(storage_root / "portable.txt")) {
|
||||||
storage_root = xe::filesystem::GetUserFolder();
|
storage_root = xe::filesystem::GetUserFolder();
|
||||||
#if defined(XE_PLATFORM_WIN32) || defined(XE_PLATFORM_LINUX)
|
#if XE_PLATFORM_ANDROID
|
||||||
storage_root = storage_root / "Xenia";
|
// TODO(Triang3l): Point to the app's external storage "files" directory.
|
||||||
#else
|
#else
|
||||||
// TODO(Triang3l): Point to the app's external storage "files" directory
|
|
||||||
// on Android.
|
|
||||||
#warning Unhandled platform for the data root.
|
|
||||||
storage_root = storage_root / "Xenia";
|
storage_root = storage_root / "Xenia";
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#include <mach/mach_time.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "xenia/base/assert.h"
|
#include "xenia/base/assert.h"
|
||||||
#include "xenia/base/clock.h"
|
#include "xenia/base/clock.h"
|
||||||
@@ -15,6 +18,12 @@
|
|||||||
namespace xe {
|
namespace xe {
|
||||||
|
|
||||||
uint64_t Clock::host_tick_frequency_platform() {
|
uint64_t Clock::host_tick_frequency_platform() {
|
||||||
|
#ifdef __APPLE__
|
||||||
|
mach_timebase_info_data_t info;
|
||||||
|
mach_timebase_info(&info);
|
||||||
|
return (uint64_t)((1000000000ull * (uint64_t)info.denom) /
|
||||||
|
(uint64_t)info.numer);
|
||||||
|
#else
|
||||||
timespec res;
|
timespec res;
|
||||||
int error = clock_getres(CLOCK_MONOTONIC_RAW, &res);
|
int error = clock_getres(CLOCK_MONOTONIC_RAW, &res);
|
||||||
assert_zero(error);
|
assert_zero(error);
|
||||||
@@ -22,14 +31,19 @@ uint64_t Clock::host_tick_frequency_platform() {
|
|||||||
|
|
||||||
// Convert nano seconds to hertz. Resolution is 1ns on most systems.
|
// Convert nano seconds to hertz. Resolution is 1ns on most systems.
|
||||||
return 1000000000ull / res.tv_nsec;
|
return 1000000000ull / res.tv_nsec;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t Clock::host_tick_count_platform() {
|
uint64_t Clock::host_tick_count_platform() {
|
||||||
|
#ifdef __APPLE__
|
||||||
|
return mach_absolute_time();
|
||||||
|
#else
|
||||||
timespec tp;
|
timespec tp;
|
||||||
int error = clock_gettime(CLOCK_MONOTONIC_RAW, &tp);
|
int error = clock_gettime(CLOCK_MONOTONIC_RAW, &tp);
|
||||||
assert_zero(error);
|
assert_zero(error);
|
||||||
|
|
||||||
return tp.tv_nsec + tp.tv_sec * 1000000000ull;
|
return tp.tv_nsec + tp.tv_sec * 1000000000ull;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t Clock::QueryHostSystemTime() {
|
uint64_t Clock::QueryHostSystemTime() {
|
||||||
|
|||||||
@@ -23,6 +23,10 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#if XE_PLATFORM_MAC
|
||||||
|
#include <limits.h>
|
||||||
|
#include <mach-o/dyld.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
|
|
||||||
@@ -43,10 +47,26 @@ std::filesystem::path to_path(const std::u16string_view source) {
|
|||||||
namespace filesystem {
|
namespace filesystem {
|
||||||
|
|
||||||
std::filesystem::path GetExecutablePath() {
|
std::filesystem::path GetExecutablePath() {
|
||||||
|
#if XE_PLATFORM_MAC
|
||||||
|
char path[PATH_MAX];
|
||||||
|
uint32_t size = sizeof(path);
|
||||||
|
if (_NSGetExecutablePath(path, &size) == 0) {
|
||||||
|
char real_path[PATH_MAX];
|
||||||
|
if (realpath(path, real_path)) {
|
||||||
|
return std::string(real_path);
|
||||||
|
}
|
||||||
|
return std::string(path);
|
||||||
|
}
|
||||||
|
return std::string();
|
||||||
|
#else
|
||||||
char buff[FILENAME_MAX] = "";
|
char buff[FILENAME_MAX] = "";
|
||||||
readlink("/proc/self/exe", buff, FILENAME_MAX);
|
ssize_t len = readlink("/proc/self/exe", buff, sizeof(buff) - 1);
|
||||||
std::string s(buff);
|
if (len != -1) {
|
||||||
return s;
|
buff[len] = '\0';
|
||||||
|
return std::string(buff);
|
||||||
|
}
|
||||||
|
return std::string();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
std::filesystem::path GetExecutableFolder() {
|
std::filesystem::path GetExecutableFolder() {
|
||||||
|
|||||||
@@ -146,7 +146,9 @@ void* AllocFixed(void* base_address, size_t length,
|
|||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
#ifdef MAP_FIXED_NOREPLACE
|
||||||
flags |= MAP_FIXED_NOREPLACE;
|
flags |= MAP_FIXED_NOREPLACE;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void* result = mmap(base_address, length, prot, flags, -1, 0);
|
void* result = mmap(base_address, length, prot, flags, -1, 0);
|
||||||
@@ -296,7 +298,7 @@ FileMappingHandle CreateFileMappingHandle(const std::filesystem::path& path,
|
|||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return kFileMappingHandleInvalid;
|
return kFileMappingHandleInvalid;
|
||||||
}
|
}
|
||||||
if (ftruncate64(ret, length) < 0) {
|
if (ftruncate(ret, length) < 0) {
|
||||||
close(ret);
|
close(ret);
|
||||||
shm_unlink(full_path.c_str());
|
shm_unlink(full_path.c_str());
|
||||||
return kFileMappingHandleInvalid;
|
return kFileMappingHandleInvalid;
|
||||||
@@ -335,7 +337,9 @@ void* MapFileView(FileMappingHandle handle, void* base_address, size_t length,
|
|||||||
|
|
||||||
int flags = MAP_SHARED;
|
int flags = MAP_SHARED;
|
||||||
if (base_address != nullptr) {
|
if (base_address != nullptr) {
|
||||||
|
#ifdef MAP_FIXED_NOREPLACE
|
||||||
flags |= MAP_FIXED_NOREPLACE;
|
flags |= MAP_FIXED_NOREPLACE;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void* result = mmap(base_address, length, prot, flags, handle, file_offset);
|
void* result = mmap(base_address, length, prot, flags, handle, file_offset);
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
add_library(xenia-gpu-null STATIC)
|
add_library(xenia-gpu-null STATIC)
|
||||||
xe_platform_sources(xenia-gpu-null ${CMAKE_CURRENT_SOURCE_DIR})
|
xe_platform_sources(xenia-gpu-null ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
target_include_directories(xenia-gpu-null PRIVATE
|
if(APPLE)
|
||||||
${PROJECT_SOURCE_DIR}/third_party/Vulkan-Headers/include
|
target_link_libraries(xenia-gpu-null PUBLIC xenia-base xenia-gpu xenia-ui xxhash)
|
||||||
)
|
else()
|
||||||
target_link_libraries(xenia-gpu-null PUBLIC xenia-base xenia-gpu xenia-ui xenia-ui-vulkan xxhash)
|
target_include_directories(xenia-gpu-null PRIVATE
|
||||||
|
${PROJECT_SOURCE_DIR}/third_party/Vulkan-Headers/include
|
||||||
|
)
|
||||||
|
target_link_libraries(xenia-gpu-null PUBLIC xenia-base xenia-gpu xenia-ui xenia-ui-vulkan xxhash)
|
||||||
|
endif()
|
||||||
xe_target_defaults(xenia-gpu-null)
|
xe_target_defaults(xenia-gpu-null)
|
||||||
|
|||||||
@@ -10,7 +10,9 @@
|
|||||||
#include "xenia/gpu/null/null_graphics_system.h"
|
#include "xenia/gpu/null/null_graphics_system.h"
|
||||||
|
|
||||||
#include "xenia/gpu/null//null_command_processor.h"
|
#include "xenia/gpu/null//null_command_processor.h"
|
||||||
|
#if !XE_PLATFORM_MAC
|
||||||
#include "xenia/ui/vulkan/vulkan_provider.h"
|
#include "xenia/ui/vulkan/vulkan_provider.h"
|
||||||
|
#endif
|
||||||
#include "xenia/xbox.h"
|
#include "xenia/xbox.h"
|
||||||
|
|
||||||
namespace xe {
|
namespace xe {
|
||||||
@@ -25,9 +27,13 @@ X_STATUS NullGraphicsSystem::Setup(cpu::Processor* processor,
|
|||||||
kernel::KernelState* kernel_state,
|
kernel::KernelState* kernel_state,
|
||||||
ui::WindowedAppContext* app_context,
|
ui::WindowedAppContext* app_context,
|
||||||
bool with_presentation) {
|
bool with_presentation) {
|
||||||
|
#if XE_PLATFORM_MAC
|
||||||
|
provider_ = nullptr;
|
||||||
|
#else
|
||||||
// This is a null graphics system, but we still setup vulkan because UI needs
|
// This is a null graphics system, but we still setup vulkan because UI needs
|
||||||
// it through us :|
|
// it through us :|
|
||||||
provider_ = xe::ui::vulkan::VulkanProvider::Create(false, with_presentation);
|
provider_ = xe::ui::vulkan::VulkanProvider::Create(false, with_presentation);
|
||||||
|
#endif
|
||||||
return GraphicsSystem::Setup(processor, kernel_state, app_context,
|
return GraphicsSystem::Setup(processor, kernel_state, app_context,
|
||||||
with_presentation);
|
with_presentation);
|
||||||
}
|
}
|
||||||
|
|||||||
6
third_party/CMakeLists.txt
vendored
6
third_party/CMakeLists.txt
vendored
@@ -121,6 +121,12 @@ if(WIN32)
|
|||||||
discord-rpc/src/connection_win.cpp
|
discord-rpc/src/connection_win.cpp
|
||||||
discord-rpc/src/discord_register_win.cpp
|
discord-rpc/src/discord_register_win.cpp
|
||||||
)
|
)
|
||||||
|
elseif(APPLE)
|
||||||
|
target_sources(discord-rpc PRIVATE
|
||||||
|
discord-rpc/src/connection_unix.cpp
|
||||||
|
discord-rpc/src/discord_register_osx.m
|
||||||
|
)
|
||||||
|
target_link_libraries(discord-rpc PRIVATE "-framework AppKit")
|
||||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||||
target_sources(discord-rpc PRIVATE
|
target_sources(discord-rpc PRIVATE
|
||||||
discord-rpc/src/connection_unix.cpp
|
discord-rpc/src/connection_unix.cpp
|
||||||
|
|||||||
Reference in New Issue
Block a user