Skip to content

Commit 0989f71

Browse files
committed
feat: add cross compiler detection (aminya#140)
* add mingw toolchains * add docker for testing
1 parent bd90abd commit 0989f71

14 files changed

+310
-12
lines changed

Taskfile.yml

+20
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,26 @@ tasks:
2323
CWD:
2424
sh: git rev-parse --show-toplevel
2525

26+
test_docker:
27+
# test gcc compiler
28+
- docker build --build-arg compiler=gcc -f ./docker/Dockerfile --target build -t project_options:build .
29+
- docker build --build-arg compiler=gcc -f ./docker/Dockerfile --target test -t project_options:test .
30+
- docker run --rm -it project_options:build
31+
- docker run --rm -it project_options:test
32+
- docker rmi project_options:build project_options:test
33+
# test llvm compiler
34+
- docker build --build-arg compiler=llvm -f ./docker/Dockerfile --target build -t project_options:build-clang .
35+
- docker build --build-arg compiler=llvm -f ./docker/Dockerfile --target test -t project_options:test-clang .
36+
- docker run --rm -it project_options:build-clang
37+
- docker run --rm -it project_options:test-clang
38+
- docker rmi project_options:build-clang project_options:test-clang
39+
test_docker_mingw:
40+
# test mingw (cross) compiler
41+
- docker build -f ./docker/Dockerfile.mingw --target build -t project_options:build-mingw .
42+
- docker run --rm -it project_options:build-mingw
43+
- docker run --rm -it --env CROSS_CC=i686-w64-mingw32-gcc --env CROSS_CXX=i686-w64-mingw32-gcc project_options:build-mingw
44+
- docker rmi project_options:build-mingw
45+
2646
lint:
2747
- |
2848
{{if eq OS "windows"}}

docker/Dockerfile

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
FROM ubuntu:20.04 AS base
2+
3+
# add setup_cpp
4+
ADD https://github.com/aminya/setup-cpp/releases/download/v0.21.0/setup_cpp_linux /setup_cpp_linux
5+
RUN chmod +x /setup_cpp_linux
6+
7+
8+
FROM base AS setup
9+
10+
ARG compiler="gcc"
11+
# install cmake, ninja, and ccache
12+
RUN /setup_cpp_linux --compiler $compiler --llvm true --cmake true --ninja true --ccache true --doxygen true --cppcheck true --vcpkg true --conan true --task true
13+
14+
# update vcpkg
15+
#WORKDIR /root/vcpkg
16+
#RUN git pull origin master
17+
#RUN ./vcpkg update
18+
#WORKDIR /
19+
20+
COPY ./docker/entrypoint.sh /docker-entrypoint.sh
21+
ENTRYPOINT [ "/docker-entrypoint.sh" ]
22+
23+
24+
FROM setup AS build
25+
COPY . /home/project_options
26+
WORKDIR /home/project_options/test
27+
CMD ["/home/project_options/docker/build.sh"]
28+
29+
30+
FROM setup AS test
31+
COPY . /home/project_options
32+
WORKDIR /home/project_options/test
33+
CMD ["/home/project_options/docker/test.sh"]
34+
35+
36+
FROM gcr.io/distroless/cc AS runner
37+
COPY --from=build /home/project_options/test/build/Release/ /home/app/
38+
WORKDIR /home/app/
39+
ENTRYPOINT ["./build/main"]

docker/Dockerfile.mingw

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
FROM ubuntu:20.04 AS base
2+
3+
# add setup_cpp
4+
ADD https://github.com/aminya/setup-cpp/releases/download/v0.21.0/setup_cpp_linux /setup_cpp_linux
5+
RUN chmod +x /setup_cpp_linux
6+
7+
8+
FROM base AS setup
9+
10+
# install cmake, ninja, and ccache
11+
RUN /setup_cpp_linux --llvm true --cmake true --ninja true --ccache true --doxygen true --cppcheck true --vcpkg true --conan true --task true
12+
13+
# TODO: install cross-compiler with setup_cpp_linux
14+
# NOTE: install mingw by hand, waiting for setup-cpp to have mingw cross-compiler support
15+
RUN apt-get update && apt-get install -y \
16+
mingw-w64 \
17+
&& rm -rf /var/lib/apt/lists/*
18+
19+
# update vcpkg
20+
#WORKDIR /root/vcpkg
21+
#RUN git pull origin master
22+
#RUN ./vcpkg update
23+
#WORKDIR /
24+
25+
COPY ./docker/entrypoint.sh /docker-entrypoint.sh
26+
ENTRYPOINT [ "/docker-entrypoint.sh" ]
27+
28+
29+
FROM setup AS build
30+
COPY . /home/project_options
31+
WORKDIR /home/project_options/test
32+
CMD ["/home/project_options/docker/build.mingw.sh"]

docker/build.mingw.sh

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!/bin/bash
2+
3+
# setup compiler
4+
export CC=${CROSS_CC:-x86_64-w64-mingw32-gcc}
5+
export CXX=${CROSS_CXX:-x86_64-w64-mingw32-g++}
6+
7+
mkdir build
8+
cd build
9+
10+
cmake -B . -G "Ninja" -DCMAKE_BUILD_TYPE:STRING=Release \
11+
-DENABLE_CROSS_COMPILING:BOOL=ON ..
12+
cmake --build . --config Release

docker/build.sh

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#!/bin/bash
2+
3+
mkdir build
4+
cd build
5+
6+
cmake -B . -G "Ninja" -DCMAKE_BUILD_TYPE:STRING=Release ..
7+
cmake --build . --config Release

docker/entrypoint.sh

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/usr/bin/env bash
2+
set -e
3+
4+
source ~/.cpprc
5+
6+
exec "$@"

docker/test.sh

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/bin/bash
2+
3+
mkdir build
4+
cd build
5+
6+
cmake -B . -G "Ninja" -DCMAKE_BUILD_TYPE:STRING=Debug ..
7+
cmake --build . --config Debug
8+
ctest -C Debug --verbose

src/CrossCompiler.cmake

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
include_guard()
2+
3+
macro(enable_cross_compiler)
4+
include("${ProjectOptions_SRC_DIR}/Utilities.cmake")
5+
detect_architecture(_arch)
6+
if(NOT DEFINED TARGET_ARCHITECTURE)
7+
if($ENV{CC} MATCHES "x86_64(-w64)?-mingw32-[gc]..?" OR $ENV{CXX} MATCHES "x86_64(-w64)?-mingw32-[gc]..?")
8+
set(TARGET_ARCHITECTURE "x64")
9+
elseif($ENV{CC} MATCHES "i686(-w64)?-mingw32-[gc]..?" OR $ENV{CXX} MATCHES "i686(-w64)?-mingw32-[gc]..?")
10+
set(TARGET_ARCHITECTURE "x86")
11+
elseif($ENV{CC} MATCHES "emcc" OR $ENV{CXX} MATCHES "em++")
12+
set(TARGET_ARCHITECTURE "wasm32")
13+
else()
14+
# TODO: check for arm compiler
15+
set(TARGET_ARCHITECTURE ${_arch})
16+
endif()
17+
endif()
18+
19+
if (NOT DEFINED HOST_TRIPLET)
20+
if(WIN32)
21+
set(HOST_TRIPLET "${_arch}-windows")
22+
elseif(APPLE)
23+
set(HOST_TRIPLET "${_arch}-osx")
24+
elseif(UNIX AND NOT APPLE)
25+
set(HOST_TRIPLET "${_arch}-linux")
26+
endif()
27+
endif()
28+
29+
if($ENV{CC} MATCHES "(x86_64|i686)(-w64)?-mingw32-[gc]..?" OR $ENV{CXX} MATCHES "(x86_64|i686)(-w64)?-mingw32-[gc]..?")
30+
set(MINGW TRUE)
31+
elseif($ENV{CC} MATCHES "emcc" OR $ENV{CXX} MATCHES "em++")
32+
set(EMSCRIPTEN TRUE)
33+
endif()
34+
35+
set(LIBRARY_LINKAGE)
36+
if(BUILD_SHARED_LIBS)
37+
set(LIBRARY_LINKAGE "dynamic")
38+
else()
39+
set(LIBRARY_LINKAGE "static")
40+
endif()
41+
42+
if (NOT DEFINED CROSS_ROOT)
43+
if($ENV{CC} MATCHES "x86_64(-w64)?-mingw32-[gc]..?" OR $ENV{CXX} MATCHES "x86_64(-w64)?-mingw32-[gc]..?")
44+
set(CROSS_ROOT "/usr/x86_64-w64-mingw32")
45+
elseif($ENV{CC} MATCHES "i686(-w64)?-mingw32-[gc]..?" OR $ENV{CXX} MATCHES "i686(-w64)?-mingw32-[gc]..?")
46+
set(CROSS_ROOT "/usr/i686-w64-mingw32")
47+
endif()
48+
# TODO: check if path is right, check for header files or something
49+
endif()
50+
51+
set(_toolchain_file)
52+
get_toolchain_file(_toolchain_file)
53+
set(CMAKE_TOOLCHAIN_FILE ${_toolchain_file})
54+
set(CROSSCOMPILING TRUE)
55+
endmacro()
56+
57+
function(get_toolchain_file value)
58+
include("${ProjectOptions_SRC_DIR}/Utilities.cmake")
59+
detect_architecture(_arch)
60+
if(DEFINED TARGET_ARCHITECTURE)
61+
set(_arch ${TARGET_ARCHITECTURE})
62+
endif()
63+
if("${_arch}" MATCHES "x64")
64+
set(_arch "x86_64")
65+
elseif("${_arch}" MATCHES "x86")
66+
set(_arch "x86_64")
67+
endif()
68+
69+
if (MINGW)
70+
set(${value}
71+
${ProjectOptions_SRC_DIR}/toolchains/${_arch}-w64-mingw32.toolchain.cmake
72+
PARENT_SCOPE)
73+
elseif(EMSCRIPTEN)
74+
set(${value}
75+
"/usr/lib/emscripten/cmake/Modules/Platform/Emscripten.cmake"
76+
PARENT_SCOPE)
77+
endif()
78+
endfunction()

src/Index.cmake

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ include("${CMAKE_CURRENT_LIST_DIR}/StaticAnalyzers.cmake")
2424
include("${CMAKE_CURRENT_LIST_DIR}/VCEnvironment.cmake")
2525
include("${CMAKE_CURRENT_LIST_DIR}/MinGW.cmake")
2626
include("${CMAKE_CURRENT_LIST_DIR}/DetectCompiler.cmake")
27+
include("${CMAKE_CURRENT_LIST_DIR}/CrossCompiler.cmake")
2728

2829
# Include msvc toolchain on windows if the generator is not visual studio. Should be called before run_vcpkg and run_conan to be effective
2930
msvc_toolchain()

src/MinGW.cmake

+32-12
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,25 @@ include_guard()
22

33
# detect mingw
44
function(is_mingw value)
5-
if(NOT WIN32 OR MSVC)
6-
set(${value}
7-
OFF
8-
PARENT_SCOPE)
9-
return()
5+
if(CROSSCOMPILING)
6+
if(MINGW)
7+
set(${value}
8+
ON
9+
PARENT_SCOPE)
10+
return()
11+
endif()
12+
else()
13+
if(NOT WIN32 OR MSVC)
14+
set(${value}
15+
OFF
16+
PARENT_SCOPE)
17+
return()
18+
endif()
1019
endif()
1120

1221
if(MINGW
13-
OR ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU")
14-
OR ("${DETECTED_CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND "${DETECTED_CMAKE_C_COMPILER_ID}" STREQUAL "GNU"))
22+
OR ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU")
23+
OR ("${DETECTED_CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND "${DETECTED_CMAKE_C_COMPILER_ID}" STREQUAL "GNU"))
1524
set(${value}
1625
ON
1726
PARENT_SCOPE)
@@ -85,11 +94,18 @@ macro(configure_mingw_vcpkg)
8594
set(VCPKG_DEFAULT_TRIPLET
8695
"${_arch}-mingw-${MINGW_LINKAGE}"
8796
CACHE STRING "Default triplet for vcpkg")
88-
set(VCPKG_DEFAULT_HOST_TRIPLET
89-
"${_arch}-mingw-${MINGW_LINKAGE}"
90-
CACHE STRING "Default target triplet for vcpkg")
9197
set($ENV{VCPKG_DEFAULT_TRIPLET} "${_arch}-mingw-${MINGW_LINKAGE}")
92-
set($ENV{VCPKG_DEFAULT_HOST_TRIPLET} "${_arch}-mingw-${MINGW_LINKAGE}")
98+
if(WIN32 AND NOT MSVC)
99+
set(VCPKG_DEFAULT_HOST_TRIPLET
100+
"${_arch}-mingw-${MINGW_LINKAGE}"
101+
CACHE STRING "Default target triplet for vcpkg")
102+
set($ENV{VCPKG_DEFAULT_HOST_TRIPLET} "${_arch}-mingw-${MINGW_LINKAGE}")
103+
elseif (CROSSCOMPILING AND HOST_TRIPLET)
104+
set(VCPKG_DEFAULT_HOST_TRIPLET
105+
"${HOST_TRIPLET}"
106+
CACHE STRING "Default target triplet for vcpkg")
107+
set($ENV{VCPKG_DEFAULT_HOST_TRIPLET} "${HOST_TRIPLET}")
108+
endif()
93109
endif()
94110
endmacro()
95111

@@ -102,7 +118,11 @@ macro(configure_mingw_vcpkg_after)
102118
include("${ProjectOptions_SRC_DIR}/Utilities.cmake")
103119
detect_architecture(_arch)
104120
string(TOLOWER "${_arch}" _arch)
105-
set(Z_VCPKG_TARGET_TRIPLET_ARCH ${_arch})
121+
if (CROSSCOMPILING AND TARGET_ARCHITECTURE)
122+
set(Z_VCPKG_TARGET_TRIPLET_ARCH ${TARGET_ARCHITECTURE})
123+
else()
124+
set(Z_VCPKG_TARGET_TRIPLET_ARCH ${_arch})
125+
endif()
106126

107127
set(VCPKG_TARGET_TRIPLET
108128
"${Z_VCPKG_TARGET_TRIPLET_ARCH}-${Z_VCPKG_TARGET_TRIPLET_PLAT}"

src/Vcpkg.cmake

+12
Original file line numberDiff line numberDiff line change
@@ -111,4 +111,16 @@ macro(run_vcpkg)
111111
CACHE STRING "vcpkg toolchain file")
112112

113113
configure_mingw_vcpkg_after()
114+
115+
if(CROSSCOMPILING)
116+
set(_toolchain_file)
117+
get_toolchain_file(_toolchain_file)
118+
if(_toolchain_file)
119+
set(VCPKG_CHAINLOAD_TOOLCHAIN_FILE
120+
${_toolchain_file}
121+
CACHE STRING "vcpkg chainload toolchain file")
122+
message(STATUS "Setup cross-compiler for ${VCPKG_TARGET_TRIPLET}")
123+
message(STATUS "Use cross-compiler toolchain: ${VCPKG_CHAINLOAD_TOOLCHAIN_FILE}")
124+
endif()
125+
endif()
114126
endmacro()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
cmake_minimum_required(VERSION 3.16)
2+
3+
set(CMAKE_SYSTEM_NAME Windows)
4+
set(CMAKE_SYSTEM_PROCESSOR "i686")
5+
6+
if ($ENV{CROSS_ROOT})
7+
#set(CMAKE_SYSROOT $ENV{CROSS_ROOT})
8+
set(CMAKE_FIND_ROOT_PATH $ENV{CROSS_ROOT})
9+
elseif (DEFINED CROSS_ROOT)
10+
#set(CMAKE_SYSROOT ${CROSS_ROOT})
11+
set(CMAKE_FIND_ROOT_PATH ${CROSS_ROOT})
12+
else()
13+
#set(CMAKE_SYSROOT /usr/i686-w64-mingw32)
14+
set(CMAKE_FIND_ROOT_PATH /usr/i686-w64-mingw32)
15+
endif()
16+
17+
set(CMAKE_C_COMPILER i686-w64-mingw32-gcc)
18+
set(CMAKE_CXX_COMPILER i686-w64-mingw32-g++)
19+
set(CMAKE_RC_COMPILER i686-w64-mingw32-windres)
20+
21+
# search for programs in the build host directories
22+
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
23+
# for libraries and headers in the target directories
24+
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
25+
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
26+
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
27+
28+
# override boost thread component suffix as mingw-w64-boost is compiled with threadapi=win32
29+
set(Boost_THREADAPI win32)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
cmake_minimum_required(VERSION 3.16)
2+
3+
set(CMAKE_SYSTEM_NAME Windows)
4+
set(CMAKE_SYSTEM_PROCESSOR "x64")
5+
6+
if ($ENV{CROSS_ROOT})
7+
#set(CMAKE_SYSROOT $ENV{CROSS_ROOT})
8+
set(CMAKE_FIND_ROOT_PATH $ENV{CROSS_ROOT})
9+
elseif (DEFINED CROSS_ROOT)
10+
#set(CMAKE_SYSROOT ${CROSS_ROOT})
11+
set(CMAKE_FIND_ROOT_PATH ${CROSS_ROOT})
12+
else()
13+
#set(CMAKE_SYSROOT /usr/x86_64-w64-mingw32)
14+
set(CMAKE_FIND_ROOT_PATH /usr/x86_64-w64-mingw32)
15+
endif()
16+
17+
set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc)
18+
set(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++)
19+
set(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres)
20+
21+
# search for programs in the build host directories
22+
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
23+
# for libraries and headers in the target directories
24+
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
25+
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
26+
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
27+
28+
# override boost thread component suffix as mingw-w64-boost is compiled with threadapi=win32
29+
set(Boost_THREADAPI win32)

test/CMakeLists.txt

+5
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ set(CMAKE_CXX_STANDARD 20)
1111
# include(${_project_options_SOURCE_DIR}/Index.cmake)
1212
include(../src/Index.cmake)
1313

14+
# opt-in cross-compiling
15+
option(ENABLE_CROSS_COMPILING "Detect cross compiler and setup toolchain" OFF)
16+
if(ENABLE_CROSS_COMPILING)
17+
enable_cross_compiler()
18+
endif()
1419
run_vcpkg()
1520

1621
project(

0 commit comments

Comments
 (0)