Skip to content

Commit

Permalink
feat: add cross compiler detection (aminya#140)
Browse files Browse the repository at this point in the history
* add mingw toolchains
* add docker for testing
  • Loading branch information
abeimler committed Oct 31, 2022
1 parent 0a757c1 commit 5c51d1d
Show file tree
Hide file tree
Showing 14 changed files with 310 additions and 12 deletions.
20 changes: 20 additions & 0 deletions Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,26 @@ tasks:
CWD:
sh: git rev-parse --show-toplevel

test_docker:
# test gcc compiler
- docker build --build-arg compiler=gcc -f ./docker/Dockerfile --target build -t project_options:build .
- docker build --build-arg compiler=gcc -f ./docker/Dockerfile --target test -t project_options:test .
- docker run --rm -it project_options:build
- docker run --rm -it project_options:test
- docker rmi project_options:build project_options:test
# test llvm compiler
- docker build --build-arg compiler=llvm -f ./docker/Dockerfile --target build -t project_options:build-clang .
- docker build --build-arg compiler=llvm -f ./docker/Dockerfile --target test -t project_options:test-clang .
- docker run --rm -it project_options:build-clang
- docker run --rm -it project_options:test-clang
- docker rmi project_options:build-clang project_options:test-clang
test_docker_mingw:
# test mingw (cross) compiler
- docker build -f ./docker/Dockerfile.mingw --target build -t project_options:build-mingw .
- docker run --rm -it project_options:build-mingw
- docker run --rm -it --env CROSS_CC=i686-w64-mingw32-gcc --env CROSS_CXX=i686-w64-mingw32-gcc project_options:build-mingw
- docker rmi project_options:build-mingw

lint:
- |
{{if eq OS "windows"}}
Expand Down
39 changes: 39 additions & 0 deletions docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
FROM ubuntu:20.04 AS base

# add setup_cpp
ADD https://github.com/aminya/setup-cpp/releases/download/v0.21.0/setup_cpp_linux /setup_cpp_linux
RUN chmod +x /setup_cpp_linux


FROM base AS setup

ARG compiler="gcc"
# install cmake, ninja, and ccache
RUN /setup_cpp_linux --compiler $compiler --llvm true --cmake true --ninja true --ccache true --doxygen true --cppcheck true --vcpkg true --conan true --task true

# update vcpkg
#WORKDIR /root/vcpkg
#RUN git pull origin master
#RUN ./vcpkg update
#WORKDIR /

COPY ./docker/entrypoint.sh /docker-entrypoint.sh
ENTRYPOINT [ "/docker-entrypoint.sh" ]


FROM setup AS build
COPY . /home/project_options
WORKDIR /home/project_options/test
CMD ["/home/project_options/docker/build.sh"]


FROM setup AS test
COPY . /home/project_options
WORKDIR /home/project_options/test
CMD ["/home/project_options/docker/test.sh"]


FROM gcr.io/distroless/cc AS runner
COPY --from=build /home/project_options/test/build/Release/ /home/app/
WORKDIR /home/app/
ENTRYPOINT ["./build/main"]
32 changes: 32 additions & 0 deletions docker/Dockerfile.mingw
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
FROM ubuntu:20.04 AS base

# add setup_cpp
ADD https://github.com/aminya/setup-cpp/releases/download/v0.21.0/setup_cpp_linux /setup_cpp_linux
RUN chmod +x /setup_cpp_linux


FROM base AS setup

# install cmake, ninja, and ccache
RUN /setup_cpp_linux --llvm true --cmake true --ninja true --ccache true --doxygen true --cppcheck true --vcpkg true --conan true --task true

# TODO: install cross-compiler with setup_cpp_linux
# NOTE: install mingw by hand, waiting for setup-cpp to have mingw cross-compiler support
RUN apt-get update && apt-get install -y \
mingw-w64 \
&& rm -rf /var/lib/apt/lists/*

# update vcpkg
#WORKDIR /root/vcpkg
#RUN git pull origin master
#RUN ./vcpkg update
#WORKDIR /

COPY ./docker/entrypoint.sh /docker-entrypoint.sh
ENTRYPOINT [ "/docker-entrypoint.sh" ]


FROM setup AS build
COPY . /home/project_options
WORKDIR /home/project_options/test
CMD ["/home/project_options/docker/build.mingw.sh"]
12 changes: 12 additions & 0 deletions docker/build.mingw.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/bash

# setup compiler
export CC=${CROSS_CC:-x86_64-w64-mingw32-gcc}
export CXX=${CROSS_CXX:-x86_64-w64-mingw32-g++}

mkdir build
cd build

cmake -B . -G "Ninja" -DCMAKE_BUILD_TYPE:STRING=Release \
-DENABLE_CROSS_COMPILING:BOOL=ON ..
cmake --build . --config Release
7 changes: 7 additions & 0 deletions docker/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/bin/bash

mkdir build
cd build

cmake -B . -G "Ninja" -DCMAKE_BUILD_TYPE:STRING=Release ..
cmake --build . --config Release
6 changes: 6 additions & 0 deletions docker/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env bash
set -e

source ~/.cpprc

exec "$@"
8 changes: 8 additions & 0 deletions docker/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/bash

mkdir build
cd build

cmake -B . -G "Ninja" -DCMAKE_BUILD_TYPE:STRING=Debug ..
cmake --build . --config Debug
ctest -C Debug --verbose
78 changes: 78 additions & 0 deletions src/CrossCompiler.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
include_guard()

macro(enable_cross_compiler)
include("${ProjectOptions_SRC_DIR}/Utilities.cmake")
detect_architecture(_arch)
if(NOT DEFINED TARGET_ARCHITECTURE)
if($ENV{CC} MATCHES "x86_64(-w64)?-mingw32-[gc]..?" OR $ENV{CXX} MATCHES "x86_64(-w64)?-mingw32-[gc]..?")
set(TARGET_ARCHITECTURE "x64")
elseif($ENV{CC} MATCHES "i686(-w64)?-mingw32-[gc]..?" OR $ENV{CXX} MATCHES "i686(-w64)?-mingw32-[gc]..?")
set(TARGET_ARCHITECTURE "x86")
elseif($ENV{CC} MATCHES "emcc" OR $ENV{CXX} MATCHES "em++")
set(TARGET_ARCHITECTURE "wasm32")
else()
# TODO: check for arm compiler
set(TARGET_ARCHITECTURE ${_arch})
endif()
endif()

if (NOT DEFINED HOST_TRIPLET)
if(WIN32)
set(HOST_TRIPLET "${_arch}-windows")
elseif(APPLE)
set(HOST_TRIPLET "${_arch}-osx")
elseif(UNIX AND NOT APPLE)
set(HOST_TRIPLET "${_arch}-linux")
endif()
endif()

if($ENV{CC} MATCHES "(x86_64|i686)(-w64)?-mingw32-[gc]..?" OR $ENV{CXX} MATCHES "(x86_64|i686)(-w64)?-mingw32-[gc]..?")
set(MINGW TRUE)
elseif($ENV{CC} MATCHES "emcc" OR $ENV{CXX} MATCHES "em++")
set(EMSCRIPTEN TRUE)
endif()

set(LIBRARY_LINKAGE)
if(BUILD_SHARED_LIBS)
set(LIBRARY_LINKAGE "dynamic")
else()
set(LIBRARY_LINKAGE "static")
endif()

if (NOT DEFINED CROSS_ROOT)
if($ENV{CC} MATCHES "x86_64(-w64)?-mingw32-[gc]..?" OR $ENV{CXX} MATCHES "x86_64(-w64)?-mingw32-[gc]..?")
set(CROSS_ROOT "/usr/x86_64-w64-mingw32")
elseif($ENV{CC} MATCHES "i686(-w64)?-mingw32-[gc]..?" OR $ENV{CXX} MATCHES "i686(-w64)?-mingw32-[gc]..?")
set(CROSS_ROOT "/usr/i686-w64-mingw32")
endif()
# TODO: check if path is right, check for header files or something
endif()

set(_toolchain_file)
get_toolchain_file(_toolchain_file)
set(CMAKE_TOOLCHAIN_FILE ${_toolchain_file})
set(CROSSCOMPILING TRUE)
endmacro()

function(get_toolchain_file value)
include("${ProjectOptions_SRC_DIR}/Utilities.cmake")
detect_architecture(_arch)
if(DEFINED TARGET_ARCHITECTURE)
set(_arch ${TARGET_ARCHITECTURE})
endif()
if("${_arch}" MATCHES "x64")
set(_arch "x86_64")
elseif("${_arch}" MATCHES "x86")
set(_arch "x86_64")
endif()

if (MINGW)
set(${value}
${ProjectOptions_SRC_DIR}/toolchains/${_arch}-w64-mingw32.toolchain.cmake
PARENT_SCOPE)
elseif(EMSCRIPTEN)
set(${value}
"/usr/lib/emscripten/cmake/Modules/Platform/Emscripten.cmake"
PARENT_SCOPE)
endif()
endfunction()
1 change: 1 addition & 0 deletions src/Index.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ include("${CMAKE_CURRENT_LIST_DIR}/StaticAnalyzers.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/VCEnvironment.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/MinGW.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/DetectCompiler.cmake")
include("${CMAKE_CURRENT_LIST_DIR}/CrossCompiler.cmake")

# Include msvc toolchain on windows if the generator is not visual studio. Should be called before run_vcpkg and run_conan to be effective
msvc_toolchain()
Expand Down
44 changes: 32 additions & 12 deletions src/MinGW.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,25 @@ include_guard()

# detect mingw
function(is_mingw value)
if(NOT WIN32 OR MSVC)
set(${value}
OFF
PARENT_SCOPE)
return()
if(CROSSCOMPILING)
if(MINGW)
set(${value}
ON
PARENT_SCOPE)
return()
endif()
else()
if(NOT WIN32 OR MSVC)
set(${value}
OFF
PARENT_SCOPE)
return()
endif()
endif()

if(MINGW
OR ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU")
OR ("${DETECTED_CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND "${DETECTED_CMAKE_C_COMPILER_ID}" STREQUAL "GNU"))
OR ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU")
OR ("${DETECTED_CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND "${DETECTED_CMAKE_C_COMPILER_ID}" STREQUAL "GNU"))
set(${value}
ON
PARENT_SCOPE)
Expand Down Expand Up @@ -85,11 +94,18 @@ macro(configure_mingw_vcpkg)
set(VCPKG_DEFAULT_TRIPLET
"${_arch}-mingw-${MINGW_LINKAGE}"
CACHE STRING "Default triplet for vcpkg")
set(VCPKG_DEFAULT_HOST_TRIPLET
"${_arch}-mingw-${MINGW_LINKAGE}"
CACHE STRING "Default target triplet for vcpkg")
set($ENV{VCPKG_DEFAULT_TRIPLET} "${_arch}-mingw-${MINGW_LINKAGE}")
set($ENV{VCPKG_DEFAULT_HOST_TRIPLET} "${_arch}-mingw-${MINGW_LINKAGE}")
if(WIN32 AND NOT MSVC)
set(VCPKG_DEFAULT_HOST_TRIPLET
"${_arch}-mingw-${MINGW_LINKAGE}"
CACHE STRING "Default target triplet for vcpkg")
set($ENV{VCPKG_DEFAULT_HOST_TRIPLET} "${_arch}-mingw-${MINGW_LINKAGE}")
elseif (CROSSCOMPILING AND HOST_TRIPLET)
set(VCPKG_DEFAULT_HOST_TRIPLET
"${HOST_TRIPLET}"
CACHE STRING "Default target triplet for vcpkg")
set($ENV{VCPKG_DEFAULT_HOST_TRIPLET} "${HOST_TRIPLET}")
endif()
endif()
endmacro()

Expand All @@ -102,7 +118,11 @@ macro(configure_mingw_vcpkg_after)
include("${ProjectOptions_SRC_DIR}/Utilities.cmake")
detect_architecture(_arch)
string(TOLOWER "${_arch}" _arch)
set(Z_VCPKG_TARGET_TRIPLET_ARCH ${_arch})
if (CROSSCOMPILING AND TARGET_ARCHITECTURE)
set(Z_VCPKG_TARGET_TRIPLET_ARCH ${TARGET_ARCHITECTURE})
else()
set(Z_VCPKG_TARGET_TRIPLET_ARCH ${_arch})
endif()

set(VCPKG_TARGET_TRIPLET
"${Z_VCPKG_TARGET_TRIPLET_ARCH}-${Z_VCPKG_TARGET_TRIPLET_PLAT}"
Expand Down
12 changes: 12 additions & 0 deletions src/Vcpkg.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,16 @@ macro(run_vcpkg)
CACHE STRING "vcpkg toolchain file")

configure_mingw_vcpkg_after()

if(CROSSCOMPILING)
set(_toolchain_file)
get_toolchain_file(_toolchain_file)
if(_toolchain_file)
set(VCPKG_CHAINLOAD_TOOLCHAIN_FILE
${_toolchain_file}
CACHE STRING "vcpkg chainload toolchain file")
message(STATUS "Setup cross-compiler for ${VCPKG_TARGET_TRIPLET}")
message(STATUS "Use cross-compiler toolchain: ${VCPKG_CHAINLOAD_TOOLCHAIN_FILE}")
endif()
endif()
endmacro()
29 changes: 29 additions & 0 deletions src/toolchains/i686-w64-mingw32.toolchain.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
cmake_minimum_required(VERSION 3.16)

set(CMAKE_SYSTEM_NAME Windows)
set(CMAKE_SYSTEM_PROCESSOR "i686")

if ($ENV{CROSS_ROOT})
#set(CMAKE_SYSROOT $ENV{CROSS_ROOT})
set(CMAKE_FIND_ROOT_PATH $ENV{CROSS_ROOT})
elseif (DEFINED CROSS_ROOT)
#set(CMAKE_SYSROOT ${CROSS_ROOT})
set(CMAKE_FIND_ROOT_PATH ${CROSS_ROOT})
else()
#set(CMAKE_SYSROOT /usr/i686-w64-mingw32)
set(CMAKE_FIND_ROOT_PATH /usr/i686-w64-mingw32)
endif()

set(CMAKE_C_COMPILER i686-w64-mingw32-gcc)
set(CMAKE_CXX_COMPILER i686-w64-mingw32-g++)
set(CMAKE_RC_COMPILER i686-w64-mingw32-windres)

# search for programs in the build host directories
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# for libraries and headers in the target directories
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

# override boost thread component suffix as mingw-w64-boost is compiled with threadapi=win32
set(Boost_THREADAPI win32)
29 changes: 29 additions & 0 deletions src/toolchains/x86_64-w64-mingw32.toolchain.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
cmake_minimum_required(VERSION 3.16)

set(CMAKE_SYSTEM_NAME Windows)
set(CMAKE_SYSTEM_PROCESSOR "x64")

if ($ENV{CROSS_ROOT})
#set(CMAKE_SYSROOT $ENV{CROSS_ROOT})
set(CMAKE_FIND_ROOT_PATH $ENV{CROSS_ROOT})
elseif (DEFINED CROSS_ROOT)
#set(CMAKE_SYSROOT ${CROSS_ROOT})
set(CMAKE_FIND_ROOT_PATH ${CROSS_ROOT})
else()
#set(CMAKE_SYSROOT /usr/x86_64-w64-mingw32)
set(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32)
endif()

set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc)
set(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++)
set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres)

# search for programs in the build host directories
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# for libraries and headers in the target directories
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

# override boost thread component suffix as mingw-w64-boost is compiled with threadapi=win32
set(Boost_THREADAPI win32)
5 changes: 5 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ set(CMAKE_CXX_STANDARD 20)
# include(${_project_options_SOURCE_DIR}/Index.cmake)
include(../src/Index.cmake)

# opt-in cross-compiling
option(ENABLE_CROSS_COMPILING "Detect cross compiler and setup toolchain" OFF)
if(ENABLE_CROSS_COMPILING)
enable_cross_compiler()
endif()
run_vcpkg()

project(
Expand Down

0 comments on commit 5c51d1d

Please sign in to comment.