Skip to content

Commit 76a4fe8

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

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: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
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+
if(NOT DEFINED MINISKETCH_FIELDS)
63+
set(MINISKETCH_FIELDS ${supported_fields} CACHE STRING "Semicolon-separated list of field sizes to build. Default=all. Available sizes: ${supported_fields}.")
64+
endif()
65+
foreach(field IN LISTS supported_fields)
66+
if(field IN_LIST MINISKETCH_FIELDS)
67+
set(have_enabled_fields YES)
68+
else()
69+
set(have_disabled_fields YES)
70+
add_compile_definitions(DISABLE_FIELD_${field})
71+
endif()
72+
endforeach()
73+
if(NOT have_enabled_fields)
74+
message(FATAL_ERROR "No field sizes are enabled.")
75+
endif()
76+
unset(have_enabled_fields)
77+
unset(supported_fields)
78+
79+
#=============================
80+
# Build Options
81+
#=============================
82+
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
83+
84+
if(MSVC)
85+
add_compile_options(/Zc:__cplusplus)
86+
endif()
87+
88+
if(MINGW)
89+
add_link_options(-static)
90+
endif()
91+
92+
#=============================
93+
# Diagnostics Options
94+
#=============================
95+
if(MSVC)
96+
# For both MSVC's cl.exe and clang-cl compilers.
97+
add_compile_options(/W3) # Production quality warning level. Enables -Wall Clang's core option.
98+
else()
99+
add_compile_options(-Wall)
100+
endif()
101+
102+
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
103+
add_compile_options(/wd4060) # Disable warning C4060 "switch statement contains no 'case' or 'default' labels".
104+
add_compile_options(/wd4065) # Disable warning C4065 "switch statement contains 'default' but no 'case' labels".
105+
add_compile_options(/wd4146) # Disable warning C4146 "unary minus operator applied to unsigned type, result still unsigned".
106+
add_compile_options(/wd4244) # Disable warning C4244 "conversion from 'type1' to 'type2', possible loss of data".
107+
else()
108+
add_compile_options(-Wundef)
109+
endif()
110+
111+
#=============================
112+
# Main Processing
113+
#=============================
114+
include(SystemIntrospection)
115+
add_subdirectory(src)
116+
117+
include(PrintConfigureSummary)
118+
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: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
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 OMPILE_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 INTERFACE
40+
$<BUILD_INTERFACE:$<$<NOT:$<BOOL:${PROJECT_IS_TOP_LEVEL}>>:${PROJECT_SOURCE_DIR}/include>>
41+
)
42+
target_link_libraries(minisketch PRIVATE minisketch_field_sources)
43+
44+
add_library(minisketch_verify EXCLUDE_FROM_ALL minisketch.cpp)
45+
target_compile_definitions(minisketch_verify
46+
PUBLIC
47+
MINISKETCH_VERIFY
48+
)
49+
target_link_libraries(minisketch_verify PRIVATE minisketch_field_sources)
50+
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
51+
target_compile_options(minisketch_verify
52+
PRIVATE
53+
/wd4702
54+
)
55+
endif()
56+
57+
if(MINISKETCH_BUILD_TESTS)
58+
add_executable(test-noverify test.cpp)
59+
target_link_libraries(test-noverify PRIVATE minisketch)
60+
add_test(NAME ${PROJECT_NAME}_test_noverify COMMAND test-noverify)
61+
62+
add_executable(test-verify test.cpp)
63+
target_link_libraries(test-verify PRIVATE minisketch_verify)
64+
add_test(NAME ${PROJECT_NAME}_test_verify COMMAND test-verify)
65+
endif()
66+
67+
if(MINISKETCH_BUILD_BENCHMARK)
68+
add_executable(bench bench.cpp)
69+
target_link_libraries(bench PRIVATE minisketch)
70+
endif()
71+
72+
if(MINISKETCH_INSTALL)
73+
include(GNUInstallDirs)
74+
install(TARGETS minisketch
75+
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
76+
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
77+
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
78+
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
79+
)
80+
endif()

0 commit comments

Comments
 (0)