Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mumble-voip/mumble.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/cmake
diff options
context:
space:
mode:
authorDavide Beatrici <git@davidebeatrici.dev>2020-07-03 17:34:26 +0300
committerDavide Beatrici <git@davidebeatrici.dev>2020-07-11 20:34:49 +0300
commitf08cfe5fa4914d41d2e3813cd41b94a9bf9e5e76 (patch)
tree5238b30e53cc8512fbc0d26d03f3e3f0cc0f12f0 /cmake
parentcf73a3565778fa5af4b592da77be01f2f5928558 (diff)
Add CMake functions and modules
Diffstat (limited to 'cmake')
-rw-r--r--cmake/FindModules/FindGRPC.cmake88
-rw-r--r--cmake/compiler.cmake120
-rw-r--r--cmake/os.cmake63
-rw-r--r--cmake/pkg-utils.cmake185
-rw-r--r--cmake/qt-utils.cmake53
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()