blob: d61323329e09e79fb9af61d7e8cfdbdd93a543a6 [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# Require cmake that can work with OpenJDK 10 and newer [1].
#
# Note: cmake in thirdparty/ will always meet this minimum.
#
# 1. https://gitlab.kitware.com/cmake/cmake/issues/17938
cmake_minimum_required(VERSION 3.11.2)
project(Kudu)
if (APPLE)
# Print out the CMAKE_OSX_* variables to help debug Apple build issues.
message(STATUS "Using CMAKE_OSX_ARCHITECTURES: ${CMAKE_OSX_ARCHITECTURES}")
message(STATUS "Using CMAKE_OSX_DEPLOYMENT_TARGET: ${CMAKE_OSX_DEPLOYMENT_TARGET}")
message(STATUS "Using CMAKE_OSX_SYSROOT: ${CMAKE_OSX_SYSROOT}")
endif()
# Prevent builds from the top-level source directory. This ensures that build
# output is well isolated from the source tree.
#
# May be overridden by setting KUDU_ALLOW_IN_SOURCE_BUILD; this is only
# recommended for experts!
if("${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}" AND
NOT "${KUDU_ALLOW_IN_SOURCE_BUILD}")
message(FATAL_ERROR
"Kudu may not be built from the top-level source directory. Create a new "
"directory and run cmake from there, passing the path to the top-level "
"source directory as the last argument. "
"To override this, rerun CMake with -DKUDU_ALLOW_IN_SOURCE_BUILD=1. "
"Also, delete 'CMakeCache.txt' and 'CMakeFiles' from the top-level source "
"directory, otherwise future builds will not work.")
endif()
# Provide a 'latest' symlink to this build directory if the "blessed"
# multi-build layout is detected:
#
# build/
# build/<first build directory>
# build/<second build directory>
# ...
if ("${CMAKE_CURRENT_BINARY_DIR}" STREQUAL
"${CMAKE_CURRENT_SOURCE_DIR}/build/latest")
message(FATAL_ERROR "Should not run cmake inside the build/latest symlink. "
"First change directories into the destination of the symlink.")
endif()
string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/build/" ""
BLESSED_BUILD_SUBDIR "${CMAKE_CURRENT_BINARY_DIR}")
string(FIND "${BLESSED_BUILD_SUBDIR}" "/" SLASH_POS)
if (SLASH_POS EQUAL -1)
# Create the symlink both during cmake invocation and when the default target
# ('all') is built. The former is useful for scripts that, after running
# cmake, only build a single target (i.e. "make lint").
execute_process(COMMAND ln ${MORE_ARGS} -nsf ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/build/latest)
add_custom_target(latest_symlink ALL
ln ${MORE_ARGS} -nsf ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/build/latest
COMMENT "Recreating ../build/latest symlink")
# 'ALL' above doesn't actually add 'latest_symlink' as a dependency to all
# targets. So, we override add_executable to ensure that whenever any executable
# is built, the symlink is re-created.
function(add_executable name)
# Call through to the original add_executable function.
_add_executable(${name} ${ARGN})
add_dependencies(${name} latest_symlink)
endfunction()
endif()
file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/version.txt" KUDU_VERSION_NUMBER)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake_modules")
include(CMakeParseArguments)
set(BUILD_SUPPORT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/build-support)
set(THIRDPARTY_DIR ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty)
set(THIRDPARTY_TOOLCHAIN_DIR ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/clang-toolchain)
set(THIRDPARTY_INSTALL_DIR ${THIRDPARTY_DIR}/installed)
set(THIRDPARTY_INSTALL_COMMON_DIR ${THIRDPARTY_INSTALL_DIR}/common)
set(THIRDPARTY_INSTALL_UNINSTRUMENTED_DIR ${THIRDPARTY_INSTALL_DIR}/uninstrumented)
set(THIRDPARTY_INSTALL_TSAN_DIR ${THIRDPARTY_INSTALL_DIR}/tsan)
# Set the Java directory so our C++ tests are able to access its contents.
# This can be useful to, e.g. spawn a Java subprocess.
set(JAVA_DIR ${CMAKE_CURRENT_SOURCE_DIR}/java)
# Adds the EXTRA_GRADLE_FLAGS environment variable to a cmake list and calls `separate_arguments`.
# This solves the problem of escaped spaces in the EXTRA_GRADLE_FLAGS environment variable.
list(APPEND GRADLE_FLAGS $ENV{EXTRA_GRADLE_FLAGS})
separate_arguments(GRADLE_FLAGS)
# We always want Gradle to use the plain console and quiet flag when called from cmake.
list(APPEND GRADLE_FLAGS --quiet --console=plain)
list(REMOVE_DUPLICATES GRADLE_FLAGS)
# Initialize Gradle to ensure the wrapper is downloaded.
# This is important so that multiple calls to Gradle don't try and
# download the gradle-wrapper.jar at the same time.
set(GRADLE_WRAPPER_JAR ${JAVA_DIR}/gradle/wrapper/gradle-wrapper.jar)
add_custom_command(OUTPUT ${GRADLE_WRAPPER_JAR}
COMMAND ./gradlew --version ${GRADLE_FLAGS}
COMMAND ./gradlew initializeTasks ${GRADLE_FLAGS}
WORKING_DIRECTORY "${JAVA_DIR}")
add_custom_target(init_gradle DEPENDS ${GRADLE_WRAPPER_JAR})
# Allow "make install" to not depend on all targets.
#
# Must be declared in the top-level CMakeLists.txt.
set(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY true)
# Codegen-dependent executables need to be linked with -rdynamic; otherwise LLVM
# can't find dependent Kudu symbols at runtime.
#
# Setting the ENABLE_EXPORTS target property for each codegen-dependent
# executable is more precise, but that's a rather long target list, so we'll
# just do it once here for all Kudu executables.
set(CMAKE_ENABLE_EXPORTS true)
# Always generate the compilation database file (compile_commands.json) for use
# with various development tools, such as IWYU and Vim's YouCompleteMe plugin.
# See http://clang.llvm.org/docs/JSONCompilationDatabase.html
set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)
# Make sure thirdparty stuff is up-to-date.
if ("$ENV{NO_REBUILD_THIRDPARTY}" STREQUAL "")
if (${KUDU_USE_TSAN})
set(TP_ARGS "tsan")
endif()
execute_process(
COMMAND ${THIRDPARTY_DIR}/build-if-necessary.sh ${TP_ARGS}
RESULT_VARIABLE THIRDPARTY_SCRIPT_RESULT)
if (NOT (${THIRDPARTY_SCRIPT_RESULT} EQUAL 0))
message(FATAL_ERROR "Thirdparty was built unsuccessfully, terminating.")
endif()
endif()
############################################################
# Compiler flags
############################################################
# Determine compiler version
include(CompilerInfo)
# compiler flags that are common across debug/release builds
execute_process(COMMAND uname -m OUTPUT_VARIABLE ARCH_NAME)
message(STATUS "Found ARCH_NAME: ${ARCH_NAME}")
# The Apple backend for aarch64 is called arm64.
# Rename to aarch64 to simplify all of our build checks.
if("${ARCH_NAME}" MATCHES "arm64")
set(ARCH_NAME "aarch64")
endif()
message(STATUS "Using ARCH_NAME: ${ARCH_NAME}")
if("${ARCH_NAME}" MATCHES "aarch64")
# Certain platforms such as ARM do not use signed chars by default
# which causes issues with certain bounds checks.
set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} -fsigned-char")
# Turn off fp-contract on aarch64 to avoid multiply-add operation result difference.
set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} -ffp-contract=off")
else()
# -msse4.2: Enable sse4.2 compiler intrinsics.
set(CXX_COMMON_FLAGS "-msse4.2")
endif()
# -Wall: Enable all warnings.
set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} -Wall")
# -Wno-sign-compare: suppress warnings for comparison between signed and unsigned
# integers
set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} -Wno-sign-compare")
# -Wno-comment: suppress warnings about backslash-newline in "//" comments,
# which appear in the Kudu source code due to the use of ASCII art and
# multi-line command line examples in comments.
set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} -Wno-comment")
# -pthread: enable multithreaded malloc
set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} -pthread")
# -fno-strict-aliasing
# Assume programs do not follow strict aliasing rules.
# GCC cannot always verify whether strict aliasing rules are indeed followed due to
# fundamental limitations in escape analysis, which can result in subtle bad code generation.
# This has a small perf hit but worth it to avoid hard to debug crashes.
set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} -fno-strict-aliasing")
# -DBOOST_DATE_TIME_POSIX_TIME_STD_CONFIG: enable nanosecond precision for boost
set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} -DBOOST_DATE_TIME_POSIX_TIME_STD_CONFIG")
# We want access to the PRI* print format macros.
add_definitions(-D__STDC_FORMAT_MACROS)
# We want short macros from util/status.h.
add_definitions(-DKUDU_HEADERS_USE_SHORT_STATUS_MACROS=1)
# Slice includes many gutil dependencies that third-party users of the Kudu
# client library don't have. Our build has them, though.
add_definitions(-DKUDU_HEADERS_USE_RICH_SLICE=1)
# We don't want to use any stubs; that's exclusively for builds using our
# exported client headers).
add_definitions(-DKUDU_HEADERS_NO_STUBS=1)
# compiler flags for different build types (run 'cmake -DCMAKE_BUILD_TYPE=<type> .')
# For all builds:
# For CMAKE_BUILD_TYPE=Debug
# -ggdb: Enable gdb debugging
# For CMAKE_BUILD_TYPE=FastDebug
# Same as DEBUG, except with some optimizations on.
# For CMAKE_BUILD_TYPE=Release
# -O3: Enable all compiler optimizations
# -g: Enable symbols for profiler tools (TODO: remove for shipping)
# -DNDEBUG: Turn off dchecks/asserts/debug only code.
# -fno-omit-frame-pointer
# use frame pointers to allow simple stack frame walking for backtraces.
# This has a small perf hit but worth it for the ability to profile in production
# For profile guided optimization (PGO) builds, in addition to the flags for release builds:
# 1. Build first with CMAKE_BUILD_TYPE_PROFILE_GEN:
# -fprofile-generate: Indicates compiler should insert profile guided optimization events
# 2. Run the benchmarks (generates *.gcda profiling data).
# 3. Build again with CMAKE_BUILD_TYPE_PROFILE_BUILD
# -fprofile-use: Compiler will use the profile outputs for optimizations
set(CXX_FLAGS_DEBUG "-ggdb")
set(CXX_FLAGS_FASTDEBUG "-ggdb -O1 -fno-omit-frame-pointer")
set(CXX_FLAGS_RELEASE "-O3 -g -DNDEBUG -fno-omit-frame-pointer")
set(CXX_FLAGS_PROFILE_GEN "${CXX_FLAGS_RELEASE} -fprofile-generate")
set(CXX_FLAGS_PROFILE_BUILD "${CXX_FLAGS_RELEASE} -fprofile-use")
# if no build build type is specified, default to debug builds
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Debug)
endif(NOT CMAKE_BUILD_TYPE)
string (TOUPPER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE)
# Alias RELEASE as RELWITHDEBINFO and MINSIZEREL. These are common CMake
# release type names and this provides compatibility with the CLion IDE.
if ("${CMAKE_BUILD_TYPE}" STREQUAL "RELWITHDEBINFO" OR "${CMAKE_BUILD_TYPE}" STREQUAL "MINSIZEREL")
set(CMAKE_BUILD_TYPE RELEASE)
endif ()
# Append to compile flags based on the build type. It's important not to clobber
# CMAKE_CXX_FLAGS because it may contain flags specified by the user.
message("Configured for ${CMAKE_BUILD_TYPE} build (set with cmake -DCMAKE_BUILD_TYPE={release,debug,...})")
if ("${CMAKE_BUILD_TYPE}" STREQUAL "DEBUG")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_FLAGS_DEBUG}")
elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "FASTDEBUG")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_FLAGS_FASTDEBUG}")
elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_FLAGS_RELEASE}")
elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "PROFILE_GEN")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_FLAGS_PROFILE_GEN}")
elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "PROFILE_BUILD")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX_FLAGS_PROFILE_BUILD}")
else()
message(FATAL_ERROR "Unknown build type: ${CMAKE_BUILD_TYPE}")
endif ()
# Add common flags
set(CMAKE_CXX_FLAGS "${CXX_COMMON_FLAGS} ${CMAKE_CXX_FLAGS}")
if ("${COMPILER_FAMILY}" STREQUAL "clang")
# Ensure that we don't use old versions of clang. There isn't anything
# particularly wrong with those, but no reason to support going back
# this far.
if ("${COMPILER_VERSION}" VERSION_LESS "6.0")
message(FATAL_ERROR "Clang version ${COMPILER_VERSION} too old. "
"Consider using the version of clang in ${THIRDPARTY_TOOLCHAIN_DIR}:\n"
""
" CC=${BUILD_SUPPORT_DIR}/ccache-clang/clang CXX=$CC++ cmake <args>")
endif()
# Using Clang with ccache causes a bunch of spurious warnings that are
# purportedly fixed in the next version of ccache. See the following for details:
#
# http://petereisentraut.blogspot.com/2011/05/ccache-and-clang.html
# http://petereisentraut.blogspot.com/2011/09/ccache-and-clang-part-2.html
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Qunused-arguments")
# Clang generates ambiguous member template warnings when calling the ev++ api.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-ambiguous-member-template")
# Emit a warning when the method/function marked as deprecated
# in its in-line documentation but lacks the deprecated attribute
# ATTRIBUTE_DEPRECATED in its signature.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wdocumentation-deprecated-sync")
# Avoid 'taking address of packed member' warnings, which pollute macOs/clang 4.0 builds.
# This is also done in chromium. See:
# https://bugs.chromium.org/p/chromium/issues/detail?id=619640
# Unfortunately older versions of clang complain about not knowing the warning, so
# this also disables the warning about unknown warnings.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unknown-warning-option -Wno-address-of-packed-member")
# Only hardcode -fcolor-diagnostics if stderr is opened on a terminal. Otherwise
# the color codes show up as noisy artifacts.
#
# This test is imperfect because 'cmake' and 'make' can be run independently
# (with different terminal options), and we're testing during the former.
#
# We also provide a manual override as -DKUDU_FORCE_COLOR_DIAGNOSTICS=1 or
# by setting an environment variable of the same name.
execute_process(COMMAND test -t 2 RESULT_VARIABLE KUDU_IS_TTY)
if ((NOT "${KUDU_FORCE_COLOR_DIAGNOSTICS}" STREQUAL "") OR
(NOT "$ENV{KUDU_FORCE_COLOR_DIAGNOSTICS}" STREQUAL "") OR
((${KUDU_IS_TTY} EQUAL 0) AND (NOT ("$ENV{TERM}" STREQUAL "dumb"))))
message("Running in a controlling terminal")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcolor-diagnostics")
else()
message("Running without a controlling terminal or in a dumb terminal")
endif()
elseif("${COMPILER_FAMILY}" STREQUAL "gcc")
# Disallow GCC < 7.0, since it doesn't support the C++17 standard
# well enough for us. https://en.cppreference.com/w/cpp/compiler_support
if ("${COMPILER_VERSION}" VERSION_LESS "7.0")
message(FATAL_ERROR "GCC <7.0 not supported. Consider using "
"thirdparty/clang-toolchain/ to build on older hosts.")
endif()
endif()
# Sanity check linking option.
if (NOT KUDU_LINK)
set(KUDU_LINK "a")
elseif(NOT ("auto" MATCHES "^${KUDU_LINK}" OR
"dynamic" MATCHES "^${KUDU_LINK}" OR
"static" MATCHES "^${KUDU_LINK}"))
message(FATAL_ERROR "Unknown value for KUDU_LINK, must be auto|dynamic|static")
else()
# Remove all but the first letter.
string(SUBSTRING "${KUDU_LINK}" 0 1 KUDU_LINK)
endif()
# If not set, any file that includes kudu_export.h (an autogenerated file) will
# use visibility("hidden") with symbols annotated with KUDU_NO_EXPORT, even when
# compiled with default visibility flags. It is overridden as needed by
# ADD_EXPORTABLE_LIBRARY() when actually compiling exported library variants.
add_definitions("-DKUDU_STATIC_DEFINE")
# Clang does not support using ASAN and TSAN simultaneously.
if ("${KUDU_USE_ASAN}" AND "${KUDU_USE_TSAN}")
message(SEND_ERROR "Can only enable one of ASAN or TSAN at a time")
endif()
# Flag to enable clang address sanitizer (using it along with leak sanitizer).
# This will only build if clang or a recent enough gcc is the chosen compiler.
if (${KUDU_USE_ASAN})
if(NOT (("${COMPILER_FAMILY}" STREQUAL "clang") OR
("${COMPILER_FAMILY}" STREQUAL "gcc" AND "${COMPILER_VERSION}" VERSION_GREATER "4.8")))
message(SEND_ERROR "Cannot use ASAN without clang or gcc >= 4.8")
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -DADDRESS_SANITIZER")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DLEAK_SANITIZER")
endif()
if (${KUDU_USE_XRAY})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fxray-instrument")
endif()
# For any C code, use the same flags.
set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17")
# Enable the Clang undefined behavior (UB) sanitizer.
if (${KUDU_USE_UBSAN})
if(NOT (("${COMPILER_FAMILY}" STREQUAL "clang") OR
("${COMPILER_FAMILY}" STREQUAL "gcc" AND "${COMPILER_VERSION}" VERSION_GREATER "4.9")))
message(SEND_ERROR "Cannot use UBSAN without clang or gcc >= 4.9")
endif()
# Enable UB and unsigned integer overflow detection.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined,integer")
# Disable 'alignment' because unaligned access is really OK on Nehalem and we do it all over the place.
# TODO(todd): enable implicit-integer-sign-change checking after fixing issues.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-sanitize=alignment,implicit-integer-sign-change,implicit-unsigned-integer-truncation,implicit-signed-integer-truncation")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize-blacklist=${CMAKE_CURRENT_SOURCE_DIR}/build-support/ubsan-blacklist.txt")
# Stop execution after UB or overflow is detected.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-sanitize-recover=undefined,integer")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUNDEFINED_SANITIZER")
endif ()
# Flag to enable thread sanitizer (clang or gcc 4.8)
if (${KUDU_USE_TSAN})
if(NOT (("${COMPILER_FAMILY}" STREQUAL "clang") OR
("${COMPILER_FAMILY}" STREQUAL "gcc" AND "${COMPILER_VERSION}" VERSION_GREATER "4.8")))
message(SEND_ERROR "Cannot use TSAN without clang or gcc >= 4.8")
endif()
add_definitions("-fsanitize=thread")
# Enables dynamic_annotations.h to actually generate code
add_definitions("-DDYNAMIC_ANNOTATIONS_ENABLED")
# changes atomicops to use the tsan implementations
add_definitions("-DTHREAD_SANITIZER")
# Disables using the precompiled template specializations for std::string, shared_ptr, etc
# so that the annotations in the header actually take effect.
add_definitions("-D_GLIBCXX_EXTERN_TEMPLATE=0")
# Compile and link against the thirdparty TSAN instrumented libstdcxx.
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath,${THIRDPARTY_INSTALL_TSAN_DIR}/lib")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=thread")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdinc++")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${THIRDPARTY_INSTALL_TSAN_DIR}/lib")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${THIRDPARTY_INSTALL_TSAN_DIR}/include/c++/v1")
# Strictly speaking, TSAN doesn't require dynamic linking. But it does
# require all code to be position independent, and the easiest way to
# guarantee that is via dynamic linking (not all 3rd party archives are
# compiled with -fPIC e.g. boost).
if(NOT "${ARCH_NAME}" MATCHES "aarch64")
if("${KUDU_LINK}" STREQUAL "a")
message("Using dynamic linking for TSAN")
set(KUDU_LINK "d")
elseif("${KUDU_LINK}" STREQUAL "s")
message(SEND_ERROR "Cannot use TSAN with static linking")
endif()
else()
# workaround for github.com/google/sanitizers/issues/1208
# TSAN with dynamic linking cause all of test cases failed on aarch64,
# we don't apply ENABLE_DIST_TEST on aarch64, so apply static linking direcly
message("Using static linking for TSAN on aarch64")
set(KUDU_LINK "s")
endif()
endif()
# If we still don't know what kind of linking to perform, choose based on
# build type (developers like fast builds).
if ("${KUDU_LINK}" STREQUAL "a")
if ("${CMAKE_BUILD_TYPE}" STREQUAL "DEBUG" OR
"${CMAKE_BUILD_TYPE}" STREQUAL "FASTDEBUG")
message("Using dynamic linking for ${CMAKE_BUILD_TYPE} builds")
set(KUDU_LINK "d")
else()
message("Using static linking for ${CMAKE_BUILD_TYPE} builds")
set(KUDU_LINK "s")
endif()
endif()
include("KuduLinker")
APPEND_LINKER_FLAGS()
if ("${KUDU_USE_ASAN}" OR "${KUDU_USE_TSAN}" OR "${KUDU_USE_UBSAN}")
# GCC 4.8 and 4.9 (latest as of this writing) don't allow you to specify a
# sanitizer blacklist.
if("${COMPILER_FAMILY}" STREQUAL "clang")
add_definitions("-fsanitize-blacklist=${BUILD_SUPPORT_DIR}/sanitize-blacklist.txt")
else()
message(WARNING "GCC does not support specifying a sanitizer blacklist. Known sanitizer check failures will not be suppressed.")
endif()
endif()
if (KUDU_USE_LTO)
if(NOT "${CMAKE_EXE_LINKER_FLAGS}" MATCHES "-fuse-ld=lld" OR
NOT "${COMPILER_FAMILY}" STREQUAL "clang")
message(FATAL_ERROR "must use clang and lld for LTO build")
endif()
if (NOT "${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE")
# Doesn't make much sense to do LTO on a non-release build -- it's slow
# and the only reason you'd want to do it is high performance.
message(FATAL_ERROR "LTO only supported for release builds")
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto=thin")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--thinlto-cache-dir=${CMAKE_CURRENT_BINARY_DIR}/lto.cache")
set(CMAKE_AR "${THIRDPARTY_TOOLCHAIN_DIR}/bin/llvm-ar")
set(CMAKE_RANLIB "${THIRDPARTY_TOOLCHAIN_DIR}/bin/llvm-ranlib")
endif()
# Code coverage
if ("${KUDU_GENERATE_COVERAGE}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage -DCOVERAGE_BUILD")
if(NOT "${COMPILER_FAMILY}" STREQUAL "clang")
# Use clang for coverage builds so that we can standardize on a single
# compiler. clang also handles flushing coverage from shared libraries
# better than gcc.
message(SEND_ERROR "Must use clang for coverage build")
endif()
endif()
# Having set KUDU_LINK due to build type and/or sanitizer, it's now safe to
# act on its value.
if ("${KUDU_LINK}" STREQUAL "d")
set(BUILD_SHARED_LIBS ON)
# Position independent code is only necessary when producing shared objects.
add_definitions(-fPIC)
endif()
# where to put generated archives (.a files)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib")
file(MAKE_DIRECTORY "${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}")
# where to put generated libraries (.so files)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib")
file(MAKE_DIRECTORY "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}")
# where to put generated binaries
set(EXECUTABLE_OUTPUT_PATH "${CMAKE_CURRENT_BINARY_DIR}/bin")
file(MAKE_DIRECTORY "${EXECUTABLE_OUTPUT_PATH}")
include_directories(${CMAKE_CURRENT_BINARY_DIR}/src)
include_directories(src)
include_directories(SYSTEM ${THIRDPARTY_INSTALL_COMMON_DIR}/include)
############################################################
# Visibility
############################################################
# For generate_export_header() and add_compiler_export_flags().
include(GenerateExportHeader)
# Honor visibility properties for all target types. See
# "cmake --help-policy CMP0063" for details.
#
# This policy was only added to cmake in version 3.3, so until the cmake in
# thirdparty is updated, we must check if the policy exists before setting it.
if(POLICY CMP0063)
cmake_policy(SET CMP0063 NEW)
endif()
# add_library() wrapper that adds a second variant of the library for use in the
# exported Kudu C++ client. This variant is suffixed with "_exported" and is
# compiled with special visibility flags to hide all symbols except those that
# are part of the public ABI.
#
# There are two different kinds of exported libraries: internal and leaf.
# Internal libraries are static archives while leaf libraries are shared
# objects built from internal libraries. In practice there is only one leaf
# library: the Kudu C++ client itself.
#
# Arguments:
#
# LIB_NAME is the name of the library. It must come first. Required.
#
# SRCS is the list of source files to compile into the library. Required.
#
# DEPS is the list of targets that both library variants depend on. Required.
#
# NONLINK_DEPS is the list of (non-linked) targets that both library variants
# depend on. Optional.
#
# COMPILE_FLAGS is a string containing any additional compilation flags that
# should be added to both library variants. Optional.
#
# EXPORTED_SHARED is a toggle that, if set, indicates that the exported variant
# is a "leaf" library. Otherwise it is an "internal" library. Optional.
#
# EXPORTED_OUTPUT_NAME is a string describing a different file name for the
# exported library variant. If not set, defaults to LIB_NAME. Optional.
#
# EXPORTED_OUTPUT_DIRECTORY is a string describing a different directory where
# the exported library variant should be written. If not set, defaults to the
# directory where this function was called. Optional.
#
# EXPORTED_DEPS is a list of targets that the exported library variant depends
# on. If not set, defaults to DEPS. Optional.
function(ADD_EXPORTABLE_LIBRARY LIB_NAME)
# Parse the arguments.
set(options EXPORTED_SHARED)
set(one_value_args COMPILE_FLAGS EXPORTED_OUTPUT_NAME EXPORTED_OUTPUT_DIRECTORY)
set(multi_value_args SRCS DEPS EXPORTED_DEPS NONLINK_DEPS)
cmake_parse_arguments(ARG "${options}" "${one_value_args}" "${multi_value_args}" ${ARGN})
if(ARG_UNPARSED_ARGUMENTS)
message(SEND_ERROR "Error: unrecognized arguments: ${ARG_UNPARSED_ARGUMENTS}")
endif()
# First add the regular version of the library. It uses
# whatever linkage was defined globally.
add_library(${LIB_NAME} ${ARG_SRCS})
if(ARG_COMPILE_FLAGS)
set_target_properties(${LIB_NAME}
PROPERTIES COMPILE_FLAGS ${ARG_COMPILE_FLAGS})
endif()
target_link_libraries(${LIB_NAME} ${ARG_DEPS})
if(ARG_NONLINK_DEPS)
add_dependencies(${LIB_NAME} ${ARG_NONLINK_DEPS})
endif()
# Now start setting up the exported variant.
set(EXPORTED_LIB_NAME ${LIB_NAME}_exported)
if(ARG_EXPORTED_SHARED)
# Leaf library.
set(EXPORTED_LINKAGE "SHARED")
set(EXPORTED_LINK_PRIVATE "LINK_PRIVATE")
else()
# Internal library.
set(EXPORTED_LINKAGE "STATIC")
set(EXPORTED_LINK_PRIVATE)
endif()
add_library(${EXPORTED_LIB_NAME} ${EXPORTED_LINKAGE} ${ARG_SRCS})
# Compile with visibility flags:
# - default for classes annotated with KUDU_EXPORT.
# - hidden for classes annotated with KUDU_NO_EXPORT.
# - hidden for everything else.
if(POLICY CMP0063)
set_target_properties(${EXPORTED_LIB_NAME}
PROPERTIES C_VISIBILITY_PRESET hidden)
set_target_properties(${EXPORTED_LIB_NAME}
PROPERTIES CXX_VISIBILITY_PRESET hidden)
set_target_properties(${EXPORTED_LIB_NAME}
PROPERTIES VISIBILITY_INLINES_HIDDEN 1)
else()
add_compiler_export_flags(EXPORTED_FLAGS)
endif()
# Exported variants are either static archives that will be linked to a shared
# object, or shared objects. Either way, -fPIC is needed.
if("${KUDU_LINK}" STREQUAL "s")
set(EXPORTED_FLAGS "${EXPORTED_FLAGS} -fPIC")
endif()
# We need to remove some definitions previously added at directory scope.
# There doesn't appear to be a good way to do this in cmake, so we do it via
# the compiler with -U (e.g. "-UFOO" means "undefine the FOO definition").
# Adding insult to injury, the COMPILE_DEFINITIONS property adds a -D prefix
# to anything passed into it, so we're forced to handle the removal via
# COMPILE_FLAGS, which, lucky for us, is emitted on the command line after
# COMPILE_DEFINITIONS.
# Exported variants need KUDU_EXPORT definitions to take effect.
set(EXPORTED_FLAGS "${EXPORTED_FLAGS} -UKUDU_STATIC_DEFINE")
# Exported variants may not use tcmalloc.
set(EXPORTED_FLAGS "${EXPORTED_FLAGS} -UTCMALLOC_ENABLED")
# Exported variants should conform to the C++03 ABI, which doesn't
# include sized deallocation (new in C++14). This reverses the setting from
# non-exported (default) flags.
if(COMPILER_SUPPORTS_SIZED_DEALLOCATION)
# Note: this is retained by the set_target_properties() call below.
target_compile_options(${EXPORTED_LIB_NAME}
PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-fno-sized-deallocation>)
endif()
set_target_properties(${EXPORTED_LIB_NAME}
PROPERTIES COMPILE_FLAGS "${ARG_COMPILE_FLAGS} ${EXPORTED_FLAGS}")
# Handle EXPORTED_OUTPUT_NAME and EXPORTED_OUTPUT_DIRECTORY.
if(ARG_EXPORTED_OUTPUT_NAME)
set_target_properties(${EXPORTED_LIB_NAME}
PROPERTIES LIBRARY_OUTPUT_NAME ${ARG_EXPORTED_OUTPUT_NAME})
endif()
if(ARG_EXPORTED_OUTPUT_DIRECTORY)
set_target_properties(${EXPORTED_LIB_NAME}
PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${ARG_EXPORTED_OUTPUT_DIRECTORY})
endif()
# Set up exported variant dependent targets.
#
# Every linked dependency is suffixed with "_exported". This is fine; the
# exported target graph is expected to be complete, and ADD_THIRDPARTY_LIB
# will provide an "exported variant" for each third party target.
if(ARG_EXPORTED_DEPS)
set(EXPORTED_DEPS ${ARG_EXPORTED_DEPS})
else()
set(EXPORTED_DEPS ${ARG_DEPS})
endif()
foreach(DEP ${EXPORTED_DEPS})
list(APPEND EXPORTED_SUFFIXED_DEPS "${DEP}_exported")
endforeach()
target_link_libraries(${EXPORTED_LIB_NAME} ${EXPORTED_LINK_PRIVATE} ${EXPORTED_SUFFIXED_DEPS})
if(ARG_NONLINK_DEPS)
add_dependencies(${EXPORTED_LIB_NAME} ${ARG_NONLINK_DEPS})
endif()
endfunction()
############################################################
# Testing
############################################################
# Add a new binary that is compiled just like a unit test but is not executed
# by or registered with "ctest". Useful for writing tests that use the Google
# Test infrastructure but cannot or should not be run pre-commit.
function(ADD_KUDU_TEST_NO_CTEST REL_TEST_NAME)
get_filename_component(TEST_NAME ${REL_TEST_NAME} NAME_WE)
add_executable(${TEST_NAME} "${REL_TEST_NAME}.cc")
target_link_libraries(${TEST_NAME} ${KUDU_TEST_LINK_LIBS})
endfunction()
# Add a new test case, with or without an executable that should be built.
#
# REL_TEST_NAME is the name of the test. It may be a single component
# (e.g. monotime-test) or contain additional components (e.g.
# net/net_util-test). Either way, the last component must be a globally
# unique name.
#
# Additional optional arguments:
#
# TIMEOUT <secs>
# Sets a timeout for running this test.
#
# NOTE: this only affects the test timeout when run via 'ctest'.
# Jenkins builds typically execute tests using dist-test, and that
# does not respect these timeouts. If a test suite is long enough
# to require a bumped timeout, consider enabling sharding of the
# test (see below).
#
# NUM_SHARDS <num shards>
# Sets the number of shards used for running this test.
#
# This configuration splits up the test cases within the binary
# into several separate shards. Each shard becomes a separate
# test case when run by ctest or when submitted for distributed testing.
# This should be used whenever a test binary is long-running and
# consists of many separate test cases.
#
# NOTE: sharding is still recommended even for tests with RUN_SERIAL
# or RESOURCE_LOCK properties. Even though the shards cannot run in
# parallel on a single machine using ctest, they will still run in
# parallel across separate machines using dist-test.
#
# PROCESSORS <num processors>
# RUN_SERIAL true
# These built-in CMake properties should be used when a test is
# a heavy consumer of CPU.
#
# The PROCESSORS flag allows ctest to ensure that tests are only
# scheduled in parallel when an appropriate number of cores are
# available. The default is to assume that a test uses a single core
# (i.e. equivalent to PROCESSORS 1).
#
# RUN_SERIAL ensures that the test does not run in parallel with any
# other test. This should be used for stress tests which start many
# threads and attempt to monopolize the machine.
#
# In order to determine an appropriate setting, you can run the test
# with the KUDU_MEASURE_TEST_CPU_CONSUMPTION environment variable
# set. See build-support/run-test.sh for more details.
#
# DATA_FILES <file1> <file2> ...
# Specify data files that should be copied into the build directory next
# to test executable into the 'testdata' sub-directory, i.e. into
# '<build_dir>/bin/testdata' with current layout of the test binaries.
# The path to the source file should be specified from the location
# of the corresponding CMakeLists.txt file.
#
# Any other arguments will be passed to set_tests_properties().
function(ADD_KUDU_TEST REL_TEST_NAME)
# Parse out properties for which we have special handling.
set(options)
set(one_value_args TIMEOUT NUM_SHARDS)
set(multi_value_args DATA_FILES)
cmake_parse_arguments(ARG "${options}" "${one_value_args}" "${multi_value_args}" ${ARGN})
if(NOT ARG_TIMEOUT)
# Default to 15 minutes.
# NOTE: this should be kept in sync with the default value of KUDU_TEST_TIMEOUT
# in build-support/run-test.sh
set(ARG_TIMEOUT 900)
endif()
if(NOT ARG_NUM_SHARDS)
set(ARG_NUM_SHARDS 1)
endif()
# Any unrecognized arguments go into ${ARG_UNPARSED_ARGUMENTS}, which we forward
# along as properties down below.
if(NO_TESTS)
return()
endif()
get_filename_component(TEST_NAME ${REL_TEST_NAME} NAME_WE)
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${REL_TEST_NAME}.cc)
# This test has a corresponding .cc file, set it up as an executable.
set(TEST_PATH "${EXECUTABLE_OUTPUT_PATH}/${TEST_NAME}")
ADD_KUDU_TEST_NO_CTEST(${REL_TEST_NAME})
elseif(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${REL_TEST_NAME})
# No executable, just invoke the test (probably a script) directly.
get_filename_component(TEST_NAME_WITH_EXT ${REL_TEST_NAME} NAME)
set(TEST_PATH "${EXECUTABLE_OUTPUT_PATH}/${TEST_NAME_WITH_EXT}")
# Ideally this would run only when the test is built, not when cmake runs,
# but add_test() doesn't yield a target (if it did, that target could depend
# on an add_custom_command() that copies the test file into place).
execute_process(COMMAND ln -sf ${CMAKE_CURRENT_SOURCE_DIR}/${REL_TEST_NAME}
${EXECUTABLE_OUTPUT_PATH})
else()
message(FATAL_ERROR "Neither ${REL_TEST_NAME} nor ${REL_TEST_NAME}.cc were found in ${CMAKE_CURRENT_SOURCE_DIR}/")
endif()
# Copy data files into the build directory.
set(DATA_FILES_DST_SUBDIR testdata)
set(DST_DIR ${EXECUTABLE_OUTPUT_PATH}/${DATA_FILES_DST_SUBDIR})
set(DATA_FILES_LIST)
foreach(DATA_FILE ${ARG_DATA_FILES})
get_filename_component(DATA_FILE_NAME ${DATA_FILE} NAME)
list(APPEND DATA_FILES_LIST ${DATA_FILES_DST_SUBDIR}/${DATA_FILE_NAME})
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/${DATA_FILE}
# Copy with read and execute permissions, since tests should not modify
# the data files in place, but data files may be scripts used by tests.
DIRECTORY_PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE
FILE_PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE
DESTINATION ${DST_DIR})
endforeach()
math(EXPR MAX_SHARD "${ARG_NUM_SHARDS} - 1")
foreach(SHARD_NUM RANGE ${MAX_SHARD})
# Only name the targets with a '.<shard>' if the test is sharded.
if(${ARG_NUM_SHARDS} EQUAL 1)
set(TARGET ${TEST_NAME})
else()
set(TARGET ${TEST_NAME}.${SHARD_NUM})
endif()
add_test(${TARGET}
${BUILD_SUPPORT_DIR}/run-test.sh ${TEST_PATH})
if(ARG_UNPARSED_ARGUMENTS)
set_tests_properties(${TARGET} PROPERTIES ${ARG_UNPARSED_ARGUMENTS})
endif()
# Set the ctest timeout to be a bit longer than the timeout we pass to
# our test wrapper. This gives the test wrapper some opportunity to do
# things like dump stacks, compress the log, etc.
math(EXPR EXTENDED_TIMEOUT "${ARG_TIMEOUT} + 30")
# Add the configured timeout to the environment for the test wrapper.
get_test_property(${TARGET} ENVIRONMENT CUR_TEST_ENV)
if(NOT CUR_TEST_ENV)
set(CUR_TEST_ENV "")
endif()
list(APPEND CUR_TEST_ENV "KUDU_TEST_TIMEOUT=${ARG_TIMEOUT}")
list(APPEND CUR_TEST_ENV "GTEST_TOTAL_SHARDS=${ARG_NUM_SHARDS}")
list(APPEND CUR_TEST_ENV "GTEST_SHARD_INDEX=${SHARD_NUM}")
# The only way we can pass information to dist-test is through the environment.
# So, use a comma-delimited environment variable to pass the list of data files
# that need to be uploaded.
if(DATA_FILES_LIST)
string(REPLACE ";" "," DATA_FILES_ENV "${DATA_FILES_LIST}")
list(APPEND CUR_TEST_ENV "KUDU_DATA_FILES=${DATA_FILES_ENV}")
endif()
set_tests_properties(${TARGET} PROPERTIES
TIMEOUT ${EXTENDED_TIMEOUT}
ENVIRONMENT "${CUR_TEST_ENV}")
endforeach(SHARD_NUM)
endfunction()
# A wrapper for add_dependencies() that is compatible with NO_TESTS.
function(ADD_KUDU_TEST_DEPENDENCIES REL_TEST_NAME)
if(NO_TESTS)
return()
endif()
get_filename_component(TEST_NAME ${REL_TEST_NAME} NAME_WE)
add_dependencies(${TEST_NAME} ${ARGN})
endfunction()
enable_testing()
############################################################
# Dependencies
############################################################
function(ADD_THIRDPARTY_LIB LIB_NAME)
set(options)
set(one_value_args SHARED_LIB STATIC_LIB)
set(multi_value_args DEPS)
cmake_parse_arguments(ARG "${options}" "${one_value_args}" "${multi_value_args}" ${ARGN})
if(ARG_UNPARSED_ARGUMENTS)
message(SEND_ERROR "Error: unrecognized arguments: ${ARG_UNPARSED_ARGUMENTS}")
endif()
if(("${KUDU_LINK}" STREQUAL "s" AND ARG_STATIC_LIB) OR (NOT ARG_SHARED_LIB))
if(NOT ARG_STATIC_LIB)
message(FATAL_ERROR "No static or shared library provided for ${LIB_NAME}")
endif()
add_library(${LIB_NAME} STATIC IMPORTED)
set_target_properties(${LIB_NAME}
PROPERTIES IMPORTED_LOCATION "${ARG_STATIC_LIB}")
message("Added static library dependency ${LIB_NAME}: ${ARG_STATIC_LIB}")
else()
add_library(${LIB_NAME} SHARED IMPORTED)
set_target_properties(${LIB_NAME}
PROPERTIES IMPORTED_LOCATION "${ARG_SHARED_LIB}")
message("Added shared library dependency ${LIB_NAME}: ${ARG_SHARED_LIB}")
endif()
if(ARG_DEPS)
set_target_properties(${LIB_NAME}
PROPERTIES IMPORTED_LINK_INTERFACE_LIBRARIES "${ARG_DEPS}")
endif()
# Set up an "exported variant" for this thirdparty library (see "Visibility"
# above). It's the same as the real target, just with an "_exported" suffix.
# We prefer the static archive if it exists (as it's akin to an "internal"
# library), but we'll settle for the shared object if we must.
#
# A shared object exported variant will force any "leaf" library that
# transitively depends on it to also depend on it at runtime; this is
# desirable for some libraries (e.g. cyrus_sasl).
set(LIB_NAME_EXPORTED "${LIB_NAME}_exported")
if(ARG_STATIC_LIB)
add_library(${LIB_NAME_EXPORTED} STATIC IMPORTED)
set_target_properties(${LIB_NAME_EXPORTED}
PROPERTIES IMPORTED_LOCATION "${ARG_STATIC_LIB}")
else()
add_library(${LIB_NAME_EXPORTED} SHARED IMPORTED)
set_target_properties(${LIB_NAME_EXPORTED}
PROPERTIES IMPORTED_LOCATION "${ARG_SHARED_LIB}")
endif()
if(ARG_DEPS)
foreach(DEP ${ARG_DEPS})
list(APPEND EXPORTED_DEPS "${DEP}_exported")
endforeach()
set_target_properties(${LIB_NAME_EXPORTED}
PROPERTIES IMPORTED_LINK_INTERFACE_LIBRARIES "${EXPORTED_DEPS}")
endif()
endfunction()
if (${KUDU_USE_TSAN})
set(THIRDPARTY_INSTALL_CURRENT_DIR ${THIRDPARTY_INSTALL_DIR}/tsan)
else()
set(THIRDPARTY_INSTALL_CURRENT_DIR ${THIRDPARTY_INSTALL_DIR}/uninstrumented)
endif()
# Look in thirdparty prefix paths before anywhere else for system dependencies.
set(CMAKE_PREFIX_PATH
${THIRDPARTY_INSTALL_COMMON_DIR}
${THIRDPARTY_INSTALL_CURRENT_DIR}
${CMAKE_PREFIX_PATH})
## Cyrus SASL
find_package(CyrusSASL REQUIRED)
include_directories(SYSTEM ${CYRUS_SASL_INCLUDE_DIR})
ADD_THIRDPARTY_LIB(cyrus_sasl
SHARED_LIB "${CYRUS_SASL_SHARED_LIB}")
## GSSAPI
find_package(GSSAPI REQUIRED)
include_directories(SYSTEM ${GSSAPI_INCLUDE_DIR})
ADD_THIRDPARTY_LIB(gssapi_krb5
SHARED_LIB "${GSSAPI_SHARED_LIB}")
## GLog (depends on libunwind)
find_package(GLog REQUIRED)
include_directories(SYSTEM ${GLOG_INCLUDE_DIR})
set(GLOG_DEPS)
if (NOT APPLE)
set(GLOG_DEPS unwind)
endif()
ADD_THIRDPARTY_LIB(glog
STATIC_LIB "${GLOG_STATIC_LIB}"
SHARED_LIB "${GLOG_SHARED_LIB}"
DEPS "${GLOG_DEPS}")
list(APPEND KUDU_BASE_LIBS glog)
## libunwind
##
## Doesn't build on OSX.
if (NOT APPLE)
find_package(LibUnwind REQUIRED)
include_directories(SYSTEM ${UNWIND_INCLUDE_DIR})
ADD_THIRDPARTY_LIB(unwind
STATIC_LIB "${UNWIND_STATIC_LIB}"
SHARED_LIB "${UNWIND_SHARED_LIB}")
list(APPEND KUDU_BASE_LIBS unwind)
endif()
## GFlags
find_package(GFlags REQUIRED)
include_directories(SYSTEM ${GFLAGS_INCLUDE_DIR})
ADD_THIRDPARTY_LIB(gflags
STATIC_LIB "${GFLAGS_STATIC_LIB}"
SHARED_LIB "${GFLAGS_SHARED_LIB}")
list(APPEND KUDU_BASE_LIBS gflags)
## GMock
find_package(GMock REQUIRED)
include_directories(SYSTEM ${GMOCK_INCLUDE_DIR} ${GTEST_INCLUDE_DIR})
ADD_THIRDPARTY_LIB(gmock
STATIC_LIB ${GMOCK_STATIC_LIBRARY}
SHARED_LIB ${GMOCK_SHARED_LIBRARY})
## Protobuf
find_package(Protobuf REQUIRED)
include_directories(SYSTEM ${PROTOBUF_INCLUDE_DIR})
ADD_THIRDPARTY_LIB(protobuf
STATIC_LIB "${PROTOBUF_STATIC_LIBRARY}"
SHARED_LIB "${PROTOBUF_SHARED_LIBRARY}")
ADD_THIRDPARTY_LIB(protoc
STATIC_LIB "${PROTOBUF_PROTOC_STATIC_LIBRARY}"
SHARED_LIB "${PROTOBUF_PROTOC_SHARED_LIBRARY}"
DEPS protobuf)
find_package(KRPC REQUIRED)
## Thrift
find_package(Thrift REQUIRED)
include_directories(SYSTEM ${THRIFT_INCLUDE_DIR})
ADD_THIRDPARTY_LIB(thrift
STATIC_LIB "${THRIFT_STATIC_LIBRARY}"
SHARED_LIB "${THRIFT_SHARED_LIBRARY}")
# The mini-HMS relies on JAVA_HOME being set in order to run the HMS, and
# JDK 1.7 or later for compiling the Kudu metastore plugin.
find_package(JavaHome REQUIRED)
find_package(Java 1.7 REQUIRED)
# Defines the add_jar() CMake command.
include(UseJava)
## Snappy
find_package(Snappy REQUIRED)
include_directories(SYSTEM ${SNAPPY_INCLUDE_DIR})
ADD_THIRDPARTY_LIB(snappy
STATIC_LIB "${SNAPPY_STATIC_LIB}"
SHARED_LIB "${SNAPPY_SHARED_LIB}")
## Libev
find_package(LibEv REQUIRED)
include_directories(SYSTEM ${LIBEV_INCLUDE_DIR})
ADD_THIRDPARTY_LIB(libev
STATIC_LIB "${LIBEV_STATIC_LIB}"
SHARED_LIB "${LIBEV_SHARED_LIB}")
## LZ4
find_package(Lz4 REQUIRED)
include_directories(SYSTEM ${LZ4_INCLUDE_DIR})
ADD_THIRDPARTY_LIB(lz4 STATIC_LIB "${LZ4_STATIC_LIB}")
## Bitshuffle
find_package(Bitshuffle REQUIRED)
include_directories(SYSTEM ${BITSHUFFLE_INCLUDE_DIR})
ADD_THIRDPARTY_LIB(bitshuffle STATIC_LIB "${BITSHUFFLE_STATIC_LIB}")
## ZLib
find_package(Zlib REQUIRED)
include_directories(SYSTEM ${ZLIB_INCLUDE_DIR})
ADD_THIRDPARTY_LIB(zlib
STATIC_LIB "${ZLIB_STATIC_LIB}"
SHARED_LIB "${ZLIB_SHARED_LIB}")
## Squeasel
find_package(Squeasel REQUIRED)
include_directories(SYSTEM ${SQUEASEL_INCLUDE_DIR})
ADD_THIRDPARTY_LIB(squeasel
STATIC_LIB "${SQUEASEL_STATIC_LIB}")
## Mustache
find_package(Mustache REQUIRED)
include_directories(SYSTEM ${MUSTACHE_INCLUDE_DIR})
ADD_THIRDPARTY_LIB(mustache
STATIC_LIB "${MUSTACHE_STATIC_LIB}")
## OpenSSL
##
## Version 1.0.0 or higher is required because we are using the following
## features introduced started OpenSSL 1.0.0:
## * The new breed of functions to work with the X509_EXTENSION stack
## * automatic usage of &errno as a safe per-thread identifier
##
## If having multiple OpenSSL libraries installed on the system,
## use the OPENSSL_ROOT_DIR cmake flag to specify where to look for the proper
## version of the OpenSSL framework/library, e.g.
##
## cmake -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl ...
##
## If no such OPENSSL_ROOT_DIR is specified, and we see that there is an OpenSSL
## binary in thirdparty (deposited there by thirdparty/install-openssl-el6-workaround.sh)
## then we'll use that one. See that script for more information.
set(CENTOS_6_4_OPENSSL_DIR "${THIRDPARTY_INSTALL_DIR}/openssl-el6-workaround/usr/")
if (NOT OPENSSL_ROOT_DIR AND EXISTS "${CENTOS_6_4_OPENSSL_DIR}")
set(OPENSSL_ROOT_DIR "${CENTOS_6_4_OPENSSL_DIR}")
add_definitions("-DKUDU_OPENSSL_REQUIRE_FIPS_HEADER")
endif()
find_package(OpenSSL 1.0.0 REQUIRED)
include_directories(SYSTEM ${OPENSSL_INCLUDE_DIR})
ADD_THIRDPARTY_LIB(openssl_ssl
SHARED_LIB "${OPENSSL_SSL_LIBRARY}")
ADD_THIRDPARTY_LIB(openssl_crypto
SHARED_LIB "${OPENSSL_CRYPTO_LIBRARY}")
## Kerberos
find_package(Kerberos REQUIRED)
include_directories(${KERBEROS_INCLUDE_DIR})
ADD_THIRDPARTY_LIB(krb5
SHARED_LIB "${KERBEROS_LIBRARY}")
if (NO_CHRONY)
add_definitions("-DNO_CHRONY")
endif()
## Google PerfTools
##
## Disabled with TSAN/ASAN.
if (NOT "${KUDU_USE_ASAN}" AND
NOT "${KUDU_USE_TSAN}")
find_package(GPerf REQUIRED)
ADD_THIRDPARTY_LIB(tcmalloc
STATIC_LIB "${TCMALLOC_STATIC_LIB}"
SHARED_LIB "${TCMALLOC_SHARED_LIB}")
ADD_THIRDPARTY_LIB(profiler
STATIC_LIB "${PROFILER_STATIC_LIB}"
SHARED_LIB "${PROFILER_SHARED_LIB}")
list(APPEND KUDU_BASE_LIBS tcmalloc profiler)
add_definitions("-DTCMALLOC_ENABLED")
set(KUDU_TCMALLOC_AVAILABLE 1)
endif()
## curl
find_package(CURL REQUIRED)
include_directories(SYSTEM ${CURL_INCLUDE_DIR})
ADD_THIRDPARTY_LIB(curl
STATIC_LIB "${CURL_STATIC_LIB}"
SHARED_LIB "${CURL_SHARED_LIB}"
DEPS zlib)
## crcutil
find_package(Crcutil REQUIRED)
include_directories(SYSTEM ${CRCUTIL_INCLUDE_DIR})
ADD_THIRDPARTY_LIB(crcutil
STATIC_LIB "${CRCUTIL_STATIC_LIB}"
SHARED_LIB "${CRCUTIL_SHARED_LIB}")
## breakpad
if (NOT APPLE)
find_package(BreakpadClient REQUIRED)
include_directories(SYSTEM ${BREAKPAD_CLIENT_INCLUDE_DIR})
ADD_THIRDPARTY_LIB(breakpad_client
STATIC_LIB "${BREAKPAD_CLIENT_STATIC_LIB}"
SHARED_LIB "${BREAKPAD_CLIENT_SHARED_LIB}")
endif()
## llvm
# Note that llvm has a unique cmake setup. See kudu/codegen/CMakeLists.txt
# for details.
find_package(LLVM REQUIRED CONFIG)
if(${LLVM_PACKAGE_VERSION} VERSION_LESS 3.4)
message(FATAL_ERROR "LLVM version (${LLVM_PACKAGE_VERSION}) must be at least 3.4")
endif()
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
## librt
if (NOT APPLE)
find_library(RT_LIB_PATH rt)
if(NOT RT_LIB_PATH)
message(FATAL_ERROR "Could not find librt on the system path")
endif()
ADD_THIRDPARTY_LIB(rt
SHARED_LIB "${RT_LIB_PATH}")
find_library(DL_LIB_PATH dl)
if(NOT DL_LIB_PATH)
message(FATAL_ERROR "Could not find libdl on the system path")
endif()
ADD_THIRDPARTY_LIB(dl
SHARED_LIB "${DL_LIB_PATH}")
endif()
## Kerberos binaries (kinit, kadmin, etc).
if (NOT NO_TESTS)
## We rely on the Kerberos binaries for testing security.
find_package(KerberosPrograms)
endif()
# The tests as well as any binaries which are run as subprocesses by tests (eg tserver,
# master, and the 'kudu' CLI tool) need to link these in. We have to set them
# here so they are accessible by all targets.
if (NOT APPLE)
set(SANITIZER_OPTIONS_OVERRIDE -Wl,-u_sanitizer_options_link_helper sanitizer_options)
set(KRB5_REALM_OVERRIDE -Wl,--undefined=krb5_realm_override_loaded krb5_realm_override)
else()
set(SANITIZER_OPTIONS_OVERRIDE -Wl,-U,_sanitizer_options_link_helper sanitizer_options)
set(KRB5_REALM_OVERRIDE -Wl,-U,krb5_realm_override_loaded krb5_realm_override)
endif()
## yaml
find_package(Yaml REQUIRED)
include_directories(SYSTEM ${YAML_INCLUDE_DIR})
ADD_THIRDPARTY_LIB(yaml
STATIC_LIB "${YAML_STATIC_LIB}"
SHARED_LIB "${YAML_SHARED_LIB}")
## gumbo-parser
find_package(GumboParser REQUIRED)
include_directories(SYSTEM ${GUMBO_PARSER_INCLUDE_DIR})
ADD_THIRDPARTY_LIB(gumbo-parser
STATIC_LIB "${GUMBO_PARSER_STATIC_LIB}"
SHARED_LIB "${GUMBO_PARSER_SHARED_LIB}")
## gumbo-query
find_package(GumboQuery REQUIRED)
include_directories(SYSTEM ${GUMBO_QUERY_INCLUDE_DIR})
ADD_THIRDPARTY_LIB(gumbo-query
STATIC_LIB "${GUMBO_QUERY_STATIC_LIB}"
SHARED_LIB "${GUMBO_QUERY_SHARED_LIB}"
DEPS gumbo-parser)
## Boost
# We use a custom cmake module and not cmake's FindBoost.
# see: cmake_modules/FindKuduBoost.cmake
find_package(KuduBoost REQUIRED)
include_directories(SYSTEM ${BOOST_INCLUDE_DIR})
ADD_THIRDPARTY_LIB(boost_date_time
STATIC_LIB "${BOOST_DATE_TIME_STATIC_LIB}"
SHARED_LIB "${BOOST_DATE_TIME_SHARED_LIB}")
############################################################
# Enable sized deallocation where supported.
# This happens down here instead of up with the rest of the
# compiler options since we only do this when tcmalloc was
# found and enabled.
############################################################
# On OS X 10.12 (El Capitan), sized-deallocation symbols are missing
# in the libc++ library for some reason.
if (APPLE)
get_filename_component(SIZED_DEALLOCATION_TEST_TCMALLOC_LIBDIR
"${TCMALLOC_STATIC_LIB}" DIRECTORY)
execute_process(
COMMAND printf
"#include <new>\nint main(){(::operator delete)(0,256);return 0;}\n"
COMMAND ${CMAKE_CXX_COMPILER}
-x c++ -fsized-deallocation -O0 -fno-builtin
-L${SIZED_DEALLOCATION_TEST_TCMALLOC_LIBDIR} -ltcmalloc -o /dev/null -
RESULT_VARIABLE SIZED_DEALLOCATION_TEST_RESULT OUTPUT_QUIET ERROR_QUIET)
if (${SIZED_DEALLOCATION_TEST_RESULT} EQUAL 0)
set(COMPILER_SUPPORTS_SIZED_DEALLOCATION TRUE)
endif()
else()
if (KUDU_TCMALLOC_AVAILABLE AND
(("${COMPILER_FAMILY}" STREQUAL "clang") OR
("${COMPILER_FAMILY}" STREQUAL "gcc" AND
"${COMPILER_VERSION}" VERSION_GREATER "5.0")))
set(COMPILER_SUPPORTS_SIZED_DEALLOCATION TRUE)
endif()
endif()
if(COMPILER_SUPPORTS_SIZED_DEALLOCATION)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsized-deallocation")
message("sized-deallocation is ENABLED")
else()
message("sized-deallocation is DISABLED")
endif()
############################################################
# Linker setup
############################################################
set(KUDU_MIN_TEST_LIBS ${KUDU_BASE_LIBS} kudu_test_main kudu_test_util)
# Prepend SANITIZER_OPTIONS_OVERRIDE if this is a sanitizer build.
# SANITIZER_OPTIONS_OVERRIDE needs to be linked first so that it is statically
# linked to the test binaries directly. Otherwise the weakly linked default
# implementations coul be be used when running tests.
if ("${KUDU_USE_ASAN}" OR "${KUDU_USE_TSAN}" OR "${KUDU_USE_UBSAN}")
list(INSERT KUDU_MIN_TEST_LIBS 0 ${SANITIZER_OPTIONS_OVERRIDE})
endif()
set(KUDU_TEST_LINK_LIBS ${KUDU_MIN_TEST_LIBS})
# This macro initializes KUDU_MIN_TEST_LIBS to KUDU_MIN_TEST_LIBS and
# appends the passed list of libraries to the end. This ensures that
# KUDU_MIN_TEST_LIBS is linked first.
macro(SET_KUDU_TEST_LINK_LIBS)
set(KUDU_TEST_LINK_LIBS ${KUDU_MIN_TEST_LIBS})
list(APPEND KUDU_TEST_LINK_LIBS ${ARGN})
endmacro()
# Use "thin archives" for our static libraries. We only use static libraries
# internal to our own build, so thin ones are just as good and much smaller.
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set(CMAKE_CXX_ARCHIVE_CREATE "<CMAKE_AR> qcT <TARGET> <LINK_FLAGS> <OBJECTS>")
set(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> qcT <TARGET> <LINK_FLAGS> <OBJECTS>")
set(CMAKE_CXX_ARCHIVE_APPEND "<CMAKE_AR> qT <TARGET> <LINK_FLAGS> <OBJECTS>")
set(CMAKE_C_ARCHIVE_APPEND "<CMAKE_AR> qT <TARGET> <LINK_FLAGS> <OBJECTS>")
endif()
############################################################
# "make ctags" target
############################################################
if (UNIX)
add_custom_target(ctags ctags --languages=c++,c -L
`find ${CMAKE_CURRENT_SOURCE_DIR}/src
${CMAKE_CURRENT_BINARY_DIR}/src`)
endif (UNIX)
############################################################
# "make etags" target
#
# Requires the exuberant-ctags system package.
############################################################
if (UNIX)
add_custom_target(etags etags --members --declarations
`find ${CMAKE_CURRENT_SOURCE_DIR}/src
${CMAKE_CURRENT_BINARY_DIR}/src
-name \\*.cc -or -name \\*.hh -or -name \\*.cpp -or
-name \\*.h -or -name \\*.c`)
endif (UNIX)
############################################################
# "make cscope" target
############################################################
if (UNIX)
add_custom_target(cscope
find ${CMAKE_CURRENT_SOURCE_DIR}/src
${CMAKE_CURRENT_BINARY_DIR}/src
-name \\*.cc -or -name \\*.hh -or -name \\*.cpp -or
-name \\*.h -or -name \\*.c
> cscope.files && cscope -q -b)
endif (UNIX)
############################################################
# "make lint" target
############################################################
if (UNIX)
# Full lint
add_custom_target(lint ${BUILD_SUPPORT_DIR}/lint.sh)
# Incremental lint - only checks files changed since the last
# merged upstream commit
add_custom_target(ilint ${BUILD_SUPPORT_DIR}/lint.sh -c)
endif (UNIX)
############################################################
# "make pb-gen": generate all protobuf source/header files
############################################################
if (UNIX)
add_custom_target(pb-gen)
endif (UNIX)
############################################################
# "make krpc-gen": generate all KRPC source/header files
############################################################
if (UNIX)
add_custom_target(krpc-gen)
endif (UNIX)
############################################################
# "generated-headers" target
############################################################
if (UNIX)
add_custom_target(generated-headers
DEPENDS pb-gen krpc-gen hms_thrift gen_version_info)
endif (UNIX)
############################################################
# "make iwyu" and "make iwyu-fix" target
############################################################
if (UNIX)
add_custom_target(iwyu ${BUILD_SUPPORT_DIR}/iwyu.py --from-git
DEPENDS generated-headers)
add_custom_target(iwyu-fix ${BUILD_SUPPORT_DIR}/iwyu.py --fix --from-git
DEPENDS generated-headers)
endif (UNIX)
############################################################
# "make tidy" target
############################################################
if (UNIX)
add_custom_target(tidy ${BUILD_SUPPORT_DIR}/tidy.sh)
add_dependencies(tidy generated-headers)
endif (UNIX)
############################################################
# "make docs" target
############################################################
if (UNIX)
add_custom_target(docs
# The docs output HTML will end up in a docs/ subdir.
${CMAKE_CURRENT_SOURCE_DIR}/docs/support/scripts/make_docs.sh
--build_root ${CMAKE_CURRENT_BINARY_DIR})
endif (UNIX)
############################################################
# "make doxygen" target
# Requires doxygen of version >= 1.8.19 that includes the
# fix of a bug that would otherwise fail the build as we
# treat warnings as errors to spot various issues in the
# C++ client API documentation.
############################################################
if (UNIX)
find_package(Doxygen 1.8.19)
if (NOT (DOXYGEN_FOUND AND DOXYGEN_DOT_FOUND))
message(WARNING "Doxygen with Dot support (graphviz) not found: 'doxygen' target is not available")
else ()
if (DOXYGEN_WARN_AS_ERROR)
set(DOXY_CLIENT_API_WARN_AS_ERROR YES)
else()
set(DOXY_CLIENT_API_WARN_AS_ERROR NO)
endif()
set(DOXY_SUBDIR ${CMAKE_CURRENT_BINARY_DIR}/docs/doxygen)
set(DOXY_CLIENT_DESTDIR ${DOXY_SUBDIR}/tmp.client)
set(DOXY_CLIENT_API_CFG ${DOXY_SUBDIR}/client_api.doxy)
set(DOXY_CLIENT_API_FOOTER ${DOXY_SUBDIR}/client_api.footer)
set(DOXY_CLIENT_API_OUTDIR ${DOXY_SUBDIR}/client_api)
list(APPEND DOXY_CLIENT_API_EXCLUDE
"share/doc/kuduClient/examples/example.cc")
# NOTE: DOXY_CLIENT_API_EXCLUDE, DOXY_CLIENT_API_OUTDIR, and
# DOXY_CLIENT_API_FOOTER are used in client_api.doxy.in template file
configure_file(docs/support/doxygen/client_api.doxy.in ${DOXY_CLIENT_API_CFG} @ONLY)
configure_file(docs/support/doxygen/client_api.footer.in ${DOXY_CLIENT_API_FOOTER} @ONLY)
add_custom_target(doxy_install_client_alt_destdir
COMMAND ${CMAKE_COMMAND} -E remove_directory ${DOXY_CLIENT_DESTDIR}
COMMAND DESTDIR=${DOXY_CLIENT_DESTDIR} ${CMAKE_MAKE_PROGRAM} install
COMMENT "Installing Kudu client files into temporary destroot"
)
add_custom_target(doxygen
COMMAND ${DOXYGEN_EXECUTABLE} ${DOXY_CLIENT_API_CFG}
WORKING_DIRECTORY ${DOXY_CLIENT_DESTDIR}/${CMAKE_INSTALL_PREFIX}
COMMENT "Generating Kudu C++ client API documentation"
)
add_dependencies(doxy_install_client_alt_destdir kudu_client_exported)
add_dependencies(doxygen doxy_install_client_alt_destdir)
# If doxygen is present, generate doxygen documentation along with 'docs'.
add_dependencies(docs doxygen)
endif ()
endif (UNIX)
############################################################
# "make site" target
#
# NOTE: It's supposed find_package(Doxygen) has already
# been run at this point.
############################################################
if (UNIX)
if (NOT DOXYGEN_FOUND)
add_custom_target(site
${CMAKE_CURRENT_SOURCE_DIR}/docs/support/scripts/make_site.sh --no-doxygen)
else ()
add_custom_target(site
${CMAKE_CURRENT_SOURCE_DIR}/docs/support/scripts/make_site.sh)
endif ()
endif (UNIX)
############################################################
# Subdirectories
############################################################
add_subdirectory(src/kudu/benchmarks)
add_subdirectory(src/kudu/cfile)
add_subdirectory(src/kudu/client)
add_subdirectory(src/kudu/clock)
add_subdirectory(src/kudu/codegen)
add_subdirectory(src/kudu/common)
add_subdirectory(src/kudu/consensus)
add_subdirectory(src/kudu/experiments)
add_subdirectory(src/kudu/fs)
# Google util libraries borrowed from supersonic, tcmalloc, Chromium, etc.
add_subdirectory(src/kudu/gutil)
add_subdirectory(src/kudu/hms)
add_subdirectory(src/kudu/integration-tests)
add_subdirectory(src/kudu/kserver)
add_subdirectory(src/kudu/master)
add_subdirectory(src/kudu/mini-cluster)
add_subdirectory(src/kudu/postgres)
add_subdirectory(src/kudu/ranger)
add_subdirectory(src/kudu/rebalance)
add_subdirectory(src/kudu/rpc)
add_subdirectory(src/kudu/security)
add_subdirectory(src/kudu/server)
add_subdirectory(src/kudu/subprocess)
add_subdirectory(src/kudu/tablet)
add_subdirectory(src/kudu/thrift)
add_subdirectory(src/kudu/tools)
add_subdirectory(src/kudu/transactions)
add_subdirectory(src/kudu/tserver)
add_subdirectory(src/kudu/util)