You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kudu.apache.org by al...@apache.org on 2020/01/22 19:24:26 UTC
[kudu] 01/04: build: restrict clang version, prefer lld,
enable thinlto
This is an automated email from the ASF dual-hosted git repository.
alexey pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/kudu.git
commit 638d95d295da0bddf3fa157792ec7de8889ac919
Author: Todd Lipcon <to...@apache.org>
AuthorDate: Thu Jan 16 22:29:29 2020 -0800
build: restrict clang version, prefer lld, enable thinlto
* Restricts clang to at least version 6.0, which gets rid of a couple
older special cases.
* We now loop through linkers trying to prefer lld where available,
either using the version provided by the compiler with -fuse-lld or
explicitly passing the path to the toolchain lld. lld should be faster
than gold and GNU ld, and also has the advantage of being a known
quantity within our toolchain.
This fixes ASAN builds on my Ubuntu 18 machine, where the version of
gold that ships with the system can't seem to link ASAN executables.
* Switches the LTO build to use ThinLTO, which provides most of the
performance benefits but at much lower cost.
Change-Id: I09ded0c44c9f7a6839489f0abf5baa4eaf1971f0
Reviewed-on: http://gerrit.cloudera.org:8080/15058
Tested-by: Kudu Jenkins
Reviewed-by: Adar Dembo <ad...@cloudera.com>
---
CMakeLists.txt | 157 ++++++++++-------------------------------
cmake_modules/KuduLinker.cmake | 154 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 191 insertions(+), 120 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0b355c1..8df04a8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -82,6 +82,7 @@ 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)
@@ -122,6 +123,10 @@ endif()
# Compiler flags
############################################################
+# Determine compiler version
+include(CompilerInfo)
+
+
# compiler flags that are common across debug/release builds
# -msse4.2: Enable sse4.2 compiler intrinsics.
execute_process(COMMAND uname -p OUTPUT_VARIABLE ARCH_NAME)
@@ -185,12 +190,6 @@ 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")
-if (NOT "${KUDU_USE_LTO}" STREQUAL "")
- set(CXX_FLAGS_RELEASE "${CXX_FLAGS_RELEASE} -flto -fuse-ld=lld")
- set(CMAKE_AR "llvm-ar")
- set(CMAKE_RANLIB "llvm-ranlib")
-endif()
-
set(CXX_FLAGS_PROFILE_GEN "${CXX_FLAGS_RELEASE} -fprofile-generate")
set(CXX_FLAGS_PROFILE_BUILD "${CXX_FLAGS_RELEASE} -fprofile-use")
@@ -227,10 +226,17 @@ endif ()
# Add common flags
set(CMAKE_CXX_FLAGS "${CXX_COMMON_FLAGS} ${CMAKE_CXX_FLAGS}")
-# Determine compiler version
-include(CompilerInfo)
-
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:
#
@@ -320,18 +326,6 @@ if (${KUDU_USE_ASAN})
message(SEND_ERROR "Cannot use ASAN without clang or gcc >= 4.8")
endif()
- # If UBSAN is also enabled, and we're on clang < 3.5, ensure static linking is
- # enabled. Otherwise, we run into https://llvm.org/bugs/show_bug.cgi?id=18211
- if("${KUDU_USE_UBSAN}" AND
- "${COMPILER_FAMILY}" STREQUAL "clang" AND
- "${COMPILER_VERSION}" VERSION_LESS "3.5")
- if("${KUDU_LINK}" STREQUAL "a")
- message("Using static linking for ASAN+UBSAN build")
- set(KUDU_LINK "s")
- elseif("${KUDU_LINK}" STREQUAL "d")
- message(SEND_ERROR "Cannot use dynamic linking when ASAN and UBSAN are both enabled")
- endif()
- endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -DADDRESS_SANITIZER")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DLEAK_SANITIZER")
endif()
@@ -400,23 +394,36 @@ if (${KUDU_USE_TSAN})
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")
- # Require clang 3.4 or newer; clang 3.3 has issues with TSAN and pthread
- # symbol interception.
- if("${COMPILER_VERSION}" VERSION_LESS "3.4")
- message(SEND_ERROR "Must use clang 3.4 or newer to run a sanitizer build."
- " Try using clang from thirdparty/")
- endif()
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")
@@ -442,93 +449,6 @@ if ("${KUDU_LINK}" STREQUAL "a")
endif()
endif()
-# Interrogates the linker version via the C++ compiler to determine whether
-# we're using the gold linker, and if so, extracts its version.
-#
-# If the gold linker is being used, sets GOLD_VERSION in the parent scope with
-# the extracted version.
-#
-# Any additional arguments are passed verbatim into the C++ compiler invocation.
-function(GET_GOLD_VERSION)
- # The gold linker is only for ELF binaries, which macOS doesn't use.
- if (APPLE)
- return()
- endif()
-
- execute_process(COMMAND ${CMAKE_CXX_COMPILER} "-Wl,--version" ${ARGN}
- ERROR_QUIET
- OUTPUT_VARIABLE LINKER_OUTPUT)
- # We're expecting LINKER_OUTPUT to look like one of these:
- # GNU gold (version 2.24) 1.11
- # GNU gold (GNU Binutils for Ubuntu 2.30) 1.15
- if (LINKER_OUTPUT MATCHES "GNU gold")
- string(REGEX MATCH "GNU gold \\([^\\)]*\\) (([0-9]+\\.?)+)" _ "${LINKER_OUTPUT}")
- if (NOT CMAKE_MATCH_1)
- message(SEND_ERROR "Could not extract GNU gold version. "
- "Linker version output: ${LINKER_OUTPUT}")
- endif()
- set(GOLD_VERSION "${CMAKE_MATCH_1}" PARENT_SCOPE)
- endif()
-endfunction()
-
-# Is the compiler hard-wired to use the gold linker?
-GET_GOLD_VERSION()
-if (GOLD_VERSION)
- set(MUST_USE_GOLD 1)
-else()
- # Can the compiler optionally enable the gold linker?
- GET_GOLD_VERSION("-fuse-ld=gold")
-
- # We can't use the gold linker if it's inside devtoolset because the compiler
- # won't find it when invoked directly from make/ninja (which is typically
- # done outside devtoolset).
- execute_process(COMMAND which ld.gold
- OUTPUT_VARIABLE GOLD_LOCATION
- OUTPUT_STRIP_TRAILING_WHITESPACE
- ERROR_QUIET)
- if ("${GOLD_LOCATION}" MATCHES "^/opt/rh/devtoolset")
- message("Skipping optional gold linker (version ${GOLD_VERSION}) because "
- "it's in devtoolset")
- set(GOLD_VERSION)
- endif()
-endif()
-if (GOLD_VERSION)
- # Older versions of the gold linker are vulnerable to a bug [1] which
- # prevents weak symbols from being overridden properly. This leads to
- # omitting of Kudu's tcmalloc dependency if using dynamic linking.
- #
- # How we handle this situation depends on other factors:
- # - If gold is optional, we won't use it.
- # - If gold is required and we're using dynamic linking, we'll either:
- # - Raise an error in RELEASE builds (we shouldn't release such a product), or
- # - Drop tcmalloc in all other builds.
- #
- # 1. https://sourceware.org/bugzilla/show_bug.cgi?id=16979.
- if ("${GOLD_VERSION}" VERSION_LESS "1.12")
- set(KUDU_BUGGY_GOLD 1)
- endif()
- if (MUST_USE_GOLD)
- message("Using hard-wired gold linker (version ${GOLD_VERSION})")
- if (KUDU_BUGGY_GOLD AND "${KUDU_LINK}" STREQUAL "d")
- if ("${CMAKE_BUILD_TYPE}" STREQUAL "RELEASE")
- message(SEND_ERROR "Configured to use buggy gold with dynamic linking "
- "in a RELEASE build; this would cause tcmalloc symbols to get dropped")
- endif()
- message("Hard-wired gold linker is buggy, dropping tcmalloc dependency")
- set(GOLD_INCOMPATIBLE_WITH_TCMALLOC 1)
- endif()
- elseif (NOT KUDU_BUGGY_GOLD)
- # The Gold linker must be manually enabled.
- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fuse-ld=gold")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fuse-ld=gold")
- message("Using optional gold linker (version ${GOLD_VERSION})")
- else()
- message("Optional gold linker is buggy, using ld linker instead")
- endif()
-else()
- message("Using ld linker")
-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")
@@ -1130,11 +1050,9 @@ endif()
## Google PerfTools
##
-## Disabled with TSAN/ASAN as well as with gold+dynamic linking (see
-## earlier comment).
+## Disabled with TSAN/ASAN.
if (NOT "${KUDU_USE_ASAN}" AND
- NOT "${KUDU_USE_TSAN}" AND
- NOT "${GOLD_INCOMPATIBLE_WITH_TCMALLOC}")
+ NOT "${KUDU_USE_TSAN}")
find_package(GPerf REQUIRED)
ADD_THIRDPARTY_LIB(tcmalloc
STATIC_LIB "${TCMALLOC_STATIC_LIB}"
@@ -1267,8 +1185,7 @@ if (APPLE)
endif()
else()
if (KUDU_TCMALLOC_AVAILABLE AND
- (("${COMPILER_FAMILY}" STREQUAL "clang" AND
- "${COMPILER_VERSION}" VERSION_GREATER "3.7") OR
+ (("${COMPILER_FAMILY}" STREQUAL "clang") OR
("${COMPILER_FAMILY}" STREQUAL "gcc" AND
"${COMPILER_VERSION}" VERSION_GREATER "5.0")))
set(COMPILER_SUPPORTS_SIZED_DEALLOCATION TRUE)
diff --git a/cmake_modules/KuduLinker.cmake b/cmake_modules/KuduLinker.cmake
new file mode 100644
index 0000000..f2b2ac4
--- /dev/null
+++ b/cmake_modules/KuduLinker.cmake
@@ -0,0 +1,154 @@
+# 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.
+
+# The Gold linker must be manually enabled.
+function(APPEND_LINKER_FLAGS)
+ # Search candidate linkers in the order of decreasing speed and functionality.
+ # In particular, lld is the best choice since it's quite fast and supports
+ # ThinLTO, etc.
+ foreach(candidate_linker lld "${THIRDPARTY_TOOLCHAIN_DIR}/bin/ld.lld" gold default)
+ if(candidate_linker STREQUAL "default")
+ set(candidate_flag "")
+ else()
+ set(candidate_flag "-fuse-ld=${candidate_linker}")
+ endif()
+ GET_LINKER_VERSION("${candidate_flag}")
+ if(NOT LINKER_FOUND)
+ continue()
+ endif()
+
+ # Older versions of the gold linker are vulnerable to a bug [1] which
+ # prevents weak symbols from being overridden properly. This leads to
+ # omitting of Kudu's tcmalloc dependency if using dynamic linking.
+ #
+ # We'll skip gold in our list of candidate linkers if this bug is relevant.
+ #
+ # 1. https://sourceware.org/bugzilla/show_bug.cgi?id=16979.
+ if ("${LINKER_FAMILY}" STREQUAL "gold")
+ if("${LINKER_VERSION}" VERSION_LESS "1.12" AND
+ "${KUDU_LINK}" STREQUAL "d")
+ message(WARNING "Skipping gold <1.12 with dynamic linking.")
+ continue()
+ endif()
+
+ # We can't use the gold linker if it's inside devtoolset because the compiler
+ # won't find it when invoked directly from make/ninja (which is typically
+ # done outside devtoolset). This seems to be fixed in devtoolset-6 or later
+ # by having the gcc/clang binary search the devtoolset bin directory even
+ # if it's not on $PATH.
+ execute_process(COMMAND which ld.gold
+ OUTPUT_VARIABLE GOLD_LOCATION
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_QUIET)
+
+ if ("${GOLD_LOCATION}" MATCHES "^/opt/rh/devtoolset-[3-5]/")
+ message(WARNING "Cannot use gold with devtoolset < 6, skipping...")
+ continue()
+ endif()
+ endif()
+
+ # LLD < 10.0.0 has a bug[1] which causes the __tsan_default_options (and similar)
+ # symbols to be defined as WEAK instead of DEFINED in the resulting binary. This
+ # causes our suppressions to not work properly, resulting in failed tests.
+ #
+ # [1] https://reviews.llvm.org/D63974
+ if ("${LINKER_FAMILY}" STREQUAL "lld" AND
+ "${LINKER_VERSION}" VERSION_LESS "10.0.0" AND
+ ("${KUDU_USE_TSAN}" OR "${KUDU_USE_ASAN}" OR "${KUDU_USE_UBSAN}"))
+ message(WARNING "Cannot use lld < 10.0.0 with TSAN/ASAN/UBSAN. Skipping...")
+ continue()
+ endif()
+ set(linker_flags "${candidate_flag}")
+ break()
+ endforeach()
+
+ if(NOT DEFINED linker_flags)
+ message(SEND_ERROR "Could not find a suitable linker")
+ endif()
+ message(STATUS "Using linker flags: ${linker_flags}")
+ foreach(var CMAKE_SHARED_LINKER_FLAGS CMAKE_EXE_LINKER_FLAGS CMAKE_MODULE_LINKER_FLAGS)
+ set(${var} "${${var}} ${linker_flags}" PARENT_SCOPE)
+ endforeach()
+endfunction()
+
+# Interrogates the linker version via the C++ compiler to determine which linker
+# we're using, along with its version.
+#
+# Sets the following variables:
+# LINKER_FOUND: true/false
+# LINKER_FAMILY: lld/ld/gold
+# LINKER_VERSION: version number of the linker
+# Any additional arguments are passed verbatim into the C++ compiler invocation.
+function(GET_LINKER_VERSION)
+ if(ARGN)
+ message(STATUS "Checking linker version with cflags: ${ARGN}")
+ else()
+ message(STATUS "Checking linker version when not specifying any flags")
+ endif()
+ execute_process(COMMAND ${CMAKE_CXX_COMPILER} "-Wl,--version" ${ARGN}
+ ERROR_QUIET
+ OUTPUT_VARIABLE LINKER_OUTPUT)
+ if (LINKER_OUTPUT MATCHES "GNU gold")
+ # We're expecting LINKER_OUTPUT to look like one of these:
+ # GNU gold (version 2.24) 1.11
+ # GNU gold (GNU Binutils for Ubuntu 2.30) 1.15
+ if (NOT "${LINKER_OUTPUT}" MATCHES "GNU gold \\([^\\)]*\\) (([0-9]+\\.?)+)")
+ message(SEND_ERROR "Could not extract GNU gold version. "
+ "Linker version output: ${LINKER_OUTPUT}")
+ endif()
+ set(LINKER_FAMILY "gold")
+ set(LINKER_VERSION "${CMAKE_MATCH_1}")
+ set(LINKER_FOUND TRUE)
+ elseif (LINKER_OUTPUT MATCHES "GNU ld")
+ # We're expecting LINKER_OUTPUT to look like one of these:
+ # GNU ld (GNU Binutils for Ubuntu) 2.30
+ # GNU ld version 2.20.51.0.2-5.42.el6 20100205
+ # GNU ld version 2.25.1-22.base.el7
+ if (NOT "${LINKER_OUTPUT}" MATCHES "GNU ld version (([0-9]+\\.?)+)" AND
+ NOT "${LINKER_OUTPUT}" MATCHES "GNU ld \\([^\\)]*\\) (([0-9]+\\.?)+)")
+ message(SEND_ERROR "Could not extract GNU ld version. "
+ "Linker version output: ${LINKER_OUTPUT}")
+ endif()
+ set(LINKER_FAMILY "ld")
+ set(LINKER_VERSION "${CMAKE_MATCH_1}")
+ set(LINKER_FOUND TRUE)
+ elseif (LINKER_OUTPUT MATCHES "LLD")
+ # Sample:
+ # LLD 9.0.0 (example.com:kudu.git a5848a4c3c8c72a1ac823182e87cd1f6c31ddc15) (compatible with GNU linkers)
+ if (NOT "${LINKER_OUTPUT}" MATCHES "LLD (([0-9]+\\.?)+)")
+ message(SEND_ERROR "Could not extract lld version. "
+ "Linker version output: ${LINKER_OUTPUT}")
+ endif()
+ set(LINKER_FAMILY "lld")
+ set(LINKER_VERSION "${CMAKE_MATCH_1}")
+ set(LINKER_FOUND TRUE)
+ else()
+ set(LINKER_FAMILY "")
+ set(LINKER_VERSION "")
+ set(LINKER_FOUND FALSE)
+ endif()
+
+ if(LINKER_FOUND)
+ message(STATUS "Found linker: ${LINKER_FAMILY} version ${LINKER_VERSION}")
+ else()
+ message(STATUS "Linker not found")
+ endif()
+ # Propagate the results to the caller.
+ set(LINKER_FOUND "${LINKER_FOUND}" PARENT_SCOPE)
+ set(LINKER_FAMILY "${LINKER_FAMILY}" PARENT_SCOPE)
+ set(LINKER_VERSION "${LINKER_VERSION}" PARENT_SCOPE)
+endfunction()