cmake_minimum_required(VERSION 3.22.1) message(STATUS "CMake version: ${CMAKE_VERSION}") set(CMAKE_BUILD_TYPE Debug CACHE STRING "") project(RealmCore) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/tools/cmake") if(NOT DEFINED REALM_CORE_SUBMODULE_BUILD AND NOT CMAKE_SOURCE_DIR STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) # Realm Core is being built as part of another project, likely an SDK set(REALM_CORE_SUBMODULE_BUILD ON) endif() # Include general CMake modules include(GNUInstallDirs) include(CheckIncludeFiles) include(CheckSymbolExists) include(CMakePushCheckState) include(Utilities) include(SpecialtyBuilds) include(GetVersion) include(CheckCXXCompilerFlag) include(CheckCXXSourceCompiles) include(CheckCXXSourceRuns) include(AcquireRealmDependency) include(CodeCoverage) if(NOT DEFINED REALM_VERSION) # Get accurate git-describe version include(GetGitRevisionDescription) git_describe(REALM_VERSION) endif() set(PROJECT_VERSION ${DEP_VERSION}) # Project-wide build flags if (NOT DEFINED CMAKE_CXX_STANDARD) set(CMAKE_CXX_STANDARD 17) endif() set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) if(NOT APPLE) # TODO: Core APIs should always built for internal usage. But there seems to be issues with cocoa. Enable it only for Android for now. set(CMAKE_CXX_VISIBILITY_PRESET hidden) elseif(APPLE) set(CMAKE_VISIBILITY_INLINES_HIDDEN 1) endif() function(check_if_cxx_compiler_flag_supported flag out_var) if(flag MATCHES "^-Wno-") # Compilers ignore unknown -Wno-foo flags, so look for -Wfoo instead. string(REPLACE "-Wno-" "-W" check_flag ${flag}) else() set(check_flag ${flag}) endif() check_cxx_compiler_flag(${check_flag} ${out_var}) endfunction() function(add_cxx_flag_if_supported flag) check_if_cxx_compiler_flag_supported(${flag} HAVE_${flag}) if(HAVE_${flag}) add_compile_options($<$:${flag}>) endif() endfunction() # Usage: append_source_file_compile_options(FILES [ ...] FLAGS [ ...]) function(append_source_file_compile_options) set(options) set(args) set(list_args FILES FLAGS) cmake_parse_arguments(append_options "${options}" "${args}" "${list_args}" ${ARGN}) if (NOT append_options_FILES) message(FATAL_ERROR "Missing FILES argument for append_source_file_compile_options") endif() if (NOT append_options_FLAGS) message(FATAL_ERROR "Missing FLAGS argument for append_source_file_compile_options") endif() foreach(FLAG_ IN LISTS append_options_FLAGS) check_if_cxx_compiler_flag_supported(${FLAG_} HAVE${FLAG_}) if (HAVE${FLAG_}) foreach(SRC_ IN LISTS append_options_FILES) get_source_file_property(OLD_OPTS ${SRC_} COMPILE_OPTIONS) if (NOT OLD_OPTS) set_source_files_properties(${SRC_} PROPERTIES COMPILE_OPTIONS "${FLAG_}") elseif(NOT "${FLAG_}" IN_LIST OLD_OPTS) set_source_files_properties(${SRC_} PROPERTIES COMPILE_OPTIONS "${OLD_OPTS};${FLAG_}") endif() endforeach() endif() endforeach() endfunction() function(add_target_option_if_supported target option_scope) foreach(option ${ARGN}) check_if_cxx_compiler_flag_supported(${option} HAVE_${option}) if(HAVE_${option}) target_compile_options(${target} ${option_scope} ${option}) endif() endforeach() endfunction() function(use_faster_linker) # If a linker has already been set, don't override. if ("${CMAKE_EXE_LINKER_FLAGS}" MATCHES "-fuse-ld=") return() endif() foreach(LINKER lld gold) # lld > gold > default # there is no link equivalent to check_cxx_compiler_flag() set(CMAKE_REQUIRED_LINK_OPTIONS "-fuse-ld=${LINKER}") check_cxx_source_compiles("int main() {}" HAVE_LINKER_${LINKER}) if(HAVE_LINKER_${LINKER}) message(STATUS "Using linker ${LINKER}") set(REALM_USE_FAST_LINKER "-fuse-ld=${LINKER}" PARENT_SCOPE) return() endif() endforeach() endfunction() # Set global warnings settings if(MSVC) add_compile_options(/W3 /D_CRT_SECURE_NO_WARNINGS /D_SCL_SECURE_NO_WARNINGS) # Don't complain about unary minus on unsigned resulting in positive number. add_compile_options(/wd4146) # We use these in our AtomicSharedPtr implementation and it can't move # to atomic> because NotificationToken relies on movability. add_compile_options(/D_SILENCE_CXX20_OLD_SHARED_PTR_ATOMIC_SUPPORT_DEPRECATION_WARNING) # Enable __cplusplus macro add_compile_options(/Zc:__cplusplus) else() add_compile_options(-Wall -Wextra -Wempty-body -Wparentheses -Wunknown-pragmas -Wunreachable-code -Wunused-parameter -Wno-missing-field-initializers) # TODO: Remove this when fixed if(ANDROID) add_compile_options(-Wno-uninitialized) elseif(${CMAKE_CXX_COMPILER_ID} MATCHES ".*[Cc]lang") # FIXME: Re-introduce -Wold-style-cast add_compile_options(-Wunreachable-code -Wshorten-64-to-32 -Wconditional-uninitialized -Wextra-semi -Wno-nested-anon-types -Wdocumentation -Wthread-safety -Wthread-safety-negative -Wmissing-prototypes) endif() # By default GCC warns that it changed how it passes bitfields by value as # function arguments on arm64 every time this happens. This warning is just # an FYI and not pointing out a problem, so just disable it. add_cxx_flag_if_supported(-Wno-psabi) add_cxx_flag_if_supported(-Wpartial-availability) # This warning is too agressive. It warns about moves that are not redundant on older # compilers that we still support. It is also harmless, unlike pessimizing moves. add_cxx_flag_if_supported(-Wno-redundant-move) # For backwards compatibility libc++ public headers have some transitive # includes which they don't use. Disabling this improves build times a bit. add_compile_definitions(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) # Ninja buffers output so we need to tell the compiler to use colors even though stdout isn't a tty. if("${CMAKE_GENERATOR}" STREQUAL "Ninja") add_cxx_flag_if_supported(-fdiagnostics-color) endif() use_faster_linker() endif() if(ANDROID) # Optimize for size vs. performance for Android. The has the following implications: # - Add `-ffunction-sections` and `-fdata-sections`. This requires that `-Wl,-gc-sections` are used when creating # the final .so file. # - `-fstrict-aliasing` is inherited from NDK r10e. # - `-fomit-frame-pointer` is inherited from NDK r10e. # - On some architectures char is unsigned by default. Make it signed # - Compile with -Oz in Release because on Android we favor code size over performance # add_compile_options(-fdata-sections -ffunction-sections -fomit-frame-pointer -fsigned-char -fstrict-aliasing -funwind-tables -no-canonical-prefixes $<$:-Oz>) endif() if(EMSCRIPTEN AND NOT REALM_CORE_SUBMODULE_BUILD) add_compile_options(-fwasm-exceptions) add_link_options(-fwasm-exceptions -sALLOW_MEMORY_GROWTH=1) set(CMAKE_EXECUTABLE_SUFFIX ".html") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --emrun") endif() set(CMAKE_DEBUG_POSTFIX "-dbg") set(CMAKE_MINSIZEDEBUG_POSTFIX "-dbg") set(CMAKE_POSITION_INDEPENDENT_CODE ON) if(CMAKE_SYSTEM_NAME MATCHES "^Windows") add_compile_definitions( WIN32_LEAN_AND_MEAN # include minimal Windows.h for faster builds UNICODE # prefer Unicode variants of Windows APIs over ANSI variants _UNICODE # prefer Unicode variants of C runtime APIs over ANSI variants ) if(NOT WINDOWS_STORE) # for regular Windows target Windows 8.1 as the minimum version # see https://docs.microsoft.com/en-us/windows/win32/WinProg/using-the-windows-headers add_compile_definitions( _WIN32_WINNT=0x0603 WINVER=0x603 NTDDI_VERSION=0x06030000 ) endif() endif() if(MSVC) add_compile_options( /MP # Enable multi-processor compilation ) if(WINDOWS_STORE) # Removing LNK4075 warnings for debug UWP builds # "LNK4075: ignoring '/INCREMENTAL' due to '/OPT:ICF' specification" # "LNK4075: ignoring '/INCREMENTAL' due to '/OPT:REF' specification" # Optional verification checks since we don't know existing contents of variables below string(REPLACE "/OPT:ICF " "/OPT:NOICF " CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG}") string(REPLACE "/OPT:REF " "/OPT:NOREF " CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG}") string(REPLACE "/INCREMENTAL:YES " "/INCREMENTAL:NO " CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG}") string(REPLACE "/INCREMENTAL " "/INCREMENTAL:NO " CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG}") # Mandatory set(CMAKE_MODULE_LINKER_FLAGS_DEBUG "${CMAKE_MODULE_LINKER_FLAGS_DEBUG} /INCREMENTAL:NO /OPT:NOREF /OPT:NOICF") set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} /INCREMENTAL:NO /OPT:NOREF /OPT:NOICF") set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} /INCREMENTAL:NO /OPT:NOREF /OPT:NOICF") else() if(NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY) set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") endif() string(REGEX REPLACE "/RTC(su|[1su])" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") endif() # Let the compiler optimize debug builds ever so slightly. # /Ob1: This allows the compiler to inline functions marked __inline. # /Oi: This enables (faster) intrinsic functions. string(REPLACE "/Ob0" "/Ob1" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}") add_compile_options($<$:/Oi>) # Prevent warnings abount non-existing .pdb files add_link_options($<$:/ignore:4099>) endif() if(UNIX) cmake_push_check_state(RESET) # Enable access to large file APIs, but don't make them the default. add_compile_definitions("_LARGEFILE_SOURCE" "_LARGEFILE64_SOURCE") set(CMAKE_REQUIRED_DEFINITIONS "-D_LARGEFILE_SOURCE" "-D_LARGEFILE64_SOURCE") # Use readdir64 if available. check_symbol_exists(readdir64 "dirent.h" REALM_HAVE_READDIR64) cmake_reset_check_state() set(CMAKE_REQUIRED_DEFINITIONS "-D_POSIX_C_SOURCE=200112L") check_symbol_exists(posix_fallocate "fcntl.h" REALM_HAVE_POSIX_FALLOCATE) if(REALM_HAVE_POSIX_FALLOCATE) add_compile_definitions("_POSIX_C_SOURCE=200112L") endif() cmake_pop_check_state() endif() # Options (passed to CMake) option(REALM_ENABLE_SYNC "Enable synchronized realms." ON) option(REALM_BUILD_TEST_CLIENT "Build the test client" OFF) option(REALM_ENABLE_ASSERTIONS "Enable assertions in release mode." OFF) option(REALM_ENABLE_ALLOC_SET_ZERO "Zero all allocations." OFF) if(NOT EMSCRIPTEN) option(REALM_ENABLE_ENCRYPTION "Enable encryption." ON) endif() option(REALM_ENABLE_MEMDEBUG "Add additional memory checks" OFF) option(REALM_VALGRIND "Tell the test suite we are running with valgrind" OFF) option(REALM_SYNC_MULTIPLEXING "Enables/disables sync session multiplexing by default" ON) set(REALM_MAX_BPNODE_SIZE "1000" CACHE STRING "Max B+ tree node size.") option(REALM_ENABLE_GEOSPATIAL "Enable geospatial types and queries." ON) option(REALM_APP_SERVICES "Enable the default app services implementation." ON) # Find dependencies set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) # Threads library is pthread-compatible # Check for these explicitly because older versions of musl define only one or the other if(CMAKE_USE_PTHREADS_INIT) check_symbol_exists(pthread_getname_np "pthread.h" REALM_HAVE_PTHREAD_GETNAME) check_symbol_exists(pthread_setname_np "pthread.h" REALM_HAVE_PTHREAD_SETNAME) endif() find_package(Backtrace) set(REALM_HAVE_BACKTRACE ${Backtrace_FOUND}) if(REALM_ENABLE_SYNC) option(REALM_FORCE_OPENSSL "Always use OpenSSL for SSL needs, regardless of target platform." OFF) if(CMAKE_SYSTEM_NAME MATCHES "^Windows|Linux|Android") set(REALM_NEEDS_OPENSSL TRUE) endif() if(REALM_NEEDS_OPENSSL OR REALM_FORCE_OPENSSL) option(REALM_INCLUDE_CERTS "Include a list of trust certificates in the build for OpenSSL certificate verification" ON) endif() elseif(REALM_ENABLE_ENCRYPTION AND CMAKE_SYSTEM_NAME MATCHES "Linux|Android") set(REALM_NEEDS_OPENSSL TRUE) endif() if(REALM_NEEDS_OPENSSL OR REALM_FORCE_OPENSSL) option(REALM_USE_SYSTEM_OPENSSL "Look for an external OpenSSL installation instead of using prebuilt one." OFF) set(_REALM_USE_OPENSSL_DEFAULT_VERIFY_PATHS ON) if(NOT REALM_USE_SYSTEM_OPENSSL AND (ANDROID OR WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "Linux")) # Use our own prebuilt OpenSSL realm_acquire_dependency(openssl ${DEP_OPENSSL_VERSION} OPENSSL_CMAKE_INCLUDE_FILE) include(${OPENSSL_CMAKE_INCLUDE_FILE}) set(_REALM_USE_OPENSSL_DEFAULT_VERIFY_PATHS OFF) endif() find_package(OpenSSL REQUIRED) set(REALM_HAVE_OPENSSL ON) option(REALM_USE_SYSTEM_OPENSSL_PATHS "Use the system OpenSSL certificate store (specified by the OPENSSLDIR environment variable) at runtime for TLS handshake." ${_REALM_USE_OPENSSL_DEFAULT_VERIFY_PATHS}) string(REGEX MATCH "^([0-9]+)\\.([0-9]+)" OPENSSL_VERSION_MAJOR_MINOR "${OPENSSL_VERSION}") elseif(APPLE) set(REALM_HAVE_SECURE_TRANSPORT "1") endif() # Use Zlib for Sync, but allow integrators to override it # Don't use find_library(ZLIB) on Apple platforms - it hardcodes the path per platform, # so for an iOS build it'll use the path from the Device plaform, which is an error on Simulator. # Just use -lz and let Xcode figure it out # Emscripten does provide Zlib, but it doesn't work with find_package and is handled specially if(NOT APPLE AND NOT EMSCRIPTEN AND NOT TARGET ZLIB::ZLIB) if(WIN32 OR (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND REALM_LINUX_TOOLCHAIN)) find_package(ZLIB) if (NOT ZLIB_FOUND) realm_acquire_dependency(zlib ${DEP_ZLIB_VERSION} ZLIB_CMAKE_INCLUDE_FILE) include(${ZLIB_CMAKE_INCLUDE_FILE}) endif() elseif(ANDROID) # On Android FindZLIB chooses the static libz over the dynamic one, but this leads to issues # (see https://github.com/android/ndk/issues/1179) # We want to link against the stub library instead of statically linking anyway, # so we hack find_library to only consider shared object libraries when looking for libz set(_CMAKE_FIND_LIBRARY_SUFFIXES_orig ${CMAKE_FIND_LIBRARY_SUFFIXES}) set(CMAKE_FIND_LIBRARY_SUFFIXES .so) endif() find_package(ZLIB REQUIRED) if(ANDROID) set(CMAKE_FIND_LIBRARY_SUFFIXES ${_CMAKE_FIND_LIBRARY_SUFFIXES_orig}) endif() endif() # Store configuration in header file configure_file(src/realm/util/config.h.in src/realm/util/config.h) # Configure source code to use right version number configure_file(src/realm/version_numbers.hpp.in src/realm/version_numbers.hpp) set(DEPRECATED_CONFIG_FILE "${RealmCore_SOURCE_DIR}/src/realm/util/config.h") if(EXISTS "${DEPRECATED_CONFIG_FILE}") message(FATAL_ERROR "${DEPRECATED_CONFIG_FILE} exists in the source directory, and will take precedence over the generated configuration in the build directory. Please remove this file before continuing. Alternatively, you can also clean your realm-core to remove this and other stale files: git clean -xfd") endif() set(JSON_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/json) # Tell the build system where to find the sources (and generated sources) include_directories(src) include_directories(${CMAKE_CURRENT_BINARY_DIR}/src) # For generated files (like config.h) add_subdirectory(src) add_subdirectory(bindgen) # Install the licence and changelog files install(FILES LICENSE CHANGELOG.md DESTINATION "doc/realm" COMPONENT devel) # Only prepare test/install/package targets if we're not a submodule if(REALM_CORE_SUBMODULE_BUILD) return() endif() # Make the project importable from the build directory set(REALM_EXPORTED_TARGETS Storage QueryParser ObjectStore RealmFFI RealmFFIStatic ) if(REALM_ENABLE_SYNC) list(APPEND REALM_EXPORTED_TARGETS Sync) endif() export(TARGETS ${REALM_EXPORTED_TARGETS} NAMESPACE Realm:: FILE RealmTargets.cmake) configure_file(tools/cmake/RealmConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/RealmConfig.cmake @ONLY) configure_file(tools/cmake/AcquireRealmDependency.cmake ${CMAKE_CURRENT_BINARY_DIR}/AcquireRealmDependency.cmake @ONLY) # Make the project importable from the install directory install(EXPORT realm NAMESPACE Realm:: FILE RealmTargets.cmake DESTINATION share/cmake/Realm COMPONENT devel ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/RealmConfig.cmake DESTINATION share/cmake/Realm COMPONENT devel ) install(FILES tools/cmake/AcquireRealmDependency.cmake DESTINATION share/cmake/Realm COMPONENT devel ) if(NOT REALM_BUILD_LIB_ONLY AND NOT REALM_NO_TESTS) enable_testing() add_subdirectory(test) endif() if (REALM_BUILD_TEST_CLIENT) add_subdirectory(test/client) endif() # CPack set(CPACK_GENERATOR "TGZ") set(CPACK_PACKAGE_VERSION ${REALM_VERSION}) set(CPACK_ARCHIVE_COMPONENT_INSTALL ON) # Generators that don't support build-time configuration selection. # Others like Xcode and Visual Studio can determine the package name # based on the build configuration at build-time. set(_single_config_generators Ninja "Unix Makefiles" ) if(CMAKE_GENERATOR IN_LIST _single_config_generators) set(CPACK_PACKAGE_NAME "realm-${CMAKE_BUILD_TYPE}") else() set(CPACK_PACKAGE_NAME "realm-\${CPACK_BUILD_CONFIG}") endif() include(CPack) cpack_add_component(runtime DEPENDS runtime) cpack_add_component(devel DEPENDS devel)