Skip to content

Commit b404055

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

File tree

5 files changed

+353
-0
lines changed

5 files changed

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

cmake/PrintConfigureSummary.cmake

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

0 commit comments

Comments
 (0)