macos build (#299)

This commit is contained in:
Bruno 2026-09-27 13:20:58 +02:00 committed by GitHub
parent 00b15a301e
commit 7a2a68f7ee
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 217 additions and 41 deletions

View File

@ -1,6 +1,7 @@
{
"Core" : {
"ModuleDirectory-x64" : "..\\..\\..\\modules\\x64"
"ModuleDirectory-x64" : "..\\..\\..\\modules\\x64",
"ModuleDirectory-arm64" : "../../../modules/arm64"
},
"UI" : {
"Language" : {

View File

@ -3,6 +3,16 @@ if (NOT TARGET fmt::fmt)
add_subdirectory(fmt)
endif()
# AppleClang 21 rejects the consteval path used by the bundled fmt 10.x.
# fmt 10.1.1 controls the constructor qualifier with FMT_CONSTEVAL; the newer
# FMT_USE_CONSTEVAL switch does not exist in this bundled version. Define
# FMT_CONSTEVAL to an empty replacement on the affected toolchain, matching
# the upstream workaround for fmt 10.x on AppleClang 21.
if(APPLE AND CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" AND
CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 21)
target_compile_definitions(fmt PUBLIC FMT_CONSTEVAL=)
endif()
# Boost
if(NOT TARGET Boost::headers)
set(BOOST_SUPERPROJECT_VERSION "1.84.0" CACHE STRING "Boost version string for modular CMakeLists")
@ -69,12 +79,16 @@ if(TARGET libzstd_static AND NOT TARGET zstd::zstd)
endif()
# zlib + minizip (nxemu-loader firmware zip extraction)
if(NOT TARGET zlibstatic)
# The bundled zlib 1.3.1 CMake temporarily renames its source zconf.h during
# out-of-source configuration. Restoring that file immediately makes quoted
# includes select the unconfigured source header on macOS, so POSIX prototypes
# such as read/write/lseek are lost. Use the SDK zlib on Apple instead.
if(APPLE)
find_package(ZLIB REQUIRED)
elseif(NOT TARGET zlibstatic)
set(ZLIB_BUILD_EXAMPLES OFF CACHE BOOL "Build zlib example/minigzip programs" FORCE)
add_subdirectory("${CMAKE_SOURCE_DIR}/external/zlib" "${CMAKE_BINARY_DIR}/external/zlib")
# zlib's CMake renames the tracked source zconf.h -> zconf.h.included during
# out-of-source configure. Undo that so the submodule working tree stays clean.
# The build still uses the generated header in ${CMAKE_BINARY_DIR}/external/zlib.
# Preserve the existing non-Apple behavior.
set(_nxemu_zlib_src "${CMAKE_SOURCE_DIR}/external/zlib")
if(EXISTS "${_nxemu_zlib_src}/zconf.h.included" AND NOT EXISTS "${_nxemu_zlib_src}/zconf.h")
file(RENAME "${_nxemu_zlib_src}/zconf.h.included" "${_nxemu_zlib_src}/zconf.h")

View File

@ -1,3 +1,7 @@
if(APPLE)
enable_language(OBJC)
endif()
add_library(discord-rpc STATIC
src/discord_rpc.cpp
src/rpc_connection.cpp

View File

@ -9,6 +9,9 @@
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#ifdef __APPLE__
#include <mach-o/dyld.h>
#endif
#endif
#ifdef _WIN32
@ -613,6 +616,29 @@ void Path::SetToModuleDirectory()
bufferSize *= 2;
buffPath.resize(bufferSize);
}
#elif defined(__APPLE__)
uint32_t bufferSize = 4096;
std::vector<char> buffPath(bufferSize);
while (true)
{
uint32_t requiredSize = bufferSize;
if (_NSGetExecutablePath(buffPath.data(), &requiredSize) == 0)
{
m_path = buffPath.data();
SetNameExtension("");
return;
}
if (requiredSize <= bufferSize)
{
m_path = "";
return;
}
bufferSize = requiredSize;
buffPath.resize(bufferSize);
}
#else
size_t bufferSize = 4096;
std::vector<char> buffPath(bufferSize);

View File

@ -31,7 +31,14 @@ void ModuleList::AddModuleFromDir(const Path & dir)
} while (dirFinder.FindNext(foundDir));
}
PathFinder fileFinder(Path(dir.GetDriveDirectory().c_str(), "*.dll"));
#if defined(_WIN32)
constexpr const char * modulePattern = "*.dll";
#elif defined(__APPLE__)
constexpr const char * modulePattern = "*.dylib";
#else
constexpr const char * modulePattern = "*.so";
#endif
PathFinder fileFinder(Path(dir.GetDriveDirectory().c_str(), modulePattern));
Path foundFile;
if (fileFinder.FindFirst(foundFile))
{

View File

@ -49,10 +49,16 @@ namespace
} clearValue;
};
#if defined(_M_ARM64) || defined(ARCHITECTURE_arm64) || defined(__aarch64__)
constexpr const char * ModuleDirectorySettingKey = "ModuleDirectory-arm64";
#else
constexpr const char * ModuleDirectorySettingKey = "ModuleDirectory-x64";
#endif
static CoreSetting settings[] = {
{ NXCoreSetting::AppBaseDirectory, &coreSettings.baseDir },
{ NXCoreSetting::AppDirectory, &coreSettings.appDir },
{ NXCoreSetting::ModuleDirectory, "", "ModuleDirectory-x64", &coreSettings.moduleDir, &coreSettings.moduleDirValue, "./modules" },
{ NXCoreSetting::ModuleDirectory, "", ModuleDirectorySettingKey, &coreSettings.moduleDir, &coreSettings.moduleDirValue, "./modules" },
#ifdef _WIN32
#ifdef _DEBUG
{ NXCoreSetting::ModuleLoader, "modules", "loader", &coreSettings.moduleLoader, "loader\\nxemu-loader_d.dll" },
@ -65,6 +71,11 @@ namespace
{ NXCoreSetting::ModuleVideo, "modules", "video", &coreSettings.moduleVideo, "video\\nxemu-video.dll" },
{ NXCoreSetting::ModuleOs, "modules", "os", &coreSettings.moduleOs, "operating_system\\nxemu-os.dll" },
#endif
#elif defined(__APPLE__)
{NXCoreSetting::ModuleLoader, "modules", "loader", &coreSettings.moduleLoader, "loader/libnxemu-loader.dylib"},
{NXCoreSetting::ModuleCpu, "modules", "cpu", &coreSettings.moduleCpu, "cpu/libnxemu-cpu.dylib"},
{NXCoreSetting::ModuleVideo, "modules", "video", &coreSettings.moduleVideo, "video/libnxemu-video.dylib"},
{NXCoreSetting::ModuleOs, "modules", "os", &coreSettings.moduleOs, "operating_system/libnxemu-os.dylib"},
#elif defined(ANDROID)
{NXCoreSetting::ModuleLoader, "modules", "loader", &coreSettings.moduleLoader, "libnxemu-loader.so"},
{NXCoreSetting::ModuleCpu, "modules", "cpu", &coreSettings.moduleCpu, "libnxemu-cpu.so"},

View File

@ -377,13 +377,12 @@ if(ARCHITECTURE_arm64)
enable_language(C ASM)
set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -x assembler-with-cpp")
if(NOT MSVC)
if(UNIX AND NOT APPLE)
target_compile_options(nxemu-cpu PRIVATE $<$<COMPILE_LANGUAGE:ASM>:-Wa,--noexecstack>)
target_link_options(nxemu-cpu PRIVATE -Wl,-z,noexecstack)
endif()
target_sources(nxemu-cpu PRIVATE
dynarmic/backend/exception_handler_generic.cpp
dynarmic/common/spin_lock_arm64.cpp
dynarmic/backend/arm64/a32_jitstate.cpp
dynarmic/backend/arm64/a32_address_space.cpp
@ -419,19 +418,83 @@ if(ARCHITECTURE_arm64)
dynarmic/backend/arm64/stack_layout.h
dynarmic/backend/arm64/verbose_debugging_output.cpp
dynarmic/backend/arm64/verbose_debugging_output.h
nce/arm_nce_asm_definitions.h
nce/arm_nce.cpp
nce/arm_nce.h
nce/arm_nce.s
nce/guest_context.h
nce/instructions.h
nce/interpreter_visitor.cpp
nce/interpreter_visitor.h
nce/patcher.cpp
nce/patcher.h
nce/visitor_base.h
)
if(APPLE)
find_program(NXEMU_MIG_EXECUTABLE mig REQUIRED)
find_path(NXEMU_MACH_EXC_INCLUDE_DIR mach/mach_exc.defs)
if(NOT NXEMU_MACH_EXC_INCLUDE_DIR)
execute_process(
COMMAND xcrun --sdk macosx --show-sdk-path
OUTPUT_VARIABLE NXEMU_MACOS_SDK
OUTPUT_STRIP_TRAILING_WHITESPACE
COMMAND_ERROR_IS_FATAL ANY
)
if(EXISTS "${NXEMU_MACOS_SDK}/usr/include/mach/mach_exc.defs")
set(NXEMU_MACH_EXC_INCLUDE_DIR "${NXEMU_MACOS_SDK}/usr/include")
endif()
endif()
if(NOT NXEMU_MACH_EXC_INCLUDE_DIR)
message(FATAL_ERROR "Unable to locate mach/mach_exc.defs required by Dynarmic fastmem on macOS")
endif()
set(_nxemu_mig_dir "${CMAKE_CURRENT_BINARY_DIR}/dynarmic/backend/arm64/mig")
set(_nxemu_mig_user_c "${_nxemu_mig_dir}/mach_exc_user.c")
set(_nxemu_mig_user_h "${_nxemu_mig_dir}/mach_exc_user.h")
set(_nxemu_mig_server_c "${_nxemu_mig_dir}/mach_exc_server.c")
set(_nxemu_mig_server_h "${_nxemu_mig_dir}/mach_exc_server.h")
add_custom_command(
OUTPUT
"${_nxemu_mig_user_c}"
"${_nxemu_mig_user_h}"
"${_nxemu_mig_server_c}"
"${_nxemu_mig_server_h}"
COMMAND ${CMAKE_COMMAND} -E make_directory "${_nxemu_mig_dir}"
COMMAND "${NXEMU_MIG_EXECUTABLE}"
-arch arm64
-user "${_nxemu_mig_user_c}"
-header "${_nxemu_mig_user_h}"
-server "${_nxemu_mig_server_c}"
-sheader "${_nxemu_mig_server_h}"
"${NXEMU_MACH_EXC_INCLUDE_DIR}/mach/mach_exc.defs"
DEPENDS "${NXEMU_MACH_EXC_INCLUDE_DIR}/mach/mach_exc.defs"
VERBATIM
COMMENT "Generating Dynarmic Mach exception server for arm64"
)
add_custom_target(nxemu-dynarmic-mig DEPENDS
"${_nxemu_mig_user_c}"
"${_nxemu_mig_user_h}"
"${_nxemu_mig_server_c}"
"${_nxemu_mig_server_h}"
)
add_dependencies(nxemu-cpu nxemu-dynarmic-mig)
target_include_directories(nxemu-cpu PRIVATE "${CMAKE_CURRENT_BINARY_DIR}")
target_sources(nxemu-cpu PRIVATE
dynarmic/backend/exception_handler_macos.cpp
dynarmic/backend/exception_handler_macos_mig.c
)
elseif(ANDROID OR CMAKE_SYSTEM_NAME STREQUAL "Linux")
target_compile_definitions(nxemu-cpu PRIVATE NXEMU_HAS_NCE=1)
target_sources(nxemu-cpu PRIVATE
dynarmic/backend/exception_handler_generic.cpp
nce/arm_nce_asm_definitions.h
nce/arm_nce.cpp
nce/arm_nce.h
nce/arm_nce.s
nce/guest_context.h
nce/instructions.h
nce/interpreter_visitor.cpp
nce/interpreter_visitor.h
nce/patcher.cpp
nce/patcher.h
nce/visitor_base.h
)
else()
target_sources(nxemu-cpu PRIVATE dynarmic/backend/exception_handler_generic.cpp)
endif()
if(TARGET merry::oaknut)
target_link_libraries(nxemu-cpu PRIVATE merry::oaknut)
elseif(TARGET oaknut)

View File

@ -520,7 +520,7 @@ void ArmDynarmic32::ClearInstructionCache()
m_jit->ClearCache();
}
void ArmDynarmic32::InvalidateCacheRange(u64 addr, std::size_t size)
void ArmDynarmic32::InvalidateCacheRange(uint64_t addr, uint64_t size)
{
m_jit->InvalidateCacheRange(static_cast<u32>(addr), size);
}

View File

@ -158,7 +158,7 @@ public:
return CheckMemoryAccess(vaddr, 16, CpuDebugWatchpointType::Write) && m_memory.WriteExclusive128(vaddr, value[1], value[0], expected[1], expected[0]);
}
void InterpreterFallback(uint64_t /*pc*/, uint64_t /*num_instructions*/) override
void InterpreterFallback(uint64_t /*pc*/, std::size_t /*num_instructions*/) override
{
g_notify->BreakPoint(__FILE__, __LINE__);
}

View File

@ -5,7 +5,7 @@
#if defined(_M_X64) || defined(ARCHITECTURE_x86_64) || defined(_M_ARM64) || defined(ARCHITECTURE_arm64)
#include "exclusive_monitor_interface.h"
#endif
#if defined(_M_ARM64) || defined(ARCHITECTURE_arm64) || defined(__aarch64__)
#if defined(NXEMU_HAS_NCE)
#include "cpu_settings_identifiers.h"
#include "nce/arm_nce.h"
#include <nxemu-module-spec/base.h>
@ -45,7 +45,7 @@ IPatchCollection * CpuInterface::CreatePatchCollection(bool is_application)
ICpuCore * CpuInterface::CreateCpuCore(ICoreSystem & system, bool is64Bit, bool usesWallClock, IKernelProcess & process, uint32_t coreIndex)
{
#if defined(_M_ARM64) || defined(ARCHITECTURE_arm64) || defined(__aarch64__)
#if defined(NXEMU_HAS_NCE)
if (is64Bit && g_settings && g_settings->GetBool(NXCpuSetting::NceEnabled))
{
return new Core::ArmNce(system, usesWallClock, process, coreIndex);

View File

@ -49,7 +49,7 @@ public:
};
static CpuSetting settings[] = {
#if defined(_M_ARM64) || defined(ARCHITECTURE_arm64)
#if defined(NXEMU_HAS_NCE)
{NXCpuSetting::CpuBackend, "cpu", "cpu_backend", &cpuSettings.cpu_backend, CpuBackend::Nce},
#else
{NXCpuSetting::CpuBackend, "cpu", "cpu_backend", &cpuSettings.cpu_backend, CpuBackend::Dynarmic},
@ -120,7 +120,11 @@ bool IsFastmemEnabled()
void UpdateNceEnabled()
{
const bool has_39bit = g_settings->GetBool(NXCoreSetting::Has39BitAddressSpace);
#if defined(NXEMU_HAS_NCE)
const bool is_nce = g_settings->GetInt(NXCpuSetting::CpuBackend) == static_cast<int32_t>(CpuBackend::Nce);
#else
const bool is_nce = false;
#endif
if (is_nce && !IsFastmemEnabled())
{
LOG_WARNING(Common, "Fastmem is required to natively execute code in a performant manner, falling back to Dynarmic");
@ -237,6 +241,14 @@ void SetupCpuSetting(void)
}
}
#if !defined(NXEMU_HAS_NCE)
if (cpuSettings.cpu_backend == CpuBackend::Nce)
{
LOG_WARNING(Common, "NCE is unavailable on this host; using Dynarmic");
cpuSettings.cpu_backend = CpuBackend::Dynarmic;
}
#endif
for (const CpuSetting & cpuSetting : settings)
{
switch (cpuSetting.settingType)

View File

@ -12,14 +12,14 @@ PatchCollection::PatchCollection(ISystemModules & modules, bool is_application)
m_is_application(is_application)
{
std::fill(std::begin(m_module_patcher_indices), std::end(m_module_patcher_indices), -1);
#if defined(_M_ARM64) || defined(ARCHITECTURE_arm64) || defined(__aarch64__)
#if defined(NXEMU_HAS_NCE)
m_patchers.emplace_back();
#endif
}
void PatchCollection::PatchText(int32_t patch_index, const uint8_t * program_image, uint32_t image_size, uint32_t code_offset, uint32_t code_size)
{
#if defined(_M_ARM64) || defined(ARCHITECTURE_arm64) || defined(__aarch64__)
#if defined(NXEMU_HAS_NCE)
if (!m_is_application || !g_settings->GetBool(NXCpuSetting::NceEnabled))
{
return;
@ -41,7 +41,7 @@ void PatchCollection::PatchText(int32_t patch_index, const uint8_t * program_ima
void PatchCollection::Relocate(int32_t patch_index, uint64_t load_base, uint8_t * program_image, uint32_t * image_size, uint32_t code_offset, uint32_t code_size, uint64_t * segment_addr, uint32_t * segment_size)
{
#if defined(_M_ARM64) || defined(ARCHITECTURE_arm64) || defined(__aarch64__)
#if defined(NXEMU_HAS_NCE)
if (!m_is_application || !g_settings->GetBool(NXCpuSetting::NceEnabled))
{
return;
@ -99,7 +99,7 @@ void PatchCollection::Relocate(int32_t patch_index, uint64_t load_base, uint8_t
uint32_t PatchCollection::GetTotalPatchSize() const
{
#if defined(_M_ARM64) || defined(ARCHITECTURE_arm64) || defined(__aarch64__)
#if defined(NXEMU_HAS_NCE)
if (!m_is_application || !g_settings->GetBool(NXCpuSetting::NceEnabled))
{
return 0;
@ -118,7 +118,7 @@ uint32_t PatchCollection::GetTotalPatchSize() const
uint32_t PatchCollection::GetPreTextSize(int32_t patch_index) const
{
#if defined(_M_ARM64) || defined(ARCHITECTURE_arm64) || defined(__aarch64__)
#if defined(NXEMU_HAS_NCE)
if (!m_is_application || !g_settings->GetBool(NXCpuSetting::NceEnabled))
{
return 0;
@ -142,7 +142,7 @@ uint32_t PatchCollection::GetPreTextSize(int32_t patch_index) const
int32_t PatchCollection::GetLastIndex() const
{
#if defined(_M_ARM64) || defined(ARCHITECTURE_arm64) || defined(__aarch64__)
#if defined(NXEMU_HAS_NCE)
return (int32_t)(m_patchers.size()) - 1;
#else
return 0;

View File

@ -1,7 +1,7 @@
#pragma once
#include <nxemu-module-spec/cpu.h>
#if defined(_M_ARM64) || defined(ARCHITECTURE_arm64) || defined(__aarch64__)
#if defined(NXEMU_HAS_NCE)
#include "nce/patcher.h"
#include <vector>
#endif
@ -25,7 +25,7 @@ private:
ISystemModules & m_modules;
bool m_is_application;
int32_t m_module_patcher_indices[13];
#if defined(_M_ARM64) || defined(ARCHITECTURE_arm64) || defined(__aarch64__)
#if defined(NXEMU_HAS_NCE)
std::vector<Core::NCE::Patcher> m_patchers;
#endif
};

View File

@ -2,8 +2,8 @@ cmake_minimum_required(VERSION 3.18)
# nxemu-os depends on yuzu "core", yuzu_audio_core, src/network, hid_core (which itself
# links "core"), cubeb, SDL, etc. Host desktop builds may still be incomplete — default OFF.
# Android needs the OS plugin .so alongside loader/cpu/video, so default ON there.
if(ANDROID)
# Android and macOS require the OS plugin alongside loader/cpu/video.
if(ANDROID OR APPLE)
set(_NXEMU_OS_BUILD_DEFAULT ON)
else()
set(_NXEMU_OS_BUILD_DEFAULT OFF)
@ -77,6 +77,13 @@ target_link_libraries(nxemu-os PRIVATE
if(ANDROID)
target_link_libraries(nxemu-os PRIVATE log)
elseif(APPLE)
find_library(NXEMU_SECURITY_FRAMEWORK Security REQUIRED)
find_library(NXEMU_COREFOUNDATION_FRAMEWORK CoreFoundation REQUIRED)
target_link_libraries(nxemu-os PRIVATE
"${NXEMU_SECURITY_FRAMEWORK}"
"${NXEMU_COREFOUNDATION_FRAMEWORK}"
)
endif()
# Use BSD socket headers and TranslateIPv4(in_addr) path (Linux/macOS/Android).

View File

@ -626,7 +626,8 @@ public:
void ClearDpc(DpcFlag flag)
{
this->GetStackParameters().dpc_flags &= ~static_cast<u8>(flag);
this->GetStackParameters().dpc_flags = static_cast<u8>(
this->GetStackParameters().dpc_flags & ~static_cast<u8>(flag));
}
u8 GetDpc() const

View File

@ -36,7 +36,8 @@ Result QueryProcessMemory(Core::System& system, uint64_t out_memory_info, PageIn
R_TRY(process->GetKPageTable().QueryInfo(std::addressof(mem_info), out_page_info, address));
const auto svc_mem_info = mem_info.GetSvcMemoryInfo();
current_memory.WriteBlock(out_memory_info, std::addressof(svc_mem_info), sizeof(svc_mem_info));
current_memory.WriteBlock(Common::ProcessAddress{out_memory_info}, std::addressof(svc_mem_info),
sizeof(svc_mem_info));
R_SUCCEED();
}

View File

@ -160,7 +160,9 @@ Result GetThreadContext3(Core::System& system, u64 out_context, Handle thread_ha
R_TRY(thread->GetThreadContext3(std::addressof(context)));
// Copy the thread context to user space.
R_UNLESS(GetCurrentMemory(kernel).WriteBlock(out_context, std::addressof(context), sizeof(context)), ResultInvalidPointer);
R_UNLESS(GetCurrentMemory(kernel).WriteBlock(Common::ProcessAddress{out_context},
std::addressof(context), sizeof(context)),
ResultInvalidPointer);
R_SUCCEED();
}

View File

@ -429,7 +429,7 @@ std::size_t HLERequestContext::WriteBufferB(const void* buffer, std::size_t size
size = buffer_size; // TODO(bunnei): This needs to be HW tested
}
memory.WriteBlock(BufferDescriptorB()[buffer_index].Address(), buffer, size);
memory.WriteBlock(Common::ProcessAddress{BufferDescriptorB()[buffer_index].Address()}, buffer, size);
return size;
}
@ -446,7 +446,7 @@ std::size_t HLERequestContext::WriteBufferC(const void* buffer, std::size_t size
size = buffer_size; // TODO(bunnei): This needs to be HW tested
}
memory.WriteBlock(BufferDescriptorC()[buffer_index].Address(), buffer, size);
memory.WriteBlock(Common::ProcessAddress{BufferDescriptorC()[buffer_index].Address()}, buffer, size);
return size;
}

View File

@ -3,6 +3,9 @@ cmake_minimum_required(VERSION 3.18)
if(NOT TARGET cubeb)
set(USE_SANITIZERS OFF CACHE BOOL "cubeb: skip sanitizers-cmake" FORCE)
if(APPLE)
set(BUNDLE_SPEEX ON CACHE BOOL "cubeb: use bundled Speex resampler" FORCE)
endif()
set(BUILD_TESTS OFF CACHE BOOL "cubeb: skip gtest" FORCE)
set(BUILD_TOOLS OFF CACHE BOOL "cubeb: skip tools" FORCE)
add_subdirectory("${CMAKE_SOURCE_DIR}/external/cubeb" "${CMAKE_BINARY_DIR}/external/cubeb")

View File

@ -189,4 +189,9 @@ target_include_directories(yuzu_common PUBLIC
target_link_libraries(yuzu_common PUBLIC Boost::context Boost::headers fmt::fmt stb::headers Threads::Threads)
target_link_libraries(yuzu_common PRIVATE lz4::lz4 zstd::zstd)
if(APPLE)
find_library(YUZU_COMMON_COREFOUNDATION_FRAMEWORK CoreFoundation REQUIRED)
target_link_libraries(yuzu_common PRIVATE ${YUZU_COMMON_COREFOUNDATION_FRAMEWORK})
endif()
create_target_directory_groups(yuzu_common)

View File

@ -329,10 +329,29 @@ target_include_directories(video_core PRIVATE ${CMAKE_SOURCE_DIR}/src/nxemu-vide
target_link_libraries(video_core PUBLIC common nxemu_core yuzu_common)
target_link_libraries(video_core PUBLIC glad shader_recompiler stb::headers bc_decoder stb_dxt)
if (YUZU_USE_BUNDLED_FFMPEG AND NOT (WIN32 OR ANDROID))
if (YUZU_USE_BUNDLED_FFMPEG AND NOT (WIN32 OR ANDROID OR APPLE))
add_dependencies(video_core ffmpeg-build)
endif()
if(APPLE AND NOT FFmpeg_LIBRARIES)
set(_ffmpeg_macos_root "${CMAKE_SOURCE_DIR}/external/ffmpeg/lib/macos-arm64")
set(_ffmpeg_macos_libs
"${_ffmpeg_macos_root}/libavfilter.a"
"${_ffmpeg_macos_root}/libavcodec.a"
"${_ffmpeg_macos_root}/libswscale.a"
"${_ffmpeg_macos_root}/libavutil.a"
)
foreach(_ffmpeg_lib IN LISTS _ffmpeg_macos_libs)
if(NOT EXISTS "${_ffmpeg_lib}")
message(FATAL_ERROR "Missing FFmpeg macOS arm64 library: ${_ffmpeg_lib}")
endif()
endforeach()
set(FFmpeg_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/external/ffmpeg/include")
set(FFmpeg_LIBRARIES ${_ffmpeg_macos_libs})
endif()
if(NOT FFmpeg_INCLUDE_DIR)
set(FFmpeg_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/external/ffmpeg/include")
endif()