Add CMake build system for valkey (#1196)
With this commit, users are able to build valkey using `CMake`.
## Example usage:
Build `valkey-server` in Release mode with TLS enabled and using
`jemalloc` as the allocator:
```bash
mkdir build-release
cd $_
cmake .. -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=/tmp/valkey-install \
-DBUILD_MALLOC=jemalloc -DBUILD_TLS=1
make -j$(nproc) install
# start valkey
/tmp/valkey-install/bin/valkey-server
```
Build `valkey-unit-tests`:
```bash
mkdir build-release-ut
cd $_
cmake .. -DCMAKE_BUILD_TYPE=Release \
-DBUILD_MALLOC=jemalloc -DBUILD_UNIT_TESTS=1
make -j$(nproc)
# Run the tests
./bin/valkey-unit-tests
```
Current features supported by this PR:
- Building against different allocators: (`jemalloc`, `tcmalloc`,
`tcmalloc_minimal` and `libc`), e.g. to enable `jemalloc` pass
`-DBUILD_MALLOC=jemalloc` to `cmake`
- OpenSSL builds (to enable TLS, pass `-DBUILD_TLS=1` to `cmake`)
- Sanitizier: pass `-DBUILD_SANITIZER=<address|thread|undefined>` to
`cmake`
- Install target + redis symbolic links
- Build `valkey-unit-tests` executable
- Standard CMake variables are supported. e.g. to install `valkey` under
`/home/you/root` pass `-DCMAKE_INSTALL_PREFIX=/home/you/root`
Why using `CMake`? To list *some* of the advantages of using `CMake`:
- Superior IDE integrations: cmake generates the file
`compile_commands.json` which is required by `clangd` to get a compiler
accuracy code completion (in other words: your VScode will thank you)
- Out of the source build tree: with the current build system, object
files are created all over the place polluting the build source tree,
the best practice is to build the project on a separate folder
- Multiple build types co-existing: with the current build system, it is
often hard to have multiple build configurations. With cmake you can do
it easily:
- It is the de-facto standard for C/C++ project these days
More build examples:
ASAN build:
```bash
mkdir build-asan
cd $_
cmake .. -DBUILD_SANITIZER=address -DBUILD_MALLOC=libc
make -j$(nproc)
```
ASAN with jemalloc:
```bash
mkdir build-asan-jemalloc
cd $_
cmake .. -DBUILD_SANITIZER=address -DBUILD_MALLOC=jemalloc
make -j$(nproc)
```
As seen by the previous examples, any combination is allowed and
co-exist on the same source tree.
## Valkey installation
With this new `CMake`, it is possible to install the binary by running
`make install` or creating a package `make package` (currently supported
on Debian like distros)
### Example 1: build & install using `make install`:
```bash
mkdir build-release
cd $_
cmake .. -DCMAKE_INSTALL_PREFIX=$HOME/valkey-install -DCMAKE_BUILD_TYPE=Release
make -j$(nproc) install
# valkey is now installed under $HOME/valkey-install
```
### Example 2: create a `.deb` installer:
```bash
mkdir build-release
cd $_
cmake .. -DCMAKE_BUILD_TYPE=Release
make -j$(nproc) package
# ... CPack deb generation output
sudo gdebi -n ./valkey_8.1.0_amd64.deb
# valkey is now installed under /opt/valkey
```
### Example 3: create installer for non Debian systems (e.g. FreeBSD or
macOS):
```bash
mkdir build-release
cd $_
cmake .. -DCMAKE_BUILD_TYPE=Release
make -j$(nproc) package
mkdir -p /opt/valkey && ./valkey-8.1.0-Darwin.sh --prefix=/opt/valkey --exclude-subdir
# valkey-server is now installed under /opt/valkey
```
Signed-off-by: Eran Ifrah <eifrah@amazon.com>
2024-11-08 04:01:37 +02:00
|
|
|
# Return the current host distro name. For example: ubuntu, debian, amzn etc
|
|
|
|
function (valkey_get_distro_name DISTRO_NAME)
|
|
|
|
if (LINUX AND NOT APPLE)
|
|
|
|
execute_process(
|
|
|
|
COMMAND /bin/bash "-c" "cat /etc/os-release |grep ^ID=|cut -d = -f 2"
|
|
|
|
OUTPUT_VARIABLE _OUT_VAR
|
|
|
|
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
|
|
|
# clean the output
|
|
|
|
string(REPLACE "\"" "" _OUT_VAR "${_OUT_VAR}")
|
|
|
|
string(REPLACE "." "" _OUT_VAR "${_OUT_VAR}")
|
|
|
|
set(${DISTRO_NAME}
|
|
|
|
"${_OUT_VAR}"
|
|
|
|
PARENT_SCOPE)
|
|
|
|
elseif (APPLE)
|
|
|
|
set(${DISTRO_NAME}
|
|
|
|
"darwin"
|
|
|
|
PARENT_SCOPE)
|
|
|
|
elseif (IS_FREEBSD)
|
|
|
|
set(${DISTRO_NAME}
|
|
|
|
"freebsd"
|
|
|
|
PARENT_SCOPE)
|
|
|
|
else ()
|
|
|
|
set(${DISTRO_NAME}
|
|
|
|
"unknown"
|
|
|
|
PARENT_SCOPE)
|
|
|
|
endif ()
|
|
|
|
endfunction ()
|
|
|
|
|
|
|
|
function (valkey_parse_version OUT_MAJOR OUT_MINOR OUT_PATCH)
|
|
|
|
# Read and parse package version from version.h file
|
|
|
|
file(STRINGS ${CMAKE_SOURCE_DIR}/src/version.h VERSION_LINES)
|
|
|
|
foreach (LINE ${VERSION_LINES})
|
|
|
|
string(FIND "${LINE}" "#define VALKEY_VERSION " VERSION_STR_POS)
|
|
|
|
if (VERSION_STR_POS GREATER -1)
|
|
|
|
string(REPLACE "#define VALKEY_VERSION " "" LINE "${LINE}")
|
|
|
|
string(REPLACE "\"" "" LINE "${LINE}")
|
|
|
|
# Change "." to ";" to make it a list
|
|
|
|
string(REPLACE "." ";" LINE "${LINE}")
|
|
|
|
list(GET LINE 0 _MAJOR)
|
|
|
|
list(GET LINE 1 _MINOR)
|
|
|
|
list(GET LINE 2 _PATCH)
|
|
|
|
message(STATUS "Valkey version: ${_MAJOR}.${_MINOR}.${_PATCH}")
|
|
|
|
# Set the output variables
|
|
|
|
set(${OUT_MAJOR}
|
|
|
|
${_MAJOR}
|
|
|
|
PARENT_SCOPE)
|
|
|
|
set(${OUT_MINOR}
|
|
|
|
${_MINOR}
|
|
|
|
PARENT_SCOPE)
|
|
|
|
set(${OUT_PATCH}
|
|
|
|
${_PATCH}
|
|
|
|
PARENT_SCOPE)
|
|
|
|
endif ()
|
|
|
|
endforeach ()
|
|
|
|
endfunction ()
|
|
|
|
|
|
|
|
# Given input argument `OPTION_VALUE`, check that the `OPTION_VALUE` is from the allowed values (one of:
|
|
|
|
# module/yes/no/1/0/true/false)
|
|
|
|
#
|
|
|
|
# Return value:
|
|
|
|
#
|
|
|
|
# If ARG is valid, return its number where:
|
|
|
|
#
|
|
|
|
# ~~~
|
|
|
|
# - `no` | `0` | `off` => return `0`
|
|
|
|
# - `yes` | `1` | `on` => return `1`
|
|
|
|
# - `module` => return `2`
|
|
|
|
# ~~~
|
|
|
|
function (valkey_parse_build_option OPTION_VALUE OUT_ARG_ENUM)
|
|
|
|
list(APPEND VALID_OPTIONS "yes")
|
|
|
|
list(APPEND VALID_OPTIONS "1")
|
|
|
|
list(APPEND VALID_OPTIONS "on")
|
|
|
|
list(APPEND VALID_OPTIONS "no")
|
|
|
|
list(APPEND VALID_OPTIONS "0")
|
|
|
|
list(APPEND VALID_OPTIONS "off")
|
|
|
|
list(APPEND VALID_OPTIONS "module")
|
|
|
|
|
|
|
|
string(TOLOWER "${OPTION_VALUE}" OPTION_VALUE)
|
|
|
|
list(FIND VALID_OPTIONS "${ARG}" OPT_INDEX)
|
|
|
|
if (VERSION_STR_POS GREATER -1)
|
|
|
|
message(FATAL_ERROR "Invalid value passed ''${OPTION_VALUE}'")
|
|
|
|
endif ()
|
|
|
|
|
|
|
|
if ("${OPTION_VALUE}" STREQUAL "yes"
|
|
|
|
OR "${OPTION_VALUE}" STREQUAL "1"
|
|
|
|
OR "${OPTION_VALUE}" STREQUAL "on")
|
|
|
|
set(${OUT_ARG_ENUM}
|
|
|
|
1
|
|
|
|
PARENT_SCOPE)
|
|
|
|
elseif (
|
|
|
|
"${OPTION_VALUE}" STREQUAL "no"
|
|
|
|
OR "${OPTION_VALUE}" STREQUAL "0"
|
|
|
|
OR "${OPTION_VALUE}" STREQUAL "off")
|
|
|
|
set(${OUT_ARG_ENUM}
|
|
|
|
0
|
|
|
|
PARENT_SCOPE)
|
|
|
|
else ()
|
|
|
|
set(${OUT_ARG_ENUM}
|
|
|
|
2
|
|
|
|
PARENT_SCOPE)
|
|
|
|
endif ()
|
|
|
|
endfunction ()
|
2024-11-22 22:17:53 +02:00
|
|
|
|
|
|
|
function (valkey_pkg_config PKGNAME OUT_VARIABLE)
|
|
|
|
if (NOT FOUND_PKGCONFIG)
|
|
|
|
# Locate pkg-config once
|
|
|
|
find_package(PkgConfig REQUIRED)
|
|
|
|
set(FOUND_PKGCONFIG 1)
|
|
|
|
endif ()
|
|
|
|
pkg_check_modules(__PREFIX REQUIRED ${PKGNAME})
|
|
|
|
message(STATUS "Found library for '${PKGNAME}': ${__PREFIX_LIBRARIES}")
|
|
|
|
set(${OUT_VARIABLE}
|
|
|
|
"${__PREFIX_LIBRARIES}"
|
|
|
|
PARENT_SCOPE)
|
|
|
|
endfunction ()
|