From 61d8096fce7b9753f157a5620fc02f5e88960b10 Mon Sep 17 00:00:00 2001 From: craffael Date: Fri, 29 Oct 2021 07:08:14 +0200 Subject: [PATCH 1/4] add CMakeSupport with Hunter --- CMakeLists.txt | 58 ++++ cmake/Config.cmake.in | 6 + cmake/HunterGate.cmake | 539 ++++++++++++++++++++++++++++++ cmake/copts.cmake | 37 +++ cmake/tcmalloc_cc_library.cmake | 202 ++++++++++++ tcmalloc/CMakeLists.txt | 542 +++++++++++++++++++++++++++++++ tcmalloc/internal/CMakeLists.txt | 260 +++++++++++++++ 7 files changed, 1644 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 cmake/Config.cmake.in create mode 100644 cmake/HunterGate.cmake create mode 100644 cmake/copts.cmake create mode 100644 cmake/tcmalloc_cc_library.cmake create mode 100644 tcmalloc/CMakeLists.txt create mode 100644 tcmalloc/internal/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..616011016 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,58 @@ +# We require 3.21 because of https://cmake.org/cmake/help/v3.22/command/target_link_libraries.html#linking-object-libraries-via-target-objects +cmake_minimum_required( VERSION 3.21) + + +include("cmake/HunterGate.cmake") + + +HunterGate( + URL "https://github.com/cpp-pm/hunter/archive/v0.23.315.tar.gz" + SHA1 "ea5d72afc0df67f2126e7fd069f20c5f723709e1" +) + +project(tcmalloc LANGUAGES CXX ASM) + + +include(GNUInstallDirs) +include("cmake/tcmalloc_cc_library.cmake") + +# Check that this is not an in-source build: +if("${PROJECT_SOURCE_DIR}" STREQUAL "${PROJECT_BINARY_DIR}") + message(SEND_ERROR "In-source builds are not allowed.") +endif() + +# Get Dependencies +########################## +hunter_add_package(abseil) +find_package(absl CONFIG REQUIRED) + + +set(TCMALLOC_COMMON_INCLUDE_DIRS "${CMAKE_CURRENT_LIST_DIR}") +set(TCMALLOC_CXX_STANDARD "17") +set(LOCAL_INCLUDE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}") +set(config_install_dir "lib/cmake/tcmalloc") + + +add_subdirectory(tcmalloc) + +# Installation +############################ + +set(generated_dir "${CMAKE_CURRENT_BINARY_DIR}/generated") +set(project_config "${generated_dir}/tcmallocConfig.cmake") + +include(CMakePackageConfigHelpers) + +configure_package_config_file( + "cmake/Config.cmake.in" + "${project_config}" + INSTALL_DESTINATION "${config_install_dir}" +) + +install( + FILES "${project_config}" + DESTINATION "${config_install_dir}" +) + +set(LOCAL_GENERATED_INCLUDE_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/lib) +install(EXPORT tcmallocTargets DESTINATION ${config_install_dir} NAMESPACE tcmalloc::) \ No newline at end of file diff --git a/cmake/Config.cmake.in b/cmake/Config.cmake.in new file mode 100644 index 000000000..0cf7505be --- /dev/null +++ b/cmake/Config.cmake.in @@ -0,0 +1,6 @@ +@PACKAGE_INIT@ + +find_package(absl CONFIG REQUIRED) + +include("${CMAKE_CURRENT_LIST_DIR}/tcmallocTargets.cmake") +check_required_components("@PROJECT_NAME@") \ No newline at end of file diff --git a/cmake/HunterGate.cmake b/cmake/HunterGate.cmake new file mode 100644 index 000000000..6d9cc2401 --- /dev/null +++ b/cmake/HunterGate.cmake @@ -0,0 +1,539 @@ +# Copyright (c) 2013-2019, Ruslan Baratov +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# This is a gate file to Hunter package manager. +# Include this file using `include` command and add package you need, example: +# +# cmake_minimum_required(VERSION 3.2) +# +# include("cmake/HunterGate.cmake") +# HunterGate( +# URL "https://github.com/path/to/hunter/archive.tar.gz" +# SHA1 "798501e983f14b28b10cda16afa4de69eee1da1d" +# ) +# +# project(MyProject) +# +# hunter_add_package(Foo) +# hunter_add_package(Boo COMPONENTS Bar Baz) +# +# Projects: +# * https://github.com/hunter-packages/gate/ +# * https://github.com/ruslo/hunter + +option(HUNTER_ENABLED "Enable Hunter package manager support" ON) + +if(HUNTER_ENABLED) + if(CMAKE_VERSION VERSION_LESS "3.2") + message( + FATAL_ERROR + "At least CMake version 3.2 required for Hunter dependency management." + " Update CMake or set HUNTER_ENABLED to OFF." + ) + endif() +endif() + +include(CMakeParseArguments) # cmake_parse_arguments + +option(HUNTER_STATUS_PRINT "Print working status" ON) +option(HUNTER_STATUS_DEBUG "Print a lot info" OFF) +option(HUNTER_TLS_VERIFY "Enable/disable TLS certificate checking on downloads" ON) + +set(HUNTER_ERROR_PAGE "https://docs.hunter.sh/en/latest/reference/errors") + +function(hunter_gate_status_print) + if(HUNTER_STATUS_PRINT OR HUNTER_STATUS_DEBUG) + foreach(print_message ${ARGV}) + message(STATUS "[hunter] ${print_message}") + endforeach() + endif() +endfunction() + +function(hunter_gate_status_debug) + if(HUNTER_STATUS_DEBUG) + foreach(print_message ${ARGV}) + string(TIMESTAMP timestamp) + message(STATUS "[hunter *** DEBUG *** ${timestamp}] ${print_message}") + endforeach() + endif() +endfunction() + +function(hunter_gate_error_page error_page) + message("------------------------------ ERROR ------------------------------") + message(" ${HUNTER_ERROR_PAGE}/${error_page}.html") + message("-------------------------------------------------------------------") + message("") + message(FATAL_ERROR "") +endfunction() + +function(hunter_gate_internal_error) + message("") + foreach(print_message ${ARGV}) + message("[hunter ** INTERNAL **] ${print_message}") + endforeach() + message("[hunter ** INTERNAL **] [Directory:${CMAKE_CURRENT_LIST_DIR}]") + message("") + hunter_gate_error_page("error.internal") +endfunction() + +function(hunter_gate_fatal_error) + cmake_parse_arguments(hunter "" "ERROR_PAGE" "" "${ARGV}") + if("${hunter_ERROR_PAGE}" STREQUAL "") + hunter_gate_internal_error("Expected ERROR_PAGE") + endif() + message("") + foreach(x ${hunter_UNPARSED_ARGUMENTS}) + message("[hunter ** FATAL ERROR **] ${x}") + endforeach() + message("[hunter ** FATAL ERROR **] [Directory:${CMAKE_CURRENT_LIST_DIR}]") + message("") + hunter_gate_error_page("${hunter_ERROR_PAGE}") +endfunction() + +function(hunter_gate_user_error) + hunter_gate_fatal_error(${ARGV} ERROR_PAGE "error.incorrect.input.data") +endfunction() + +function(hunter_gate_self root version sha1 result) + string(COMPARE EQUAL "${root}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("root is empty") + endif() + + string(COMPARE EQUAL "${version}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("version is empty") + endif() + + string(COMPARE EQUAL "${sha1}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("sha1 is empty") + endif() + + string(SUBSTRING "${sha1}" 0 7 archive_id) + + if(EXISTS "${root}/cmake/Hunter") + set(hunter_self "${root}") + else() + set( + hunter_self + "${root}/_Base/Download/Hunter/${version}/${archive_id}/Unpacked" + ) + endif() + + set("${result}" "${hunter_self}" PARENT_SCOPE) +endfunction() + +# Set HUNTER_GATE_ROOT cmake variable to suitable value. +function(hunter_gate_detect_root) + # Check CMake variable + string(COMPARE NOTEQUAL "${HUNTER_ROOT}" "" not_empty) + if(not_empty) + set(HUNTER_GATE_ROOT "${HUNTER_ROOT}" PARENT_SCOPE) + hunter_gate_status_debug("HUNTER_ROOT detected by cmake variable") + return() + endif() + + # Check environment variable + string(COMPARE NOTEQUAL "$ENV{HUNTER_ROOT}" "" not_empty) + if(not_empty) + set(HUNTER_GATE_ROOT "$ENV{HUNTER_ROOT}" PARENT_SCOPE) + hunter_gate_status_debug("HUNTER_ROOT detected by environment variable") + return() + endif() + + # Check HOME environment variable + string(COMPARE NOTEQUAL "$ENV{HOME}" "" result) + if(result) + set(HUNTER_GATE_ROOT "$ENV{HOME}/.hunter" PARENT_SCOPE) + hunter_gate_status_debug("HUNTER_ROOT set using HOME environment variable") + return() + endif() + + # Check SYSTEMDRIVE and USERPROFILE environment variable (windows only) + if(WIN32) + string(COMPARE NOTEQUAL "$ENV{SYSTEMDRIVE}" "" result) + if(result) + set(HUNTER_GATE_ROOT "$ENV{SYSTEMDRIVE}/.hunter" PARENT_SCOPE) + hunter_gate_status_debug( + "HUNTER_ROOT set using SYSTEMDRIVE environment variable" + ) + return() + endif() + + string(COMPARE NOTEQUAL "$ENV{USERPROFILE}" "" result) + if(result) + set(HUNTER_GATE_ROOT "$ENV{USERPROFILE}/.hunter" PARENT_SCOPE) + hunter_gate_status_debug( + "HUNTER_ROOT set using USERPROFILE environment variable" + ) + return() + endif() + endif() + + hunter_gate_fatal_error( + "Can't detect HUNTER_ROOT" + ERROR_PAGE "error.detect.hunter.root" + ) +endfunction() + +function(hunter_gate_download dir) + string( + COMPARE + NOTEQUAL + "$ENV{HUNTER_DISABLE_AUTOINSTALL}" + "" + disable_autoinstall + ) + if(disable_autoinstall AND NOT HUNTER_RUN_INSTALL) + hunter_gate_fatal_error( + "Hunter not found in '${dir}'" + "Set HUNTER_RUN_INSTALL=ON to auto-install it from '${HUNTER_GATE_URL}'" + "Settings:" + " HUNTER_ROOT: ${HUNTER_GATE_ROOT}" + " HUNTER_SHA1: ${HUNTER_GATE_SHA1}" + ERROR_PAGE "error.run.install" + ) + endif() + string(COMPARE EQUAL "${dir}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("Empty 'dir' argument") + endif() + + string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("HUNTER_GATE_SHA1 empty") + endif() + + string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("HUNTER_GATE_URL empty") + endif() + + set(done_location "${dir}/DONE") + set(sha1_location "${dir}/SHA1") + + set(build_dir "${dir}/Build") + set(cmakelists "${dir}/CMakeLists.txt") + + hunter_gate_status_debug("Locking directory: ${dir}") + file(LOCK "${dir}" DIRECTORY GUARD FUNCTION) + hunter_gate_status_debug("Lock done") + + if(EXISTS "${done_location}") + # while waiting for lock other instance can do all the job + hunter_gate_status_debug("File '${done_location}' found, skip install") + return() + endif() + + file(REMOVE_RECURSE "${build_dir}") + file(REMOVE_RECURSE "${cmakelists}") + + file(MAKE_DIRECTORY "${build_dir}") # check directory permissions + + # Disabling languages speeds up a little bit, reduces noise in the output + # and avoids path too long windows error + file( + WRITE + "${cmakelists}" + "cmake_minimum_required(VERSION 3.2)\n" + "project(HunterDownload LANGUAGES NONE)\n" + "include(ExternalProject)\n" + "ExternalProject_Add(\n" + " Hunter\n" + " URL\n" + " \"${HUNTER_GATE_URL}\"\n" + " URL_HASH\n" + " SHA1=${HUNTER_GATE_SHA1}\n" + " DOWNLOAD_DIR\n" + " \"${dir}\"\n" + " TLS_VERIFY\n" + " ${HUNTER_TLS_VERIFY}\n" + " SOURCE_DIR\n" + " \"${dir}/Unpacked\"\n" + " CONFIGURE_COMMAND\n" + " \"\"\n" + " BUILD_COMMAND\n" + " \"\"\n" + " INSTALL_COMMAND\n" + " \"\"\n" + ")\n" + ) + + if(HUNTER_STATUS_DEBUG) + set(logging_params "") + else() + set(logging_params OUTPUT_QUIET) + endif() + + hunter_gate_status_debug("Run generate") + + # Need to add toolchain file too. + # Otherwise on Visual Studio + MDD this will fail with error: + # "Could not find an appropriate version of the Windows 10 SDK installed on this machine" + if(EXISTS "${CMAKE_TOOLCHAIN_FILE}") + get_filename_component(absolute_CMAKE_TOOLCHAIN_FILE "${CMAKE_TOOLCHAIN_FILE}" ABSOLUTE) + set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=${absolute_CMAKE_TOOLCHAIN_FILE}") + else() + # 'toolchain_arg' can't be empty + set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=") + endif() + + string(COMPARE EQUAL "${CMAKE_MAKE_PROGRAM}" "" no_make) + if(no_make) + set(make_arg "") + else() + # Test case: remove Ninja from PATH but set it via CMAKE_MAKE_PROGRAM + set(make_arg "-DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}") + endif() + + execute_process( + COMMAND + "${CMAKE_COMMAND}" + "-H${dir}" + "-B${build_dir}" + "-G${CMAKE_GENERATOR}" + "${toolchain_arg}" + ${make_arg} + WORKING_DIRECTORY "${dir}" + RESULT_VARIABLE download_result + ${logging_params} + ) + + if(NOT download_result EQUAL 0) + hunter_gate_internal_error( + "Configure project failed." + "To reproduce the error run: ${CMAKE_COMMAND} -H${dir} -B${build_dir} -G${CMAKE_GENERATOR} ${toolchain_arg} ${make_arg}" + "In directory ${dir}" + ) + endif() + + hunter_gate_status_print( + "Initializing Hunter workspace (${HUNTER_GATE_SHA1})" + " ${HUNTER_GATE_URL}" + " -> ${dir}" + ) + execute_process( + COMMAND "${CMAKE_COMMAND}" --build "${build_dir}" + WORKING_DIRECTORY "${dir}" + RESULT_VARIABLE download_result + ${logging_params} + ) + + if(NOT download_result EQUAL 0) + hunter_gate_internal_error("Build project failed") + endif() + + file(REMOVE_RECURSE "${build_dir}") + file(REMOVE_RECURSE "${cmakelists}") + + file(WRITE "${sha1_location}" "${HUNTER_GATE_SHA1}") + file(WRITE "${done_location}" "DONE") + + hunter_gate_status_debug("Finished") +endfunction() + +# Must be a macro so master file 'cmake/Hunter' can +# apply all variables easily just by 'include' command +# (otherwise PARENT_SCOPE magic needed) +macro(HunterGate) + if(HUNTER_GATE_DONE) + # variable HUNTER_GATE_DONE set explicitly for external project + # (see `hunter_download`) + set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES) + endif() + + # First HunterGate command will init Hunter, others will be ignored + get_property(_hunter_gate_done GLOBAL PROPERTY HUNTER_GATE_DONE SET) + + if(NOT HUNTER_ENABLED) + # Empty function to avoid error "unknown function" + function(hunter_add_package) + endfunction() + + set( + _hunter_gate_disabled_mode_dir + "${CMAKE_CURRENT_LIST_DIR}/cmake/Hunter/disabled-mode" + ) + if(EXISTS "${_hunter_gate_disabled_mode_dir}") + hunter_gate_status_debug( + "Adding \"disabled-mode\" modules: ${_hunter_gate_disabled_mode_dir}" + ) + list(APPEND CMAKE_PREFIX_PATH "${_hunter_gate_disabled_mode_dir}") + endif() + elseif(_hunter_gate_done) + hunter_gate_status_debug("Secondary HunterGate (use old settings)") + hunter_gate_self( + "${HUNTER_CACHED_ROOT}" + "${HUNTER_VERSION}" + "${HUNTER_SHA1}" + _hunter_self + ) + include("${_hunter_self}/cmake/Hunter") + else() + set(HUNTER_GATE_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}") + + string(COMPARE NOTEQUAL "${PROJECT_NAME}" "" _have_project_name) + if(_have_project_name) + hunter_gate_fatal_error( + "Please set HunterGate *before* 'project' command. " + "Detected project: ${PROJECT_NAME}" + ERROR_PAGE "error.huntergate.before.project" + ) + endif() + + cmake_parse_arguments( + HUNTER_GATE "LOCAL" "URL;SHA1;GLOBAL;FILEPATH" "" ${ARGV} + ) + + string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" _empty_sha1) + string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" _empty_url) + string( + COMPARE + NOTEQUAL + "${HUNTER_GATE_UNPARSED_ARGUMENTS}" + "" + _have_unparsed + ) + string(COMPARE NOTEQUAL "${HUNTER_GATE_GLOBAL}" "" _have_global) + string(COMPARE NOTEQUAL "${HUNTER_GATE_FILEPATH}" "" _have_filepath) + + if(_have_unparsed) + hunter_gate_user_error( + "HunterGate unparsed arguments: ${HUNTER_GATE_UNPARSED_ARGUMENTS}" + ) + endif() + if(_empty_sha1) + hunter_gate_user_error("SHA1 suboption of HunterGate is mandatory") + endif() + if(_empty_url) + hunter_gate_user_error("URL suboption of HunterGate is mandatory") + endif() + if(_have_global) + if(HUNTER_GATE_LOCAL) + hunter_gate_user_error("Unexpected LOCAL (already has GLOBAL)") + endif() + if(_have_filepath) + hunter_gate_user_error("Unexpected FILEPATH (already has GLOBAL)") + endif() + endif() + if(HUNTER_GATE_LOCAL) + if(_have_global) + hunter_gate_user_error("Unexpected GLOBAL (already has LOCAL)") + endif() + if(_have_filepath) + hunter_gate_user_error("Unexpected FILEPATH (already has LOCAL)") + endif() + endif() + if(_have_filepath) + if(_have_global) + hunter_gate_user_error("Unexpected GLOBAL (already has FILEPATH)") + endif() + if(HUNTER_GATE_LOCAL) + hunter_gate_user_error("Unexpected LOCAL (already has FILEPATH)") + endif() + endif() + + hunter_gate_detect_root() # set HUNTER_GATE_ROOT + + # Beautify path, fix probable problems with windows path slashes + get_filename_component( + HUNTER_GATE_ROOT "${HUNTER_GATE_ROOT}" ABSOLUTE + ) + hunter_gate_status_debug("HUNTER_ROOT: ${HUNTER_GATE_ROOT}") + if(NOT HUNTER_ALLOW_SPACES_IN_PATH) + string(FIND "${HUNTER_GATE_ROOT}" " " _contain_spaces) + if(NOT _contain_spaces EQUAL -1) + hunter_gate_fatal_error( + "HUNTER_ROOT (${HUNTER_GATE_ROOT}) contains spaces." + "Set HUNTER_ALLOW_SPACES_IN_PATH=ON to skip this error" + "(Use at your own risk!)" + ERROR_PAGE "error.spaces.in.hunter.root" + ) + endif() + endif() + + string( + REGEX + MATCH + "[0-9]+\\.[0-9]+\\.[0-9]+[-_a-z0-9]*" + HUNTER_GATE_VERSION + "${HUNTER_GATE_URL}" + ) + string(COMPARE EQUAL "${HUNTER_GATE_VERSION}" "" _is_empty) + if(_is_empty) + set(HUNTER_GATE_VERSION "unknown") + endif() + + hunter_gate_self( + "${HUNTER_GATE_ROOT}" + "${HUNTER_GATE_VERSION}" + "${HUNTER_GATE_SHA1}" + _hunter_self + ) + + set(_master_location "${_hunter_self}/cmake/Hunter") + if(EXISTS "${HUNTER_GATE_ROOT}/cmake/Hunter") + # Hunter downloaded manually (e.g. by 'git clone') + set(_unused "xxxxxxxxxx") + set(HUNTER_GATE_SHA1 "${_unused}") + set(HUNTER_GATE_VERSION "${_unused}") + else() + get_filename_component(_archive_id_location "${_hunter_self}/.." ABSOLUTE) + set(_done_location "${_archive_id_location}/DONE") + set(_sha1_location "${_archive_id_location}/SHA1") + + # Check Hunter already downloaded by HunterGate + if(NOT EXISTS "${_done_location}") + hunter_gate_download("${_archive_id_location}") + endif() + + if(NOT EXISTS "${_done_location}") + hunter_gate_internal_error("hunter_gate_download failed") + endif() + + if(NOT EXISTS "${_sha1_location}") + hunter_gate_internal_error("${_sha1_location} not found") + endif() + file(READ "${_sha1_location}" _sha1_value) + string(COMPARE EQUAL "${_sha1_value}" "${HUNTER_GATE_SHA1}" _is_equal) + if(NOT _is_equal) + hunter_gate_internal_error( + "Short SHA1 collision:" + " ${_sha1_value} (from ${_sha1_location})" + " ${HUNTER_GATE_SHA1} (HunterGate)" + ) + endif() + if(NOT EXISTS "${_master_location}") + hunter_gate_user_error( + "Master file not found:" + " ${_master_location}" + "try to update Hunter/HunterGate" + ) + endif() + endif() + include("${_master_location}") + set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES) + endif() +endmacro() diff --git a/cmake/copts.cmake b/cmake/copts.cmake new file mode 100644 index 000000000..7bb41719a --- /dev/null +++ b/cmake/copts.cmake @@ -0,0 +1,37 @@ +# +# Copyright 2021 Raffael Casagrande +# +# Licensed 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 +# +# https://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. +# + +# Determine basic compile options: + set(TCMALLOC_LLVM_FLAGS -Wno-deprecated-declarations + -Wno-implicit-int-float-conversion + -Wno-sign-compare + -Wno-uninitialized + -Wno-unused-function + -Wno-unused-variable) + + set(TCMALLOC_GCC_FLAGS -Wno-attribute-alias + -Wno-sign-compare + -Wno-uninitialized + -Wno-unused-function + # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425 + -Wno-unused-result + -Wno-unused-variable) + + if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + set(TCMALLOC_DEFAULT_COPTS ${TCMALLOC_LLVM_FLAGS}) + elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set(TCMALLOC_DEFAULT_COPTS ${TCMALLOC_GCC_FLAGS}) + endif() \ No newline at end of file diff --git a/cmake/tcmalloc_cc_library.cmake b/cmake/tcmalloc_cc_library.cmake new file mode 100644 index 000000000..6a4a7a71b --- /dev/null +++ b/cmake/tcmalloc_cc_library.cmake @@ -0,0 +1,202 @@ +# +# Copyright 2017 The Abseil Authors. +# Copyright 2021 Raffael Casagrande +# +# Licensed 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 +# +# https://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. +# + +include(CMakeParseArguments) +include(cmake/copts.cmake) + +# The IDE folder for Tcmalloc that will be used if Tcmalloc is included in a CMake +# project that sets +# set_property(GLOBAL PROPERTY USE_FOLDERS ON) +# For example, Visual Studio supports folders. +if(NOT DEFINED TCMALLOC_IDE_FOLDER) + set(TCMALLOC_IDE_FOLDER tcmalloc) +endif() + +# tcmalloc_cc_library() +# +# CMake function to imitate Bazel's cc_library rule. +# +# Parameters: +# NAME: name of target (see Note) +# HDRS: List of public header files for the library +# SRCS: List of source files for the library +# DEPS: List of other libraries to be linked in to the binary targets +# COPTS: List of private compile options +# DEFINES: List of public defines +# LINKOPTS: List of link options +# PUBLIC: Add this so that this library will be exported under tcmalloc:: +# Also in IDE, target will appear in tcmalloc folder while non PUBLIC will be in tcmalloc/internal. +# TESTONLY: When added, this target will only be built if BUILD_TESTING=ON. +# ALWAYSLINK: Add this so that any binary that depends on this library will link all the object files listed in srcs. +# LINKSTATIC: Link this library always statically (even if BUILD_SHARED_LIBS=ON) +# +# Note: +# By default, tcmalloc_cc_library will always create a library named tcmalloc_${NAME}, +# and alias target tcmalloc::${NAME}. The tcmalloc:: form should always be used. +# This is to reduce namespace pollution. +# +# tcmalloc_cc_library( +# NAME +# awesome +# HDRS +# "a.h" +# SRCS +# "a.cc" +# ) +# tcmalloc_cc_library( +# NAME +# fantastic_lib +# SRCS +# "b.cc" +# DEPS +# tcmalloc::awesome # not "awesome" ! +# PUBLIC +# ) +# +# tcmalloc_cc_library( +# NAME +# main_lib +# ... +# DEPS +# tcmalloc::fantastic_lib +# ) +# +function(tcmalloc_cc_library) + cmake_parse_arguments(TCMALLOC_CC_LIB + "DISABLE_INSTALL;PUBLIC;TESTONLY;ALWAYSLINK;LINKSTATIC" + "NAME" + "HDRS;SRCS;COPTS;DEFINES;LINKOPTS;DEPS" + ${ARGN} + ) + + set(_NAME "${TCMALLOC_CC_LIB_NAME}") + + # Check if this is a header-only library + set(TCMALLOC_CC_SRCS "${TCMALLOC_CC_LIB_SRCS}") + list(FILTER "${TCMALLOC_CC_SRCS}" EXCLUDE REGEX ".*\\.(h|inc)") + + if(TCMALLOC_CC_SRCS STREQUAL "") + set(TCMALLOC_CC_LIB_IS_INTERFACE 1) + else() + set(TCMALLOC_CC_LIB_IS_INTERFACE 0) + endif() + + # Determine this build target's relationship to the DLL. It's one of two things: + # 1. "shared" -- This is a shared library, perhaps on a non-windows platform + # where DLL doesn't make sense. + # 2. "static" -- This target does not depend on the DLL and should be built + # statically. + if(BUILD_SHARED_LIBS AND NOT TCMALLOC_CC_LIB_LINKSTATIC) + set(_build_type "SHARED") + else() + set(_build_type "STATIC") + endif() + + if(NOT TCMALLOC_CC_LIB_IS_INTERFACE) + if(_build_type STREQUAL "STATIC" OR _build_type STREQUAL "SHARED") + if(TCMALLOC_CC_LIB_ALWAYSLINK) + # If ALWAYSLINK is set, we must create a OBJECT library (see cmake manual) + # but since an object library doesn't support transitive dependencies completly, + # we create a wrapper INTERFACE target which then links in the OBJECT target + # See also https://cmake.org/cmake/help/v3.22/command/target_link_libraries.html#linking-object-libraries-via-target-objects + add_library("${_NAME}_obj" OBJECT ${TCMALLOC_CC_LIB_SRCS} ${TCMALLOC_CC_LIB_HDRS}) + target_link_libraries("${_NAME}_obj" PUBLIC ${TCMALLOC_CC_LIB_DEPS}) + add_library(${_NAME} INTERFACE) + target_link_libraries(${_NAME} + INTERFACE + "${_NAME}_obj" + $> + ) + set(_realname ${_NAME}_obj) + + install(TARGETS ${_NAME}_obj EXPORT ${PROJECT_NAME}Targets + OBJECTS DESTINATION ${CMAKE_INSTALL_LIBDIR} + ) + else() + add_library(${_NAME} ${_build_type} "") + target_sources(${_NAME} PRIVATE ${TCMALLOC_CC_LIB_SRCS} ${TCMALLOC_CC_LIB_HDRS}) + target_link_libraries(${_NAME} + PUBLIC ${TCMALLOC_CC_LIB_DEPS} + PRIVATE ${TCMALLOC_CC_LIB_LINKOPTS} + ) + set(_realname ${_NAME}) + endif() + else() + message(FATAL_ERROR "Invalid build type: ${_build_type}") + endif() + + # Linker language can be inferred from sources, but in the case of DLLs we + # don't have any .cc files so it would be ambiguous. We could set it + # explicitly only in the case of DLLs but, because "CXX" is always the + # correct linker language for static or for shared libraries, we set it + # unconditionally. + set_property(TARGET ${_realname} PROPERTY LINKER_LANGUAGE "CXX") + + target_include_directories(${_realname} + PUBLIC + "$" + $ + ) + + target_compile_options(${_realname} + PRIVATE ${TCMALLOC_DEFAULT_COPTS} ${TCMALLOC_CC_LIB_COPTS}) + target_compile_definitions(${_realname} PUBLIC ${TCMALLOC_CC_LIB_DEFINES}) + + # Add all Tcmalloc targets to a a folder in the IDE for organization. + if(TCMALLOC_CC_LIB_PUBLIC) + set_property(TARGET ${_realname} PROPERTY FOLDER ${TCMALLOC_IDE_FOLDER}) + elseif(TCMALLOC_CC_LIB_TESTONLY) + set_property(TARGET ${_realname} PROPERTY FOLDER ${TCMALLOC_IDE_FOLDER}/test) + else() + set_property(TARGET ${_realname} PROPERTY FOLDER ${TCMALLOC_IDE_FOLDER}/internal) + endif() + + # INTERFACE libraries can't have the CXX_STANDARD property set + set_property(TARGET ${_realname} PROPERTY CXX_STANDARD ${TCMALLOC_CXX_STANDARD}) + set_property(TARGET ${_realname} PROPERTY CXX_STANDARD_REQUIRED ON) + + + set_target_properties(${_NAME} PROPERTIES + OUTPUT_NAME "tcmalloc_${_NAME}" + ) + else() + # Generating header-only library + add_library(${_NAME} INTERFACE) + target_include_directories(${_NAME} + INTERFACE + "$" + $ + ) + + target_link_libraries(${_NAME} + INTERFACE + ${TCMALLOC_CC_LIB_DEPS} + ${TCMALLOC_CC_LIB_LINKOPTS} + ) + target_compile_definitions(${_NAME} INTERFACE ${TCMALLOC_CC_LIB_DEFINES}) + endif() + + install(TARGETS ${_NAME} EXPORT ${PROJECT_NAME}Targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + ) + + install(FILES ${TCMALLOC_CC_LIB_HDRS} DESTINATION "include/tcmalloc") + + add_library(tcmalloc::${TCMALLOC_CC_LIB_NAME} ALIAS ${_NAME}) +endfunction() \ No newline at end of file diff --git a/tcmalloc/CMakeLists.txt b/tcmalloc/CMakeLists.txt new file mode 100644 index 000000000..8e71ca682 --- /dev/null +++ b/tcmalloc/CMakeLists.txt @@ -0,0 +1,542 @@ +add_subdirectory(internal) + +tcmalloc_cc_library( + NAME "experiment" + SRCS "experiment.cc" + HDRS + "experiment.h" + "experiment_config.h" + DEPS + "tcmalloc::malloc_extension" + "tcmalloc::environment" + "tcmalloc::logging" + "absl::core_headers" + "absl::strings" + "absl::optional" +) + +# Dependencies required by :tcmalloc and its variants. Since :common is built +# several different ways it should not be included on this list. +set(tcmalloc_deps + "tcmalloc::experiment" + "tcmalloc::malloc_extension" + "tcmalloc::new_extension" + "absl::base" + "absl::config" + "absl::core_headers" + "absl::dynamic_annotations" + "absl::leak_check" + "absl::stacktrace" + "absl::symbolize" + "absl::memory" + "absl::strings" + "absl::bits" + "tcmalloc::config" + "tcmalloc::declarations" + "tcmalloc::linked_list" + "tcmalloc::logging" + "tcmalloc::memory_stats" + "tcmalloc::optimization" + "tcmalloc::percpu" +) + +# This library provides tcmalloc always +tcmalloc_cc_library( + NAME "tcmalloc" + SRCS + "libc_override.h" + "libc_override_gcc_and_weak.h" + "libc_override_glibc.h" + "libc_override_redefine.h" + "tcmalloc.cc" + "tcmalloc.h" + LINKSTATIC + PUBLIC + DEPS ${tcmalloc_deps} + "tcmalloc::common" + + ALWAYSLINK +) + +# Provides tcmalloc always; use per-thread mode. +tcmalloc_cc_library( + NAME "tcmalloc_deprecated_perthread" + SRCS + "libc_override.h" + "libc_override_gcc_and_weak.h" + "libc_override_glibc.h" + "libc_override_redefine.h" + "tcmalloc.cc" + "tcmalloc.h" + + COPTS "-DTCMALLOC_DEPRECATED_PERTHREAD" + LINKSTATIC + DEPS ${tcmalloc_deps} + "tcmalloc::common_deprecated_perthread" + + ALWAYSLINK +) + +# An opt tcmalloc build with ASSERTs forced on (by turning off +# NDEBUG). Useful for tracking down crashes in production binaries. +# To use add malloc "//tcmalloc:opt_with_assertions" in your +# target's build rule. +tcmalloc_cc_library( + NAME "opt_with_assertions" + SRCS + "libc_override.h" + "libc_override_gcc_and_weak.h" + "libc_override_glibc.h" + "libc_override_redefine.h" + "tcmalloc.cc" + "tcmalloc.h" + PUBLIC + COPTS + "-O2" + "-UNDEBUG" + LINKSTATIC + DEPS ${tcmalloc_deps} + "tcmalloc::common" + ALWAYSLINK +) + +tcmalloc_cc_library( + NAME "size_class_info" + HDRS "size_class_info.h" + DEPS + "tcmalloc::logging" +) + +# List of common source files used by the various tcmalloc libraries. +set(common_srcs + "arena.cc" + "arena.h" + "background.cc" + "central_freelist.cc" + "central_freelist.h" + "common.cc" + "common.h" + "cpu_cache.cc" + "cpu_cache.h" + "experimental_pow2_below64_size_class.cc" + "experimental_pow2_size_class.cc" + "legacy_size_classes.cc" + "guarded_page_allocator.h" + "guarded_page_allocator.cc" + "huge_address_map.cc" + "huge_allocator.cc" + "huge_allocator.h" + "huge_cache.cc" + "huge_cache.h" + "huge_region.h" + "huge_page_aware_allocator.cc" + "huge_page_aware_allocator.h" + "huge_page_filler.h" + "huge_pages.h" + "page_allocator.cc" + "page_allocator.h" + "page_allocator_interface.cc" + "page_allocator_interface.h" + "page_heap.cc" + "page_heap.h" + "page_heap_allocator.h" + "pagemap.cc" + "pagemap.h" + "parameters.cc" + "peak_heap_tracker.cc" + "sampler.cc" + "sampler.h" + "size_classes.cc" + "span.cc" + "span.h" + "span_stats.h" + "stack_trace_table.cc" + "stack_trace_table.h" + "static_vars.cc" + "static_vars.h" + "stats.cc" + "system-alloc.cc" + "system-alloc.h" + "thread_cache.cc" + "thread_cache.h" + "tracking.h" + "transfer_cache_stats.h" + "transfer_cache.cc" + "transfer_cache.h" + "transfer_cache_internals.h" +) + +set(common_hdrs + "arena.h" + "central_freelist.h" + "common.h" + "cpu_cache.h" + "guarded_page_allocator.h" + "huge_address_map.h" + "huge_allocator.h" + "tcmalloc_policy.h" + "huge_cache.h" + "huge_page_filler.h" + "huge_pages.h" + "huge_region.h" + "huge_page_aware_allocator.h" + "page_allocator.h" + "page_allocator_interface.h" + "page_heap.h" + "page_heap_allocator.h" + "pages.h" + "pagemap.h" + "parameters.h" + "peak_heap_tracker.h" + "sampler.h" + "span.h" + "span_stats.h" + "stack_trace_table.h" + "stats.h" + "static_vars.h" + "system-alloc.h" + "thread_cache.h" + "tracking.h" + "transfer_cache_stats.h" + "transfer_cache.h" + "transfer_cache_internals.h" +) + +set(common_deps + "tcmalloc::experiment" + "tcmalloc::malloc_extension" + "tcmalloc::new_extension" + "tcmalloc::noruntime_size_classes" + "tcmalloc::size_class_info" + "absl::algorithm_container" + "absl::base" + "absl::config" + "absl::core_headers" + "absl::dynamic_annotations" + "absl::fixed_array" + "absl::stacktrace" + "absl::symbolize" + "absl::synchronization" + "absl::hash" + "absl::memory" + "absl::strings" + "absl::str_format" + "absl::time" + "absl::optional" + "absl::span" + "tcmalloc::atomic_stats_counter" + "absl::bits" + "tcmalloc::config" + "tcmalloc::declarations" + "tcmalloc::environment" + "tcmalloc::linked_list" + "tcmalloc::logging" + "tcmalloc::mincore" + "tcmalloc::numa" + "tcmalloc::cache_topology" + "tcmalloc::optimization" + "tcmalloc::parameter_accessors" + "tcmalloc::percpu" + "tcmalloc::percpu_tcmalloc" + "tcmalloc::range_tracker" + "tcmalloc::timeseries_tracker" + "tcmalloc::util" +) + +tcmalloc_cc_library( + NAME "common" + SRCS ${common_srcs} + HDRS ${common_hdrs} + LINKSTATIC + DEPS ${common_deps} + ALWAYSLINK +) + +tcmalloc_cc_library( + NAME "common_deprecated_perthread" + SRCS ${common_srcs} + HDRS ${common_hdrs} + COPTS "-DTCMALLOC_DEPRECATED_PERTHREAD" + LINKSTATIC + DEPS ${common_deps} + ALWAYSLINK +) + +# TEMPORARY. WILL BE REMOVED. +# Add a dep to this if you want your binary to use hugepage-aware +# allocator. +tcmalloc_cc_library( + NAME "want_hpaa" + SRCS "want_hpaa.cc" + COPTS "-g0" + PUBLIC + DEPS + "tcmalloc::config" + "absl::core_headers" + ALWAYSLINK +) + +# TEMPORARY. WILL BE REMOVED. +# Add a dep to this if you want your binary to use hugepage-aware +# allocator with hpaa_subrelease=true. +tcmalloc_cc_library( + NAME "want_hpaa_subrelease" + SRCS "want_hpaa_subrelease.cc" + COPTS "-g0" + PUBLIC + DEPS + "tcmalloc::config" + "absl::core_headers" + ALWAYSLINK +) + +# TEMPORARY. WILL BE REMOVED. +# Add a dep to this if you want your binary to not use hugepage-aware +# allocator. +tcmalloc_cc_library( + NAME "want_no_hpaa" + SRCS "want_no_hpaa.cc" + COPTS "-g0" + PUBLIC + DEPS + "tcmalloc::config" + "absl::core_headers" + ALWAYSLINK +) + +# TEMPORARY. WILL BE REMOVED. +# Add a dep to this if you want your binary to use old span sizes. +tcmalloc_cc_library( + NAME "want_legacy_spans" + SRCS "want_legacy_spans.cc" + COPTS "-g0" + DEPS + "tcmalloc::config" + "absl::core_headers" + ALWAYSLINK +) + +# Add a dep to this if you want your binary to enable NUMA awareness by +# default. +tcmalloc_cc_library( + NAME "want_numa_aware" + SRCS "want_numa_aware.cc" + COPTS "-g0" + DEPS + "tcmalloc::config" + "absl::core_headers" + ALWAYSLINK +) + +tcmalloc_cc_library( + NAME "runtime_size_classes" + SRCS "runtime_size_classes.cc" + HDRS "runtime_size_classes.h" + DEPS + "tcmalloc::size_class_info" + "tcmalloc::environment" + "tcmalloc::logging" + "absl::core_headers" + "absl::strings" + ALWAYSLINK +) + +tcmalloc_cc_library( + NAME "noruntime_size_classes" + SRCS "noruntime_size_classes.cc" + HDRS "runtime_size_classes.h" + DEPS + "tcmalloc::size_class_info" + "absl::core_headers" + "absl::strings" + ALWAYSLINK +) + +# TCMalloc with large pages is usually faster but fragmentation is higher. See +# https://github.com/google/tcmalloc/tree/master/docs/tuning.md for more details. +tcmalloc_cc_library( + NAME "tcmalloc_large_pages" + SRCS + "libc_override.h" + "libc_override_gcc_and_weak.h" + "libc_override_glibc.h" + "libc_override_redefine.h" + "tcmalloc.cc" + "tcmalloc.h" + + COPTS "-DTCMALLOC_LARGE_PAGES" + LINKSTATIC + PUBLIC + DEPS ${tcmalloc_deps} + "tcmalloc::common_large_pages" + + ALWAYSLINK +) + +tcmalloc_cc_library( + NAME "common_large_pages" + SRCS ${common_srcs} + HDRS ${common_hdrs} + COPTS "-DTCMALLOC_LARGE_PAGES" + LINKSTATIC + DEPS ${common_deps} + ALWAYSLINK +) + +# TCMalloc with 256k pages is usually faster but fragmentation is higher. See +# https://github.com/google/tcmalloc/tree/master/docs/tuning.md for more details. +tcmalloc_cc_library( + NAME "tcmalloc_256k_pages" + SRCS + "libc_override.h" + "libc_override_gcc_and_weak.h" + "libc_override_glibc.h" + "libc_override_redefine.h" + "tcmalloc.cc" + "tcmalloc.h" + + COPTS "-DTCMALLOC_256K_PAGES" + LINKSTATIC + PUBLIC + DEPS ${tcmalloc_deps} + "tcmalloc::common_256k_pages" + ALWAYSLINK +) + +tcmalloc_cc_library( + NAME "common_256k_pages" + SRCS ${common_srcs} + HDRS ${common_hdrs} + COPTS "-DTCMALLOC_256K_PAGES" + LINKSTATIC + DEPS ${common_deps} + ALWAYSLINK +) + +tcmalloc_cc_library( + NAME "tcmalloc_256k_pages_and_numa" + SRCS + "libc_override.h" + "libc_override_gcc_and_weak.h" + "libc_override_glibc.h" + "libc_override_redefine.h" + "tcmalloc.cc" + "tcmalloc.h" + + COPTS + "-DTCMALLOC_256K_PAGES" + "-DTCMALLOC_NUMA_AWARE" + + LINKSTATIC + DEPS ${tcmalloc_deps} + "tcmalloc::common_256k_pages_and_numa" + ALWAYSLINK +) + +tcmalloc_cc_library( + NAME "common_256k_pages_and_numa" + SRCS ${common_srcs} + HDRS ${common_hdrs} + COPTS + "-DTCMALLOC_256K_PAGES" + "-DTCMALLOC_NUMA_AWARE" + + LINKSTATIC + DEPS ${common_deps} + ALWAYSLINK +) + +# TCMalloc small-but-slow is a a version of TCMalloc that chooses to minimize +# fragmentation at a *severe* cost to performance. It should be used by +# applications that have significant memory constraints but don't need to +# frequently allocate/free objects. +# +# See https://github.com/google/tcmalloc/tree/master/docs/tuning.md for more details. +tcmalloc_cc_library( + NAME "tcmalloc_small_but_slow" + SRCS + "libc_override.h" + "libc_override_gcc_and_weak.h" + "libc_override_glibc.h" + "libc_override_redefine.h" + "tcmalloc.cc" + "tcmalloc.h" + + COPTS "-DTCMALLOC_SMALL_BUT_SLOW" + LINKSTATIC + PUBLIC + DEPS ${tcmalloc_deps} + "tcmalloc::common_small_but_slow" + ALWAYSLINK +) + +tcmalloc_cc_library( + NAME "common_small_but_slow" + SRCS ${common_srcs} + HDRS ${common_hdrs} + COPTS "-DTCMALLOC_SMALL_BUT_SLOW" + LINKSTATIC + DEPS ${common_deps} + ALWAYSLINK +) + +# TCMalloc with NUMA awareness compiled in. Note that by default NUMA awareness +# will still be disabled at runtime - this default can be changed by adding a +# dependency upon want_numa_aware or overridden by setting the +# TCMALLOC_NUMA_AWARE environment variable. +tcmalloc_cc_library( + NAME "tcmalloc_numa_aware" + SRCS + "libc_override.h" + "libc_override_gcc_and_weak.h" + "libc_override_glibc.h" + "libc_override_redefine.h" + "tcmalloc.cc" + "tcmalloc.h" + + COPTS "-DTCMALLOC_NUMA_AWARE" + LINKSTATIC + DEPS ${tcmalloc_deps} + "tcmalloc::common_numa_aware" + ALWAYSLINK +) + +tcmalloc_cc_library( + NAME "common_numa_aware" + SRCS ${common_srcs} + HDRS ${common_hdrs} + COPTS "-DTCMALLOC_NUMA_AWARE" + LINKSTATIC + DEPS ${common_deps} + ALWAYSLINK +) + + +tcmalloc_cc_library( + NAME "malloc_extension" + SRCS "malloc_extension.cc" + HDRS + "internal_malloc_extension.h" + "malloc_extension.h" + PUBLIC + DEPS + "tcmalloc::parameter_accessors" + "absl::config" + "absl::core_headers" + "absl::malloc_internal" + "absl::function_ref" + "absl::memory" + "absl::strings" + "absl::time" + "absl::optional" + "absl::span" + +) + +tcmalloc_cc_library( + NAME "new_extension" + SRCS "new_extension.cc" + HDRS "new_extension.h" + DEPS + "absl::core_headers" +) \ No newline at end of file diff --git a/tcmalloc/internal/CMakeLists.txt b/tcmalloc/internal/CMakeLists.txt new file mode 100644 index 000000000..b86cf451d --- /dev/null +++ b/tcmalloc/internal/CMakeLists.txt @@ -0,0 +1,260 @@ + +tcmalloc_cc_library( + NAME "atomic_danger" + HDRS "atomic_danger.h" + DEPS "tcmalloc::config" +) + +tcmalloc_cc_library( + NAME "atomic_stats_counter" + HDRS "atomic_stats_counter.h" + DEPS + "tcmalloc::config" + "absl::core_headers" +) + +tcmalloc_cc_library( + NAME "clock" + HDRS "clock.h" + DEPS + "tcmalloc::config" + "absl::base" + "absl::function_ref" + "absl::time" +) + +tcmalloc_cc_library( + NAME "config" + HDRS "config.h" + DEPS + "absl::config" +) + +tcmalloc_cc_library( + NAME "declarations" + HDRS "declarations.h" +) + +tcmalloc_cc_library( + NAME "environment" + SRCS "environment.cc" + HDRS "environment.h" + DEPS "tcmalloc::config" +) + +tcmalloc_cc_library( + NAME "lifetime_predictions" + HDRS "lifetime_predictions.h" + DEPS + "tcmalloc::linked_list" + "absl::algorithm_container" + "absl::base" + "absl::core_headers" + "absl::malloc_internal" + "absl::stacktrace" + "absl::hash" + "absl::time" +) + +tcmalloc_cc_library( + NAME "lifetime_tracker" + HDRS "lifetime_tracker.h" + DEPS + "tcmalloc::clock" + "tcmalloc::lifetime_predictions" + "tcmalloc::linked_list" + "absl::algorithm_container" + "absl::base" + "absl::core_headers" + "absl::malloc_internal" + "absl::stacktrace" + "absl::hash" + "absl::memory" + "absl::time" +) + +tcmalloc_cc_library( + NAME "linked_list" + HDRS "linked_list.h" + DEPS + "tcmalloc::logging" + "absl::core_headers" + +) + +tcmalloc_cc_library( + NAME "linux_syscall_support" + HDRS "linux_syscall_support.h" +) + +tcmalloc_cc_library( + NAME "logging" + SRCS "logging.cc" + HDRS "logging.h" + DEPS + "tcmalloc::config" + "tcmalloc::parameter_accessors" + "tcmalloc::malloc_extension" + "absl::base" + "absl::core_headers" + "absl::stacktrace" + "absl::strings" + "absl::str_format" +) + +tcmalloc_cc_library( + NAME "memory_stats" + SRCS "memory_stats.cc" + HDRS "memory_stats.h" + DEPS + "tcmalloc::config" + "tcmalloc::logging" + "tcmalloc::util" + "absl::strings" +) + +tcmalloc_cc_library( + NAME "mincore" + SRCS "mincore.cc" + HDRS "mincore.h" + LINKSTATIC + DEPS "tcmalloc::config" +) + +tcmalloc_cc_library( + NAME "mock_span" + TESTONLY + HDRS "mock_span.h" + DEPS + "tcmalloc::linked_list" +) + +tcmalloc_cc_library( + NAME "cache_topology" + SRCS "cache_topology.cc" + HDRS "cache_topology.h" + DEPS + "tcmalloc::config" + "tcmalloc::logging" + "tcmalloc::util" + "absl::base" + "absl::core_headers" + "absl::function_ref" + "absl::strings" +) + +tcmalloc_cc_library( + NAME "numa" + SRCS "numa.cc" + HDRS "numa.h" + DEPS + "tcmalloc::config" + "tcmalloc::environment" + "tcmalloc::logging" + "tcmalloc::percpu" + "tcmalloc::util" + "absl::base" + "absl::core_headers" + "absl::function_ref" + "absl::strings" +) + +tcmalloc_cc_library( + NAME "optimization" + HDRS "optimization.h" + DEPS + "tcmalloc::logging" +) + +tcmalloc_cc_library( + NAME "parameter_accessors" + HDRS "parameter_accessors.h" + DEPS + "absl::core_headers" + "absl::time" +) + +tcmalloc_cc_library( + NAME "percpu" + SRCS + "percpu.cc" + "percpu_rseq_asm.S" + "percpu_rseq_unsupported.cc" + HDRS + "percpu.h" + DEPS + "tcmalloc::atomic_danger" + "tcmalloc::config" + "tcmalloc::linux_syscall_support" + "tcmalloc::logging" + "tcmalloc::optimization" + "tcmalloc::util" + "absl::base" + "absl::core_headers" + "absl::dynamic_annotations" +) + +tcmalloc_cc_library( + NAME "percpu_tcmalloc" + HDRS "percpu_tcmalloc.h" + DEPS + "tcmalloc::mincore" + "tcmalloc::percpu" + "absl::base" + "absl::dynamic_annotations" +) + +tcmalloc_cc_library( + NAME "proc_maps" + SRCS "proc_maps.cc" + HDRS "proc_maps.h" + DEPS + "tcmalloc::config" + "tcmalloc::logging" + "tcmalloc::util" + "absl::core_headers" + "absl::str_format" + +) + +tcmalloc_cc_library( + NAME "range_tracker" + HDRS "range_tracker.h" + DEPS + "tcmalloc::logging" + "tcmalloc::optimization" + "absl::bits" +) + +# An empty rule to force libc malloc instead of TCMalloc. +tcmalloc_cc_library( + NAME "system_malloc" + COPTS TCMALLOC_DEFAULT_COPTS + LINKSTATIC +) + +tcmalloc_cc_library( + NAME "timeseries_tracker" + HDRS "timeseries_tracker.h" + DEPS + "tcmalloc::clock" + "tcmalloc::logging" + "absl::base" + "absl::function_ref" + "absl::bits" + "absl::int128" + "absl::time" +) + +tcmalloc_cc_library( + NAME "util" + SRCS "util.cc" + HDRS "util.h" + DEPS + "tcmalloc::config" + "tcmalloc::logging" + "absl::base" + "absl::core_headers" + "absl::time" + "absl::span" +) \ No newline at end of file From 9aa0708991f50a690787701f184255ff0319d334 Mon Sep 17 00:00:00 2001 From: craffael Date: Fri, 29 Oct 2021 11:50:03 +0200 Subject: [PATCH 2/4] relax minimum cmake requirement --- CMakeLists.txt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 616011016..9be3f0615 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,12 @@ -# We require 3.21 because of https://cmake.org/cmake/help/v3.22/command/target_link_libraries.html#linking-object-libraries-via-target-objects -cmake_minimum_required( VERSION 3.21) +cmake_minimum_required( VERSION 3.10) -include("cmake/HunterGate.cmake") +# It's best to use 3.21 because of https://cmake.org/cmake/help/v3.22/command/target_link_libraries.html#linking-object-libraries-via-target-objects +if(${CMAKE_VERSION} VERSION_LESS "3.21.0") + message(WARN "It is recommended to use CMake Version 3.21.0 or higher to build tcmalloc. See Note in https://cmake.org/cmake/help/v3.22/command/target_link_libraries.html#linking-object-libraries-via-target-objects") +endif() +include("cmake/HunterGate.cmake") HunterGate( URL "https://github.com/cpp-pm/hunter/archive/v0.23.315.tar.gz" From 497bce2255ab6b5baffece2970e1df0323afc15f Mon Sep 17 00:00:00 2001 From: craffael Date: Fri, 29 Oct 2021 18:29:09 +0200 Subject: [PATCH 3/4] require cmake 3.21 --- CMakeLists.txt | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9be3f0615..e0180a1cb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,5 @@ - -cmake_minimum_required( VERSION 3.10) - -# It's best to use 3.21 because of https://cmake.org/cmake/help/v3.22/command/target_link_libraries.html#linking-object-libraries-via-target-objects -if(${CMAKE_VERSION} VERSION_LESS "3.21.0") - message(WARN "It is recommended to use CMake Version 3.21.0 or higher to build tcmalloc. See Note in https://cmake.org/cmake/help/v3.22/command/target_link_libraries.html#linking-object-libraries-via-target-objects") -endif() +# We require 3.21 because of https://cmake.org/cmake/help/v3.22/command/target_link_libraries.html#linking-object-libraries-via-target-objects +cmake_minimum_required( VERSION 3.21) include("cmake/HunterGate.cmake") From 81be46a2c01d62aa56e1e056a1840e8149361573 Mon Sep 17 00:00:00 2001 From: craffael Date: Tue, 2 Nov 2021 08:40:11 +0100 Subject: [PATCH 4/4] remove hunter specific settings --- CMakeLists.txt | 24 +- cmake/HunterGate.cmake | 539 ----------------------------------------- 2 files changed, 11 insertions(+), 552 deletions(-) delete mode 100644 cmake/HunterGate.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index e0180a1cb..9c8e6f521 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,13 +1,6 @@ # We require 3.21 because of https://cmake.org/cmake/help/v3.22/command/target_link_libraries.html#linking-object-libraries-via-target-objects cmake_minimum_required( VERSION 3.21) -include("cmake/HunterGate.cmake") - -HunterGate( - URL "https://github.com/cpp-pm/hunter/archive/v0.23.315.tar.gz" - SHA1 "ea5d72afc0df67f2126e7fd069f20c5f723709e1" -) - project(tcmalloc LANGUAGES CXX ASM) @@ -20,21 +13,26 @@ if("${PROJECT_SOURCE_DIR}" STREQUAL "${PROJECT_BINARY_DIR}") endif() # Get Dependencies -########################## -hunter_add_package(abseil) +####################################### find_package(absl CONFIG REQUIRED) - +# Set Tcmalloc specific properties +####################################### +# Include directory for all tcmalloc targets set(TCMALLOC_COMMON_INCLUDE_DIRS "${CMAKE_CURRENT_LIST_DIR}") + +# C++ Standard used by TCMALLOC set(TCMALLOC_CXX_STANDARD "17") -set(LOCAL_INCLUDE_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}") -set(config_install_dir "lib/cmake/tcmalloc") +# Directory into which cmake install script are copied +set(config_install_dir "lib/cmake/tcmalloc") +# Add sources +####################################### add_subdirectory(tcmalloc) # Installation -############################ +####################################### set(generated_dir "${CMAKE_CURRENT_BINARY_DIR}/generated") set(project_config "${generated_dir}/tcmallocConfig.cmake") diff --git a/cmake/HunterGate.cmake b/cmake/HunterGate.cmake deleted file mode 100644 index 6d9cc2401..000000000 --- a/cmake/HunterGate.cmake +++ /dev/null @@ -1,539 +0,0 @@ -# Copyright (c) 2013-2019, Ruslan Baratov -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are met: -# -# * Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# * Redistributions in binary form must reproduce the above copyright notice, -# this list of conditions and the following disclaimer in the documentation -# and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -# This is a gate file to Hunter package manager. -# Include this file using `include` command and add package you need, example: -# -# cmake_minimum_required(VERSION 3.2) -# -# include("cmake/HunterGate.cmake") -# HunterGate( -# URL "https://github.com/path/to/hunter/archive.tar.gz" -# SHA1 "798501e983f14b28b10cda16afa4de69eee1da1d" -# ) -# -# project(MyProject) -# -# hunter_add_package(Foo) -# hunter_add_package(Boo COMPONENTS Bar Baz) -# -# Projects: -# * https://github.com/hunter-packages/gate/ -# * https://github.com/ruslo/hunter - -option(HUNTER_ENABLED "Enable Hunter package manager support" ON) - -if(HUNTER_ENABLED) - if(CMAKE_VERSION VERSION_LESS "3.2") - message( - FATAL_ERROR - "At least CMake version 3.2 required for Hunter dependency management." - " Update CMake or set HUNTER_ENABLED to OFF." - ) - endif() -endif() - -include(CMakeParseArguments) # cmake_parse_arguments - -option(HUNTER_STATUS_PRINT "Print working status" ON) -option(HUNTER_STATUS_DEBUG "Print a lot info" OFF) -option(HUNTER_TLS_VERIFY "Enable/disable TLS certificate checking on downloads" ON) - -set(HUNTER_ERROR_PAGE "https://docs.hunter.sh/en/latest/reference/errors") - -function(hunter_gate_status_print) - if(HUNTER_STATUS_PRINT OR HUNTER_STATUS_DEBUG) - foreach(print_message ${ARGV}) - message(STATUS "[hunter] ${print_message}") - endforeach() - endif() -endfunction() - -function(hunter_gate_status_debug) - if(HUNTER_STATUS_DEBUG) - foreach(print_message ${ARGV}) - string(TIMESTAMP timestamp) - message(STATUS "[hunter *** DEBUG *** ${timestamp}] ${print_message}") - endforeach() - endif() -endfunction() - -function(hunter_gate_error_page error_page) - message("------------------------------ ERROR ------------------------------") - message(" ${HUNTER_ERROR_PAGE}/${error_page}.html") - message("-------------------------------------------------------------------") - message("") - message(FATAL_ERROR "") -endfunction() - -function(hunter_gate_internal_error) - message("") - foreach(print_message ${ARGV}) - message("[hunter ** INTERNAL **] ${print_message}") - endforeach() - message("[hunter ** INTERNAL **] [Directory:${CMAKE_CURRENT_LIST_DIR}]") - message("") - hunter_gate_error_page("error.internal") -endfunction() - -function(hunter_gate_fatal_error) - cmake_parse_arguments(hunter "" "ERROR_PAGE" "" "${ARGV}") - if("${hunter_ERROR_PAGE}" STREQUAL "") - hunter_gate_internal_error("Expected ERROR_PAGE") - endif() - message("") - foreach(x ${hunter_UNPARSED_ARGUMENTS}) - message("[hunter ** FATAL ERROR **] ${x}") - endforeach() - message("[hunter ** FATAL ERROR **] [Directory:${CMAKE_CURRENT_LIST_DIR}]") - message("") - hunter_gate_error_page("${hunter_ERROR_PAGE}") -endfunction() - -function(hunter_gate_user_error) - hunter_gate_fatal_error(${ARGV} ERROR_PAGE "error.incorrect.input.data") -endfunction() - -function(hunter_gate_self root version sha1 result) - string(COMPARE EQUAL "${root}" "" is_bad) - if(is_bad) - hunter_gate_internal_error("root is empty") - endif() - - string(COMPARE EQUAL "${version}" "" is_bad) - if(is_bad) - hunter_gate_internal_error("version is empty") - endif() - - string(COMPARE EQUAL "${sha1}" "" is_bad) - if(is_bad) - hunter_gate_internal_error("sha1 is empty") - endif() - - string(SUBSTRING "${sha1}" 0 7 archive_id) - - if(EXISTS "${root}/cmake/Hunter") - set(hunter_self "${root}") - else() - set( - hunter_self - "${root}/_Base/Download/Hunter/${version}/${archive_id}/Unpacked" - ) - endif() - - set("${result}" "${hunter_self}" PARENT_SCOPE) -endfunction() - -# Set HUNTER_GATE_ROOT cmake variable to suitable value. -function(hunter_gate_detect_root) - # Check CMake variable - string(COMPARE NOTEQUAL "${HUNTER_ROOT}" "" not_empty) - if(not_empty) - set(HUNTER_GATE_ROOT "${HUNTER_ROOT}" PARENT_SCOPE) - hunter_gate_status_debug("HUNTER_ROOT detected by cmake variable") - return() - endif() - - # Check environment variable - string(COMPARE NOTEQUAL "$ENV{HUNTER_ROOT}" "" not_empty) - if(not_empty) - set(HUNTER_GATE_ROOT "$ENV{HUNTER_ROOT}" PARENT_SCOPE) - hunter_gate_status_debug("HUNTER_ROOT detected by environment variable") - return() - endif() - - # Check HOME environment variable - string(COMPARE NOTEQUAL "$ENV{HOME}" "" result) - if(result) - set(HUNTER_GATE_ROOT "$ENV{HOME}/.hunter" PARENT_SCOPE) - hunter_gate_status_debug("HUNTER_ROOT set using HOME environment variable") - return() - endif() - - # Check SYSTEMDRIVE and USERPROFILE environment variable (windows only) - if(WIN32) - string(COMPARE NOTEQUAL "$ENV{SYSTEMDRIVE}" "" result) - if(result) - set(HUNTER_GATE_ROOT "$ENV{SYSTEMDRIVE}/.hunter" PARENT_SCOPE) - hunter_gate_status_debug( - "HUNTER_ROOT set using SYSTEMDRIVE environment variable" - ) - return() - endif() - - string(COMPARE NOTEQUAL "$ENV{USERPROFILE}" "" result) - if(result) - set(HUNTER_GATE_ROOT "$ENV{USERPROFILE}/.hunter" PARENT_SCOPE) - hunter_gate_status_debug( - "HUNTER_ROOT set using USERPROFILE environment variable" - ) - return() - endif() - endif() - - hunter_gate_fatal_error( - "Can't detect HUNTER_ROOT" - ERROR_PAGE "error.detect.hunter.root" - ) -endfunction() - -function(hunter_gate_download dir) - string( - COMPARE - NOTEQUAL - "$ENV{HUNTER_DISABLE_AUTOINSTALL}" - "" - disable_autoinstall - ) - if(disable_autoinstall AND NOT HUNTER_RUN_INSTALL) - hunter_gate_fatal_error( - "Hunter not found in '${dir}'" - "Set HUNTER_RUN_INSTALL=ON to auto-install it from '${HUNTER_GATE_URL}'" - "Settings:" - " HUNTER_ROOT: ${HUNTER_GATE_ROOT}" - " HUNTER_SHA1: ${HUNTER_GATE_SHA1}" - ERROR_PAGE "error.run.install" - ) - endif() - string(COMPARE EQUAL "${dir}" "" is_bad) - if(is_bad) - hunter_gate_internal_error("Empty 'dir' argument") - endif() - - string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" is_bad) - if(is_bad) - hunter_gate_internal_error("HUNTER_GATE_SHA1 empty") - endif() - - string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" is_bad) - if(is_bad) - hunter_gate_internal_error("HUNTER_GATE_URL empty") - endif() - - set(done_location "${dir}/DONE") - set(sha1_location "${dir}/SHA1") - - set(build_dir "${dir}/Build") - set(cmakelists "${dir}/CMakeLists.txt") - - hunter_gate_status_debug("Locking directory: ${dir}") - file(LOCK "${dir}" DIRECTORY GUARD FUNCTION) - hunter_gate_status_debug("Lock done") - - if(EXISTS "${done_location}") - # while waiting for lock other instance can do all the job - hunter_gate_status_debug("File '${done_location}' found, skip install") - return() - endif() - - file(REMOVE_RECURSE "${build_dir}") - file(REMOVE_RECURSE "${cmakelists}") - - file(MAKE_DIRECTORY "${build_dir}") # check directory permissions - - # Disabling languages speeds up a little bit, reduces noise in the output - # and avoids path too long windows error - file( - WRITE - "${cmakelists}" - "cmake_minimum_required(VERSION 3.2)\n" - "project(HunterDownload LANGUAGES NONE)\n" - "include(ExternalProject)\n" - "ExternalProject_Add(\n" - " Hunter\n" - " URL\n" - " \"${HUNTER_GATE_URL}\"\n" - " URL_HASH\n" - " SHA1=${HUNTER_GATE_SHA1}\n" - " DOWNLOAD_DIR\n" - " \"${dir}\"\n" - " TLS_VERIFY\n" - " ${HUNTER_TLS_VERIFY}\n" - " SOURCE_DIR\n" - " \"${dir}/Unpacked\"\n" - " CONFIGURE_COMMAND\n" - " \"\"\n" - " BUILD_COMMAND\n" - " \"\"\n" - " INSTALL_COMMAND\n" - " \"\"\n" - ")\n" - ) - - if(HUNTER_STATUS_DEBUG) - set(logging_params "") - else() - set(logging_params OUTPUT_QUIET) - endif() - - hunter_gate_status_debug("Run generate") - - # Need to add toolchain file too. - # Otherwise on Visual Studio + MDD this will fail with error: - # "Could not find an appropriate version of the Windows 10 SDK installed on this machine" - if(EXISTS "${CMAKE_TOOLCHAIN_FILE}") - get_filename_component(absolute_CMAKE_TOOLCHAIN_FILE "${CMAKE_TOOLCHAIN_FILE}" ABSOLUTE) - set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=${absolute_CMAKE_TOOLCHAIN_FILE}") - else() - # 'toolchain_arg' can't be empty - set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=") - endif() - - string(COMPARE EQUAL "${CMAKE_MAKE_PROGRAM}" "" no_make) - if(no_make) - set(make_arg "") - else() - # Test case: remove Ninja from PATH but set it via CMAKE_MAKE_PROGRAM - set(make_arg "-DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}") - endif() - - execute_process( - COMMAND - "${CMAKE_COMMAND}" - "-H${dir}" - "-B${build_dir}" - "-G${CMAKE_GENERATOR}" - "${toolchain_arg}" - ${make_arg} - WORKING_DIRECTORY "${dir}" - RESULT_VARIABLE download_result - ${logging_params} - ) - - if(NOT download_result EQUAL 0) - hunter_gate_internal_error( - "Configure project failed." - "To reproduce the error run: ${CMAKE_COMMAND} -H${dir} -B${build_dir} -G${CMAKE_GENERATOR} ${toolchain_arg} ${make_arg}" - "In directory ${dir}" - ) - endif() - - hunter_gate_status_print( - "Initializing Hunter workspace (${HUNTER_GATE_SHA1})" - " ${HUNTER_GATE_URL}" - " -> ${dir}" - ) - execute_process( - COMMAND "${CMAKE_COMMAND}" --build "${build_dir}" - WORKING_DIRECTORY "${dir}" - RESULT_VARIABLE download_result - ${logging_params} - ) - - if(NOT download_result EQUAL 0) - hunter_gate_internal_error("Build project failed") - endif() - - file(REMOVE_RECURSE "${build_dir}") - file(REMOVE_RECURSE "${cmakelists}") - - file(WRITE "${sha1_location}" "${HUNTER_GATE_SHA1}") - file(WRITE "${done_location}" "DONE") - - hunter_gate_status_debug("Finished") -endfunction() - -# Must be a macro so master file 'cmake/Hunter' can -# apply all variables easily just by 'include' command -# (otherwise PARENT_SCOPE magic needed) -macro(HunterGate) - if(HUNTER_GATE_DONE) - # variable HUNTER_GATE_DONE set explicitly for external project - # (see `hunter_download`) - set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES) - endif() - - # First HunterGate command will init Hunter, others will be ignored - get_property(_hunter_gate_done GLOBAL PROPERTY HUNTER_GATE_DONE SET) - - if(NOT HUNTER_ENABLED) - # Empty function to avoid error "unknown function" - function(hunter_add_package) - endfunction() - - set( - _hunter_gate_disabled_mode_dir - "${CMAKE_CURRENT_LIST_DIR}/cmake/Hunter/disabled-mode" - ) - if(EXISTS "${_hunter_gate_disabled_mode_dir}") - hunter_gate_status_debug( - "Adding \"disabled-mode\" modules: ${_hunter_gate_disabled_mode_dir}" - ) - list(APPEND CMAKE_PREFIX_PATH "${_hunter_gate_disabled_mode_dir}") - endif() - elseif(_hunter_gate_done) - hunter_gate_status_debug("Secondary HunterGate (use old settings)") - hunter_gate_self( - "${HUNTER_CACHED_ROOT}" - "${HUNTER_VERSION}" - "${HUNTER_SHA1}" - _hunter_self - ) - include("${_hunter_self}/cmake/Hunter") - else() - set(HUNTER_GATE_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}") - - string(COMPARE NOTEQUAL "${PROJECT_NAME}" "" _have_project_name) - if(_have_project_name) - hunter_gate_fatal_error( - "Please set HunterGate *before* 'project' command. " - "Detected project: ${PROJECT_NAME}" - ERROR_PAGE "error.huntergate.before.project" - ) - endif() - - cmake_parse_arguments( - HUNTER_GATE "LOCAL" "URL;SHA1;GLOBAL;FILEPATH" "" ${ARGV} - ) - - string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" _empty_sha1) - string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" _empty_url) - string( - COMPARE - NOTEQUAL - "${HUNTER_GATE_UNPARSED_ARGUMENTS}" - "" - _have_unparsed - ) - string(COMPARE NOTEQUAL "${HUNTER_GATE_GLOBAL}" "" _have_global) - string(COMPARE NOTEQUAL "${HUNTER_GATE_FILEPATH}" "" _have_filepath) - - if(_have_unparsed) - hunter_gate_user_error( - "HunterGate unparsed arguments: ${HUNTER_GATE_UNPARSED_ARGUMENTS}" - ) - endif() - if(_empty_sha1) - hunter_gate_user_error("SHA1 suboption of HunterGate is mandatory") - endif() - if(_empty_url) - hunter_gate_user_error("URL suboption of HunterGate is mandatory") - endif() - if(_have_global) - if(HUNTER_GATE_LOCAL) - hunter_gate_user_error("Unexpected LOCAL (already has GLOBAL)") - endif() - if(_have_filepath) - hunter_gate_user_error("Unexpected FILEPATH (already has GLOBAL)") - endif() - endif() - if(HUNTER_GATE_LOCAL) - if(_have_global) - hunter_gate_user_error("Unexpected GLOBAL (already has LOCAL)") - endif() - if(_have_filepath) - hunter_gate_user_error("Unexpected FILEPATH (already has LOCAL)") - endif() - endif() - if(_have_filepath) - if(_have_global) - hunter_gate_user_error("Unexpected GLOBAL (already has FILEPATH)") - endif() - if(HUNTER_GATE_LOCAL) - hunter_gate_user_error("Unexpected LOCAL (already has FILEPATH)") - endif() - endif() - - hunter_gate_detect_root() # set HUNTER_GATE_ROOT - - # Beautify path, fix probable problems with windows path slashes - get_filename_component( - HUNTER_GATE_ROOT "${HUNTER_GATE_ROOT}" ABSOLUTE - ) - hunter_gate_status_debug("HUNTER_ROOT: ${HUNTER_GATE_ROOT}") - if(NOT HUNTER_ALLOW_SPACES_IN_PATH) - string(FIND "${HUNTER_GATE_ROOT}" " " _contain_spaces) - if(NOT _contain_spaces EQUAL -1) - hunter_gate_fatal_error( - "HUNTER_ROOT (${HUNTER_GATE_ROOT}) contains spaces." - "Set HUNTER_ALLOW_SPACES_IN_PATH=ON to skip this error" - "(Use at your own risk!)" - ERROR_PAGE "error.spaces.in.hunter.root" - ) - endif() - endif() - - string( - REGEX - MATCH - "[0-9]+\\.[0-9]+\\.[0-9]+[-_a-z0-9]*" - HUNTER_GATE_VERSION - "${HUNTER_GATE_URL}" - ) - string(COMPARE EQUAL "${HUNTER_GATE_VERSION}" "" _is_empty) - if(_is_empty) - set(HUNTER_GATE_VERSION "unknown") - endif() - - hunter_gate_self( - "${HUNTER_GATE_ROOT}" - "${HUNTER_GATE_VERSION}" - "${HUNTER_GATE_SHA1}" - _hunter_self - ) - - set(_master_location "${_hunter_self}/cmake/Hunter") - if(EXISTS "${HUNTER_GATE_ROOT}/cmake/Hunter") - # Hunter downloaded manually (e.g. by 'git clone') - set(_unused "xxxxxxxxxx") - set(HUNTER_GATE_SHA1 "${_unused}") - set(HUNTER_GATE_VERSION "${_unused}") - else() - get_filename_component(_archive_id_location "${_hunter_self}/.." ABSOLUTE) - set(_done_location "${_archive_id_location}/DONE") - set(_sha1_location "${_archive_id_location}/SHA1") - - # Check Hunter already downloaded by HunterGate - if(NOT EXISTS "${_done_location}") - hunter_gate_download("${_archive_id_location}") - endif() - - if(NOT EXISTS "${_done_location}") - hunter_gate_internal_error("hunter_gate_download failed") - endif() - - if(NOT EXISTS "${_sha1_location}") - hunter_gate_internal_error("${_sha1_location} not found") - endif() - file(READ "${_sha1_location}" _sha1_value) - string(COMPARE EQUAL "${_sha1_value}" "${HUNTER_GATE_SHA1}" _is_equal) - if(NOT _is_equal) - hunter_gate_internal_error( - "Short SHA1 collision:" - " ${_sha1_value} (from ${_sha1_location})" - " ${HUNTER_GATE_SHA1} (HunterGate)" - ) - endif() - if(NOT EXISTS "${_master_location}") - hunter_gate_user_error( - "Master file not found:" - " ${_master_location}" - "try to update Hunter/HunterGate" - ) - endif() - endif() - include("${_master_location}") - set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES) - endif() -endmacro()