Skip to content

Commit 5712ef4

Browse files
committed
cmake: mutualize the detection framework
1 parent 15a1ffc commit 5712ef4

File tree

12 files changed

+229
-273
lines changed

12 files changed

+229
-273
lines changed
Lines changed: 61 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Daemon BSD Source Code
2-
# Copyright (c) 2022, Daemon Developers
2+
# Copyright (c) 2022-2025, Daemon Developers
33
# All rights reserved.
44
#
55
# Redistribution and use in source and binary forms, with or without
@@ -30,90 +30,74 @@
3030

3131
# When adding a new architecture, look at all the places DAEMON_ARCH is used.
3232

33-
try_compile(BUILD_RESULT
34-
"${CMAKE_BINARY_DIR}"
35-
"${CMAKE_CURRENT_LIST_DIR}/Architecture/Architecture.cpp"
36-
CMAKE_FLAGS CMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES}
37-
OUTPUT_VARIABLE BUILD_LOG
38-
)
39-
40-
# Setting -Werror in CXXFLAGS would produce errors instead of warning
41-
# but that should not break the architecture detection,
42-
# so we only print a CMake warning there and use BUILD_LOG content to
43-
# detect unknown platforms.
44-
# Catching compilation error is still useful, for example to detect
45-
# undefined types, missing header or things like that.
46-
# Setting USE_WERROR to ON doesn't print this warning.
47-
if (NOT BUILD_RESULT)
48-
message(WARNING
49-
"Failed to build Architecture.cpp\n"
50-
"Setting -Werror in CXXFLAGS can produce false positive errors\n"
51-
"${BUILD_LOG}"
52-
)
53-
endif()
54-
55-
string(REGEX MATCH "DAEMON_ARCH_([a-zA-Z0-9_]+)" DAEMON_ARCH_DEFINE "${BUILD_LOG}")
56-
string(REPLACE "DAEMON_ARCH_" "" DAEMON_ARCH "${DAEMON_ARCH_DEFINE}")
57-
58-
set("DAEMON_ARCH_${DAEMON_ARCH}" ON)
33+
option(USE_ARCH_INTRINSICS "Enable custom code using intrinsics functions or asm declarations" ON)
34+
mark_as_advanced(USE_ARCH_INTRINSICS)
5935

60-
if (NOT DAEMON_ARCH)
61-
message(FATAL_ERROR
62-
"Missing DAEMON_ARCH, there is a mistake in Architecture.cpp\n"
63-
"${BUILD_LOG}"
64-
)
65-
endif()
66-
67-
message(STATUS "Detected target architecture: ${DAEMON_ARCH}")
68-
69-
add_definitions(-D${DAEMON_ARCH_DEFINE})
70-
71-
# This string can be modified without breaking compatibility.
72-
daemon_add_buildinfo("char*" "DAEMON_ARCH_STRING" "\"${DAEMON_ARCH}\"")
73-
74-
# Modifying NACL_ARCH breaks engine compatibility with nexe game binaries
75-
# since NACL_ARCH contributes to the nexe file name.
76-
set(DAEMON_NACL_ARCH "${DAEMON_ARCH}")
77-
if (DAEMON_TARGET_SYSTEM_Unix_COMPATIBILITY)
78-
set(ARMHF_USAGE arm64 armel)
79-
if (DAEMON_ARCH IN_LIST ARMHF_USAGE)
80-
# Load 32-bit armhf nexe on 64-bit arm64 engine on Linux with multiarch.
81-
# The nexe is system agnostic so there should be no difference with armel.
82-
set(DAEMON_NACL_ARCH "armhf")
83-
endif()
84-
elseif(DAEMON_TARGET_SYSTEM_macOS)
85-
if ("${DAEMON_ARCH}" STREQUAL arm64)
86-
# You can get emulated NaCl going like this:
87-
# cp external_deps/macos-amd64-default_10/{nacl_loader,irt_core-amd64.nexe} build/
88-
set(DAEMON_NACL_ARCH "amd64")
36+
function(daemon_detect_arch)
37+
run_daemon_detection("" "ARCH" "Architecture.c" "")
38+
39+
set(DAEMON_ARCH "${arch_name}" PARENT_SCOPE)
40+
41+
message(STATUS "Detected target architecture: ${arch_name}")
42+
43+
add_definitions(-DDAEMON_ARCH_${arch_name})
44+
45+
set(nacl_arch "${arch_name}")
46+
if (DAEMON_TARGET_SYSTEM_Unix_COMPATIBILITY)
47+
set(armhf_usage "arm64;armel")
48+
if ("${arch_name}" IN_LIST armhf_usage)
49+
# Load 32-bit armhf nexe on 64-bit arm64 engine on Linux with multiarch.
50+
# The nexe is system agnostic so there should be no difference with armel.
51+
set(nacl_arch "armhf")
52+
endif()
53+
elseif(DAEMON_TARGET_SYSTEM_macOS)
54+
if ("${arch_name}" STREQUAL "arm64")
55+
# You can get emulated NaCl going like this:
56+
# cp external_deps/macos-amd64-default_10/{nacl_loader,irt_core-amd64.nexe} build/
57+
set(nacl_arch "amd64")
58+
endif()
8959
endif()
90-
endif()
9160

92-
set("DAEMON_NACL_ARCH_${DAEMON_NACL_ARCH}" ON)
61+
# The DAEMON_NACL_ARCH variable contributes to the nexe file name.
62+
set(DAEMON_NACL_ARCH "${nacl_arch}" PARENT_SCOPE)
63+
endfunction()
9364

94-
daemon_add_buildinfo("char*" "DAEMON_NACL_ARCH_STRING" "\"${DAEMON_NACL_ARCH}\"")
65+
function(daemon_set_arch_intrinsics name)
66+
message(STATUS "Enabling ${name} architecture intrinsics")
67+
add_definitions(-DDAEMON_USE_ARCH_INTRINSICS_${name})
68+
endfunction()
9569

96-
option(USE_ARCH_INTRINSICS "Enable custom code using intrinsics functions or asm declarations" ON)
97-
mark_as_advanced(USE_ARCH_INTRINSICS)
98-
99-
macro(set_arch_intrinsics name)
70+
function(daemon_set_intrinsics)
10071
if (USE_ARCH_INTRINSICS)
101-
message(STATUS "Enabling ${name} architecture intrinsics")
102-
add_definitions(-DDAEMON_USE_ARCH_INTRINSICS_${name}=1)
72+
# Makes possible to do things like that in C++ code:
73+
# > if defined(DAEMON_USER_ARCH_INTRINSICS)
74+
add_definitions(-DDAEMON_USE_ARCH_INTRINSICS)
75+
76+
# Makes possible to do things like that in C++ code:
77+
# > if defined(DAEMON_USER_ARCH_INTRINSICS_amd64)
78+
# > if defined(DAEMON_USER_ARCH_INTRINSICS_i686)
79+
daemon_set_arch_intrinsics("${DAEMON_ARCH}")
80+
81+
set(amd64_PARENT "i686")
82+
set(arm64_PARENT "armhf")
83+
84+
if ("${DAEMON_ARCH}_PARENT")
85+
daemon_set_arch_intrinsics("${${DAEMON_ARCH}_PARENT}")
86+
endif()
10387
else()
104-
message(STATUS "Disabling ${name} architecture intrinsics")
88+
message(STATUS "Disabling ${DAEMON_ARCH} architecture intrinsics")
10589
endif()
106-
endmacro()
90+
endfunction()
10791

108-
if (USE_ARCH_INTRINSICS)
109-
add_definitions(-DDAEMON_USE_ARCH_INTRINSICS=1)
110-
endif()
92+
daemon_detect_arch()
93+
daemon_set_intrinsics()
11194

112-
set_arch_intrinsics(${DAEMON_ARCH})
113-
114-
set(amd64_PARENT "i686")
115-
set(arm64_PARENT "armhf")
95+
# Makes possible to do things like that in CMake code:
96+
# > if (DAEMON_ARCH_arm64)
97+
# > if (DAEMON_NACL_ARCH_armhf)
98+
set("DAEMON_ARCH_${DAEMON_ARCH}" ON)
99+
set("DAEMON_NACL_ARCH_${DAEMON_NACL_ARCH}" ON)
116100

117-
if (${DAEMON_ARCH}_PARENT)
118-
set_arch_intrinsics(${${DAEMON_ARCH}_PARENT})
119-
endif()
101+
# Add printable strings to the executable.
102+
daemon_add_buildinfo("char*" "DAEMON_ARCH_STRING" "\"${DAEMON_NACL_ARCH}\"")
103+
daemon_add_buildinfo("char*" "DAEMON_NACL_ARCH_STRING" "\"${DAEMON_NACL_ARCH}\"")

cmake/DaemonPlatform/Compiler.cmake

Lines changed: 14 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Daemon BSD Source Code
2-
# Copyright (c) 2024, Daemon Developers
2+
# Copyright (c) 2024-2025, Daemon Developers
33
# All rights reserved.
44
#
55
# Redistribution and use in source and binary forms, with or without
@@ -28,63 +28,18 @@
2828
# Compiler detection.
2929
################################################################################
3030

31-
# FIXME: Force -W#pragma-messages and -Wno-error
32-
# In case there is -Wno-#pragma-messages or -Werror in CFLAGS/CXXFLAGS
31+
# When adding a new compiler, look at all the places DAEMON_C_COMPILER
32+
# and DAEMON_CXX_COMPILER are used.
3333

34-
function(detect_daemon_compiler lang)
34+
function(daemon_detect_compiler lang)
3535
set(C_NAME "C")
3636
set(CXX_NAME "C++")
3737
set(C_EXT ".c")
3838
set(CXX_EXT ".cpp")
3939

40-
try_compile(BUILD_RESULT
41-
"${CMAKE_BINARY_DIR}"
42-
"${CMAKE_CURRENT_LIST_DIR}/Compiler/Compiler${${lang}_EXT}"
43-
CMAKE_FLAGS CMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES}
44-
OUTPUT_VARIABLE BUILD_LOG
45-
)
46-
4740
get_filename_component(compiler_basename "${CMAKE_${lang}_COMPILER}" NAME)
4841

49-
if (NOT BUILD_RESULT)
50-
message(WARNING "Failed to build Compiler${${lang}_EXT}, relying on CMake builtin detection.")
51-
set(compiler_name "Unknown")
52-
else()
53-
set(BUILD_LOG "\n${BUILD_LOG}\n")
54-
string(REGEX REPLACE "\n[^\n]*<REPORT<" "\n" BUILD_LOG "${BUILD_LOG}")
55-
string(REGEX REPLACE ">REPORT>[^\n]*\n" "\n" BUILD_LOG "${BUILD_LOG}")
56-
57-
string(REGEX REPLACE ".*\nDAEMON_COMPILER_NAME=([^\n]*)\n.*" "\\1"
58-
compiler_name "${BUILD_LOG}")
59-
60-
foreach(name GCC;Clang;generic;${compiler_name})
61-
set(compatibility_regex ".*\nDAEMON_COMPILER_${name}_COMPATIBILITY=([^\n]*)\n.*")
62-
if ("${BUILD_LOG}" MATCHES ${compatibility_regex})
63-
string(REGEX REPLACE ${compatibility_regex} "\\1"
64-
compiler_${name}_compatibility "${BUILD_LOG}")
65-
endif()
66-
67-
set(version_regex ".*\nDAEMON_COMPILER_${name}_VERSION=([^\n]*)\n.*")
68-
if ("${BUILD_LOG}" MATCHES ${version_regex})
69-
string(REGEX REPLACE ${version_regex} "\\1"
70-
compiler_${name}_version "${BUILD_LOG}")
71-
endif()
72-
73-
set(version_string_regex ".*\nDAEMON_COMPILER_${name}_VERSION_STRING=([^\n]*)\n.*")
74-
if ("${BUILD_LOG}" MATCHES ${version_string_regex})
75-
string(REGEX REPLACE ${version_string_regex} "\\1"
76-
compiler_${name}_version_string "${BUILD_LOG}")
77-
endif()
78-
79-
set(DAEMON_${lang}_COMPILER_${name}_VERSION
80-
"${compiler_${name}_version}"
81-
PARENT_SCOPE)
82-
83-
set(DAEMON_${lang}_COMPILER_${name}_COMPATIBILITY
84-
"${compiler_${name}_compatibility}"
85-
PARENT_SCOPE)
86-
endforeach()
87-
endif()
42+
run_daemon_detection("${lang}_" "COMPILER" "Compiler${${lang}_EXT}" "GCC;Clang;generic")
8843

8944
if (compiler_name STREQUAL "Unknown")
9045
if (CMAKE_${lang}_COMPILER_ID)
@@ -189,7 +144,7 @@ foreach(lang C;CXX)
189144
set(DAEMON_${lang}_COMPILER_VERSION "${CMAKE_${lang}_COMPILER_VERSION}")
190145
get_filename_component(DAEMON_${lang}_COMPILER_BASENAME "${CMAKE_${lang}_COMPILER}" NAME)
191146
else()
192-
detect_daemon_compiler(${lang})
147+
daemon_detect_compiler(${lang})
193148

194149
if (DAEMON_${lang}_COMPILER_Clang_COMPATIBILITY)
195150
if (NOT DAEMON_${lang}_COMPILER_NAME STREQUAL "Clang")
@@ -233,9 +188,15 @@ foreach(lang C;CXX)
233188

234189
message(STATUS "Detected ${${lang}_NAME} compiler: ${DAEMON_${lang}_COMPILER_STRING}")
235190

191+
# Makes possible to do things like that in C++ code:
192+
# > if defined(__DAEMON_CXX_COMPILER_Clang)
236193
set(compiler_var_name "DAEMON_${lang}_COMPILER_${DAEMON_${lang}_COMPILER_NAME}")
237-
set(${compiler_var_name} ON)
238-
add_definitions(-D${compiler_var_name}=1)
194+
add_definitions(-D${compiler_var_name})
195+
196+
# Makes possible to do things like that in CMake code:
197+
# > if (DAEMON_CXX_COMPILER_Clang)
198+
set("${compiler_var_name}" ON)
239199

200+
# Add printable string to the executable.
240201
daemon_add_buildinfo("char*" "DAEMON_${lang}_COMPILER_STRING" "\"${DAEMON_${lang}_COMPILER_STRING}\"")
241202
endforeach()
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# Daemon BSD Source Code
2+
# Copyright (c) 2025, Daemon Developers
3+
# All rights reserved.
4+
#
5+
# Redistribution and use in source and binary forms, with or without
6+
# modification, are permitted provided that the following conditions are met:
7+
# * Redistributions of source code must retain the above copyright
8+
# notice, this list of conditions and the following disclaimer.
9+
# * Redistributions in binary form must reproduce the above copyright
10+
# notice, this list of conditions and the following disclaimer in the
11+
# documentation and/or other materials provided with the distribution.
12+
# * Neither the name of the <organization> nor the
13+
# names of its contributors may be used to endorse or promote products
14+
# derived from this software without specific prior written permission.
15+
#
16+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17+
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19+
# DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
20+
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21+
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22+
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23+
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26+
27+
# Make sure to always call this macro from within a function, not in the global scope.
28+
# As a macro it produces a lot of variables in the parent scope but it is meant to
29+
# only be called by functions so they should never pollute the globale scope.
30+
# It's a macro because we need to write a lot of variables in the calling function scope
31+
# and we need to write some variables to the parent scope of the calling function.
32+
macro(run_daemon_detection slug_prefix report_slug file_name compat_list)
33+
string(TOLOWER "${report_slug}" local_slug)
34+
35+
# Setting -Werror in CXXFLAGS would produce errors instead of warning
36+
# but that should not break the detection,
37+
# so we only print a CMake warning there and use build_log content to
38+
# detect unknown platforms.
39+
# Catching compilation error is still useful, for example to detect
40+
# undefined types, missing header or things like that.
41+
# Setting USE_WERROR to ON doesn't print this warning as the flag
42+
# is set after the detection.
43+
try_compile(build_result
44+
"${CMAKE_BINARY_DIR}"
45+
"${CMAKE_CURRENT_LIST_DIR}/Detection/${file_name}"
46+
# TODO: Force -W#pragma-messages and -Wno-error
47+
# In case there is -Wno-#pragma-messages or -Werror in CFLAGS/CXXFLAGS
48+
CMAKE_FLAGS CMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES}
49+
OUTPUT_VARIABLE build_log
50+
)
51+
52+
if (NOT build_result)
53+
message(WARNING "Failed to build ${file_name}.\n"
54+
"Setting -Werror in CFLAGS can produce false positive errors\n"
55+
"${build_log}"
56+
)
57+
set(${local_slug}_name "Unknown" PARENT_SCOPE)
58+
else()
59+
set(build_log "\n${build_log}\n")
60+
61+
string(REGEX REPLACE "\n[^\n]*<REPORT<" "\n" build_log "${build_log}")
62+
string(REGEX REPLACE ">REPORT>[^\n]*\n" "\n" build_log "${build_log}")
63+
64+
string(REGEX REPLACE ".*\nDAEMON_${report_slug}_NAME=([^\n]*)\n.*" "\\1"
65+
${local_slug}_name "${build_log}")
66+
67+
foreach(name ${compat_list};${${local_slug}_name})
68+
set(COMPATIBILITY_REGEX ".*\nDAEMON_${report_slug}_${name}_COMPATIBILITY=([^\n]*)\n.*")
69+
if ("${build_log}" MATCHES ${COMPATIBILITY_REGEX})
70+
string(REGEX REPLACE ${COMPATIBILITY_REGEX} "\\1"
71+
${local_slug}_${name}_compatibility "${build_log}")
72+
73+
set("DAEMON_${slug_prefix}${report_slug}_${name}_COMPATIBILITY"
74+
"${${local_slug}_${name}_compatibility}"
75+
PARENT_SCOPE)
76+
endif()
77+
78+
set(VERSION_REGEX ".*\nDAEMON_${report_slug}_${name}_VERSION=([^\n]*)\n.*")
79+
if ("${build_log}" MATCHES ${VERSION_REGEX})
80+
string(REGEX REPLACE ${VERSION_REGEX} "\\1"
81+
${local_slug}_${name}_version "${build_log}")
82+
83+
set("DAEMON_${slug_prefix}${report_slug}_${name}_VERSION"
84+
"${${report_slug}_${name}_version}"
85+
PARENT_SCOPE)
86+
endif()
87+
88+
set(VERSION_STRING_REGEX ".*\nDAEMON_${report_slug}_${name}_VERSION_STRING=([^\n]*)\n.*")
89+
if ("${build_log}" MATCHES ${VERSION_STRING_REGEX})
90+
string(REGEX REPLACE ${VERSION_STRING_REGEX} "\\1"
91+
${local_slug}_${name}_version_string "${build_log}")
92+
endif()
93+
endforeach()
94+
endif()
95+
endmacro()
96+
97+
# Target detection.
98+
include(${CMAKE_CURRENT_LIST_DIR}/System.cmake)
99+
include(${CMAKE_CURRENT_LIST_DIR}/Architecture.cmake)
100+
101+
# Compiler detection.
102+
include(${CMAKE_CURRENT_LIST_DIR}/Compiler.cmake)

0 commit comments

Comments
 (0)