Skip to content

Commit a0c86c7

Browse files
committed
build: Add CMake-based build system
1 parent ea8f66b commit a0c86c7

File tree

5 files changed

+356
-0
lines changed

5 files changed

+356
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,6 @@ stamp-h1
3333

3434
test*
3535
bench
36+
37+
# CMake build directories.
38+
/*build*

CMakeLists.txt

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
cmake_minimum_required(VERSION 3.22)
2+
3+
#=============================
4+
# Project / Package Metadata
5+
#=============================
6+
project(minisketch
7+
VERSION 0.0.1
8+
DESCRIPTION "A library for BCH-based set reconciliation"
9+
HOMEPAGE_URL "https://github.com/bitcoin-core/minisketch"
10+
LANGUAGES CXX
11+
)
12+
13+
# ============================================================
14+
# Project Initialization
15+
# ============================================================
16+
enable_testing()
17+
include(CTestUseLaunchers)
18+
19+
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
20+
21+
if(NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
22+
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
23+
endif()
24+
if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY)
25+
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
26+
endif()
27+
if(NOT CMAKE_ARCHIVE_OUTPUT_DIRECTORY)
28+
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
29+
endif()
30+
31+
# Prevent include directories from parent project from leaking into this one.
32+
set_property(DIRECTORY PROPERTY INCLUDE_DIRECTORIES "")
33+
34+
#=============================
35+
# Language Setup
36+
#=============================
37+
if(DEFINED CMAKE_CXX_STANDARD)
38+
if(CMAKE_CXX_STANDARD EQUAL 98 OR CMAKE_CXX_STANDARD LESS 11)
39+
message(FATAL_ERROR "This project requires at least C++11")
40+
endif()
41+
else()
42+
set(CMAKE_CXX_STANDARD 11)
43+
endif()
44+
set(CMAKE_CXX_STANDARD_REQUIRED ON)
45+
if(NOT DEFINED CMAKE_CXX_EXTENSIONS)
46+
set(CMAKE_CXX_EXTENSIONS OFF)
47+
endif()
48+
49+
#=============================
50+
# Configurable Options
51+
#=============================
52+
option(MINISKETCH_INSTALL "Enable installation." ${PROJECT_IS_TOP_LEVEL})
53+
if(NOT PROJECT_IS_TOP_LEVEL)
54+
mark_as_advanced(MINISKETCH_INSTALL)
55+
endif()
56+
57+
option(MINISKETCH_BUILD_TESTS "Build tests." ON)
58+
option(MINISKETCH_BUILD_BENCHMARK "Build benchmark." OFF)
59+
60+
set(supported_fields "")
61+
set(have_enabled_fields NO)
62+
set(have_disabled_fields NO)
63+
foreach(i RANGE 2 64)
64+
list(APPEND supported_fields ${i})
65+
endforeach()
66+
if(NOT DEFINED MINISKETCH_FIELDS)
67+
set(MINISKETCH_FIELDS ${supported_fields} CACHE STRING "Semicolon-separated list of field sizes to build. Default=all. Available sizes: ${supported_fields}.")
68+
endif()
69+
foreach(field IN LISTS supported_fields)
70+
if(field IN_LIST MINISKETCH_FIELDS)
71+
set(have_enabled_fields YES)
72+
else()
73+
set(have_disabled_fields YES)
74+
add_compile_definitions(DISABLE_FIELD_${field})
75+
endif()
76+
endforeach()
77+
if(NOT have_enabled_fields)
78+
message(FATAL_ERROR "No field sizes are enabled.")
79+
endif()
80+
unset(have_enabled_fields)
81+
unset(supported_fields)
82+
83+
#=============================
84+
# Build Options
85+
#=============================
86+
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
87+
88+
if(MSVC)
89+
add_compile_options(/Zc:__cplusplus)
90+
endif()
91+
92+
if(MINGW)
93+
add_link_options(-static)
94+
endif()
95+
96+
#=============================
97+
# Diagnostics Options
98+
#=============================
99+
if(MSVC)
100+
# For both MSVC's cl.exe and clang-cl compilers.
101+
add_compile_options(/W3) # Production quality warning level. Enables -Wall Clang's core option.
102+
else()
103+
add_compile_options(-Wall)
104+
endif()
105+
106+
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
107+
add_compile_options(/wd4060) # Disable warning C4060 "switch statement contains no 'case' or 'default' labels".
108+
add_compile_options(/wd4065) # Disable warning C4065 "switch statement contains 'default' but no 'case' labels".
109+
add_compile_options(/wd4146) # Disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned".
110+
add_compile_options(/wd4244) # Disable warning C4244 "conversion from 'type1' to 'type2', possible loss of data".
111+
else()
112+
add_compile_options(-Wundef)
113+
endif()
114+
115+
#=============================
116+
# Main Processing
117+
#=============================
118+
include(SystemIntrospection)
119+
add_subdirectory(src)
120+
121+
include(PrintConfigureSummary)
122+
print_configure_summary()

cmake/PrintConfigureSummary.cmake

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
include_guard(GLOBAL)
2+
3+
function(indent_message header content indent_num)
4+
if(indent_num GREATER 0)
5+
string(REPEAT " " ${indent_num} indentation)
6+
string(REPEAT "." ${indent_num} tail)
7+
string(REGEX REPLACE "${tail}$" "" header "${header}")
8+
endif()
9+
message("${indentation}${header} ${content}")
10+
endfunction()
11+
12+
# Print compiler's flags on best-effort. Include the abstracted
13+
# CMake flags that we touch ourselves.
14+
function(print_flags_per_config config indent_num)
15+
string(STRIP "${CMAKE_CXX_COMPILER_ARG1} ${CMAKE_CXX_FLAGS}" combined_cxx_flags)
16+
string(TOUPPER "${config}" config_uppercase)
17+
string(STRIP "${combined_cxx_flags} ${CMAKE_CXX_FLAGS_${config_uppercase}}" combined_cxx_flags)
18+
string(STRIP "${combined_cxx_flags} ${CMAKE_CXX${CMAKE_CXX_STANDARD}_STANDARD_COMPILE_OPTION}" combined_cxx_flags)
19+
if(CMAKE_POSITION_INDEPENDENT_CODE)
20+
string(JOIN " " combined_cxx_flags ${combined_cxx_flags} ${CMAKE_CXX_COMPILE_OPTIONS_PIC})
21+
endif()
22+
if(CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY AND CMAKE_CXX_VISIBILITY_PRESET)
23+
string(JOIN " " combined_cxx_flags ${combined_cxx_flags} ${CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY}${CMAKE_CXX_VISIBILITY_PRESET})
24+
endif()
25+
get_directory_property(compile_options COMPILE_OPTIONS)
26+
string(JOIN " " combined_cxx_flags ${combined_cxx_flags} ${compile_options})
27+
indent_message("CXXFLAGS .............................." "${combined_cxx_flags}" ${indent_num})
28+
endfunction()
29+
30+
function(print_configure_summary)
31+
message("")
32+
if(PROJECT_IS_TOP_LEVEL)
33+
message("Configure summary")
34+
message("=================")
35+
else()
36+
message("minisketch configure summary")
37+
message("============================")
38+
endif()
39+
if(BUILD_SHARED_LIBS)
40+
set(library_type "Shared")
41+
else()
42+
set(library_type "Static")
43+
endif()
44+
message("Library type .......................... ${library_type}")
45+
message("Build options:")
46+
if(have_disabled_fields)
47+
set(filed_sizes "${MINISKETCH_FIELDS}")
48+
else()
49+
set(filed_sizes "All")
50+
endif()
51+
message(" field sizes ........................ ${filed_sizes}")
52+
if(HAVE_CLMUL)
53+
set(clmul_status "Enabled")
54+
else()
55+
set(clmul_status "Disabled")
56+
endif()
57+
message(" clmul fields ........................ ${clmul_status}")
58+
if(CMAKE_CXX_STANDARD GREATER_EQUAL 20)
59+
set(clz_status "C++20")
60+
elseif(HAVE_CLZ)
61+
set(clz_status "Compiler builtin")
62+
else()
63+
set(clz_status "Default")
64+
endif()
65+
message(" clz implementation .................. ${clz_status}")
66+
message("Optional binaries:")
67+
message(" benchmark ........................... ${MINISKETCH_BUILD_BENCHMARK}")
68+
message(" tests ............................... ${MINISKETCH_BUILD_TESTS}")
69+
message("")
70+
if(CMAKE_CROSSCOMPILING)
71+
set(cross_status "TRUE, for ${CMAKE_SYSTEM_NAME}, ${CMAKE_SYSTEM_PROCESSOR}")
72+
else()
73+
set(cross_status "FALSE")
74+
endif()
75+
message("Cross compiling ....................... ${cross_status}")
76+
message("C++ compiler .......................... ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}, ${CMAKE_CXX_COMPILER}")
77+
get_property(_is_multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
78+
if(_is_multi_config)
79+
list(JOIN CMAKE_CONFIGURATION_TYPES ", " configs)
80+
message("Available build configurations ........ ${configs}")
81+
if(CMAKE_GENERATOR MATCHES "Visual Studio")
82+
set(default_config "Debug")
83+
else()
84+
list(GET CMAKE_CONFIGURATION_TYPES 0 default_config)
85+
endif()
86+
message("Default build configuration ........... ${default_config}")
87+
foreach(config IN LISTS CMAKE_CONFIGURATION_TYPES)
88+
message("'${config}' build configuration:")
89+
print_flags_per_config("${config}" 2)
90+
endforeach()
91+
else()
92+
message("CMAKE_BUILD_TYPE ...................... ${CMAKE_BUILD_TYPE}")
93+
print_flags_per_config("${CMAKE_BUILD_TYPE}" 0)
94+
endif()
95+
unset(_is_multi_config)
96+
97+
message([=[
98+
99+
NOTE: The summary above may not exactly match the final applied build flags
100+
if any additional CMAKE_* or environment variables have been modified.
101+
To see the exact flags applied, build with the --verbose option.]=]
102+
)
103+
104+
if(have_disabled_fields AND PROJECT_IS_TOP_LEVEL)
105+
message("")
106+
message(WARNING
107+
"Only compiling in support for field sizes: ${MINISKETCH_FIELDS}\n"
108+
"This means the library will lack support for other field sizes entirely.\n"
109+
)
110+
endif()
111+
message("")
112+
endfunction()

cmake/SystemIntrospection.cmake

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
include_guard(GLOBAL)
2+
3+
include(CheckCXXSourceCompiles)
4+
include(CMakePushCheckState)
5+
cmake_push_check_state(RESET)
6+
7+
# Check for clmul instructions support.
8+
if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
9+
set(CMAKE_REQUIRED_FLAGS "-mpclmul")
10+
endif()
11+
check_cxx_source_compiles("
12+
#include <immintrin.h>
13+
#include <stdint.h>
14+
15+
int main()
16+
{
17+
__m128i a = _mm_cvtsi64_si128((uint64_t)7);
18+
__m128i b = _mm_clmulepi64_si128(a, a, 37);
19+
__m128i c = _mm_srli_epi64(b, 41);
20+
__m128i d = _mm_xor_si128(b, c);
21+
uint64_t e = _mm_cvtsi128_si64(d);
22+
return e == 0;
23+
}
24+
" HAVE_CLMUL
25+
)
26+
if(HAVE_CLMUL)
27+
set(CLMUL_CXXFLAGS ${CMAKE_REQUIRED_FLAGS})
28+
endif()
29+
30+
if(CMAKE_CXX_STANDARD LESS 20)
31+
# Check for working clz builtins.
32+
check_cxx_source_compiles("
33+
int main()
34+
{
35+
unsigned a = __builtin_clz(1);
36+
unsigned long b = __builtin_clzl(1);
37+
unsigned long long c = __builtin_clzll(1);
38+
}
39+
" HAVE_CLZ
40+
)
41+
endif()
42+
43+
cmake_pop_check_state()

src/CMakeLists.txt

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
add_library(minisketch_field_sources INTERFACE)
2+
target_sources(minisketch_field_sources
3+
INTERFACE
4+
fields/generic_1byte.cpp
5+
fields/generic_2bytes.cpp
6+
fields/generic_3bytes.cpp
7+
fields/generic_4bytes.cpp
8+
fields/generic_5bytes.cpp
9+
fields/generic_6bytes.cpp
10+
fields/generic_7bytes.cpp
11+
fields/generic_8bytes.cpp
12+
)
13+
if(HAVE_CLMUL)
14+
set(clmul_sources
15+
fields/clmul_1byte.cpp
16+
fields/clmul_2bytes.cpp
17+
fields/clmul_3bytes.cpp
18+
fields/clmul_4bytes.cpp
19+
fields/clmul_5bytes.cpp
20+
fields/clmul_6bytes.cpp
21+
fields/clmul_7bytes.cpp
22+
fields/clmul_8bytes.cpp
23+
)
24+
set_property(SOURCE minisketch.cpp
25+
PROPERTY COMPILE_DEFINITIONS HAVE_CLMUL
26+
)
27+
set_property(SOURCE ${clmul_sources}
28+
PROPERTY COMPILE_OPTIONS ${CLMUL_CXXFLAGS}
29+
)
30+
target_sources(minisketch_field_sources INTERFACE ${clmul_sources})
31+
endif()
32+
33+
add_compile_definitions($<$<BOOL:${HAVE_CLZ}>:HAVE_CLZ>)
34+
35+
add_library(minisketch minisketch.cpp)
36+
set_property(TARGET minisketch PROPERTY PUBLIC_HEADER
37+
${PROJECT_SOURCE_DIR}/include/minisketch.h
38+
)
39+
target_include_directories(minisketch
40+
INTERFACE
41+
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
42+
)
43+
target_link_libraries(minisketch PRIVATE minisketch_field_sources)
44+
45+
add_library(minisketch_verify EXCLUDE_FROM_ALL minisketch.cpp)
46+
target_compile_definitions(minisketch_verify
47+
PUBLIC
48+
MINISKETCH_VERIFY
49+
)
50+
target_link_libraries(minisketch_verify PRIVATE minisketch_field_sources)
51+
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
52+
target_compile_options(minisketch_verify
53+
PRIVATE
54+
/wd4702
55+
)
56+
endif()
57+
58+
if(MINISKETCH_BUILD_TESTS)
59+
add_executable(test-noverify test.cpp)
60+
target_link_libraries(test-noverify PRIVATE minisketch)
61+
add_test(NAME ${PROJECT_NAME}_test_noverify COMMAND test-noverify)
62+
63+
add_executable(test-verify test.cpp)
64+
target_link_libraries(test-verify PRIVATE minisketch_verify)
65+
add_test(NAME ${PROJECT_NAME}_test_verify COMMAND test-verify)
66+
endif()
67+
68+
if(MINISKETCH_BUILD_BENCHMARK)
69+
add_executable(bench bench.cpp)
70+
target_link_libraries(bench PRIVATE minisketch)
71+
endif()
72+
73+
if(MINISKETCH_INSTALL)
74+
include(GNUInstallDirs)
75+
install(TARGETS minisketch)
76+
endif()

0 commit comments

Comments
 (0)