X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=cmake%2FQuasselMacros.cmake;h=1c0c687ca8137ddae4bd85812bf9a094842cd657;hp=bc665725d77e274d38f70d552fb8607143af878a;hb=a078e08390e41385a3145f22e83afbf622621c2f;hpb=0216d4a650c02155b5bcd517567209f674d8a120 diff --git a/cmake/QuasselMacros.cmake b/cmake/QuasselMacros.cmake index bc665725..1c0c687c 100644 --- a/cmake/QuasselMacros.cmake +++ b/cmake/QuasselMacros.cmake @@ -1,83 +1,160 @@ -# This file contains various macros useful for building Quassel. +# This file contains various functions and macros useful for building Quassel. # -# (C) 2014 by the Quassel Project -# -# The qt5_use_modules function was taken from Qt 5.10.1 (and modified): -# (C) 2005-2011 Kitware, Inc. +# (C) 2014-2018 by the Quassel Project # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. +################################################################################################### + +include(CMakeParseArguments) + +################################################################################################### +# Adds a library target for a Quassel module. +# +# It expects the (CamelCased) module name as a parameter, and derives various +# strings from it. For example, quassel_add_module(Client) produces +# - a library target named quassel_client with output name (lib)quassel-client(.so) +# - an alias target named Quassel::Client in global scope +# +# The function exports the TARGET variable which can be used in the current scope +# for setting source files, properties, link dependencies and so on. +# To refer to the target outside of the current scope, e.g. for linking, use +# the alias name. +# +function(quassel_add_module _module) + # Derive target, alias target, output name from the given module name + set(alias "Quassel::${_module}") + set(target ${alias}) + string(TOLOWER ${target} target) + string(REPLACE "::" "_" target ${target}) + string(REPLACE "_" "-" output_name ${target}) + + add_library(${target} STATIC "") + add_library(${alias} ALIAS ${target}) + + set_target_properties(${target} PROPERTIES + OUTPUT_NAME ${output_name} + ) -############################ -# Macros for dealing with Qt -############################ + target_include_directories(${target} + PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE ${CMAKE_CURRENT_BINARY_DIR} # for generated files + ) -# Qt 5.11 removed the qt5_use_modules function, so we need to provide it until we can switch to a modern CMake version. -# If present, the Qt-provided version will be used automatically instead. -function(qt5_use_modules _target _link_type) - if (NOT TARGET ${_target}) - message(FATAL_ERROR "The first argument to qt5_use_modules must be an existing target.") + # Export the target name for further use + set(TARGET ${target} PARENT_SCOPE) +endfunction() + +################################################################################################### +# Provides a library that contains data files as a Qt resource (.qrc). +# +# quassel_add_resource(QrcName +# [BASEDIR basedir] +# [PREFIX prefix] +# PATTERNS pattern1 pattern2... +# [DEPENDS dep1 dep2...] +# ) +# +# The first parameter is the CamelCased name of the resource; the library target will be called +# "Quassel::Resource::QrcName". The library provides a Qt resource named "qrcname" (lowercased QrcName) +# containing the files matching PATTERNS relative to BASEDIR (by default, the current source dir). +# The resource prefix can be set by giving the PREFIX argument. +# Additional target dependencies can be specified with DEPENDS. +# +function(quassel_add_resource _name) + set(options ) + set(oneValueArgs BASEDIR PREFIX) + set(multiValueArgs DEPENDS PATTERNS) + cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if (NOT ARG_BASEDIR) + set(ARG_BASEDIR ${CMAKE_CURRENT_SOURCE_DIR}) endif() - if ("${_link_type}" STREQUAL "LINK_PUBLIC" OR "${_link_type}" STREQUAL "LINK_PRIVATE" ) - set(_qt5_modules ${ARGN}) - set(_qt5_link_type ${_link_type}) + get_filename_component(basedir ${ARG_BASEDIR} REALPATH) + + string(TOLOWER ${_name} lower_name) + + set(qrc_target quassel-qrc-${lower_name}) + set(qrc_file ${lower_name}.qrc) + set(qrc_src qrc_${lower_name}.cpp) + set(qrc_filepath ${CMAKE_CURRENT_BINARY_DIR}/${qrc_file}) + set(qrc_srcpath ${CMAKE_CURRENT_BINARY_DIR}/${qrc_src}) + + # This target will always be built, so the qrc file will always be freshly generated. + # That way, changes to the glob result are always taken into account. + add_custom_target(${qrc_target} VERBATIM + COMMENT "Generating ${qrc_file}" + COMMAND ${CMAKE_COMMAND} -P ${CMAKE_SOURCE_DIR}/cmake/GenerateQrc.cmake "${qrc_filepath}" "${ARG_PREFIX}" "${ARG_PATTERNS}" + DEPENDS ${ARG_DEPENDS} + BYPRODUCTS ${qrc_filepath} + WORKING_DIRECTORY ${basedir} + ) + set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${qrc_filepath}) + + # RCC sucks and expects the data files relative to the qrc file, with no way to configure it differently. + # Only when reading from stdin ("-") it takes the working directory as a base, so we have to use this if + # we want to use generated qrc files (which obviously cannot be placed in the source directory). + # Since neither autorcc nor qt5_add_resources() support this, we have to invoke rcc manually :( + # + # On Windows, input redirection apparently doesn't work, however piping does. Use this for all platforms for + # consistency, accommodating for the fact that the 'cat' equivalent on Windows is 'type'. + if (WIN32) + set(cat_cmd type) else() - set(_qt5_modules ${_link_type} ${ARGN}) + set(cat_cmd cat) endif() + add_custom_command(VERBATIM + COMMENT "Generating ${qrc_src}" + COMMAND ${cat_cmd} "$" + | "$>" --name "${lower_name}" --output "$" - + DEPENDS ${qrc_target} + MAIN_DEPENDENCY ${qrc_filepath} + OUTPUT ${qrc_srcpath} + WORKING_DIRECTORY ${basedir} + ) + + # Generate library target that can be referenced elsewhere + quassel_add_module(Resource::${_name}) + target_sources(${TARGET} PRIVATE ${qrc_srcpath}) + set_target_properties(${TARGET} PROPERTIES AUTOMOC OFF AUTOUIC OFF AUTORCC OFF) + + # Set variable for referencing the target from outside + set(RESOURCE_TARGET ${TARGET} PARENT_SCOPE) +endfunction() + +################################################################################################### +# target_link_if_exists(Target +# [PUBLIC dep1 dep2...] +# [PRIVATE dep3 dep4...] +# ) +# +# Convenience function to add dependencies to a target only if they exist. This is useful when +# handling targets that are conditionally created, e.g. resource libraries depending on -DEMBED_DATA. +# +# NOTE: In order to link a given target, it must already have been created, i.e its subdirectory +# must already have been added. This is also true for globally visible ALIAS targets that +# can otherwise be linked to regardless of creation order; "if (TARGET...)" does not +# support handling this case correctly. +# +function(target_link_if_exists _target) + set(options ) + set(oneValueArgs ) + set(multiValueArgs PUBLIC PRIVATE) + cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - if ("${_qt5_modules}" STREQUAL "") - message(FATAL_ERROR "qt5_use_modules requires at least one Qt module to use.") + if (ARG_PUBLIC) + foreach(dep ${ARG_PUBLIC}) + if (TARGET ${dep}) + target_link_libraries(${_target} PUBLIC ${dep}) + endif() + endforeach() endif() - foreach(_module ${_qt5_modules}) - if (NOT Qt5${_module}_FOUND) - find_package(Qt5${_module} PATHS "${_Qt5_COMPONENT_PATH}" NO_DEFAULT_PATH) - if (NOT Qt5${_module}_FOUND) - message(FATAL_ERROR "Can not use \"${_module}\" module which has not yet been found.") + + if (ARG_PRIVATE) + foreach(dep ${ARG_PRIVATE}) + if (TARGET ${dep}) + target_link_libraries(${_target} PRIVATE ${dep}) endif() - endif() - target_link_libraries(${_target} ${_qt5_link_type} ${Qt5${_module}_LIBRARIES}) - set_property(TARGET ${_target} APPEND PROPERTY INCLUDE_DIRECTORIES ${Qt5${_module}_INCLUDE_DIRS}) - set_property(TARGET ${_target} APPEND PROPERTY COMPILE_DEFINITIONS ${Qt5${_module}_COMPILE_DEFINITIONS}) - if (Qt5_POSITION_INDEPENDENT_CODE - AND (CMAKE_VERSION VERSION_LESS 2.8.12 - AND (NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU" - OR CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0))) - set_property(TARGET ${_target} PROPERTY POSITION_INDEPENDENT_CODE ${Qt5_POSITION_INDEPENDENT_CODE}) - endif() - endforeach() + endforeach() + endif() endfunction() - -###################################### -# Macros for dealing with translations -###################################### - -# This generates a .ts from a .po file -macro(generate_ts outvar basename) - set(input ${basename}.po) - set(output ${CMAKE_BINARY_DIR}/po/${basename}.ts) - add_custom_command(OUTPUT ${output} - COMMAND ${QT_LCONVERT_EXECUTABLE} - ARGS -i ${input} - -of ts - -o ${output} - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/po -# This is a workaround to add (duplicate) strings that lconvert missed to the .ts - COMMAND ${QT_LUPDATE_EXECUTABLE} - ARGS -silent - ${CMAKE_SOURCE_DIR}/src/ - -ts ${output} - DEPENDS ${basename}.po) - set(${outvar} ${output}) -endmacro(generate_ts outvar basename) - -# This generates a .qm from a .ts file -macro(generate_qm outvar basename) - set(input ${CMAKE_BINARY_DIR}/po/${basename}.ts) - set(output ${CMAKE_BINARY_DIR}/po/${basename}.qm) - add_custom_command(OUTPUT ${output} - COMMAND ${QT_LRELEASE_EXECUTABLE} - ARGS -silent - ${input} - DEPENDS ${basename}.ts) - set(${outvar} ${output}) -endmacro(generate_qm outvar basename)