Files
ZeroTierOne/CMakeLists.txt
T
Grant Limberg c02c649cd3 more build updates.
removing openssl dependency (except on Linux where it's still necessary)
upgrade cpp-httplib
new cmake-presets
2026-06-15 18:51:24 -07:00

673 lines
29 KiB
CMake

# CMake build script for libzerotiercore.a
cmake_minimum_required(VERSION 3.15)
project(zerotier-one LANGUAGES CXX C)
# ---------------------------------------------------------------------------
# Options
# ---------------------------------------------------------------------------
option(ZT1_CENTRAL_CONTROLLER "Build with ZeroTier Central Controller support" OFF)
option(ADDRESS_SANITIZER "Build with Address Sanitizer enabled (only for x86_64/arm64)" OFF)
option(EXT_OSDEP "Build with external osdep feature" OFF)
option(ZT_IA32 "Force a 32-bit (i386) build on x86 hosts mismarked as i386" OFF)
# Feature toggles mirrored from make-linux.mk's ZT_* switches.
option(ZT_TRACE "Enable tracing (-DZT_TRACE)" OFF)
option(ZT_RULES_ENGINE_DEBUGGING "Enable rules-engine debugging" OFF)
option(ZT_DEBUG_TRACE "Enable debug tracing" OFF)
option(ZT_USE_TEST_TAP "Build with the test tap device" OFF)
option(ZT_VAULT_SUPPORT "Enable HashiCorp Vault support (links libcurl)" OFF)
option(ZT_STATIC "Link the executables statically" OFF)
option(ZT_QNAP "Build for QNAP (embedded)" OFF)
option(ZT_UBIQUITI "Build for Ubiquiti (embedded)" OFF)
option(ZT_SYNOLOGY "Build for Synology (embedded)" OFF)
set(PROJ_DIR ${PROJECT_SOURCE_DIR})
# make builds release by default and switches to debug flags under ZT_DEBUG=1;
# mirror that with CMAKE_BUILD_TYPE, defaulting to Release when unset.
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS Debug Release RelWithDebInfo MinSizeRel)
endif()
# ---------------------------------------------------------------------------
# CPU architecture detection and architecture-specific flags
#
# Translated from make-linux.mk. CMAKE_SYSTEM_PROCESSOR is CMake's canonical
# target-processor variable: it reflects the host for native builds and is set
# by the toolchain file when cross-compiling. ZT_ARCHITECTURE mirrors the
# numeric arch codes used by the Makefile and is exported to the binary as
# ZT_BUILD_ARCHITECTURE (read by one.cpp via version.h).
#
# Note: node/Constants.hpp already auto-defines ZT_NO_TYPE_PUNNING for every
# non-x86 architecture, and AES.hpp auto-defines ZT_AES_NEON whenever ARM
# crypto extensions are present (-march=armv8-a+crypto). The explicit -D flags
# below are therefore belt-and-suspenders that keep this a faithful mirror of
# make-linux.mk.
# ---------------------------------------------------------------------------
string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" CPU_ARCHITECTURE)
# On the Visual Studio generators CMAKE_SYSTEM_PROCESSOR reflects the *host*, not the
# target. The target architecture is CMAKE_GENERATOR_PLATFORM (-A Win32/x64/ARM64, set
# by the windows-* presets); normalize it to the canonical names the matrix matches on.
if(MSVC AND CMAKE_GENERATOR_PLATFORM)
string(TOLOWER "${CMAKE_GENERATOR_PLATFORM}" _zt_genplat)
if(_zt_genplat STREQUAL "win32")
set(CPU_ARCHITECTURE "x86")
elseif(_zt_genplat STREQUAL "x64")
set(CPU_ARCHITECTURE "amd64")
elseif(_zt_genplat STREQUAL "arm64")
set(CPU_ARCHITECTURE "arm64")
endif()
message(STATUS "MSVC target platform (CMAKE_GENERATOR_PLATFORM): ${CMAKE_GENERATOR_PLATFORM} -> ${CPU_ARCHITECTURE}")
endif()
message(STATUS "Target CPU (CMAKE_SYSTEM_PROCESSOR): ${CMAKE_SYSTEM_PROCESSOR}")
# ZeroTier architecture code (see node/Constants.hpp); 999 = unknown.
set(ZT_ARCHITECTURE 999)
# Crypto-assembly gates, also consumed by node/CMakeLists.txt to select sources.
set(ZT_USE_X64_ASM_SALSA FALSE)
set(ZT_USE_X64_ASM_ED25519 FALSE)
set(ZT_USE_ARM32_NEON_ASM_CRYPTO FALSE)
set(ZT_SSO_SUPPORTED FALSE)
if(CPU_ARCHITECTURE STREQUAL "x86_64" OR CPU_ARCHITECTURE STREQUAL "amd64")
set(ZT_ARCHITECTURE 2)
set(ZT_USE_X64_ASM_SALSA TRUE)
# x64 ed25519 asm (qhasm): Linux/BSD only here, matching make-mac.mk which omits it on
# macOS (macOS uses the portable Ed25519). NB: it *does* assemble on macOS and the .s
# export macOS-underscored symbols, so this is a parity choice with make-mac.mk, not a
# technical limitation.
if(NOT APPLE)
set(ZT_USE_X64_ASM_ED25519 TRUE)
endif()
set(ZT_SSO_SUPPORTED TRUE)
# macOS x86_64 has SSE2 by default; skip the explicit flag (it would also leak into
# the arm64 slice of a universal build). See the aarch64 branch note below.
if(NOT MSVC AND NOT APPLE)
add_compile_options(-msse -msse2)
endif()
elseif(CPU_ARCHITECTURE STREQUAL "e2k" OR CPU_ARCHITECTURE STREQUAL "e2k64")
# Elbrus 2000: x86-compatible arch code, but no x86 crypto assembly.
set(ZT_ARCHITECTURE 2)
elseif(CPU_ARCHITECTURE STREQUAL "i386" OR CPU_ARCHITECTURE STREQUAL "i486"
OR CPU_ARCHITECTURE STREQUAL "i586" OR CPU_ARCHITECTURE STREQUAL "i686"
OR CPU_ARCHITECTURE STREQUAL "x86")
set(ZT_ARCHITECTURE 1)
set(ZT_SSO_SUPPORTED TRUE)
elseif(CPU_ARCHITECTURE STREQUAL "aarch64" OR CPU_ARCHITECTURE STREQUAL "arm64")
set(ZT_ARCHITECTURE 4)
set(ZT_SSO_SUPPORTED TRUE)
# On Apple, omit the explicit arch defines/flags and let Constants.hpp / AES.hpp
# self-detect from compiler builtins (per -arch slice) -- this is what make-mac.mk
# does, and it's required for universal (arm64 + x86_64) builds, where a global
# -march=armv8-a+crypto or -DZT_ARCH_ARM_HAS_NEON would wrongly hit the x86_64 slice.
if(NOT APPLE)
add_definitions(-DZT_NO_TYPE_PUNNING -DZT_ARCH_ARM_HAS_NEON)
if(NOT MSVC)
add_compile_options(-march=armv8-a+crypto -mtune=generic -mstrict-align)
endif()
endif()
elseif(CPU_ARCHITECTURE MATCHES "^(arm|armel|armhf|armv6|armv6l|armv6k|armv6kz|armv6zk|armv7|armv7l|armv7hl|armv7ve)$")
set(ZT_ARCHITECTURE 3)
set(ZT_USE_ARM32_NEON_ASM_CRYPTO TRUE)
add_definitions(-DZT_NO_TYPE_PUNNING)
if(CPU_ARCHITECTURE STREQUAL "armhf")
set(ZT_SSO_SUPPORTED TRUE)
endif()
elseif(CPU_ARCHITECTURE STREQUAL "powerpc64le")
set(ZT_ARCHITECTURE 8)
add_definitions(-DZT_NO_TYPE_PUNNING)
elseif(CPU_ARCHITECTURE STREQUAL "powerpc")
set(ZT_ARCHITECTURE 8)
add_definitions(-DZT_NO_TYPE_PUNNING -DZT_NO_CAPABILITIES)
elseif(CPU_ARCHITECTURE STREQUAL "ppc64le" OR CPU_ARCHITECTURE STREQUAL "ppc64el")
set(ZT_ARCHITECTURE 8)
elseif(CPU_ARCHITECTURE STREQUAL "mips" OR CPU_ARCHITECTURE STREQUAL "mipsel")
set(ZT_ARCHITECTURE 5)
add_definitions(-DZT_NO_TYPE_PUNNING)
elseif(CPU_ARCHITECTURE STREQUAL "mips64" OR CPU_ARCHITECTURE STREQUAL "mips64el")
set(ZT_ARCHITECTURE 6)
add_definitions(-DZT_NO_TYPE_PUNNING)
elseif(CPU_ARCHITECTURE STREQUAL "s390x")
set(ZT_ARCHITECTURE 16)
elseif(CPU_ARCHITECTURE STREQUAL "riscv64")
set(ZT_ARCHITECTURE 0)
elseif(CPU_ARCHITECTURE STREQUAL "loongarch64")
set(ZT_ARCHITECTURE 17)
add_definitions(-DZT_NO_TYPE_PUNNING)
endif()
# Embedded platform markers (make-linux.mk); these also disable SSO.
if(ZT_QNAP)
add_definitions(-D__QNAP__)
set(ZT_EMBEDDED TRUE)
endif()
if(ZT_UBIQUITI)
add_definitions(-D__UBIQUITI__)
set(ZT_EMBEDDED TRUE)
endif()
if(ZT_SYNOLOGY)
add_definitions(-D__SYNOLOGY__)
set(ZT_EMBEDDED TRUE)
endif()
# SSO is unavailable for external-osdep and embedded builds (make-linux.mk).
if(EXT_OSDEP OR ZT_EMBEDDED)
set(ZT_SSO_SUPPORTED FALSE)
endif()
# Fail if the architecture could not be determined.
if(ZT_ARCHITECTURE EQUAL 999)
message(FATAL_ERROR
"Unsupported/undetected CPU architecture '${CMAKE_SYSTEM_PROCESSOR}'. "
"Add a case for it above (mirror make-linux.mk).")
endif()
message(STATUS "ZeroTier architecture code (ZT_BUILD_ARCHITECTURE): ${ZT_ARCHITECTURE}")
# Intel 32-bit override: some images mismark x86_64 as i386. Force 32-bit and
# disable x86-64 crypto assembly.
if(ZT_IA32)
add_compile_options(-m32)
add_link_options(-m32)
set(ZT_USE_X64_ASM_SALSA FALSE)
set(ZT_USE_X64_ASM_ED25519 FALSE)
endif()
# "ARM32 hell": conservative per-board flags. Mirrors make-linux.mk, which
# branches on the Debian architecture (host-based dpkg probe, as in the
# Makefile) and the EXT_OSDEP feature. NEON crypto assembly ends up disabled
# on arm32 except in the EXT_OSDEP path.
if(ZT_ARCHITECTURE EQUAL 3)
execute_process(
COMMAND dpkg --print-architecture
OUTPUT_VARIABLE ZT_DPKG_ARCH
OUTPUT_STRIP_TRAILING_WHITESPACE
ERROR_QUIET)
if(ZT_DPKG_ARCH STREQUAL "armel")
add_compile_options(-march=armv5t -mfloat-abi=soft -msoft-float -mno-unaligned-access -marm)
set(ZT_USE_ARM32_NEON_ASM_CRYPTO FALSE)
elseif(NOT EXT_OSDEP)
add_compile_options(-mfloat-abi=hard -march=armv6zk -marm -mfpu=vfp -mno-unaligned-access -mtp=cp15 -mcpu=arm1176jzf-s)
add_compile_options($<$<COMPILE_LANGUAGE:CXX>:-fexceptions>)
set(ZT_USE_ARM32_NEON_ASM_CRYPTO FALSE)
else()
add_definitions(-DZT_NO_PEER_METRICS)
endif()
endif()
# MSVC cannot assemble the GNU .s crypto sources; use the SSE-intrinsic Salsa20
# instead (matches windows/ZeroTierOne.vcxproj). The x64 default ISA already
# includes SSE2, so the -msse/-march/-m32 options above (guarded if(NOT MSVC))
# aren't needed here.
if(MSVC)
set(ZT_USE_X64_ASM_SALSA FALSE)
set(ZT_USE_X64_ASM_ED25519 FALSE)
set(ZT_USE_ARM32_NEON_ASM_CRYPTO FALSE)
# SSE-intrinsic Salsa20 on Intel targets only (x86 = 1, x64 = 2); ARM64 (4) uses
# the portable path. Matches windows/ZeroTierOne.vcxproj, which defines
# ZT_SALSA20_SSE for both Win32 and x64 with the *default* ISA -- MSVC's SSE/SSE2
# intrinsics are always available, so no /arch flag is needed (and 32-bit MSVC
# already defaults to /arch:SSE2).
if(ZT_ARCHITECTURE EQUAL 1 OR ZT_ARCHITECTURE EQUAL 2)
add_definitions(-DZT_SALSA20_SSE)
endif()
endif()
# Single sign-on (OIDC) support.
if(ZT_SSO_SUPPORTED)
add_definitions(-DZT_SSO_SUPPORTED=1)
endif()
# A universal macOS build can't put the per-arch crypto .s asm in the (fat) core target --
# it would be assembled for the wrong slice. Mirror make-mac.mk: keep the x64 Salsa20/12
# asm but build it as a separate x86_64-only object (node/CMakeLists.txt) and define
# ZT_USE_X64_ASM_SALSA2012 so Packet.cpp uses it -- its `&& ZT_ARCH_X64` guard keeps it off
# the arm64 slice. The ed25519/arm32 asm aren't used on macOS, so drop those.
list(LENGTH CMAKE_OSX_ARCHITECTURES _zt_osx_arch_count)
if(APPLE AND _zt_osx_arch_count GREATER 1)
set(ZT_USE_X64_ASM_SALSA FALSE) # not added to the fat core target...
set(ZT_MACOS_UNIVERSAL_X64_SALSA_ASM TRUE) # ...built x86_64-only and linked in instead
add_definitions(-DZT_USE_X64_ASM_SALSA2012)
set(ZT_USE_X64_ASM_ED25519 FALSE)
set(ZT_USE_ARM32_NEON_ASM_CRYPTO FALSE)
endif()
# Faster crypto assembly. These -D gates pair with the source selection in
# node/CMakeLists.txt, which reads the ZT_USE_*_ASM_* variables set above.
if(ZT_USE_X64_ASM_SALSA)
add_definitions(-DZT_USE_X64_ASM_SALSA2012)
endif()
if(ZT_USE_X64_ASM_ED25519)
add_definitions(-DZT_USE_FAST_X64_ED25519)
endif()
if(ZT_USE_ARM32_NEON_ASM_CRYPTO)
add_definitions(-DZT_USE_ARM32_NEON_ASM_SALSA2012)
endif()
# Build platform code reported into the binary (read by one.cpp via version.h).
# Codes match the other build systems: make-linux.mk = 1, Windows .vcxproj = 2,
# make-mac.mk = 3, root Makefile FreeBSD = 7 / OpenBSD = 9. NetBSD has no
# assigned code anywhere, so it falls back to version.h's default of 0.
if(APPLE)
set(ZT_BUILD_PLATFORM 3)
elseif(WIN32)
set(ZT_BUILD_PLATFORM 2)
elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
set(ZT_BUILD_PLATFORM 7)
elseif(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
set(ZT_BUILD_PLATFORM 9)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(ZT_BUILD_PLATFORM 1)
else()
set(ZT_BUILD_PLATFORM 0)
endif()
add_definitions(-DZT_BUILD_PLATFORM=${ZT_BUILD_PLATFORM} -DZT_BUILD_ARCHITECTURE=${ZT_ARCHITECTURE})
# Address Sanitizer (only meaningful on x86_64/arm64).
if(ADDRESS_SANITIZER AND NOT MSVC AND (ZT_ARCHITECTURE EQUAL 2 OR ZT_ARCHITECTURE EQUAL 4))
add_compile_options(-fsanitize=address)
add_link_options(-fsanitize=address)
endif()
# ---------------------------------------------------------------------------
# C++ language standard
#
# make-linux.mk compiles everything as C++17 (controller and daemon alike), so
# we do the same. Extensions stay ON, which yields -std=gnu++17 -- a superset of
# the Makefile's -std=c++17, so anything that builds under make also builds here.
# ---------------------------------------------------------------------------
set(CMAKE_CXX_STANDARD 17 CACHE STRING "C++ standard to conform to" FORCE)
set(CMAKE_CXX_STANDARD_REQUIRED True CACHE BOOL "C++ standard required" FORCE)
set(CMAKE_CXX_EXTENSIONS ON CACHE BOOL "Enable compiler-specific extensions" FORCE)
# ---------------------------------------------------------------------------
# Global compile definitions
# ---------------------------------------------------------------------------
add_definitions(-DCMAKE_BUILD)
# The Central Controller is not supported on Windows (no libpq / redis / google-
# cloud-cpp path there); the daemon is the only supported Windows build.
if(WIN32 AND ZT1_CENTRAL_CONTROLLER)
message(FATAL_ERROR
"ZT1_CENTRAL_CONTROLLER is not supported on Windows -- build the daemon "
"(configure without -DZT1_CENTRAL_CONTROLLER).")
endif()
# ZT_NONFREE pulls in the bundled FileDB-based network controller -- the controller
# that ships in official daemon builds. Mirrors make-linux.mk, where ZT_CONTROLLER=1
# implies ZT_NONFREE=1; ZT1_CENTRAL_CONTROLLER is a superset that adds the Postgres/
# PubSub/BigTable/Redis backends on top (handled inside nonfree/controller).
option(ZT_NONFREE "Build the bundled FileDB network controller into the daemon (required by ZT1_CENTRAL_CONTROLLER)" ON)
if(ZT1_CENTRAL_CONTROLLER)
set(ZT_NONFREE ON)
endif()
if(ZT_NONFREE)
add_definitions(-DZT_NONFREE_CONTROLLER=1)
endif()
if(ZT1_CENTRAL_CONTROLLER)
add_definitions(
-DZT_CONTROLLER_USE_LIBPQ=1
-DZT1_CENTRAL_CONTROLLER=1
-DZT_OPENTELEMETRY_ENABLED=1
-DZT_NO_PEER_METRICS=1
)
endif()
# ---------------------------------------------------------------------------
# Compiler and linker flags (translated from make-linux.mk)
#
# CMAKE_BUILD_TYPE supplies -O3 -DNDEBUG for Release and -g for Debug; the lines
# below add the remaining flags make uses so the two builds match. make applies
# these to ZeroTier's own objects only; here they are global, so bundled
# third-party targets see them too (harmless -- we set no -Werror).
# ---------------------------------------------------------------------------
# Warnings: every configuration, matching make.
if(MSVC)
add_compile_options(/W3)
else()
add_compile_options(-Wall -Wno-deprecated)
endif()
# Position independence: PIC for all libraries, PIE for the executables (paired
# with -pie below). Equivalent to make's -fPIC -fPIE hardening, applied the
# idiomatic CMake way so -fPIE does NOT leak into bundled shared libraries
# (e.g. redis++), which fails to link on aarch64. (No-op on MSVC/Windows.)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
if(MSVC)
# Static CRT to match the vcxproj's /MT (/MTd for Debug). CMP0091 (NEW via
# cmake_minimum_required >= 3.15) routes this instead of patching CMAKE_*_FLAGS.
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
# /MP parallel compile, /EHsc C++ exceptions, /utf-8 source + exec charset.
add_compile_options(/MP /EHsc /utf-8)
# Always-on Windows defines from the vcxproj.
add_compile_definitions(WIN32 NOMINMAX FD_SETSIZE=1024 _CRT_SECURE_NO_WARNINGS)
else()
# Release adds a stack protector; debug uses -O1 globally (with -O2 for the hot
# crypto sources, set per-file in node/CMakeLists.txt).
add_compile_options($<$<NOT:$<CONFIG:Debug>>:-fstack-protector>)
add_compile_options($<$<CONFIG:Debug>:-O1>)
endif()
# make's debug build also defines these (ZT_DEBUG implies ZT_TRACE).
add_compile_definitions($<$<CONFIG:Debug>:ZT_DEBUG> $<$<CONFIG:Debug>:ZT_TRACE>)
# Stop libstdc++ from pulling in its mt/pool/extptr/debug allocators (GNU
# libstdc++ only; no-op on macOS/libc++, irrelevant to MSVC's STL).
if(NOT MSVC)
add_definitions(-D_MT_ALLOCATOR_H -D_POOL_ALLOCATOR_H -D_EXTPTR_ALLOCATOR_H -D_DEBUG_ALLOCATOR_H)
endif()
# GNU-ld hardening (Linux/BSD only -- not understood by the macOS or MSVC linkers).
# make applies -Wl,-z,noexecstack to every build and -pie -Wl,-z,relro,-z,now to
# release, and disables self-update on Linux/BSD (left to package management).
if(UNIX AND NOT APPLE)
string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,-z,noexecstack")
string(APPEND CMAKE_EXE_LINKER_FLAGS_RELEASE " -pie -Wl,-z,relro,-z,now")
add_compile_definitions(ZT_SOFTWARE_UPDATE_DEFAULT="disable")
elseif(WIN32)
# Windows daemon defines from the vcxproj. ZT_EXPORT takes the dllexport branch in
# include/ZeroTierOne.h, which suppresses its `#pragma comment(lib, "ZeroTierOne_x64.lib")`
# auto-link of the prebuilt SDK static library -- we build the core in-tree, not against
# the SDK lib. Self-update default: "apply" on release, "disable" on debug.
add_compile_definitions(STATICLIB ZT_SSO_ENABLED=1 ZT_USE_MINIUPNPC MINIUPNP_STATICLIB ZT_EXPORT)
add_compile_definitions(ZT_SOFTWARE_UPDATE_DEFAULT="$<IF:$<CONFIG:Debug>,disable,apply>")
endif()
# Optional feature toggles (mirror make-linux.mk's ZT_* switches).
if(ZT_TRACE)
add_definitions(-DZT_TRACE)
endif()
if(ZT_RULES_ENGINE_DEBUGGING)
add_definitions(-DZT_RULES_ENGINE_DEBUGGING)
endif()
if(ZT_DEBUG_TRACE)
add_definitions(-DZT_DEBUG_TRACE)
endif()
if(ZT_USE_TEST_TAP)
add_definitions(-DZT_USE_TEST_TAP)
endif()
if(ZT_VAULT_SUPPORT)
add_definitions(-DZT_VAULT_SUPPORT=1)
endif()
if(ZT_STATIC)
string(APPEND CMAKE_EXE_LINKER_FLAGS " -static")
endif()
# ---------------------------------------------------------------------------
# Dependencies
# ---------------------------------------------------------------------------
include(FetchContent)
include(ExternalProject)
# OpenSSL is not used by the C++ daemon: the control plane is plain-HTTP cpp-httplib
# (HTTPLIB_USE_OPENSSL_IF_AVAILABLE=OFF) and SSO/OIDC TLS lives in rustybits (native-tls).
# It IS needed for the controller (libpq/redis TLS) and on Linux/BSD (rustybits' native-tls
# links system OpenSSL there). macOS/Windows daemons need none -- which is what lets a
# universal macOS build avoid a fat OpenSSL.
if(ZT1_CENTRAL_CONTROLLER OR (UNIX AND NOT APPLE))
set(ZT_NEED_OPENSSL TRUE)
endif()
if(ZT_NEED_OPENSSL)
find_package(OpenSSL REQUIRED)
endif()
find_package(nlohmann_json REQUIRED)
# inja: found if installed (Homebrew), otherwise fetched (Debian has no package).
include(cmake/inja.cmake)
# Threads (prefer pthreads)
set(THREADS_PREFER_PTHREAD_FLAG TRUE CACHE INTERNAL "Use pthreads" FORCE)
find_package(Threads REQUIRED)
if(CMAKE_USE_PTHREADS_INIT)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
endif()
# OpenTelemetry: the controller build needs the full SDK + exporters; everyone
# else only needs the API.
if(ZT1_CENTRAL_CONTROLLER)
find_package(PostgreSQL REQUIRED)
# opentelemetry-cpp + google-cloud-cpp come from scripts/bootstrap-deps.sh. Find
# them non-fatally so we can emit an actionable error (vs CMake's default) if the
# prefix wasn't provided. A wrong-mode prefix (api-only OTel) also lands here,
# since the missing sdk/exporter components leave opentelemetry-cpp_FOUND false.
find_package(opentelemetry-cpp QUIET COMPONENTS api sdk exporters_otlp_grpc exporters_otlp_http)
find_package(google_cloud_cpp_bigtable QUIET)
find_package(google_cloud_cpp_pubsub QUIET)
if(NOT opentelemetry-cpp_FOUND OR NOT google_cloud_cpp_bigtable_FOUND OR NOT google_cloud_cpp_pubsub_FOUND)
message(FATAL_ERROR [=[
Controller dependencies (opentelemetry-cpp and/or google-cloud-cpp) were not found on
CMAKE_PREFIX_PATH. Build them, then re-run CMake pointing at the prefix:
ZT_CONTROLLER_DEPS=1 scripts/bootstrap-deps.sh # builds OTel + google-cloud-cpp into ./.deps
cmake -DZT1_CENTRAL_CONTROLLER=1 -DCMAKE_PREFIX_PATH="<prefix>" -S . -B build
bootstrap-deps.sh prints the exact -DCMAKE_PREFIX_PATH to use when it finishes.
See nonfree/controller/README_CENTRAL_CONTROLLER.md.
]=])
endif()
else()
# Daemon/non-controller: only the OTel API (header-only), from the same bootstrap prefix.
find_package(opentelemetry-cpp QUIET COMPONENTS api)
if(NOT opentelemetry-cpp_FOUND)
message(FATAL_ERROR [=[
opentelemetry-cpp (API) was not found on CMAKE_PREFIX_PATH. Build the header-only OTel
API, then re-run CMake pointing at the prefix:
scripts/bootstrap-deps.sh # quick, header-only (this is the default)
cmake -DCMAKE_PREFIX_PATH="<prefix>" -S . -B build
bootstrap-deps.sh prints the exact -DCMAKE_PREFIX_PATH to use when it finishes.
]=])
endif()
endif()
# Bundled / fetched dependencies. redis-plus-plus is controller-only (the daemon
# never links it -- all redis++ references sit behind ZT1_CENTRAL_CONTROLLER), so
# only pull it in for the controller build. This also keeps it out of the Windows
# daemon build, where the controller is unsupported.
include(cmake/cpp-httplib.cmake)
include(cmake/miniupnpc.cmake)
if(ZT1_CENTRAL_CONTROLLER)
include(cmake/redis-plus-plus.cmake)
endif()
# ---------------------------------------------------------------------------
# rustybits (built via cargo, linked as a static library)
# ---------------------------------------------------------------------------
if(WIN32)
# cargo builds for the host triple by default; cross-target the selected arch
# explicitly so an x64 host can build x86/ARM64. The lib then lands under
# target/<triple>/release. (The cbindgen header always goes to target/rustybits.h
# per rustybits/build.rs, regardless of --target.) Requires the Rust target to be
# installed: rustup target add {i686,aarch64}-pc-windows-msvc.
if(ZT_ARCHITECTURE EQUAL 1)
set(RUSTYBITS_TRIPLE i686-pc-windows-msvc)
elseif(ZT_ARCHITECTURE EQUAL 4)
set(RUSTYBITS_TRIPLE aarch64-pc-windows-msvc)
else()
set(RUSTYBITS_TRIPLE x86_64-pc-windows-msvc)
endif()
set(RUSTYBITS_LIB ${PROJ_DIR}/rustybits/target/${RUSTYBITS_TRIPLE}/release/rustybits.lib)
set(RUSTYBITS_BUILD_COMMAND cd ${PROJ_DIR}/rustybits && cargo build --release --target ${RUSTYBITS_TRIPLE})
elseif(APPLE)
# Honor CMAKE_OSX_ARCHITECTURES so rustybits matches the C/C++ slices. cargo builds
# one target triple at a time, so a universal (multi-arch) build builds each arch and
# lipo's them into one fat archive. Unset = native host build. Cross / universal builds
# need the Rust target(s): rustup target add {x86_64,aarch64}-apple-darwin.
set(_rb_triples "")
foreach(_a IN LISTS CMAKE_OSX_ARCHITECTURES)
if(_a STREQUAL "x86_64")
list(APPEND _rb_triples x86_64-apple-darwin)
elseif(_a STREQUAL "arm64")
list(APPEND _rb_triples aarch64-apple-darwin)
endif()
endforeach()
list(LENGTH _rb_triples _rb_n)
if(_rb_n GREATER 1)
# Universal: build each arch, then lipo into a single fat static lib.
set(RUSTYBITS_LIB ${PROJ_DIR}/rustybits/target/zt-universal/librustybits.a)
set(RUSTYBITS_BUILD_COMMAND "")
set(_rb_lipo_inputs "")
foreach(_t IN LISTS _rb_triples)
if(RUSTYBITS_BUILD_COMMAND)
list(APPEND RUSTYBITS_BUILD_COMMAND COMMAND)
endif()
list(APPEND RUSTYBITS_BUILD_COMMAND cd ${PROJ_DIR}/rustybits && cargo build --release --target ${_t})
list(APPEND _rb_lipo_inputs ${PROJ_DIR}/rustybits/target/${_t}/release/librustybits.a)
endforeach()
list(APPEND RUSTYBITS_BUILD_COMMAND
COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJ_DIR}/rustybits/target/zt-universal
COMMAND lipo -create -output ${RUSTYBITS_LIB} ${_rb_lipo_inputs})
elseif(_rb_n EQUAL 1)
# Single explicit arch (e.g. cross-compiling x86_64 on an arm64 host).
set(RUSTYBITS_LIB ${PROJ_DIR}/rustybits/target/${_rb_triples}/release/librustybits.a)
set(RUSTYBITS_BUILD_COMMAND cd ${PROJ_DIR}/rustybits && cargo build --release --target ${_rb_triples})
else()
# No explicit arch: native host build.
set(RUSTYBITS_LIB ${PROJ_DIR}/rustybits/target/release/librustybits.a)
set(RUSTYBITS_BUILD_COMMAND cd ${PROJ_DIR}/rustybits && cargo build --release)
endif()
else()
# Linux / BSD: native host build.
set(RUSTYBITS_LIB ${PROJ_DIR}/rustybits/target/release/librustybits.a)
set(RUSTYBITS_BUILD_COMMAND cd ${PROJ_DIR}/rustybits && cargo build --release)
endif()
set(RUSTYBITS_INCLUDE_DIR ${PROJ_DIR}/rustybits/target)
ExternalProject_Add(
rustybits_build
DOWNLOAD_COMMAND ""
CONFIGURE_COMMAND ""
BUILD_COMMAND ${RUSTYBITS_BUILD_COMMAND}
INSTALL_COMMAND ""
BUILD_BYPRODUCTS ${RUSTYBITS_LIB} ${RUSTYBITS_INCLUDE_DIR}/rustybits.h
)
add_library(rustybits STATIC IMPORTED GLOBAL)
set_property(TARGET rustybits PROPERTY IMPORTED_LOCATION ${RUSTYBITS_LIB})
add_dependencies(rustybits rustybits_build)
# Make `make clean` also clean rustybits. CMake's clean target can only delete
# files (it can't run `cargo clean`), but removing the target dir is exactly
# what `cargo clean` does.
set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_CLEAN_FILES ${PROJ_DIR}/rustybits/target)
# ---------------------------------------------------------------------------
# Subdirectories
# ---------------------------------------------------------------------------
add_subdirectory(ext)
add_subdirectory(node)
add_subdirectory(osdep)
add_subdirectory(service)
# The bundled network controller is built only for ZT_NONFREE (official) builds.
if(ZT_NONFREE)
add_subdirectory(nonfree)
endif()
# ---------------------------------------------------------------------------
# Link libraries
# ---------------------------------------------------------------------------
set(LINKED_LIBRARIES
prometheus-cpp-lite
zerotier-service
zerotier-osdep
zerotier-core
Threads::Threads
nlohmann_json::nlohmann_json
opentelemetry-cpp::api
rustybits
)
# OpenSSL only where it's actually needed (controller / Linux rustybits); the macOS/
# Windows daemon links none. See the find_package(OpenSSL) note above.
if(ZT_NEED_OPENSSL)
list(APPEND LINKED_LIBRARIES OpenSSL::Crypto OpenSSL::SSL)
endif()
# The bundled FileDB network controller (only built when ZT_NONFREE; central
# backends are layered in under ZT1_CENTRAL_CONTROLLER inside the target).
if(ZT_NONFREE)
list(APPEND LINKED_LIBRARIES zerotier-controller)
endif()
# Controller-only OpenTelemetry exporters.
if(ZT1_CENTRAL_CONTROLLER)
list(APPEND LINKED_LIBRARIES
opentelemetry-cpp::sdk
opentelemetry-cpp::trace
opentelemetry-cpp::proto_grpc
opentelemetry-cpp::otlp_grpc_client
opentelemetry-cpp::otlp_grpc_exporter
opentelemetry-cpp::otlp_grpc_log_record_exporter
opentelemetry-cpp::otlp_grpc_metrics_exporter
opentelemetry-cpp::otlp_http_exporter
opentelemetry-cpp::otlp_http_log_record_exporter
opentelemetry-cpp::otlp_http_metric_exporter
)
endif()
# HashiCorp Vault support links libcurl (make-linux.mk).
if(ZT_VAULT_SUPPORT)
find_package(CURL REQUIRED)
list(APPEND LINKED_LIBRARIES CURL::libcurl)
endif()
# Apple system frameworks.
if(APPLE)
find_library(COREFOUNDATION_LIBRARY CoreFoundation)
find_library(SECURITY_LIBRARY Security)
find_library(SYSTEM_CONFIGURATION_LIBRARY SystemConfiguration)
find_library(CARBON_LIBRARY Carbon)
find_library(CORESERVICES_LIBRARY CoreServices)
list(APPEND LINKED_LIBRARIES
${COREFOUNDATION_LIBRARY}
${SECURITY_LIBRARY}
${CARBON_LIBRARY}
${SYSTEM_CONFIGURATION_LIBRARY}
${CORESERVICES_LIBRARY}
)
endif()
# Windows system libraries (from windows/ZeroTierOne/ZeroTierOne.vcxproj).
if(WIN32)
list(APPEND LINKED_LIBRARIES
ws2_32 wsock32 Iphlpapi Rpcrt4 bcrypt crypt32 ncrypt ntdll secur32 userenv wbemuuid)
endif()
# ---------------------------------------------------------------------------
# Targets
# ---------------------------------------------------------------------------
add_executable(zerotier-one
one.cpp
ext/http-parser/http_parser.c
)
# On Windows one.cpp pulls in the service wrapper and includes it as
# "windows/ZeroTierOne/...", so compile those sources in and add the repo root to
# the include path. (The SDK and TAP driver stay in the MSBuild solution.)
if(WIN32)
target_sources(zerotier-one PRIVATE
windows/ZeroTierOne/ServiceBase.cpp
windows/ZeroTierOne/ServiceInstaller.cpp
windows/ZeroTierOne/ZeroTierOneService.cpp
)
target_include_directories(zerotier-one PRIVATE ${PROJ_DIR})
endif()
target_link_libraries(zerotier-one ${LINKED_LIBRARIES})
# The Windows .vcxproj doesn't build the selftest; skip it on Windows too.
if(NOT WIN32)
add_executable(zerotier-selftest
selftest.cpp
)
target_link_libraries(zerotier-selftest
zerotier-core
zerotier-osdep
Threads::Threads
nlohmann_json::nlohmann_json
prometheus-cpp-lite
)
endif()