From dda1431d8b91733ef01e4a9be1cca3ac609630c6 Mon Sep 17 00:00:00 2001 From: crueter Date: Mon, 10 Nov 2025 01:41:11 -0500 Subject: [PATCH] [cmake] allow fully static MinGW builds + (theoretical) clangarm64 Requires qt6-static, obviously... at least for eden. eden-cli also can be built fully static Notable challenges n such: 1. VkMemAlloc conflicts with Qt, since it embeds vk_mem_alloc.h in qrhivulkan; we can get around this by conditionally defining VMA_IMPLEMENTATION; that is, define it in the SDL2 frontend and undef it in the Qt frontend. It's not ideal, but I mean... it works, no? 2. find_library, pkgconfig, and some Config modules will always look for a .dll, so we have to tell CMake to look for .a 3. In spite of this, some will end up using .dll.a (implib) as their link targets; this is, well, bad, so we create a find_library hook that rejects dll.a 4. Some libraries have specific configs (boost lol) 5. Some libraries use _static targets (zstd, mbedtls) 6. Some extra libraries need to be linked, i.e. jbig, lzma, etc 7. QuaZip is sad Needs testing on all platforms, and for both frontends on desktop, to ensure Vulkan still works as expected. Signed-off-by: crueter --- CMakeLists.txt | 84 ++++++++++++++++++++++++++++ CMakeModules/Findzstd.cmake | 26 +++++---- src/CMakeLists.txt | 8 ++- src/common/CMakeLists.txt | 2 +- src/core/CMakeLists.txt | 2 +- src/dedicated_room/CMakeLists.txt | 2 +- src/video_core/CMakeLists.txt | 4 -- src/video_core/vulkan_common/vma.cpp | 6 -- src/yuzu/main_window.cpp | 5 ++ src/yuzu_cmd/CMakeLists.txt | 7 +++ src/yuzu_cmd/yuzu.cpp | 6 +- 11 files changed, 123 insertions(+), 29 deletions(-) delete mode 100644 src/video_core/vulkan_common/vma.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 8ae534444e..67ecd73337 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,6 +21,11 @@ elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") set(PLATFORM_LINUX ON) endif() +# dumb heuristic to detect msys2 +if (CMAKE_COMMAND MATCHES "msys64") + set(PLATFORM_MSYS ON) +endif() + if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") set(CXX_CLANG ON) if (MSVC) @@ -85,6 +90,84 @@ if (PLATFORM_NETBSD) set(ENV{PKG_CONFIG_PATH} "${PKG_CONFIG_PATH}:${CMAKE_SYSROOT}/usr/pkg/lib/ffmpeg7/pkgconfig") endif() +# MSYS2 utilities +if (PLATFORM_MSYS) + # really, really dumb heuristic to detect what environment we are in + macro(system var) + if (CMAKE_COMMAND MATCHES ${var}) + set(MSYSTEM ${var}) + endif() + endmacro() + + system(mingw64) + system(clang64) + system(clangarm64) + system(ucrt64) + + if (NOT DEFINED MSYSTEM) + set(MSYSTEM msys2) + endif() + + # we (generally) want to prioritize environment-specific binaries if possible + # some, like autoconf, are not present on environments besides msys2 though + set(CMAKE_PROGRAM_PATH C:/msys64/${MSYSTEM}/usr/bin C:/msys64/usr/bin) +endif() + +# static stuff +option(YUZU_STATIC_BUILD "Use static libraries and executables if available" OFF) + +if (YUZU_STATIC_BUILD) + # lol + set(Boost_USE_STATIC_LIBS ON) + set(BUILD_SHARED_LIBS OFF) + + ## find .a libs first (static, usually) + set(CMAKE_FIND_LIBRARY_SUFFIXES ".a") + + ## some libraries define a Library::Name_static alternative ## + set(YUZU_STATIC_SUFFIX _static) + + ## some libraries use CMAKE_IMPORT_LIBRARY_SUFFIX e.g. Harfbuzz ## + set(CMAKE_IMPORT_LIBRARY_SUFFIX ".a") + + # simple hook to reject ".dll.a" libraries + function(find_library var) + # also skip previously-found libraries cuz... yaknow + if (${var}) + return() + endif() + + _find_library(${var} ${ARGN}) + if (${var}) + get_filename_component(lib_name "${${var}}" NAME) + if (lib_name MATCHES "dll\\.a$") + unset(${var} CACHE) + set(${var} "${var}-NOTFOUND" CACHE INTERNAL "" FORCE) + endif() + endif() + endfunction() + + ## other hooks needed ## + macro(extra_libs) + foreach(lib ${ARGN}) + find_library(${lib}_LIBRARY ${lib} REQUIRED) + link_libraries(${${lib}_LIBRARY}) + endforeach() + endmacro() + + # libtiff.a + extra_libs(jbig lzma deflate) + + # libfreetype.a + extra_libs(bz2 Lerc) + + # libharfbuzz.a + extra_libs(graphite2 rpcrt4) + + # msys2 quazip does not build a static lib + set(QuaZip-Qt6_FORCE_BUNDLED ON) +endif() + # Detect current compilation architecture and create standard definitions # ======================================================================= @@ -582,6 +665,7 @@ else() find_package(stb MODULE) find_package(Opus 1.3 MODULE REQUIRED) + find_package(ZLIB 1.2 REQUIRED) find_package(zstd 1.5 REQUIRED MODULE) diff --git a/CMakeModules/Findzstd.cmake b/CMakeModules/Findzstd.cmake index abcdbc2a3e..60e706328d 100644 --- a/CMakeModules/Findzstd.cmake +++ b/CMakeModules/Findzstd.cmake @@ -6,22 +6,28 @@ include(FindPackageHandleStandardArgs) -find_package(PkgConfig QUIET) -pkg_search_module(ZSTD QUIET IMPORTED_TARGET libzstd) -find_package_handle_standard_args(zstd - REQUIRED_VARS ZSTD_LINK_LIBRARIES - VERSION_VAR ZSTD_VERSION -) +find_package(zstd QUIET CONFIG) +if (zstd_CONSIDERED_CONFIGS) + find_package_handle_standard_args(zstd CONFIG_MODE) +else() + find_package(PkgConfig QUIET) + pkg_search_module(ZSTD QUIET IMPORTED_TARGET libzstd) + find_package_handle_standard_args(zstd + REQUIRED_VARS ZSTD_LINK_LIBRARIES + VERSION_VAR ZSTD_VERSION + ) +endif() if (zstd_FOUND AND NOT TARGET zstd::zstd) - if (TARGET zstd::libzstd_shared) + if (TARGET zstd::libzstd_shared AND NOT YUZU_STATIC_BUILD) add_library(zstd::zstd ALIAS zstd::libzstd_shared) - add_library(zstd::libzstd ALIAS zstd::libzstd_shared) elseif (TARGET zstd::libzstd_static) add_library(zstd::zstd ALIAS zstd::libzstd_static) - add_library(zstd::libzstd ALIAS zstd::libzstd_static) else() add_library(zstd::zstd ALIAS PkgConfig::ZSTD) - add_library(zstd::libzstd ALIAS PkgConfig::ZSTD) endif() endif() + +if (NOT TARGET zstd::libzstd) + add_library(zstd::libzstd ALIAS zstd::zstd) +endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 81c2f81292..0aa959673c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -178,13 +178,15 @@ else() if (MINGW) add_compile_definitions(MINGW_HAS_SECURE_API) + # Only windows has this requirement, thanks windows - if (WIN32) + if (WIN32 AND ARCHITECTURE_x86_64) add_compile_options("-msse4.1") endif() - if (MINGW_STATIC_BUILD) + + if (YUZU_STATIC_BUILD) add_compile_definitions(QT_STATICPLUGIN) - add_compile_options("-static") + add_compile_options(-static) endif() endif() diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index b07778be28..999b380595 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -252,7 +252,7 @@ if(CXX_CLANG) endif() if (BOOST_NO_HEADERS) - target_link_libraries(common PUBLIC Boost::algorithm Boost::icl Boost::pool Boost::filesystem) + target_link_libraries(common PUBLIC Boost::algorithm Boost::icl Boost::pool) else() target_link_libraries(common PUBLIC Boost::headers) endif() diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 452e5f42e4..46813b4880 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1199,7 +1199,7 @@ else() target_link_libraries(core PUBLIC Boost::headers) endif() -target_link_libraries(core PRIVATE fmt::fmt nlohmann_json::nlohmann_json RenderDoc::API MbedTLS::mbedcrypto MbedTLS::mbedtls) +target_link_libraries(core PRIVATE fmt::fmt nlohmann_json::nlohmann_json RenderDoc::API MbedTLS::mbedcrypto${YUZU_STATIC_SUFFIX} MbedTLS::mbedtls${YUZU_STATIC_SUFFIX}) if (MINGW) target_link_libraries(core PRIVATE ws2_32 mswsock wlanapi) endif() diff --git a/src/dedicated_room/CMakeLists.txt b/src/dedicated_room/CMakeLists.txt index 3e0658a1fb..b37c9626a9 100644 --- a/src/dedicated_room/CMakeLists.txt +++ b/src/dedicated_room/CMakeLists.txt @@ -19,7 +19,7 @@ if (ENABLE_WEB_SERVICE) target_link_libraries(yuzu-room PRIVATE web_service) endif() -target_link_libraries(yuzu-room PRIVATE MbedTLS::mbedcrypto MbedTLS::mbedtls) +target_link_libraries(yuzu-room PRIVATE MbedTLS::mbedcrypto${YUZU_STATIC_SUFFIX} MbedTLS::mbedtls${YUZU_STATIC_SUFFIX}) if (MSVC) target_link_libraries(yuzu-room PRIVATE getopt) endif() diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index f437663963..94599532b3 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -312,7 +312,6 @@ add_library(video_core STATIC vulkan_common/vulkan_wrapper.h vulkan_common/nsight_aftermath_tracker.cpp vulkan_common/nsight_aftermath_tracker.h - vulkan_common/vma.cpp vulkan_common/vma.h vulkan_common/vulkan.h ) @@ -369,9 +368,6 @@ else() # xbyak set_source_files_properties(macro/macro_jit_x64.cpp PROPERTIES COMPILE_OPTIONS "-Wno-conversion;-Wno-shadow") - # VMA - set_source_files_properties(vulkan_common/vma.cpp PROPERTIES COMPILE_OPTIONS "-Wno-conversion;-Wno-unused-variable;-Wno-unused-parameter;-Wno-missing-field-initializers") - # Get around GCC failing with intrinsics in Debug if (CXX_GCC AND CMAKE_BUILD_TYPE MATCHES "Debug") set_source_files_properties(host1x/vic.cpp PROPERTIES COMPILE_OPTIONS "-O2") diff --git a/src/video_core/vulkan_common/vma.cpp b/src/video_core/vulkan_common/vma.cpp deleted file mode 100644 index addf107628..0000000000 --- a/src/video_core/vulkan_common/vma.cpp +++ /dev/null @@ -1,6 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#define VMA_IMPLEMENTATION - -#include "video_core/vulkan_common/vma.h" diff --git a/src/yuzu/main_window.cpp b/src/yuzu/main_window.cpp index b26baf7202..1846be5455 100644 --- a/src/yuzu/main_window.cpp +++ b/src/yuzu/main_window.cpp @@ -1,6 +1,10 @@ // SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later +#ifdef QT_STATICPLUGIN +#undef VMA_IMPLEMENTATION +#endif + #include "common/fs/ryujinx_compat.h" #include "main_window.h" #include "network/network.h" @@ -263,6 +267,7 @@ using namespace Common::Literals; #endif #ifdef QT_STATICPLUGIN +#include Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin); #endif diff --git a/src/yuzu_cmd/CMakeLists.txt b/src/yuzu_cmd/CMakeLists.txt index b26628e074..7d1f5f3b9f 100644 --- a/src/yuzu_cmd/CMakeLists.txt +++ b/src/yuzu_cmd/CMakeLists.txt @@ -56,3 +56,10 @@ if(WIN32) endif() create_target_directory_groups(yuzu-cmd) + +if (YUZU_STATIC_BUILD) + # yuzu-cmd requires us to explicitly link libpthread, libgcc, and libstdc++ as static + # At a guess, it's probably because Qt handles the Qt executable for us + target_link_options(yuzu-cmd PRIVATE -static -lpthread) + target_link_options(yuzu-cmd PRIVATE -static-libgcc -static-libstdc++) +endif() diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index de16ba7815..b7b98f7bef 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -4,12 +4,13 @@ // SPDX-FileCopyrightText: 2014 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include +#define VMA_IMPLEMENTATION +#include "video_core/vulkan_common/vma.h" + #include #include #include #include -#include #include @@ -17,7 +18,6 @@ #include "common/logging/backend.h" #include "common/logging/log.h" #include "common/scm_rev.h" -#include "common/scope_exit.h" #include "common/settings.h" #include "common/string_util.h" #include "core/core.h"