-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
build: Add CMake-based build system (8 of N) #18
Changes from all commits
7903bd5
ae430cf
e0621e9
3736470
482e844
1a1dda5
a65da0d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -80,6 +80,13 @@ set(CMAKE_CXX_EXTENSIONS OFF) | |
|
||
set(configure_warnings) | ||
|
||
# The core interface library aims to encapsulate all common build flags. | ||
# It is intended to be a usage requirement for all other targets. | ||
add_library(core INTERFACE) | ||
|
||
include(TryAppendCXXFlags) | ||
include(TryAppendLinkerFlag) | ||
|
||
if(WIN32) | ||
#[=[ | ||
This build system supports two ways to build binaries for Windows. | ||
|
@@ -97,29 +104,63 @@ if(WIN32) | |
- A run-time library must be specified explicitly using _MT definition. | ||
]=] | ||
|
||
add_compile_definitions(_WIN32_WINNT=0x0601 _WIN32_IE=0x0501 WIN32_LEAN_AND_MEAN NOMINMAX) | ||
target_compile_definitions(core INTERFACE | ||
_WIN32_WINNT=0x0601 | ||
_WIN32_IE=0x0501 | ||
WIN32_LEAN_AND_MEAN | ||
NOMINMAX | ||
) | ||
|
||
if(MSVC) | ||
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>") | ||
add_compile_options(/utf-8 /Zc:__cplusplus) | ||
target_compile_options(core INTERFACE | ||
/utf-8 | ||
/Zc:__cplusplus | ||
) | ||
# Improve parallelism in MSBuild. | ||
# See: https://devblogs.microsoft.com/cppblog/improved-parallelism-in-msbuild/. | ||
list(APPEND CMAKE_VS_GLOBALS "UseMultiToolTask=true") | ||
endif() | ||
|
||
if(MINGW) | ||
add_compile_definitions(WIN32 _WINDOWS _MT) | ||
target_compile_definitions(core INTERFACE | ||
WIN32 | ||
_WINDOWS | ||
_MT | ||
) | ||
# We require Windows 7 (NT 6.1) or later. | ||
add_link_options(-Wl,--major-subsystem-version,6 -Wl,--minor-subsystem-version,1) | ||
try_append_linker_flag(core "-Wl,--major-subsystem-version,6") | ||
try_append_linker_flag(core "-Wl,--minor-subsystem-version,1") | ||
endif() | ||
endif() | ||
|
||
# Use 64-bit off_t on 32-bit Linux. | ||
if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SIZEOF_VOID_P EQUAL 4) | ||
# Ensure 64-bit offsets are used for filesystem accesses for 32-bit compilation. | ||
target_compile_definitions(core INTERFACE | ||
_FILE_OFFSET_BITS=64 | ||
) | ||
endif() | ||
|
||
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") | ||
add_compile_definitions(MAC_OSX) | ||
target_compile_definitions(core INTERFACE | ||
MAC_OSX | ||
) | ||
# These flags are specific to ld64, and may cause issues with other linkers. | ||
# For example: GNU ld will interpret -dead_strip as -de and then try and use | ||
# "ad_strip" as the symbol for the entry point. | ||
try_append_linker_flag(core "-Wl,-dead_strip") | ||
try_append_linker_flag(core "-Wl,-dead_strip_dylibs") | ||
try_append_linker_flag(core "-Wl,-headerpad_max_install_names") | ||
endif() | ||
|
||
if(CMAKE_CROSSCOMPILING AND DEPENDS_ALLOW_HOST_PACKAGES) | ||
list(APPEND CMAKE_FIND_ROOT_PATH "${CMAKE_SYSTEM_PREFIX_PATH}") | ||
if(CMAKE_CROSSCOMPILING) | ||
target_compile_definitions(core INTERFACE ${DEPENDS_COMPILE_DEFINITIONS}) | ||
target_compile_options(core INTERFACE "$<$<COMPILE_LANGUAGE:C>:${DEPENDS_C_COMPILER_FLAGS}>") | ||
target_compile_options(core INTERFACE "$<$<COMPILE_LANGUAGE:CXX>:${DEPENDS_CXX_COMPILER_FLAGS}>") | ||
if(DEPENDS_ALLOW_HOST_PACKAGES) | ||
list(APPEND CMAKE_FIND_ROOT_PATH "${CMAKE_SYSTEM_PREFIX_PATH}") | ||
endif() | ||
endif() | ||
|
||
include(AddThreadsIfNeeded) | ||
|
@@ -140,6 +181,47 @@ include(cmake/leveldb.cmake) | |
include(cmake/minisketch.cmake) | ||
include(cmake/secp256k1.cmake) | ||
|
||
include(ProcessConfigurations) | ||
set_default_config(RelWithDebInfo) | ||
|
||
# Redefine configuration flags. | ||
target_compile_definitions(core INTERFACE | ||
$<$<CONFIG:Debug>:DEBUG> | ||
$<$<CONFIG:Debug>:DEBUG_LOCKORDER> | ||
$<$<CONFIG:Debug>:DEBUG_LOCKCONTENTION> | ||
$<$<CONFIG:Debug>:RPC_DOC_CHECK> | ||
$<$<CONFIG:Debug>:ABORT_ON_FAILED_ASSUME> | ||
) | ||
# We leave assertions on. | ||
if(MSVC) | ||
remove_c_flag_from_all_configs(/DNDEBUG) | ||
remove_cxx_flag_from_all_configs(/DNDEBUG) | ||
else() | ||
remove_c_flag_from_all_configs(-DNDEBUG) | ||
remove_cxx_flag_from_all_configs(-DNDEBUG) | ||
|
||
# Prefer -O2 optimization level. (-O3 is CMake's default for Release for many compilers.) | ||
replace_c_flag_in_config(Release -O3 -O2) | ||
replace_cxx_flag_in_config(Release -O3 -O2) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe this means the user has no way to override and is stuck with "-O2" builds ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FWIW, an issue with the user's opportunities to override build system options described in details in bitcoin-core/secp256k1#1249. |
||
|
||
set(debug_c_flags "") | ||
set(debug_cxx_flags "") | ||
try_append_cxx_flags(debug_cxx_flags "-O0" RESULT_VAR compiler_supports_O0) | ||
if(compiler_supports_O0) | ||
string(STRIP "${debug_c_flags} -O0" debug_c_flags) | ||
endif() | ||
try_append_cxx_flags(debug_cxx_flags "-g3" RESULT_VAR compiler_supports_g3) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The "-g" flags should be on for Debug + RelWithDebInfo, off for MinSizeRel/Release. But it appears they're applied here unconditionally? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, though your multi-config output looks as I'd expect. I must be misunderstanding something. Ignore the above comment for now. |
||
if(compiler_supports_g3) | ||
string(STRIP "${debug_c_flags} -g3" debug_c_flags) | ||
else() | ||
try_append_cxx_flags(debug_cxx_flags "-g") | ||
string(STRIP "${debug_c_flags} -g" debug_c_flags) | ||
endif() | ||
try_append_cxx_flags(debug_cxx_flags "-ftrapv") | ||
set(CMAKE_C_FLAGS_DEBUG "${debug_c_flags}") | ||
set(CMAKE_CXX_FLAGS_DEBUG "${debug_cxx_flags}") | ||
endif() | ||
|
||
include(cmake/optional.cmake) | ||
|
||
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.14) | ||
|
@@ -163,6 +245,9 @@ add_subdirectory(test) | |
|
||
include(cmake/tests.cmake) | ||
|
||
get_target_property(definitions core INTERFACE_COMPILE_DEFINITIONS) | ||
separate_by_configs(definitions) | ||
|
||
message("\n") | ||
message("Configure summary") | ||
message("=================") | ||
|
@@ -190,40 +275,33 @@ else() | |
set(cross_status "FALSE") | ||
endif() | ||
message("Cross compiling ....................... ${cross_status}") | ||
get_directory_property(definitions COMPILE_DEFINITIONS) | ||
string(REPLACE ";" " " definitions "${definitions}") | ||
message("Preprocessor defined macros ........... ${definitions}") | ||
message("Preprocessor defined macros ........... ${definitions_ALL}") | ||
message("C compiler ............................ ${CMAKE_C_COMPILER}") | ||
message("CFLAGS ................................ ${CMAKE_C_FLAGS}") | ||
list(JOIN DEPENDS_C_COMPILER_FLAGS " " depends_c_flags) | ||
string(STRIP "${CMAKE_C_FLAGS} ${depends_c_flags}" combined_c_flags) | ||
message("CFLAGS ................................ ${combined_c_flags}") | ||
message("C++ compiler .......................... ${CMAKE_CXX_COMPILER}") | ||
message("CXXFLAGS .............................. ${CMAKE_CXX_FLAGS}") | ||
get_directory_property(common_compile_options COMPILE_OPTIONS) | ||
string(REPLACE ";" " " common_compile_options "${common_compile_options}") | ||
list(JOIN DEPENDS_CXX_COMPILER_FLAGS " " depends_cxx_flags) | ||
string(STRIP "${CMAKE_CXX_FLAGS} ${depends_cxx_flags}" combined_cxx_flags) | ||
message("CXXFLAGS .............................. ${combined_cxx_flags}") | ||
get_target_property(common_compile_options core INTERFACE_COMPILE_OPTIONS) | ||
if(common_compile_options) | ||
list(JOIN common_compile_options " " common_compile_options) | ||
else() | ||
set(common_compile_options) | ||
endif() | ||
string(GENEX_STRIP "${common_compile_options}" common_compile_options) | ||
message("Common compile options ................ ${common_compile_options}") | ||
get_directory_property(common_link_options LINK_OPTIONS) | ||
string(REPLACE ";" " " common_link_options "${common_link_options}") | ||
message("Common link options ................... ${common_link_options}") | ||
if(DEFINED CMAKE_BUILD_TYPE) | ||
message("Build type:") | ||
message(" - CMAKE_BUILD_TYPE ................... ${CMAKE_BUILD_TYPE}") | ||
string(TOUPPER "${CMAKE_BUILD_TYPE}" build_type) | ||
message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_${build_type}}") | ||
message(" - CXXFLAGS ........................... ${CMAKE_CXX_FLAGS_${build_type}}") | ||
message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_${build_type}}") | ||
message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_${build_type}}") | ||
get_target_property(common_link_options core INTERFACE_LINK_OPTIONS) | ||
if(common_link_options) | ||
list(JOIN common_link_options " " common_link_options) | ||
else() | ||
message("Available configurations .............. ${CMAKE_CONFIGURATION_TYPES}") | ||
message("Debug configuration:") | ||
message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_DEBUG}") | ||
message(" - CXXFLAGS ........................... ${CMAKE_CXX_FLAGS_DEBUG}") | ||
message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_DEBUG}") | ||
message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_DEBUG}") | ||
message("Release configuration:") | ||
message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_RELEASE}") | ||
message(" - CXXFLAGS ........................... ${CMAKE_CXX_FLAGS_RELEASE}") | ||
message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_RELEASE}") | ||
message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") | ||
set(common_link_options) | ||
endif() | ||
message("Common link options ................... ${common_link_options}") | ||
message("Linker flags for executables .......... ${CMAKE_EXE_LINKER_FLAGS}") | ||
message("Linker flags for shared libraries ..... ${CMAKE_SHARED_LINKER_FLAGS}") | ||
print_config_flags() | ||
message("Use assembly routines ................. ${ASM}") | ||
message("Use ccache for compiling .............. ${CCACHE}") | ||
message("\n") | ||
|
@@ -234,3 +312,17 @@ if(configure_warnings) | |
endforeach() | ||
message(" ******\n") | ||
endif() | ||
|
||
# We want all build properties to be encapsulated properly. | ||
get_directory_property(global_compile_definitions COMPILE_DEFINITIONS) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sanity checking -- Love it! |
||
if(global_compile_definitions) | ||
message(AUTHOR_WARNING "The directory's COMPILE_DEFINITIONS property is not empty: ${global_compile_definitions}") | ||
endif() | ||
get_directory_property(global_compile_options COMPILE_OPTIONS) | ||
if(global_compile_options) | ||
message(AUTHOR_WARNING "The directory's COMPILE_OPTIONS property is not empty: ${global_compile_options}") | ||
endif() | ||
get_directory_property(global_link_options LINK_OPTIONS) | ||
if(global_link_options) | ||
message(AUTHOR_WARNING "The directory's LINK_OPTIONS property is not empty: ${global_link_options}") | ||
endif() |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
# Copyright (c) 2023-present The Bitcoin Core developers | ||
# Distributed under the MIT software license, see the accompanying | ||
# file COPYING or https://opensource.org/license/mit/. | ||
|
||
function(get_all_configs output) | ||
get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) | ||
if(is_multi_config) | ||
set(all_configs ${CMAKE_CONFIGURATION_TYPES}) | ||
else() | ||
get_property(all_configs CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS) | ||
if(NOT all_configs) | ||
# See https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#default-and-custom-configurations | ||
set(all_configs Debug Release RelWithDebInfo MinSizeRel) | ||
endif() | ||
endif() | ||
set(${output} "${all_configs}" PARENT_SCOPE) | ||
endfunction() | ||
|
||
|
||
#[=[ | ||
Set the default build configuration. | ||
|
||
See: https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#build-configurations. | ||
|
||
On single-configuration generators, this function sets the CMAKE_BUILD_TYPE variable to | ||
the default build configuration, which can be overridden by the user at configure time if needed. | ||
|
||
On multi-configuration generators, this function rearranges the CMAKE_CONFIGURATION_TYPES list, | ||
ensuring that the default build configuration appears first while maintaining the order of the | ||
remaining configurations. The user can choose a build configuration at build time. | ||
]=] | ||
function(set_default_config config) | ||
get_all_configs(all_configs) | ||
if(NOT ${config} IN_LIST all_configs) | ||
message(FATAL_ERROR "The default config is \"${config}\", but must be one of ${all_configs}.") | ||
endif() | ||
|
||
list(REMOVE_ITEM all_configs ${config}) | ||
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.15) | ||
list(PREPEND all_configs ${config}) | ||
else() | ||
set(all_configs ${config} ${all_configs}) | ||
endif() | ||
|
||
get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) | ||
if(is_multi_config) | ||
get_property(help_string CACHE CMAKE_CONFIGURATION_TYPES PROPERTY HELPSTRING) | ||
set(CMAKE_CONFIGURATION_TYPES "${all_configs}" CACHE STRING "${help_string}" FORCE) | ||
else() | ||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY | ||
STRINGS "${all_configs}" | ||
) | ||
if(NOT CMAKE_BUILD_TYPE) | ||
message(STATUS "Setting build type to \"${config}\" as none was specified") | ||
get_property(help_string CACHE CMAKE_BUILD_TYPE PROPERTY HELPSTRING) | ||
set(CMAKE_BUILD_TYPE "${config}" CACHE STRING "${help_string}" FORCE) | ||
endif() | ||
endif() | ||
endfunction() | ||
|
||
function(remove_c_flag_from_all_configs flag) | ||
get_all_configs(all_configs) | ||
foreach(config IN LISTS all_configs) | ||
string(TOUPPER "${config}" config_uppercase) | ||
set(flags "${CMAKE_C_FLAGS_${config_uppercase}}") | ||
separate_arguments(flags) | ||
list(FILTER flags EXCLUDE REGEX "${flag}") | ||
list(JOIN flags " " new_flags) | ||
set(CMAKE_C_FLAGS_${config_uppercase} "${new_flags}" PARENT_SCOPE) | ||
endforeach() | ||
endfunction() | ||
|
||
function(remove_cxx_flag_from_all_configs flag) | ||
get_all_configs(all_configs) | ||
foreach(config IN LISTS all_configs) | ||
string(TOUPPER "${config}" config_uppercase) | ||
set(flags "${CMAKE_CXX_FLAGS_${config_uppercase}}") | ||
separate_arguments(flags) | ||
list(FILTER flags EXCLUDE REGEX "${flag}") | ||
list(JOIN flags " " new_flags) | ||
set(CMAKE_CXX_FLAGS_${config_uppercase} "${new_flags}" PARENT_SCOPE) | ||
endforeach() | ||
endfunction() | ||
|
||
function(replace_c_flag_in_config config old_flag new_flag) | ||
string(TOUPPER "${config}" config_uppercase) | ||
string(REGEX REPLACE "(^| )${old_flag}( |$)" "\\1${new_flag}\\2" new_flags "${CMAKE_C_FLAGS_${config_uppercase}}") | ||
set(CMAKE_C_FLAGS_${config_uppercase} "${new_flags}" PARENT_SCOPE) | ||
endfunction() | ||
|
||
function(replace_cxx_flag_in_config config old_flag new_flag) | ||
string(TOUPPER "${config}" config_uppercase) | ||
string(REGEX REPLACE "(^| )${old_flag}( |$)" "\\1${new_flag}\\2" new_flags "${CMAKE_CXX_FLAGS_${config_uppercase}}") | ||
set(CMAKE_CXX_FLAGS_${config_uppercase} "${new_flags}" PARENT_SCOPE) | ||
endfunction() | ||
|
||
function(separate_by_configs options) | ||
list(JOIN ${options} " " ${options}_ALL) | ||
string(GENEX_STRIP "${${options}_ALL}" ${options}_ALL) | ||
set(${options}_ALL "${${options}_ALL}" PARENT_SCOPE) | ||
|
||
get_all_configs(all_configs) | ||
foreach(config IN LISTS all_configs) | ||
string(REGEX MATCHALL "\\$<\\$<CONFIG:${config}>[^\n]*>" match "${${options}}") | ||
list(JOIN match " " match) | ||
string(REPLACE "\$<\$<CONFIG:${config}>:" "" match "${match}") | ||
string(REPLACE ">" "" match "${match}") | ||
string(TOUPPER "${config}" conf_upper) | ||
set(${options}_${conf_upper} "${match}" PARENT_SCOPE) | ||
endforeach() | ||
endfunction() | ||
|
||
function(print_config_flags) | ||
macro(print_flags config) | ||
string(TOUPPER "${config}" config_uppercase) | ||
message(" - Preprocessor defined macros ........ ${definitions_${config_uppercase}}") | ||
message(" - CFLAGS ............................. ${CMAKE_C_FLAGS_${config_uppercase}}") | ||
message(" - CXXFLAGS ........................... ${CMAKE_CXX_FLAGS_${config_uppercase}}") | ||
message(" - LDFLAGS for executables ............ ${CMAKE_EXE_LINKER_FLAGS_${config_uppercase}}") | ||
message(" - LDFLAGS for shared libraries ....... ${CMAKE_SHARED_LINKER_FLAGS_${config_uppercase}}") | ||
endmacro() | ||
|
||
get_property(is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) | ||
if(is_multi_config) | ||
list(JOIN CMAKE_CONFIGURATION_TYPES " " configs) | ||
message("Available build types (configurations) ${configs}") | ||
foreach(config IN LISTS CMAKE_CONFIGURATION_TYPES) | ||
message("'${config}' build type (configuration):") | ||
print_flags(${config}) | ||
endforeach() | ||
else() | ||
message("Build type (configuration):") | ||
message(" - CMAKE_BUILD_TYPE ................... ${CMAKE_BUILD_TYPE}") | ||
print_flags(${CMAKE_BUILD_TYPE}) | ||
endif() | ||
endfunction() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a CPPFLAG (preprocessor) flag, not a cflag/cxxflag and not c/cxx specific. Surely it's possible to remove it from the list of definitions instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree :)
This is all about CMake's default platform-specific
CMAKE_<LANG>_FLAGS_<CONFIG>_INIT
variables. There are no preprocessor variable among them. And CMake indeed sets initial preprocessor definitions in the mentioned above language-specific variables.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also: https://gitlab.kitware.com/cmake/cmake/-/issues/12928