diff options
author | Davide Beatrici <git@davidebeatrici.dev> | 2020-07-03 17:34:26 +0300 |
---|---|---|
committer | Davide Beatrici <git@davidebeatrici.dev> | 2020-07-11 20:34:49 +0300 |
commit | f08cfe5fa4914d41d2e3813cd41b94a9bf9e5e76 (patch) | |
tree | 5238b30e53cc8512fbc0d26d03f3e3f0cc0f12f0 /cmake | |
parent | cf73a3565778fa5af4b592da77be01f2f5928558 (diff) |
Add CMake functions and modules
Diffstat (limited to 'cmake')
-rw-r--r-- | cmake/FindModules/FindGRPC.cmake | 88 | ||||
-rw-r--r-- | cmake/compiler.cmake | 120 | ||||
-rw-r--r-- | cmake/os.cmake | 63 | ||||
-rw-r--r-- | cmake/pkg-utils.cmake | 185 | ||||
-rw-r--r-- | cmake/qt-utils.cmake | 53 |
5 files changed, 509 insertions, 0 deletions
diff --git a/cmake/FindModules/FindGRPC.cmake b/cmake/FindModules/FindGRPC.cmake new file mode 100644 index 000000000..f9ea5299c --- /dev/null +++ b/cmake/FindModules/FindGRPC.cmake @@ -0,0 +1,88 @@ +# https://github.com/IvanSafonov/grpc-cmake-example + +# MIT License +# +# Copyright (c) 2018 Ivan Safonov +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +# +# Locate and configure the gRPC library +# +# Adds the following targets: +# +# gRPC::grpc - gRPC library +# gRPC::grpc++ - gRPC C++ library +# gRPC::grpc++_reflection - gRPC C++ reflection library +# gRPC::grpc_cpp_plugin - C++ generator plugin for Protocol Buffers +# + +# Find gRPC include directory +find_path(GRPC_INCLUDE_DIR grpc/grpc.h) +mark_as_advanced(GRPC_INCLUDE_DIR) + +# Find gRPC library +if(NOT TARGET gRPC::grpc) + find_library(GRPC_LIBRARY NAMES grpc) + mark_as_advanced(GRPC_LIBRARY) + add_library(gRPC::grpc UNKNOWN IMPORTED) + set_target_properties(gRPC::grpc PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${GRPC_INCLUDE_DIR} + INTERFACE_LINK_LIBRARIES "-lpthread;-ldl" + IMPORTED_LOCATION ${GRPC_LIBRARY} + ) +endif() + +# Find gRPC C++ library +if(NOT TARGET gRPC::grpc++) + find_library(GRPC_GRPC++_LIBRARY NAMES grpc++) + mark_as_advanced(GRPC_GRPC++_LIBRARY) + add_library(gRPC::grpc++ UNKNOWN IMPORTED) + set_target_properties(gRPC::grpc++ PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${GRPC_INCLUDE_DIR} + INTERFACE_LINK_LIBRARIES gRPC::grpc + IMPORTED_LOCATION ${GRPC_GRPC++_LIBRARY} + ) +endif() + +# Find gRPC C++ reflection library +if(NOT TARGET gRPC::grpc++_reflection) + find_library(GRPC_GRPC++_REFLECTION_LIBRARY NAMES grpc++_reflection) + mark_as_advanced(GRPC_GRPC++_REFLECTION_LIBRARY) + add_library(gRPC::grpc++_reflection UNKNOWN IMPORTED) + set_target_properties(gRPC::grpc++_reflection PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES ${GRPC_INCLUDE_DIR} + INTERFACE_LINK_LIBRARIES gRPC::grpc++ + IMPORTED_LOCATION ${GRPC_GRPC++_REFLECTION_LIBRARY} + ) +endif() + +# Find gRPC CPP generator +if(NOT TARGET gRPC::grpc_cpp_plugin) + find_program(GRPC_CPP_PLUGIN NAMES grpc_cpp_plugin) + mark_as_advanced(GRPC_CPP_PLUGIN) + add_executable(gRPC::grpc_cpp_plugin IMPORTED) + set_target_properties(gRPC::grpc_cpp_plugin PROPERTIES + IMPORTED_LOCATION ${GRPC_CPP_PLUGIN} + ) +endif() + +if(TARGET gRPC::grpc AND TARGET gRPC::grpc++ AND TARGET gRPC::grpc++_reflection AND TARGET gRPC::grpc_cpp_plugin) + set(GRPC_FOUND PARENT_SCOPE TRUE) +endif() diff --git a/cmake/compiler.cmake b/cmake/compiler.cmake new file mode 100644 index 000000000..4a7acc82d --- /dev/null +++ b/cmake/compiler.cmake @@ -0,0 +1,120 @@ +# Copyright 2019-2020 The Mumble Developers. All rights reserved. +# Use of this source code is governed by a BSD-style license +# that can be found in the LICENSE file at the root of the +# Mumble source tree or at <https://www.mumble.info/LICENSE>. + +if(${CMAKE_SIZEOF_VOID_P} EQUAL 8) + set(64_BIT TRUE) +elseif(${CMAKE_SIZEOF_VOID_P} EQUAL 4) + set(32_BIT TRUE) +endif() + +if(MSVC) + if($<CONFIG:Release>) + add_compile_options( + "/Ox" + "/fp:fast" + ) + endif() + + if(32_BIT) + # SSE2 code is generated by default, unless an explict arch is set. + # Our 32 bit binaries should not contain any SSE2 code, so override the default. + add_compile_options("-arch:SSE") + endif() + + if(symbols) + # Configure build to be able to properly debug release builds (https://docs.microsoft.com/cpp/build/how-to-debug-a-release-build). + # This includes explicitely disabling /Oy to help debugging (https://docs.microsoft.com/cpp/build/reference/oy-frame-pointer-omission). + # Also set /Zo to enhance optimized debugging (https://docs.microsoft.com/cpp/build/reference/zo-enhance-optimized-debugging). + add_compile_options( + "/GR" + "/Zi" + "/Zo" + "/Oy-" + ) + add_link_options( + "/DEBUG" + "/OPT:REF" + "/OPT:ICF" + "/INCREMENTAL:NO" + ) + endif() + + if(warnings-as-errors) + add_compile_options("/WX") + add_link_options("/WX") + endif() +elseif(UNIX OR MINGW) + add_compile_options( + "-fvisibility=hidden" + "-Wall" + "-Wextra" + ) + + if(options) + add_compile_options( + "-O3" + "-march=native" + "-ffast-math" + "-ftree-vectorize" + ) + endif() + + if(warnings-as-errors) + add_compile_options("-Werror") + endif() + + if(APPLE) + add_link_options("-Wl,-dead_strip") + + if(symbols) + add_compile_options( + "-gfull" + "-gdwarf-2" + ) + endif() + else() + if(NOT MINGW) + add_link_options( + "-Wl,-z,relro" + "-Wl,-z,now" + ) + endif() + + # Ensure _FORTIFY_SOURCE is not used in debug builds. + # + # First, ensure _FORTIFY_SOURCE is undefined. + # Then -- and, only for release builds -- set _FORTIFY_SOURCE=2. + # + # We can't use _FORTIFY_SOURCE in debug builds (which are built with -O0) because _FORTIFY_SOURCE=1 requires -O1 and _FORTIFY_SOURCE=2 requires -O2. + # Modern GLIBCs warn about this since https://sourceware.org/bugzilla/show_bug.cgi?id=13979. + # In Mumble builds with warnings-as-errors, this will cause build failures. + add_compile_options("-U_FORTIFY_SOURCE") + + if($<CONFIG:Debug>) + if(NOT MINGW) + add_compile_options("-fstack-protector") + endif() + add_compile_options("-fPIE") + add_link_options( + "-pie" + "-Wl,--no-add-needed" + ) + else() + add_compile_options("-D_FORTIFY_SOURCE=2") + endif() + + if(symbols) + add_compile_options("-g") + endif() + endif() +endif() + +function(target_disable_warnings TARGET) + if(MSVC) + target_compile_options(${TARGET} PRIVATE "/w") + else() + target_compile_options(${TARGET} PRIVATE "-w") + endif() +endfunction() diff --git a/cmake/os.cmake b/cmake/os.cmake new file mode 100644 index 000000000..659ba6a68 --- /dev/null +++ b/cmake/os.cmake @@ -0,0 +1,63 @@ +# Copyright 2019-2020 The Mumble Developers. All rights reserved. +# Use of this source code is governed by a BSD-style license +# that can be found in the LICENSE file at the root of the +# Mumble source tree or at <https://www.mumble.info/LICENSE>. + +if(BUILD_TESTING) + if(WIN32 AND NOT ${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Windows") + # We're building for Windows on a different operating system. + find_program(WINE + NAMES + "wine" + "wine-development" + DOC + "Wine (to run tests)" + ) + if(WINE) + set(CMAKE_CROSSCOMPILING_EMULATOR ${WINE}) + message(STATUS "The following Wine binary will be used to run tests: \"${WINE}\"") + else() + message(STATUS "You are cross-compiling for Windows but don't have Wine, you will not be able to run tests.") + endif() + endif() +endif() + +# Qt-related performance tweaks. +add_definitions( + "-DQT_USE_FAST_CONCATENATION" + "-DQT_USE_FAST_OPERATOR_PLUS" + # TODO: Uncomment the following definitions when the resulting errors are fixed. + #"-DQT_NO_CAST_FROM_ASCII" + #"-DQT_NO_CAST_TO_ASCII" +) + +if(WIN32) + add_definitions( + "-DUNICODE" + "-DWIN32_LEAN_AND_MEAN" + ) +else() + if(${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD") + include_directories("/usr/local/include") + link_directories("/usr/local/lib") + endif() + + find_pkg(OpenSSL QUIET) + find_pkg(Qt5 QUIET) + + if(NOT OpenSSL_FOUND) + if(APPLE) + # Homebrew + set(OPENSSL_ROOT_DIR "/usr/local/opt/openssl") + endif() + endif() + + if(NOT Qt5_FOUND) + if(APPLE) + # Homebrew + set(Qt5_DIR "/usr/local/opt/qt5/lib/cmake/Qt5") + elseif(${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD") + set(Qt5_DIR "/usr/local/lib/qt5/cmake/Qt5") + endif() + endif() +endif() diff --git a/cmake/pkg-utils.cmake b/cmake/pkg-utils.cmake new file mode 100644 index 000000000..02ef906cb --- /dev/null +++ b/cmake/pkg-utils.cmake @@ -0,0 +1,185 @@ +# Copyright 2019-2020 The Mumble Developers. All rights reserved. +# Use of this source code is governed by a BSD-style license +# that can be found in the LICENSE file at the root of the +# Mumble source tree or at <https://www.mumble.info/LICENSE>. + +find_package(PkgConfig QUIET) + +include(FindPackageMessage) + +function(pkgconfig_search MODULE) + if(NOT PkgConfig_FOUND) + return() + endif() + + # We don't want pkg_search_module() to write into the variables that will be passed to the pkgconfig_search()'s caller. + set(PRIVATE "PRIVATE_${MODULE}") + + pkg_search_module(${PRIVATE} ${MODULE} QUIET) + + if(NOT ${PRIVATE}_FOUND) + return() + endif() + + if(NOT ${PRIVATE}_LINK_LIBRARIES) + foreach(LIBRARY ${${PRIVATE}_LIBRARIES}) + # A cache entry named by <VAR> is created to store the result of find_library(). + # If the library is found the result is stored in the variable and the search will not be repeated unless the variable is cleared. + # Using a name that depends on the loop-item is suggested in contrast to clearing the variable. + # @ref https://cmake.org/pipermail/cmake/2011-November/047171.html + find_library(${LIBRARY}_LINK ${PRIVATE_LIBRARY} PATHS ${${PRIVATE}_LIBRARY_DIRS}) + list(APPEND ${PRIVATE}_LINK_LIBRARIES ${${LIBRARY}_LINK}) + endforeach() + endif() + + set(${MODULE}_INCLUDE_DIRS ${${PRIVATE}_INCLUDE_DIRS} PARENT_SCOPE) + set(${MODULE}_LIBRARIES ${${PRIVATE}_LINK_LIBRARIES} PARENT_SCOPE) + set(${MODULE}_VERSION ${${PRIVATE}_VERSION} PARENT_SCOPE) + set(${MODULE}_FOUND ${${PRIVATE}_FOUND} PARENT_SCOPE) +endfunction() + +# This macro's main purpose is to call find_package() with CONFIG and then with MODULE if it fails. +# It also handles multiple package names and searches them with pkg-config if they are not found. +macro(find_pkg ARG_ALIASES) + # We specify "CONFIG", "MODULE" and "NO_MODULE" so that they are not considered unparsed arguments (passed to find_package()). + cmake_parse_arguments(FIND_PACKAGE "ARG_ALIASES;CONFIG;MODULE;NO_DEFAULT_PATH;NO_MODULE;REQUIRED;QUIET" "" "COMPONENTS;OPTIONAL_COMPONENTS;PATHS" ${ARGN}) + + if(FIND_PACKAGE_PATHS) + list(APPEND FIND_PACKAGE_ARGUMENTS "PATHS" ${FIND_PACKAGE_PATHS}) + endif() + + if(FIND_PACKAGE_NO_DEFAULT_PATH) + list(APPEND FIND_PACKAGE_ARGUMENTS "NO_DEFAULT_PATH") + endif() + + # We add the aliases to a clean list because of an issue with list(GET). + # If we pass the argument list directly to it, LAST_ALIAS is always set to "NOTFOUND". + foreach(ALIAS ${ARG_ALIASES}) + list(APPEND ALIASES ${ALIAS}) + endforeach() + + list(REMOVE_DUPLICATES ALIASES) + + list(GET ALIASES -1 LAST_ALIAS) + + foreach(ALIAS ${ALIASES}) + set(NAME ${ALIAS}) + + if(FIND_PACKAGE_COMPONENTS) + foreach(COMPONENT ${FIND_PACKAGE_COMPONENTS}) + find_package(${NAME} COMPONENTS ${COMPONENT} ${FIND_PACKAGE_ARGUMENTS} QUIET CONFIG ${FIND_PACKAGE_UNPARSED_ARGUMENTS}) + if(NOT ${NAME}_FOUND) + find_package(${NAME} COMPONENTS ${COMPONENT} ${FIND_PACKAGE_ARGUMENTS} QUIET MODULE ${FIND_PACKAGE_UNPARSED_ARGUMENTS}) + endif() + + if(NOT ${NAME}_FOUND) + if(NOT ${NAME} STREQUAL ${LAST_ALIAS}) + break() + else() + if(FIND_PACKAGE_REQUIRED) + message(FATAL_ERROR "${NAME} component not found: ${COMPONENT}") + endif() + + if(NOT FIND_PACKAGE_QUIET) + message(STATUS "${NAME} component not found: ${COMPONENT}") + endif() + + break() + endif() + endif() + + if(NOT FIND_PACKAGE_QUIET) + if(${NAME}_VERSION) + find_package_message(${NAME} "${NAME} component found: ${COMPONENT} | Version: ${${NAME}_VERSION}" "[${NAME}][${COMPONENT}][${${NAME}_VERSION}]") + else() + find_package_message(${NAME} "${NAME} component found: ${COMPONENT}" "[${NAME}][${COMPONENT}]") + endif() + endif() + endforeach() + + if(NOT ${NAME}_FOUND) + continue() + endif() + else() + find_package(${NAME} ${FIND_PACKAGE_ARGUMENTS} QUIET CONFIG ${FIND_PACKAGE_UNPARSED_ARGUMENTS}) + if(NOT ${NAME}_FOUND) + find_package(${NAME} ${FIND_PACKAGE_ARGUMENTS} QUIET MODULE ${FIND_PACKAGE_UNPARSED_ARGUMENTS}) + if(NOT ${NAME}_FOUND) + pkgconfig_search(${NAME}) + endif() + endif() + + if(NOT ${NAME}_FOUND) + if(NOT ${NAME} STREQUAL ${LAST_ALIAS}) + continue() + else() + if(FIND_PACKAGE_REQUIRED) + message(FATAL_ERROR "${NAME} not found") + endif() + + if(NOT FIND_PACKAGE_QUIET) + message(STATUS "${NAME} not found") + endif() + + break() + endif() + endif() + + if(NOT FIND_PACKAGE_QUIET) + if(${NAME}_VERSION) + find_package_message(${NAME} "${NAME} found | Version: ${${NAME}_VERSION}" "[${NAME}][${${NAME}_VERSION}]") + else() + find_package_message(${NAME} "${NAME} found" "[${NAME}]") + endif() + endif() + endif() + + if(FIND_PACKAGE_OPTIONAL_COMPONENTS) + foreach(COMPONENT ${FIND_PACKAGE_OPTIONAL_COMPONENTS}) + find_package(${NAME} COMPONENTS ${COMPONENT} ${FIND_PACKAGE_ARGUMENTS} QUIET CONFIG ${FIND_PACKAGE_UNPARSED_ARGUMENTS}) + if(NOT ${NAME}_FOUND) + find_package(${NAME} COMPONENTS ${COMPONENT} ${FIND_PACKAGE_ARGUMENTS} QUIET MODULE ${FIND_PACKAGE_UNPARSED_ARGUMENTS}) + endif() + + if(${NAME}_FOUND AND NOT FIND_PACKAGE_QUIET) + if(${NAME}_VERSION) + find_package_message(${NAME} "${NAME} optional component found: ${COMPONENT} | Version: ${${NAME}_VERSION}" "[${NAME}][${COMPONENT}][${${NAME}_VERSION}]") + else() + find_package_message(${NAME} "${NAME} optional component found: ${COMPONENT}" "[${NAME}][${COMPONENT}]") + endif() + endif() + endforeach() + endif() + + if(${NAME}_FOUND) + break() + endif() + endforeach() + + unset(ALIASES) + unset(LAST_ALIAS) + unset(FIND_PACKAGE_ARGUMENTS) + + if(${NAME}_FOUND) + if(NOT ${NAME}_VERSION OR NOT ${NAME}_LIBRARIES) + # The FindOpenSSL module defines the variables with an uppercase prefix. + string(TOUPPER ${NAME} NAME_UPPER) + + if(NOT ${NAME}_VERSION) + set(${NAME}_VERSION ${${NAME_UPPER}_VERSION}) + endif() + + if(NOT ${NAME}_LIBRARIES) + set(${NAME}_LIBRARIES ${${NAME_UPPER}_LIBRARIES}) + endif() + + unset(NAME_UPPER) + endif() + elseif(NOT FIND_PACKAGE_QUIET) + if(NOT PkgConfig_FOUND) + message(WARNING "pkg-config was not found, consider installing it for better chances of finding a package") + endif() + endif() + + unset(NAME) +endmacro() diff --git a/cmake/qt-utils.cmake b/cmake/qt-utils.cmake new file mode 100644 index 000000000..6b810959d --- /dev/null +++ b/cmake/qt-utils.cmake @@ -0,0 +1,53 @@ +# Copyright 2019-2020 The Mumble Developers. All rights reserved. +# Use of this source code is governed by a BSD-style license +# that can be found in the LICENSE file at the root of the +# Mumble source tree or at <https://www.mumble.info/LICENSE>. + +function(include_qt_plugin TARGET SCOPE PLUGIN) + set(PATH "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_plugin_import.cpp") + if(NOT EXISTS ${PATH}) + file(WRITE ${PATH} "#include <QtPlugin>\n") + set_property(SOURCE ${PATH} PROPERTY GENERATED TRUE SKIP_AUTOGEN TRUE) + else() + file(READ ${PATH} CONTENT) + string(FIND ${CONTENT} ${PLUGIN} INDEX) + if(NOT ${INDEX} EQUAL -1) + set(FOUND TRUE) + endif() + endif() + + if(NOT FOUND) + file(APPEND ${PATH} "Q_IMPORT_PLUGIN(${PLUGIN})\n") + endif() + + get_property(TARGET_SOURCES TARGET ${TARGET} PROPERTY SOURCES) + if(NOT ${PATH} IN_LIST TARGET_SOURCES) + target_sources(${TARGET} ${SCOPE} ${PATH}) + endif() +endfunction() + +function(create_translations_qrc TS_DIR TS_FILES QRC_FILENAME) + find_pkg(Qt5 COMPONENTS LinguistTools REQUIRED) + + # Workaround for Qt bug: CMake deletes .ts files upon clean. + # @ref https://bugreports.qt.io/browse/QTBUG-41736 + # @ref https://stackoverflow.com/a/24245615/1917249 + set_directory_properties(PROPERTIES CLEAN_NO_CUSTOM TRUE) + + # Update the translation files (e.g. add new strings) and compile them. + qt5_create_translation(QM_FILES ${TS_DIR} ${TS_FILES}) + + set(QRC_PATH "${CMAKE_CURRENT_BINARY_DIR}/${QRC_FILENAME}") + + # Create a resource file (.qrc) containing the name of the compiled translation files (.qm). + # This is required in order to embed those files into the built executable. + # NOTE: We write the files' name instead of their path because they are in the same directory as the resource file. + file(WRITE ${QRC_PATH} "<!DOCTYPE RCC><RCC version=\"1.0\">\n<qresource>\n") + + foreach(QM_FILE ${QM_FILES}) + get_filename_component(FILENAME ${QM_FILE} NAME) + file(APPEND ${QRC_PATH} "\t<file>${FILENAME}</file>\n") + endforeach() + + file(APPEND ${QRC_PATH} "</qresource>\n</RCC>\n") +endfunction() |