Add MinGW-w64 cross-compilation support for Windows
Add CMake toolchain file and module to enable cross-compiling openFPGALoader for Windows from Linux using MinGW-w64. Features: - Automatic download and build of libusb and libftdi dependencies - CMake toolchain file for x86_64-w64-mingw32 - Fully static executable (only depends on Windows system DLLs) - Works on Debian/Ubuntu, Fedora/RHEL/Rocky Linux Usage: cmake -DCMAKE_TOOLCHAIN_FILE=cmake/Toolchain-x86_64-w64-mingw32.cmake .. cmake --build . --parallel Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
63b0e34a6f
commit
afecedb9fb
|
|
@ -4,6 +4,12 @@ cmake_minimum_required(VERSION 3.10)
|
|||
project(openFPGALoader VERSION "1.0.0" LANGUAGES CXX)
|
||||
add_definitions(-DVERSION=\"v${PROJECT_VERSION}\")
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Windows" AND NOT CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
|
||||
set(windows_crosscompile ON)
|
||||
else()
|
||||
set(windows_crosscompile OFF)
|
||||
endif()
|
||||
|
||||
####################################################################################################
|
||||
# Generics Options
|
||||
####################################################################################################
|
||||
|
|
@ -30,7 +36,12 @@ option(ENABLE_CABLE_ALL "Enable all cables" ON
|
|||
|
||||
option(ENABLE_ANLOGIC_CABLE "enable Anlogic cable (requires libUSB)" ${ENABLE_CABLE_ALL})
|
||||
option(ENABLE_CH347 "enable CH347 cable (requires libUSB)" ${ENABLE_CABLE_ALL})
|
||||
option(ENABLE_CMSISDAP "enable cmsis DAP interface (requires hidapi)" ${ENABLE_CABLE_ALL})
|
||||
# CMSIS-DAP requires hidapi which is complex to cross-compile, disable by default for cross-compilation
|
||||
if (NOT windows_crosscompile)
|
||||
option(ENABLE_CMSISDAP "enable cmsis DAP interface (requires hidapi)" ${ENABLE_CABLE_ALL})
|
||||
else()
|
||||
option(ENABLE_CMSISDAP "enable cmsis DAP interface (requires hidapi)" OFF)
|
||||
endif()
|
||||
option(ENABLE_DIRTYJTAG "enable dirtyJtag cable (requires libUSB)" ${ENABLE_CABLE_ALL})
|
||||
option(ENABLE_ESP_USB "enable ESP32S3 cable (requires libUSB)" ${ENABLE_CABLE_ALL})
|
||||
option(ENABLE_JLINK "enable JLink cable (requires libUSB)" ${ENABLE_CABLE_ALL})
|
||||
|
|
@ -60,6 +71,38 @@ else()
|
|||
set(ENABLE_XILINX_VIRTUAL_CABLE OFF)
|
||||
endif()
|
||||
|
||||
####################################################################################################
|
||||
# Cross-compilation support
|
||||
####################################################################################################
|
||||
|
||||
# Detect cross-compilation for Windows from Linux/macOS
|
||||
if(windows_crosscompile)
|
||||
set(CROSS_COMPILING_WINDOWS TRUE)
|
||||
message(STATUS "Cross-compiling for Windows from ${CMAKE_HOST_SYSTEM_NAME}")
|
||||
|
||||
# Option to automatically download and build cross-compile dependencies
|
||||
option(CROSS_COMPILE_DEPS "Download and build Windows dependencies for cross-compilation" ON)
|
||||
|
||||
if(CROSS_COMPILE_DEPS)
|
||||
# Include the cross-compilation module
|
||||
list(INSERT CMAKE_MODULE_PATH 0 ${PROJECT_SOURCE_DIR}/cmake/Modules)
|
||||
include(CrossCompileWindows)
|
||||
|
||||
# Setup the dependencies (downloads libusb, builds libftdi)
|
||||
setup_windows_cross_compile_deps()
|
||||
|
||||
# Update pkg-config path for the dependencies
|
||||
set(ENV{PKG_CONFIG_PATH} "${CROSS_DEPS_INSTALL_DIR}/lib/pkgconfig:$ENV{PKG_CONFIG_PATH}")
|
||||
|
||||
# Add the cross-compiled dependencies to the search path
|
||||
list(APPEND CMAKE_PREFIX_PATH ${CROSS_DEPS_INSTALL_DIR})
|
||||
include_directories(${CROSS_DEPS_INSTALL_DIR}/include)
|
||||
link_directories(${CROSS_DEPS_INSTALL_DIR}/lib)
|
||||
endif()
|
||||
else()
|
||||
set(CROSS_COMPILING_WINDOWS FALSE)
|
||||
endif()
|
||||
|
||||
####################################################################################################
|
||||
# VENDORS Options
|
||||
####################################################################################################
|
||||
|
|
|
|||
|
|
@ -0,0 +1,198 @@
|
|||
# CrossCompileWindows.cmake
|
||||
# Downloads and builds dependencies for cross-compiling openFPGALoader to Windows.
|
||||
|
||||
include(ExternalProject)
|
||||
include(FetchContent)
|
||||
|
||||
set(LIBUSB_VERSION "1.0.27" CACHE STRING "libusb version")
|
||||
set(LIBFTDI_VERSION "1.5" CACHE STRING "libftdi version")
|
||||
|
||||
set(LIBUSB_URL "https://github.com/libusb/libusb/releases/download/v${LIBUSB_VERSION}/libusb-${LIBUSB_VERSION}.7z")
|
||||
set(LIBFTDI_URL "https://www.intra2net.com/en/developer/libftdi/download/libftdi1-${LIBFTDI_VERSION}.tar.bz2")
|
||||
|
||||
if(NOT DEFINED CROSS_DEPS_DIR)
|
||||
set(CROSS_DEPS_DIR "${CMAKE_BINARY_DIR}/cross-deps")
|
||||
endif()
|
||||
|
||||
set(CROSS_DEPS_INSTALL_DIR "${CROSS_DEPS_DIR}/install")
|
||||
set(CROSS_DEPS_BUILD_DIR "${CROSS_DEPS_DIR}/build")
|
||||
set(CROSS_DEPS_SRC_DIR "${CROSS_DEPS_DIR}/src")
|
||||
|
||||
file(MAKE_DIRECTORY ${CROSS_DEPS_DIR})
|
||||
file(MAKE_DIRECTORY ${CROSS_DEPS_INSTALL_DIR})
|
||||
file(MAKE_DIRECTORY ${CROSS_DEPS_INSTALL_DIR}/include)
|
||||
file(MAKE_DIRECTORY ${CROSS_DEPS_INSTALL_DIR}/lib)
|
||||
file(MAKE_DIRECTORY ${CROSS_DEPS_INSTALL_DIR}/lib/pkgconfig)
|
||||
file(MAKE_DIRECTORY ${CROSS_DEPS_BUILD_DIR})
|
||||
file(MAKE_DIRECTORY ${CROSS_DEPS_SRC_DIR})
|
||||
|
||||
find_program(SEVENZIP_EXECUTABLE NAMES 7z 7za p7zip)
|
||||
if(NOT SEVENZIP_EXECUTABLE)
|
||||
message(FATAL_ERROR "7z/p7zip not found. Please install p7zip or 7zip.")
|
||||
endif()
|
||||
|
||||
function(setup_libusb_windows)
|
||||
set(LIBUSB_ARCHIVE "${CROSS_DEPS_SRC_DIR}/libusb-${LIBUSB_VERSION}.7z")
|
||||
set(LIBUSB_EXTRACT_DIR "${CROSS_DEPS_SRC_DIR}/libusb-${LIBUSB_VERSION}")
|
||||
|
||||
if(NOT EXISTS ${LIBUSB_ARCHIVE})
|
||||
message(STATUS "Downloading libusb ${LIBUSB_VERSION}...")
|
||||
file(DOWNLOAD ${LIBUSB_URL} ${LIBUSB_ARCHIVE} SHOW_PROGRESS STATUS DOWNLOAD_STATUS)
|
||||
list(GET DOWNLOAD_STATUS 0 STATUS_CODE)
|
||||
if(NOT STATUS_CODE EQUAL 0)
|
||||
message(FATAL_ERROR "Failed to download libusb: ${DOWNLOAD_STATUS}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS "${LIBUSB_EXTRACT_DIR}/MinGW64")
|
||||
message(STATUS "Extracting libusb...")
|
||||
file(MAKE_DIRECTORY ${LIBUSB_EXTRACT_DIR})
|
||||
execute_process(
|
||||
COMMAND ${SEVENZIP_EXECUTABLE} x -y -o${LIBUSB_EXTRACT_DIR} ${LIBUSB_ARCHIVE}
|
||||
WORKING_DIRECTORY ${CROSS_DEPS_SRC_DIR}
|
||||
RESULT_VARIABLE EXTRACT_RESULT
|
||||
)
|
||||
if(NOT EXTRACT_RESULT EQUAL 0)
|
||||
message(FATAL_ERROR "Failed to extract libusb")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
message(STATUS "Installing libusb headers and libraries...")
|
||||
file(MAKE_DIRECTORY "${CROSS_DEPS_INSTALL_DIR}/include/libusb-1.0")
|
||||
file(COPY "${LIBUSB_EXTRACT_DIR}/include/libusb.h"
|
||||
DESTINATION "${CROSS_DEPS_INSTALL_DIR}/include/libusb-1.0/")
|
||||
file(COPY "${LIBUSB_EXTRACT_DIR}/MinGW64/static/libusb-1.0.a"
|
||||
DESTINATION "${CROSS_DEPS_INSTALL_DIR}/lib/")
|
||||
|
||||
file(WRITE "${CROSS_DEPS_INSTALL_DIR}/lib/pkgconfig/libusb-1.0.pc"
|
||||
"prefix=${CROSS_DEPS_INSTALL_DIR}
|
||||
exec_prefix=\${prefix}
|
||||
libdir=\${exec_prefix}/lib
|
||||
includedir=\${prefix}/include/libusb-1.0
|
||||
|
||||
Name: libusb-1.0
|
||||
Description: C API for USB device access from Windows
|
||||
Version: ${LIBUSB_VERSION}
|
||||
Libs: -L\${libdir} -lusb-1.0
|
||||
Cflags: -I\${includedir}
|
||||
")
|
||||
|
||||
set(LIBUSB_FOUND TRUE PARENT_SCOPE)
|
||||
set(LIBUSB_INCLUDE_DIRS "${CROSS_DEPS_INSTALL_DIR}/include/libusb-1.0" PARENT_SCOPE)
|
||||
set(LIBUSB_LIBRARIES "${CROSS_DEPS_INSTALL_DIR}/lib/libusb-1.0.a" PARENT_SCOPE)
|
||||
set(LIBUSB_VERSION ${LIBUSB_VERSION} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(setup_libftdi_windows)
|
||||
set(LIBFTDI_ARCHIVE "${CROSS_DEPS_SRC_DIR}/libftdi1-${LIBFTDI_VERSION}.tar.bz2")
|
||||
set(LIBFTDI_SRC_DIR "${CROSS_DEPS_SRC_DIR}/libftdi1-${LIBFTDI_VERSION}")
|
||||
set(LIBFTDI_BUILD_DIR "${CROSS_DEPS_BUILD_DIR}/libftdi1")
|
||||
|
||||
if(NOT EXISTS ${LIBFTDI_ARCHIVE})
|
||||
message(STATUS "Downloading libftdi ${LIBFTDI_VERSION}...")
|
||||
file(DOWNLOAD ${LIBFTDI_URL} ${LIBFTDI_ARCHIVE} SHOW_PROGRESS STATUS DOWNLOAD_STATUS)
|
||||
list(GET DOWNLOAD_STATUS 0 STATUS_CODE)
|
||||
if(NOT STATUS_CODE EQUAL 0)
|
||||
message(FATAL_ERROR "Failed to download libftdi: ${DOWNLOAD_STATUS}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS ${LIBFTDI_SRC_DIR})
|
||||
message(STATUS "Extracting libftdi...")
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -E tar xjf ${LIBFTDI_ARCHIVE}
|
||||
WORKING_DIRECTORY ${CROSS_DEPS_SRC_DIR}
|
||||
RESULT_VARIABLE EXTRACT_RESULT
|
||||
)
|
||||
if(NOT EXTRACT_RESULT EQUAL 0)
|
||||
message(FATAL_ERROR "Failed to extract libftdi")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS "${CROSS_DEPS_INSTALL_DIR}/lib/libftdi1.a")
|
||||
message(STATUS "Building libftdi for Windows...")
|
||||
file(MAKE_DIRECTORY ${LIBFTDI_BUILD_DIR})
|
||||
|
||||
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_SRC_DIR}
|
||||
WORKING_DIRECTORY ${LIBFTDI_BUILD_DIR}
|
||||
RESULT_VARIABLE CONFIG_RESULT
|
||||
)
|
||||
if(NOT CONFIG_RESULT EQUAL 0)
|
||||
message(FATAL_ERROR "Failed to configure libftdi")
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} --build . --parallel
|
||||
WORKING_DIRECTORY ${LIBFTDI_BUILD_DIR}
|
||||
RESULT_VARIABLE BUILD_RESULT
|
||||
)
|
||||
if(NOT BUILD_RESULT EQUAL 0)
|
||||
message(FATAL_ERROR "Failed to build libftdi")
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} --install .
|
||||
WORKING_DIRECTORY ${LIBFTDI_BUILD_DIR}
|
||||
RESULT_VARIABLE INSTALL_RESULT
|
||||
)
|
||||
if(NOT INSTALL_RESULT EQUAL 0)
|
||||
message(FATAL_ERROR "Failed to install libftdi")
|
||||
endif()
|
||||
|
||||
file(WRITE "${CROSS_DEPS_INSTALL_DIR}/lib/pkgconfig/libftdi1.pc"
|
||||
"prefix=${CROSS_DEPS_INSTALL_DIR}
|
||||
exec_prefix=\${prefix}
|
||||
libdir=\${prefix}/lib
|
||||
includedir=\${prefix}/include/libftdi1
|
||||
|
||||
Name: libftdi1
|
||||
Description: Library to program and control the FTDI USB controller
|
||||
Requires: libusb-1.0
|
||||
Version: ${LIBFTDI_VERSION}
|
||||
Libs: -L\${libdir} -lftdi1
|
||||
Cflags: -I\${includedir}
|
||||
")
|
||||
endif()
|
||||
|
||||
set(LIBFTDI_FOUND TRUE PARENT_SCOPE)
|
||||
set(LIBFTDI_INCLUDE_DIRS "${CROSS_DEPS_INSTALL_DIR}/include/libftdi1" PARENT_SCOPE)
|
||||
set(LIBFTDI_LIBRARIES "${CROSS_DEPS_INSTALL_DIR}/lib/libftdi1.a" PARENT_SCOPE)
|
||||
set(LIBFTDI_VERSION ${LIBFTDI_VERSION} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(setup_windows_cross_compile_deps)
|
||||
message(STATUS "Setting up Windows cross-compilation dependencies...")
|
||||
message(STATUS " Dependencies directory: ${CROSS_DEPS_DIR}")
|
||||
message(STATUS " Install directory: ${CROSS_DEPS_INSTALL_DIR}")
|
||||
|
||||
setup_libusb_windows()
|
||||
setup_libftdi_windows()
|
||||
|
||||
list(APPEND CMAKE_PREFIX_PATH ${CROSS_DEPS_INSTALL_DIR})
|
||||
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} PARENT_SCOPE)
|
||||
set(ENV{PKG_CONFIG_PATH} "${CROSS_DEPS_INSTALL_DIR}/lib/pkgconfig:$ENV{PKG_CONFIG_PATH}")
|
||||
|
||||
set(LIBUSB_FOUND TRUE PARENT_SCOPE)
|
||||
set(LIBUSB_INCLUDE_DIRS "${CROSS_DEPS_INSTALL_DIR}/include/libusb-1.0" PARENT_SCOPE)
|
||||
set(LIBUSB_LIBRARIES "${CROSS_DEPS_INSTALL_DIR}/lib/libusb-1.0.a" PARENT_SCOPE)
|
||||
|
||||
set(LIBFTDI_FOUND TRUE PARENT_SCOPE)
|
||||
set(LIBFTDI_INCLUDE_DIRS "${CROSS_DEPS_INSTALL_DIR}/include/libftdi1" PARENT_SCOPE)
|
||||
set(LIBFTDI_LIBRARIES "${CROSS_DEPS_INSTALL_DIR}/lib/libftdi1.a" PARENT_SCOPE)
|
||||
|
||||
set(CROSS_DEPS_INSTALL_DIR ${CROSS_DEPS_INSTALL_DIR} PARENT_SCOPE)
|
||||
|
||||
message(STATUS "Windows cross-compilation dependencies ready!")
|
||||
endfunction()
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
# CMake Toolchain file for cross-compiling to Windows x64 using MinGW-w64
|
||||
# Usage: cmake -DCMAKE_TOOLCHAIN_FILE=cmake/Toolchain-x86_64-w64-mingw32.cmake ..
|
||||
|
||||
set(CMAKE_SYSTEM_NAME Windows)
|
||||
set(CMAKE_SYSTEM_PROCESSOR x86_64)
|
||||
|
||||
find_program(CMAKE_C_COMPILER NAMES x86_64-w64-mingw32-gcc)
|
||||
find_program(CMAKE_CXX_COMPILER NAMES x86_64-w64-mingw32-g++)
|
||||
find_program(CMAKE_RC_COMPILER NAMES x86_64-w64-mingw32-windres)
|
||||
|
||||
if(NOT CMAKE_C_COMPILER)
|
||||
message(FATAL_ERROR "x86_64-w64-mingw32-gcc not found. Please install mingw-w64 toolchain.")
|
||||
endif()
|
||||
|
||||
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)
|
||||
|
|
@ -194,6 +194,70 @@ Alternatively, if you want to build it by hand:
|
|||
Windows
|
||||
=======
|
||||
|
||||
MSYS2 (Native Build)
|
||||
--------------------
|
||||
|
||||
openFPGALoader can be installed via MSYS2:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
pacman -S mingw-w64-ucrt-x86_64-openFPGALoader
|
||||
|
||||
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).
|
||||
|
||||
**Prerequisites (Debian/Ubuntu):**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo apt install \
|
||||
mingw-w64 \
|
||||
cmake \
|
||||
pkg-config \
|
||||
p7zip-full
|
||||
|
||||
**Prerequisites (Fedora/RHEL/Rocky):**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo dnf install \
|
||||
mingw64-gcc \
|
||||
mingw64-gcc-c++ \
|
||||
mingw64-zlib \
|
||||
mingw64-zlib-static \
|
||||
cmake \
|
||||
p7zip \
|
||||
p7zip-plugins
|
||||
|
||||
**Build:**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
git clone https://github.com/trabucayre/openFPGALoader
|
||||
cd openFPGALoader
|
||||
mkdir build-win64
|
||||
cd build-win64
|
||||
cmake -DCMAKE_TOOLCHAIN_FILE=../cmake/Toolchain-x86_64-w64-mingw32.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).
|
||||
|
||||
**Optional: Strip debug symbols to reduce size:**
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
x86_64-w64-mingw32-strip openFPGALoader.exe
|
||||
|
||||
**Cross-compilation options:**
|
||||
|
||||
- ``-DCROSS_COMPILE_DEPS=OFF`` - Disable automatic dependency download (use system libraries)
|
||||
- ``-DENABLE_CMSISDAP=ON`` - Enable CMSIS-DAP support (requires manually providing hidapi)
|
||||
|
||||
Common
|
||||
======
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue