Skip to content

Commit f74b7e2

Browse files
committed
Merge #75: build: Introduce CMake-based build system
850cc86 ci: Add GHA workflow with native Windows job (Hennadii Stepanov) 40d5670 doc: Add "Building with CMake" section to `README.md` (Hennadii Stepanov) a0c86c7 build: Add CMake-based build system (Hennadii Stepanov) Pull request description: This PR introduces a new CMake-based build system, which can be reused in downstream projects, including Bitcoin Core. Additionally, a GitHub Actions CI task for MSVC and clang-cl has been added, following this [feedback](#72 (comment)). ### Autotools vs CMake configuration option parity | Autotools | CMake | |---|---| | `--disable-ccache` | N/A | | `--enable-tests` | `-DMINISKETCH_BUILD_TESTS` | | `--enable-benchmark` | `-DMINISKETCH_BUILD_BENCHMARK` | | `--enable-fields=,-separated list` | `-DMINISKETCH_FIELDS=;-separated list` | | | `-DMINISKETCH_INSTALL` | ### Notes on the implementation 1. The default `CMAKE_BUILD_TYPE` is left unset. 2. CMake's per-configuration compiler flags are not modified. As a result, they may include `-DNDEBUG`. 3. The target name `test` is reserved. Therefore, the testing binary has been renamed to `test-noverify`. Alternatively, following the naming used in the `libsecp256k1` repo, the test binaries could be renamed as: - `test` --> `noverify_tests` - `test-verify` --> `verify_tests` ACKs for top commit: purpleKarrot: ACK 850cc86 sipa: Weakly-tested ACK 850cc86 theuni: ACK 850cc86. Tree-SHA512: 1ce8c034045d8faa07ff44f34875fd72d83a3d864bacc127368e98ae915c6be06f5ee33f0a6015e3b130fbedfd63d15f5080218d9d788c90f87430521747dfc0
2 parents ea8f66b + 850cc86 commit f74b7e2

File tree

7 files changed

+464
-1
lines changed

7 files changed

+464
-1
lines changed

.github/workflows/ci.yml

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
name: CI
2+
on:
3+
pull_request:
4+
push:
5+
branches:
6+
- '**'
7+
tags-ignore:
8+
- '**'
9+
10+
concurrency:
11+
group: ${{ github.event_name != 'pull_request' && github.run_id || github.ref }}
12+
cancel-in-progress: true
13+
14+
jobs:
15+
windows-native:
16+
name: ${{ matrix.configuration.job_name }}
17+
# See: https://github.com/actions/runner-images#available-images.
18+
runs-on: windows-2025
19+
20+
strategy:
21+
fail-fast: false
22+
matrix:
23+
configuration:
24+
- job_name: 'x64 (MSVC): Windows (VS 2022)'
25+
build_configuration: 'Release'
26+
- job_name: 'x64 (MSVC): Windows (VS 2022, fields=32)'
27+
cmake_options: '-DMINISKETCH_FIELDS=32'
28+
build_configuration: 'Release'
29+
- job_name: 'x64 (MSVC): Windows (VS 2022, debug)'
30+
build_configuration: 'Debug'
31+
# TODO: Resolve the issue and re-enable benchmark.
32+
# See: https://github.com/bitcoin-core/minisketch/pull/96.
33+
skip_benchmark: true
34+
- job_name: 'x64 (MSVC): Windows (VS 2022, shared)'
35+
cmake_options: '-DBUILD_SHARED_LIBS=ON'
36+
build_configuration: 'Release'
37+
- job_name: 'x64 (clang-cl): Windows (VS 2022)'
38+
cmake_options: '-T ClangCL'
39+
build_configuration: 'Release'
40+
# TODO: Resolve the issue and re-enable benchmark.
41+
# See: https://github.com/bitcoin-core/minisketch/pull/96.
42+
skip_benchmark: true
43+
44+
steps:
45+
- name: Checkout
46+
uses: actions/checkout@v4
47+
48+
- name: Generate buildsystem
49+
env:
50+
CXXFLAGS: '/WX'
51+
run: cmake -B build -DMINISKETCH_BUILD_BENCHMARK=ON ${{ matrix.configuration.cmake_options }}
52+
53+
- name: Build
54+
run: cmake --build build --config ${{ matrix.configuration.build_configuration }}
55+
56+
- name: Binaries info
57+
shell: bash
58+
run: |
59+
cd build/bin/${{ matrix.configuration.build_configuration }}
60+
file * | grep "\.exe\|\.dll"
61+
62+
- name: Check
63+
working-directory: build
64+
run: ctest --output-on-failure -j $env:NUMBER_OF_PROCESSORS -C ${{ matrix.configuration.build_configuration }}
65+
66+
- name: Benchmark
67+
if: ${{ ! matrix.configuration.skip_benchmark }}
68+
working-directory: build
69+
run: bin\${{ matrix.configuration.build_configuration }}\bench.exe

.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()

README.md

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ Below we compare the PinSketch algorithm (which `libminisketch` is an implementa
6666
* **Difference type:** PinSketch can only compute the symmetric difference from a merged sketch, while CPISync and IBLT can distinguish which side certain elements were missing on. When the decoder has access to one of the sets, this generally doesn't matter, as he can look up each of the elements in the symmetric difference with one of the sets.
6767
* **Secure sketch:** Whether the sketch satisfies the definition of a secure sketch<sup>[[1]](#myfootnote1)</sup>, which implies a minimal amount about a set can be extracted from a sketch by anyone who does not know most of the elements already. This makes the algorithm appropriate for applications like fingerprint authentication.
6868

69-
## Building
69+
## Building with Autotools
7070

7171
The build system is very rudimentary for now, and [improvements](https://github.com/bitcoin-core/minisketch/pulls) are welcome.
7272

@@ -78,6 +78,44 @@ cd minisketch
7878
./autogen.sh && ./configure && make
7979
```
8080

81+
## Building with CMake
82+
83+
To maintain a pristine source tree, CMake encourages performing an out-of-source build by using a separate dedicated build directory.
84+
85+
### Building on POSIX systems
86+
87+
The following commands will produce the same `libminisketch.a` file as in the example [above](#building-with-autotools):
88+
89+
```bash
90+
cmake -B build -DCMAKE_CXX_FLAGS="-g -O2" # Generate a build system in subdirectory "build"
91+
cmake --build build # Run the actual build process
92+
ctest --test-dir build # Run the test suite
93+
sudo cmake --install build # Install the library into the system (optional)
94+
```
95+
96+
Run `cmake -B build -LH` or `ccmake -B build` to see the full list of configurable build options.
97+
98+
### Cross compiling
99+
100+
The following example works on modern Ubuntu/Debian systems:
101+
102+
```bash
103+
sudo apt install g++-mingw-w64-x86-64-posix
104+
cmake -B build -DCMAKE_SYSTEM_NAME=Windows -DCMAKE_CXX_COMPILER=x86_64-w64-mingw32-g++-posix
105+
cmake --build build
106+
```
107+
108+
### Building on Windows
109+
110+
The following example assumes the use of Visual Studio 2022 and CMake v3.21 or newer.
111+
112+
In "Developer Command Prompt for VS 2022":
113+
114+
```cmd
115+
cmake -B build
116+
cmake --build build --config Release
117+
```
118+
81119
## Usage
82120

83121
In this section Alice and Bob are trying to find the difference between their sets.

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()

0 commit comments

Comments
 (0)