From 2dcaac317caf872cc7d198c3f2ad7bacdd00f0f7 Mon Sep 17 00:00:00 2001 From: rhemf Date: Thu, 16 Jul 2026 14:05:33 +0100 Subject: [PATCH 1/2] Add native Windows ARM64 (AArch64) support Enables building and running Cemu natively on Windows on ARM (e.g. Snapdragon devices) with clang-cl. The existing AArch64 recompiler backend is used, so no x64 emulation is involved. Build system (CMakeLists.txt, dependencies/ih264d, src/Cafe): - Auto-select the arm64-windows-static vcpkg triplet and detect the AArch64 architecture even when the emulated host shell misreports it. - Disable IPO for clang-cl (LTO would force lld-link, which cannot read vcpkg's MSVC /GL objects) and link clang_rt.builtins for the compiler-rt calls (e.g. __udivti3) that lld-link does not add. - Set the static CRT on the xbyak_aarch64 target. - Locate pkgconf under the actual vcpkg host triplet instead of a hardcoded x64-windows path. - Build the bundled ih264d decoder as portable C on ARM64/Windows; its NEON .s files use ELF-only :got: relocations that do not assemble for COFF targets. Source (precompiled.h, ExceptionHandler_win32, Debugger, LatteTextureCache): - Guard x86-only intrinsics/paths behind ARCH_X86_64. clang-cl defines _MSC_VER but not __GNUC__, so several `#if defined(_MSC_VER)` branches wrongly selected x86 intrinsics on ARM64. Adds AArch64 register dumping to the crash handler. Manifest: use processorArchitecture="*" for Common-Controls so it resolves on ARM64. See BUILD.md for the build steps (Ninja + clang-cl + -DCMAKE_LINKER_TYPE=MSVC). Co-Authored-By: Claude Opus 4.8 --- BUILD.md | 30 +++++++++++++ CMakeLists.txt | 45 +++++++++++++++++-- dependencies/ih264d/CMakeLists.txt | 20 ++++++++- .../decoder/arm/ih264d_function_selector.c | 2 +- dist/windows/Cemu.manifest | 2 +- src/Cafe/CMakeLists.txt | 7 ++- src/Cafe/HW/Espresso/Debugger/Debugger.cpp | 2 +- src/Cafe/HW/Latte/Core/LatteTextureCache.cpp | 2 +- .../ExceptionHandler_win32.cpp | 16 +++++++ src/Common/precompiled.h | 25 ++++++++--- 10 files changed, 134 insertions(+), 17 deletions(-) diff --git a/BUILD.md b/BUILD.md index 6e1a2be9..e4352e03 100644 --- a/BUILD.md +++ b/BUILD.md @@ -42,6 +42,36 @@ Instructions for Visual Studio 2022: Any other IDE should also work as long as it has CMake and MSVC support. CLion and Visual Studio Code have been confirmed to work. +### Windows on ARM64 (Snapdragon) + +Native ARM64 builds are supported and use **clang-cl**. The recompiler uses the +AArch64 backend (`xbyak_aarch64`), so it runs natively rather than under x64 +emulation. + +Prerequisites (Visual Studio 2022 or Build Tools 2022 with these components): +- MSVC v143 - ARM64/ARM64EC build tools +- C++ Clang Compiler for Windows and *MSBuild support for LLVM (clang-cl) toolset* +- C++ CMake tools for Windows (CMake 3.29 or newer) +- Windows 11 SDK + +The Visual Studio CMake generator cannot assemble the codebase, so build from the +command line with Ninja. Open an **"ARM64 Native Tools Command Prompt for VS 2022"** +(or run `vcvarsarm64.bat`), then: + +``` +git clone --recursive https://github.com/cemu-project/Cemu +cd Cemu +cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=release ^ + -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl ^ + -DCMAKE_LINKER_TYPE=MSVC +cmake --build build +``` + +`-DCMAKE_LINKER_TYPE=MSVC` makes clang link with the MSVC `link.exe` (required so +that vcpkg's static libraries link correctly). The resulting binary is +`bin/Cemu_release.exe`. Note: on ARM64 the bundled H.264 decoder (ih264d) is built +as portable C, and libusb is used via the standard vcpkg package. + ## Linux To compile Cemu, a recent enough compiler and STL with C++20 support is required! Clang-15 or higher is what we recommend. diff --git a/CMakeLists.txt b/CMakeLists.txt index 644032ce..eee12591 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,7 +51,17 @@ if (ENABLE_VCPKG) # CONFIG option set(CMAKE_FIND_PACKAGE_PREFER_CONFIG TRUE) if (WIN32) - set(VCPKG_TARGET_TRIPLET "x64-windows-static" CACHE STRING "") + # Auto-select the vcpkg triplet based on the target architecture. + # Override on the command line with -DVCPKG_TARGET_TRIPLET=... + if (NOT DEFINED VCPKG_TARGET_TRIPLET) + if (CMAKE_GENERATOR_PLATFORM MATCHES "(ARM64|arm64)" OR + CMAKE_SYSTEM_PROCESSOR MATCHES "(ARM64|arm64|aarch64)" OR + "$ENV{VSCMD_ARG_TGT_ARCH}" STREQUAL "arm64") + set(VCPKG_TARGET_TRIPLET "arm64-windows-static" CACHE STRING "") + else() + set(VCPKG_TARGET_TRIPLET "x64-windows-static" CACHE STRING "") + endif() + endif() endif() endif() @@ -72,9 +82,13 @@ add_definitions(-DEMULATOR_VERSION_PATCH=${EMULATOR_VERSION_PATCH}) set_property(GLOBAL PROPERTY USE_FOLDERS ON) -# enable link time optimization for release builds -set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE ON) -set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO ON) +# enable link time optimization for release builds. +# Skip it for clang-cl on Windows: IPO forces the LLVM linker (lld-link), which +# cannot consume the MSVC /GL objects inside vcpkg static libraries. +if(NOT (MSVC AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang")) + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE ON) + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO ON) +endif() if (MSVC) set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT CemuBin) @@ -256,11 +270,34 @@ add_subdirectory("dependencies/ih264d" EXCLUDE_FROM_ALL) if (CMAKE_OSX_ARCHITECTURES) set(CEMU_ARCHITECTURE ${CMAKE_OSX_ARCHITECTURES}) +elseif (WIN32 AND (CMAKE_GENERATOR_PLATFORM MATCHES "(ARM64|arm64)" OR "$ENV{VSCMD_ARG_TGT_ARCH}" STREQUAL "arm64")) + # Windows ARM64: the host toolchain / emulated shell can misreport the + # processor, so trust the requested target platform instead. + set(CEMU_ARCHITECTURE "aarch64") else() set(CEMU_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR}) endif() if(CEMU_ARCHITECTURE MATCHES "(aarch64)|(AARCH64)|(arm64)|(ARM64)") add_subdirectory("dependencies/xbyak_aarch64" EXCLUDE_FROM_ALL) + if(MSVC) + # Match the static CRT used by the rest of the project (vcpkg static triplet) + set_property(TARGET xbyak_aarch64 PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") + endif() + if(MSVC AND CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + # clang-cl emits calls to compiler-rt builtins (e.g. __udivti3 for 128-bit + # integer division) that lld-link does not link automatically. Link the + # clang_rt.builtins library that ships next to the compiler. + get_filename_component(_llvm_bin "${CMAKE_CXX_COMPILER}" DIRECTORY) + get_filename_component(_llvm_root "${_llvm_bin}" DIRECTORY) + file(GLOB _clang_rt_builtins "${_llvm_root}/lib/clang/*/lib/windows/clang_rt.builtins-aarch64.lib") + if(_clang_rt_builtins) + list(GET _clang_rt_builtins 0 _clang_rt_builtins) + link_libraries("${_clang_rt_builtins}") + message(STATUS "Linking compiler-rt builtins: ${_clang_rt_builtins}") + else() + message(WARNING "clang_rt.builtins-aarch64.lib not found; link may fail with undefined __udivti3") + endif() + endif() endif() find_package(ZArchive QUIET) diff --git a/dependencies/ih264d/CMakeLists.txt b/dependencies/ih264d/CMakeLists.txt index a8ef3776..ded53b68 100644 --- a/dependencies/ih264d/CMakeLists.txt +++ b/dependencies/ih264d/CMakeLists.txt @@ -123,7 +123,12 @@ else() set(IH264D_ARCHITECTURE ${CMAKE_SYSTEM_PROCESSOR}) endif() -if (IH264D_ARCHITECTURE STREQUAL "x86_64" OR IH264D_ARCHITECTURE STREQUAL "amd64" OR IH264D_ARCHITECTURE STREQUAL "AMD64") +# Normalize the architecture string so matching is case-insensitive. +# MSVC/CMake reports "ARM64"/"AMD64" (uppercase) whereas the checks below use +# the lowercase names emitted by GCC/Clang toolchains. +string(TOLOWER "${IH264D_ARCHITECTURE}" IH264D_ARCHITECTURE) + +if (IH264D_ARCHITECTURE STREQUAL "x86_64" OR IH264D_ARCHITECTURE STREQUAL "amd64") set(LIBAVCDEC_X86_INCLUDES "common/x86" "decoder/x86") include_directories("common/" "decoder/" ${LIBAVCDEC_X86_INCLUDES}) target_sources(ih264d PRIVATE @@ -147,6 +152,18 @@ target_sources(ih264d PRIVATE "decoder/x86/ih264d_function_selector_ssse3.c" ) elseif(IH264D_ARCHITECTURE STREQUAL "aarch64" OR IH264D_ARCHITECTURE STREQUAL "arm64") +if(MSVC) +# Windows on ARM64: build the generic C decoder. The NEON .s files are GAS syntax +# and use ELF-only ":got:" relocations that cannot be assembled for COFF targets, +# so we fall back to portable C (only affects H.264/FMV decode performance). +set(LIBAVCDEC_ARM_INCLUDES "common/armv8" "decoder/arm") +include_directories("common/" "decoder/" ${LIBAVCDEC_ARM_INCLUDES}) +target_sources(ih264d PRIVATE +"common/armv8/ih264_platform_macros.h" +"decoder/arm/ih264d_function_selector.c" +) +target_compile_definitions(ih264d PRIVATE ARMV8 DISABLE_NEON DEFAULT_ARCH=D_ARCH_ARM_NONEON) +else() enable_language( C CXX ASM ) set(LIBAVCDEC_ARM_INCLUDES "common/armv8" "decoder/arm") include_directories("common/" "decoder/" ${LIBAVCDEC_ARM_INCLUDES}) @@ -189,6 +206,7 @@ endif() if(APPLE) target_sources(ih264d PRIVATE "common/armv8/macos_arm_symbol_aliases.s") endif() +endif() else() message(FATAL_ERROR "ih264d unknown architecture: ${IH264D_ARCHITECTURE}") endif() diff --git a/dependencies/ih264d/decoder/arm/ih264d_function_selector.c b/dependencies/ih264d/decoder/arm/ih264d_function_selector.c index 925043bc..9b1aa52f 100644 --- a/dependencies/ih264d/decoder/arm/ih264d_function_selector.c +++ b/dependencies/ih264d/decoder/arm/ih264d_function_selector.c @@ -61,7 +61,7 @@ void ih264d_init_function_ptr(dec_struct_t *ps_codec) ih264d_init_function_ptr_generic(ps_codec); switch(e_proc_arch) { -#if defined(ARMV8) +#if defined(ARMV8) && !defined(DISABLE_NEON) case ARCH_ARMV8_GENERIC: default: ih264d_init_function_ptr_av8(ps_codec); diff --git a/dist/windows/Cemu.manifest b/dist/windows/Cemu.manifest index 5ff952b1..179d4ca9 100644 --- a/dist/windows/Cemu.manifest +++ b/dist/windows/Cemu.manifest @@ -2,7 +2,7 @@ - + diff --git a/src/Cafe/CMakeLists.txt b/src/Cafe/CMakeLists.txt index b509e722..026e20ac 100644 --- a/src/Cafe/CMakeLists.txt +++ b/src/Cafe/CMakeLists.txt @@ -668,7 +668,12 @@ endif() if (ENABLE_LIBUSB) if (ENABLE_VCPKG) if(WIN32) - set(PKG_CONFIG_EXECUTABLE "${VCPKG_INSTALLED_DIR}/x64-windows/tools/pkgconf/pkgconf.exe") + # pkgconf is a host tool; locate it under whichever host triplet vcpkg + # used (x64-windows on Intel hosts, arm64-windows on ARM64 hosts). + file(GLOB _cemu_pkgconf "${VCPKG_INSTALLED_DIR}/*/tools/pkgconf/pkgconf.exe") + if(_cemu_pkgconf) + list(GET _cemu_pkgconf 0 PKG_CONFIG_EXECUTABLE) + endif() endif() find_package(PkgConfig REQUIRED) pkg_check_modules(libusb REQUIRED IMPORTED_TARGET libusb-1.0) diff --git a/src/Cafe/HW/Espresso/Debugger/Debugger.cpp b/src/Cafe/HW/Espresso/Debugger/Debugger.cpp index 3670cc1e..dc7e2031 100644 --- a/src/Cafe/HW/Espresso/Debugger/Debugger.cpp +++ b/src/Cafe/HW/Espresso/Debugger/Debugger.cpp @@ -199,7 +199,7 @@ void debugger_updateMemoryBreakpoint(DebuggerBreakpoint* bp) { std::vector schedulerThreadHandles = coreinit::OSGetSchedulerThreads(); -#if BOOST_OS_WINDOWS +#if BOOST_OS_WINDOWS && defined(ARCH_X86_64) s_debuggerState.activeMemoryBreakpoint = bp; for (auto& hThreadNH : schedulerThreadHandles) { diff --git a/src/Cafe/HW/Latte/Core/LatteTextureCache.cpp b/src/Cafe/HW/Latte/Core/LatteTextureCache.cpp index 3145e90e..ed6d1592 100644 --- a/src/Cafe/HW/Latte/Core/LatteTextureCache.cpp +++ b/src/Cafe/HW/Latte/Core/LatteTextureCache.cpp @@ -146,7 +146,7 @@ uint32 LatteTexture_CalculateTextureDataHash(LatteTexture* hostTexture) bool isCompressedFormat = hostTexture->IsCompressedFormat(); if( isCompressedFormat == false ) { -#if BOOST_OS_WINDOWS +#if BOOST_OS_WINDOWS && defined(ARCH_X86_64) if (g_CPUFeatures.x86.avx2) { __m256i h256 = { 0 }; diff --git a/src/Common/ExceptionHandler/ExceptionHandler_win32.cpp b/src/Common/ExceptionHandler/ExceptionHandler_win32.cpp index 6b205d26..3181d5b0 100644 --- a/src/Common/ExceptionHandler/ExceptionHandler_win32.cpp +++ b/src/Common/ExceptionHandler/ExceptionHandler_win32.cpp @@ -209,6 +209,7 @@ void createCrashlog(EXCEPTION_POINTERS* e, PCONTEXT context) // register info sprintf(dumpLine, "\n"); cemuLog_writePlainToLog(dumpLine); +#if defined(ARCH_X86_64) sprintf(dumpLine, "RAX=%016I64x RBX=%016I64x RCX=%016I64x RDX=%016I64x\n", context->Rax, context->Rbx, context->Rcx, context->Rdx); cemuLog_writePlainToLog(dumpLine); sprintf(dumpLine, "RSP=%016I64x RBP=%016I64x RDI=%016I64x RSI=%016I64x\n", context->Rsp, context->Rbp, context->Rdi, context->Rsi); @@ -217,6 +218,17 @@ void createCrashlog(EXCEPTION_POINTERS* e, PCONTEXT context) cemuLog_writePlainToLog(dumpLine); sprintf(dumpLine, "R12=%016I64x R13=%016I64x R14=%016I64x R15=%016I64x\n", context->R12, context->R13, context->R14, context->R15); cemuLog_writePlainToLog(dumpLine); +#else // AArch64 + for (int i = 0; i < 28; i += 4) + { + sprintf(dumpLine, "X%-2d=%016I64x X%-2d=%016I64x X%-2d=%016I64x X%-2d=%016I64x\n", + i, context->X[i], i + 1, context->X[i + 1], i + 2, context->X[i + 2], i + 3, context->X[i + 3]); + cemuLog_writePlainToLog(dumpLine); + } + sprintf(dumpLine, "X28=%016I64x FP =%016I64x LR =%016I64x SP =%016I64x PC =%016I64x\n", + context->X[28], context->Fp, context->Lr, context->Sp, context->Pc); + cemuLog_writePlainToLog(dumpLine); +#endif CrashLog_SetOutputChannels(false, true); ExceptionHandler_LogGeneralInfo(); @@ -264,11 +276,15 @@ LONG WINAPI VectoredExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo) if (r != EXCEPTION_CONTINUE_SEARCH) return r; +#if defined(ARCH_X86_64) if (GetBits(pExceptionInfo->ContextRecord->Dr6, 0, 1) || GetBits(pExceptionInfo->ContextRecord->Dr6, 1, 1)) debugger_handleSingleStepException(pExceptionInfo->ContextRecord->Dr6); else if (GetBits(pExceptionInfo->ContextRecord->Dr6, 2, 1) || GetBits(pExceptionInfo->ContextRecord->Dr6, 3, 1)) g_gdbstub->HandleAccessException(pExceptionInfo->ContextRecord->Dr6); return EXCEPTION_CONTINUE_EXECUTION; +#else // AArch64: hardware debug registers (Dr6) not available; debugger single-step unsupported for now + return EXCEPTION_CONTINUE_SEARCH; +#endif } return EXCEPTION_CONTINUE_SEARCH; } diff --git a/src/Common/precompiled.h b/src/Common/precompiled.h index e0373952..f2f18155 100644 --- a/src/Common/precompiled.h +++ b/src/Common/precompiled.h @@ -268,6 +268,15 @@ typedef union _LARGE_INTEGER { inline T& operator^= (T& a, T b) { return reinterpret_cast( reinterpret_cast::type&>(a) ^= static_cast::type>(b) ); } #endif +#if defined(_MSC_VER) && defined(_M_ARM64) +// _umul128 is an x86-64 intrinsic and is not provided by on AArch64 +inline uint64 _umul128(uint64 multiplier, uint64 multiplicand, uint64 *highProduct) { + unsigned __int128 x = (unsigned __int128)multiplier * (unsigned __int128)multiplicand; + *highProduct = (uint64)(x >> 64); + return (uint64)(x & 0xFFFFFFFFFFFFFFFF); +} +#endif + template inline T GetBits(T value, uint32 index, uint32 numBits) { @@ -343,10 +352,10 @@ inline uint64 _udiv128(uint64 highDividend, uint64 lowDividend, uint64 divisor, FORCE_INLINE int BSF(uint32 v) // returns index of first bit set, counting from LSB. If v is 0 then result is undefined { -#if defined(_MSC_VER) +#if defined(__GNUC__) || defined(__clang__) + return __builtin_ctz(v); // clang-cl also defines _MSC_VER, so check this first +#elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86)) return _tzcnt_u32(v); // TZCNT requires BMI1. But if not supported it will execute as BSF -#elif defined(__GNUC__) || defined(__clang__) - return __builtin_ctz(v); #else return std::countr_zero(v); #endif @@ -610,12 +619,14 @@ inline uint32 GetTitleIdLow(uint64 titleId) return titleId & 0xFFFFFFFF; } -#if defined(__GNUC__) -#define memcpy_dwords(__dest, __src, __numDwords) memcpy((__dest), (__src), (__numDwords) * sizeof(uint32)) -#define memcpy_qwords(__dest, __src, __numQwords) memcpy((__dest), (__src), (__numQwords) * sizeof(uint64)) -#else +// __movsd/__movsq are x86-only MSVC intrinsics; use memcpy everywhere else +// (clang-cl does not define __GNUC__, and AArch64 has no such intrinsics) +#if defined(_MSC_VER) && !defined(__clang__) && defined(ARCH_X86_64) #define memcpy_dwords(__dest, __src, __numDwords) __movsd((unsigned long*)(__dest), (const unsigned long*)(__src), __numDwords) #define memcpy_qwords(__dest, __src, __numQwords) __movsq((unsigned long long*)(__dest), (const unsigned long long*)(__src), __numQwords) +#else +#define memcpy_dwords(__dest, __src, __numDwords) memcpy((__dest), (__src), (__numDwords) * sizeof(uint32)) +#define memcpy_qwords(__dest, __src, __numQwords) memcpy((__dest), (__src), (__numQwords) * sizeof(uint64)) #endif // PPC context and memory functions From acfe7db8732af8c6f085ee66bddfcbb6db3dd69b Mon Sep 17 00:00:00 2001 From: rhemf Date: Thu, 16 Jul 2026 15:30:08 +0100 Subject: [PATCH 2/2] ci: add Windows ARM64 build job Builds Cemu for windows-11-arm with clang-cl + Ninja and uploads the ARM64 exe as an artifact, so official ARM64 Windows builds can be produced. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/build.yml | 78 +++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3aaf9a93..577d6d23 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -204,6 +204,84 @@ jobs: name: cemu-installer-windows-x64 path: ./src/resource/cemu-${{ inputs.next_version_major }}.${{ inputs.next_version_minor }}-windows-x64-installer.exe + build-windows-arm64: + continue-on-error: true + runs-on: windows-11-arm + steps: + - name: "Checkout repo" + uses: actions/checkout@v6 + with: + submodules: "recursive" + + - name: Setup release mode parameters + run: | + echo "BUILD_MODE=release" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append + echo "BUILD_FLAGS=" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append + echo "Build mode is release" + + - name: Setup build flags for version + if: ${{ inputs.next_version_major != '' }} + run: | + echo "[INFO] Version ${{ inputs.next_version_major }}.${{ inputs.next_version_minor }}" + echo "BUILD_FLAGS=${{ env.BUILD_FLAGS }} -DEMULATOR_VERSION_MAJOR=${{ inputs.next_version_major }} -DEMULATOR_VERSION_MINOR=${{ inputs.next_version_minor }}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf8 -Append + + - name: "Ensure clang-cl (LLVM) toolset is installed in Visual Studio" + run: | + $vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" + $vsPath = & $vswhere -latest -products * -property installationPath + $setup = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\setup.exe" + $modifyArgs = "modify --installPath `"$vsPath`" --add Microsoft.VisualStudio.Component.VC.Llvm.Clang --add Microsoft.VisualStudio.Component.VC.Llvm.ClangToolset --quiet --norestart" + Start-Process -FilePath $setup -Wait -ArgumentList $modifyArgs + + - name: "Setup MSVC environment (arm64)" + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: arm64 + + - name: "Setup Ninja" + run: choco install ninja -y + + - name: "Setup cmake" + uses: jwlawson/actions-setup-cmake@v2 + with: + cmake-version: '3.29.0' + + - name: "Bootstrap vcpkg" + run: | + ./dependencies/vcpkg/bootstrap-vcpkg.bat + + - name: 'Setup NuGet Credentials for vcpkg' + shell: 'bash' + run: | + `./dependencies/vcpkg/vcpkg.exe fetch nuget | tail -n 1` \ + sources add \ + -source "https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json" \ + -storepasswordincleartext \ + -name "GitHub" \ + -username "${{ github.repository_owner }}" \ + -password "${{ secrets.GITHUB_TOKEN }}" + `./dependencies/vcpkg/vcpkg.exe fetch nuget | tail -n 1` \ + setapikey "${{ secrets.GITHUB_TOKEN }}" \ + -source "https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json" + + - name: "cmake" + run: | + echo "[INFO] BUILD_FLAGS: ${{ env.BUILD_FLAGS }}" + cmake -S . -B build -G Ninja ${{ env.BUILD_FLAGS }} -DCMAKE_BUILD_TYPE=${{ env.BUILD_MODE }} -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl -DCMAKE_LINKER_TYPE=MSVC -DVCPKG_INSTALL_OPTIONS="--clean-after-build" + + - name: "Build Cemu" + run: | + cmake --build build + + - name: Prepare artifact + run: Rename-Item bin/Cemu_release.exe Cemu.exe + + - name: Upload artifact + uses: actions/upload-artifact@v6 + with: + name: cemu-bin-windows-arm64 + path: ./bin/Cemu.exe + build-macos: runs-on: macos-14 strategy: