From 278e04ebd6e5b5d0e96d77e1fc839af3ccd2b3ce Mon Sep 17 00:00:00 2001 From: Selim Sandal <49725809+selimsandal@users.noreply.github.com> Date: Tue, 17 Feb 2026 22:05:53 +0300 Subject: [PATCH 1/2] windows: make zlib static by default --- CMakeLists.txt | 47 ++++++++++++++++++++++++++++++++++--------- doc/guide/install.rst | 9 +++++++++ 2 files changed, 47 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 53a9c1c..4bed17b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,7 @@ option(ENABLE_OPTIM "Enable build with -O3 optimization level" option(BUILD_STATIC "Whether or not to build with static libraries" OFF) option(USE_PKGCONFIG "Use pkgconfig to find libraries" ON) option(LINK_CMAKE_THREADS "Use CMake find_package to link the threading library" OFF) +option(WINDOWS_STATIC_ZLIB "Link zlib statically for Windows builds" ON) if (${CMAKE_SYSTEM_NAME} MATCHES "Windows") set(ENABLE_UDEV OFF) @@ -223,16 +224,44 @@ if (USE_PKGCONFIG) endif() # zlib support (gzip) - pkg_check_modules(ZLIB zlib) - if (NOT ZLIB_FOUND) - # try zlib-ng - pkg_check_modules(ZLIB zlib-ng) - if (ZLIB_FOUND) - add_definitions(-DHAS_ZLIBNG) - else() - message(FATAL_ERROR "Could find ZLIB") + if (${CMAKE_SYSTEM_NAME} MATCHES "Windows") + if (WINDOWS_STATIC_ZLIB) + set(ZLIB_USE_STATIC_LIBS ON) endif() - endif(NOT ZLIB_FOUND) + + # Use CMake zlib finder for Windows builds to avoid host pkg-config contamination + # during cross-compilation and to allow static linking selection. + find_package(ZLIB QUIET) + if (NOT ZLIB_FOUND) + if (windows_crosscompile) + message(FATAL_ERROR + "zlib for Windows target not found. Install MinGW zlib development files " + "(for example: libz-mingw-w64-dev on Debian/Ubuntu or mingw64-zlib on Fedora).") + else() + message(FATAL_ERROR + "zlib for Windows build not found. Install zlib development files for your " + "Windows toolchain.") + endif() + endif() + + if (WINDOWS_STATIC_ZLIB AND ZLIB_LIBRARIES MATCHES "\\.dll\\.a$") + message(FATAL_ERROR + "Static zlib requested (WINDOWS_STATIC_ZLIB=ON), but CMake selected " + "'${ZLIB_LIBRARIES}'. Install static zlib (for example mingw64-zlib-static) " + "or set -DWINDOWS_STATIC_ZLIB=OFF.") + endif() + else() + pkg_check_modules(ZLIB zlib) + if (NOT ZLIB_FOUND) + # try zlib-ng + pkg_check_modules(ZLIB zlib-ng) + if (ZLIB_FOUND) + add_definitions(-DHAS_ZLIBNG) + else() + message(FATAL_ERROR "Could find ZLIB") + endif() + endif(NOT ZLIB_FOUND) + endif() if (ENABLE_UDEV) pkg_check_modules(LIBUDEV libudev) diff --git a/doc/guide/install.rst b/doc/guide/install.rst index 27fa0de..757bc7a 100644 --- a/doc/guide/install.rst +++ b/doc/guide/install.rst @@ -216,6 +216,7 @@ The build system will automatically download and build the required dependencies sudo apt install \ mingw-w64 \ + libz-mingw-w64-dev \ cmake \ pkg-config \ p7zip-full @@ -247,6 +248,13 @@ The build system will automatically download and build the required dependencies The resulting ``openFPGALoader.exe`` will be a statically-linked executable that only depends on standard Windows system DLLs (KERNEL32, msvcrt, WS2_32). +.. NOTE:: + ``zlib`` for the Windows target is required. Configuration fails if it is + missing (install ``libz-mingw-w64-dev`` on Debian/Ubuntu or + ``mingw64-zlib`` on Fedora/RHEL/Rocky). + ``zlib`` is linked statically by default on Windows builds + (``-DWINDOWS_STATIC_ZLIB=ON``). + **Optional: Strip debug symbols to reduce size:** .. code-block:: bash @@ -257,6 +265,7 @@ that only depends on standard Windows system DLLs (KERNEL32, msvcrt, WS2_32). - ``-DCROSS_COMPILE_DEPS=OFF`` - Disable automatic dependency download (use system libraries) - ``-DENABLE_CMSISDAP=ON`` - Enable CMSIS-DAP support (requires manually providing hidapi) +- ``-DWINDOWS_STATIC_ZLIB=OFF`` - Allow dynamic zlib linkage (produces ``zlib1.dll`` runtime dependency) Common ====== From 7a2ea1376ed12c6981d892a8c8bbc5b6ea28127d Mon Sep 17 00:00:00 2001 From: Selim Sandal <49725809+selimsandal@users.noreply.github.com> Date: Tue, 17 Feb 2026 22:17:35 +0300 Subject: [PATCH 2/2] windows: add clang cross-compile support on Linux --- cmake/Modules/CrossCompileWindows.cmake | 44 ++++++++++++---- .../Toolchain-x86_64-w64-mingw32-clang.cmake | 52 +++++++++++++++++++ doc/guide/install.rst | 26 ++++++++-- 3 files changed, 108 insertions(+), 14 deletions(-) create mode 100644 cmake/Toolchain-x86_64-w64-mingw32-clang.cmake diff --git a/cmake/Modules/CrossCompileWindows.cmake b/cmake/Modules/CrossCompileWindows.cmake index a5a7bcc..ef07483 100644 --- a/cmake/Modules/CrossCompileWindows.cmake +++ b/cmake/Modules/CrossCompileWindows.cmake @@ -113,18 +113,42 @@ function(setup_libftdi_windows) message(STATUS "Building libftdi for Windows...") file(MAKE_DIRECTORY ${LIBFTDI_BUILD_DIR}) + set(LIBFTDI_CMAKE_ARGS + -DCMAKE_SYSTEM_NAME=Windows + -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} + -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} + -DCMAKE_INSTALL_PREFIX=${CROSS_DEPS_INSTALL_DIR} + -DCMAKE_PREFIX_PATH=${CROSS_DEPS_INSTALL_DIR} + -DLIBUSB_INCLUDE_DIRS=${CROSS_DEPS_INSTALL_DIR}/include/libusb-1.0 + -DLIBUSB_LIBRARIES=${CROSS_DEPS_INSTALL_DIR}/lib/libusb-1.0.a + -DFTDIPP=OFF -DBUILD_TESTS=OFF -DDOCUMENTATION=OFF + -DEXAMPLES=OFF -DFTDI_EEPROM=OFF -DPYTHON_BINDINGS=OFF + -DSTATICLIBS=ON + ) + + if(CMAKE_RC_COMPILER) + list(APPEND LIBFTDI_CMAKE_ARGS -DCMAKE_RC_COMPILER=${CMAKE_RC_COMPILER}) + endif() + + foreach(_lang C CXX RC) + if(DEFINED CMAKE_${_lang}_COMPILER_TARGET AND NOT "${CMAKE_${_lang}_COMPILER_TARGET}" STREQUAL "") + list(APPEND LIBFTDI_CMAKE_ARGS "-DCMAKE_${_lang}_COMPILER_TARGET=${CMAKE_${_lang}_COMPILER_TARGET}") + endif() + endforeach() + + foreach(_flags_var CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + if(DEFINED ${_flags_var} AND NOT "${${_flags_var}}" STREQUAL "") + list(APPEND LIBFTDI_CMAKE_ARGS "-D${_flags_var}=${${_flags_var}}") + endif() + endforeach() + + if(DEFINED CMAKE_SYSROOT AND NOT "${CMAKE_SYSROOT}" STREQUAL "") + list(APPEND LIBFTDI_CMAKE_ARGS -DCMAKE_SYSROOT=${CMAKE_SYSROOT}) + endif() + execute_process( COMMAND ${CMAKE_COMMAND} - -DCMAKE_SYSTEM_NAME=Windows - -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} - -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} - -DCMAKE_INSTALL_PREFIX=${CROSS_DEPS_INSTALL_DIR} - -DCMAKE_PREFIX_PATH=${CROSS_DEPS_INSTALL_DIR} - -DLIBUSB_INCLUDE_DIRS=${CROSS_DEPS_INSTALL_DIR}/include/libusb-1.0 - -DLIBUSB_LIBRARIES=${CROSS_DEPS_INSTALL_DIR}/lib/libusb-1.0.a - -DFTDIPP=OFF -DBUILD_TESTS=OFF -DDOCUMENTATION=OFF - -DEXAMPLES=OFF -DFTDI_EEPROM=OFF -DPYTHON_BINDINGS=OFF - -DSTATICLIBS=ON + ${LIBFTDI_CMAKE_ARGS} ${LIBFTDI_SRC_DIR} WORKING_DIRECTORY ${LIBFTDI_BUILD_DIR} RESULT_VARIABLE CONFIG_RESULT diff --git a/cmake/Toolchain-x86_64-w64-mingw32-clang.cmake b/cmake/Toolchain-x86_64-w64-mingw32-clang.cmake new file mode 100644 index 0000000..c9951c6 --- /dev/null +++ b/cmake/Toolchain-x86_64-w64-mingw32-clang.cmake @@ -0,0 +1,52 @@ +# CMake Toolchain file for cross-compiling to Windows x64 using Clang + MinGW-w64 +# Usage: cmake -DCMAKE_TOOLCHAIN_FILE=cmake/Toolchain-x86_64-w64-mingw32-clang.cmake .. + +set(CMAKE_SYSTEM_NAME Windows) +set(CMAKE_SYSTEM_PROCESSOR x86_64) + +set(WINDOWS_TARGET_TRIPLE "x86_64-w64-mingw32") + +find_program(CMAKE_C_COMPILER NAMES clang) +find_program(CMAKE_CXX_COMPILER NAMES clang++) +find_program(CMAKE_RC_COMPILER NAMES llvm-rc x86_64-w64-mingw32-windres) + +if(NOT CMAKE_C_COMPILER OR NOT CMAKE_CXX_COMPILER) + message(FATAL_ERROR "clang/clang++ not found. Please install clang.") +endif() + +set(CMAKE_C_COMPILER_TARGET ${WINDOWS_TARGET_TRIPLE}) +set(CMAKE_CXX_COMPILER_TARGET ${WINDOWS_TARGET_TRIPLE}) + +if(CMAKE_RC_COMPILER AND CMAKE_RC_COMPILER MATCHES "llvm-rc$") + set(CMAKE_RC_COMPILER_TARGET ${WINDOWS_TARGET_TRIPLE}) +endif() + +# Keep target selection compatible with older CMake versions. +set(CMAKE_C_FLAGS_INIT "--target=${WINDOWS_TARGET_TRIPLE}") +set(CMAKE_CXX_FLAGS_INIT "--target=${WINDOWS_TARGET_TRIPLE}") + +option(CROSS_COMPILE_DEPS "Download and build Windows dependencies for cross-compilation" ON) + +set(CROSS_DEPS_DIR "${CMAKE_BINARY_DIR}/cross-deps" CACHE PATH "Directory for cross-compiled dependencies") + +if(EXISTS "/usr/x86_64-w64-mingw32/sys-root/mingw") + set(MINGW_SYSROOT "/usr/x86_64-w64-mingw32/sys-root/mingw") +elseif(EXISTS "/usr/x86_64-w64-mingw32") + set(MINGW_SYSROOT "/usr/x86_64-w64-mingw32") +else() + set(MINGW_SYSROOT "") +endif() + +set(CMAKE_FIND_ROOT_PATH ${CROSS_DEPS_DIR} ${MINGW_SYSROOT}) +set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + +set(CMAKE_EXE_LINKER_FLAGS_INIT "-static -static-libgcc -static-libstdc++") + +set(ENABLE_UDEV OFF CACHE BOOL "" FORCE) +set(ENABLE_LIBGPIOD OFF CACHE BOOL "" FORCE) +set(ENABLE_REMOTEBITBANG OFF CACHE BOOL "" FORCE) +set(ENABLE_XILINX_VIRTUAL_CABLE OFF CACHE BOOL "" FORCE) +set(BUILD_STATIC ON CACHE BOOL "" FORCE) diff --git a/doc/guide/install.rst b/doc/guide/install.rst index 757bc7a..717f6da 100644 --- a/doc/guide/install.rst +++ b/doc/guide/install.rst @@ -206,9 +206,9 @@ openFPGALoader can be installed via MSYS2: Cross-compilation from Linux ---------------------------- -openFPGALoader can be cross-compiled for Windows from Linux using MinGW-w64. -The build system will automatically download and build the required dependencies -(libusb, libftdi). +openFPGALoader can be cross-compiled for Windows from Linux using MinGW-w64 +toolchains (GCC or Clang). The build system will automatically download and +build the required dependencies (libusb, libftdi). **Prerequisites (Debian/Ubuntu):** @@ -217,6 +217,8 @@ The build system will automatically download and build the required dependencies sudo apt install \ mingw-w64 \ libz-mingw-w64-dev \ + clang \ + lld \ cmake \ pkg-config \ p7zip-full @@ -230,11 +232,13 @@ The build system will automatically download and build the required dependencies mingw64-gcc-c++ \ mingw64-zlib \ mingw64-zlib-static \ + clang \ + lld \ cmake \ p7zip \ p7zip-plugins -**Build:** +**Build (shared steps):** .. code-block:: bash @@ -242,9 +246,21 @@ The build system will automatically download and build the required dependencies cd openFPGALoader mkdir build-win64 cd build-win64 + +**Configure + build with GCC (MinGW-w64):** + +.. code-block:: bash + cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-x86_64-w64-mingw32.cmake .. cmake --build . --parallel +**Configure + build with Clang (MinGW-w64 target):** + +.. code-block:: bash + + cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-x86_64-w64-mingw32-clang.cmake .. + cmake --build . --parallel + The resulting ``openFPGALoader.exe`` will be a statically-linked executable that only depends on standard Windows system DLLs (KERNEL32, msvcrt, WS2_32). @@ -260,6 +276,8 @@ that only depends on standard Windows system DLLs (KERNEL32, msvcrt, WS2_32). .. code-block:: bash x86_64-w64-mingw32-strip openFPGALoader.exe + # or + llvm-strip openFPGALoader.exe **Cross-compilation options:**