1 # This file contains various functions and macros useful for building Quassel.
3 # (C) 2014-2018 by the Quassel Project <devel@quassel-irc.org>
5 # Redistribution and use is allowed according to the terms of the BSD license.
6 # For details see the accompanying COPYING-CMAKE-SCRIPTS file.
7 ###################################################################################################
9 include(CMakeParseArguments)
10 include(QuasselCompileFeatures)
12 ###################################################################################################
13 # Adds a library target for a Quassel module.
15 # quassel_add_module(Module
19 # The function expects the (CamelCased) module name as a parameter, and derives various
20 # strings from it. For example, quassel_add_module(Client) produces
21 # - a library target named quassel_client with output name (lib)quassel-client(.so)
22 # - an alias target named Quassel::Client in global scope
24 # If the optional argument STATIC is given, a static library is built; otherwise, on
25 # platforms other than Windows, a shared library is created. For shared libraries, also
26 # an install rule is added.
28 # The function exports the TARGET variable which can be used in the current scope
29 # for setting source files, properties, link dependencies and so on.
30 # To refer to the target outside of the current scope, e.g. for linking, use
33 function(quassel_add_module _module)
37 cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
39 # Derive target, alias target, output name from the given module name
40 set(alias "Quassel::${_module}")
42 string(TOLOWER ${target} target)
43 string(REPLACE "::" "_" target ${target})
44 string(REPLACE "_" "-" output_name ${target})
46 # On Windows, building shared libraries requires export headers.
47 # Let's bother with that later.
48 if (ARG_STATIC OR WIN32)
54 add_library(${target} ${buildmode} "")
55 add_library(${alias} ALIAS ${target})
57 target_link_libraries(${target} PRIVATE Qt5::Core)
58 target_include_directories(${target}
59 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}
60 PRIVATE ${CMAKE_CURRENT_BINARY_DIR} # for generated files
62 target_compile_features(${target} PUBLIC ${QUASSEL_COMPILE_FEATURES})
64 set_target_properties(${target} PROPERTIES
65 OUTPUT_NAME ${output_name}
66 VERSION ${QUASSEL_MAJOR}.${QUASSEL_MINOR}.${QUASSEL_PATCH}
69 if (buildmode STREQUAL "SHARED")
70 install(TARGETS ${target} DESTINATION ${CMAKE_INSTALL_LIBDIR})
73 # Export the target name for further use
74 set(TARGET ${target} PARENT_SCOPE)
77 ###################################################################################################
78 # Provides a library that contains data files as a Qt resource (.qrc).
80 # quassel_add_resource(QrcName
83 # PATTERNS pattern1 pattern2...
84 # [DEPENDS dep1 dep2...]
87 # The first parameter is the CamelCased name of the resource; the library target will be called
88 # "Quassel::Resource::QrcName". The library provides a Qt resource named "qrcname" (lowercased QrcName)
89 # containing the files matching PATTERNS relative to BASEDIR (by default, the current source dir).
90 # The resource prefix can be set by giving the PREFIX argument.
91 # Additional target dependencies can be specified with DEPENDS.
93 function(quassel_add_resource _name)
95 set(oneValueArgs BASEDIR PREFIX)
96 set(multiValueArgs DEPENDS PATTERNS)
97 cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
100 set(ARG_BASEDIR ${CMAKE_CURRENT_SOURCE_DIR})
102 get_filename_component(basedir ${ARG_BASEDIR} REALPATH)
104 string(TOLOWER ${_name} lower_name)
106 set(qrc_target quassel-qrc-${lower_name})
107 set(qrc_file ${lower_name}.qrc)
108 set(qrc_src qrc_${lower_name}.cpp)
109 set(qrc_filepath ${CMAKE_CURRENT_BINARY_DIR}/${qrc_file})
110 set(qrc_srcpath ${CMAKE_CURRENT_BINARY_DIR}/${qrc_src})
112 # This target will always be built, so the qrc file will always be freshly generated.
113 # That way, changes to the glob result are always taken into account.
114 add_custom_target(${qrc_target} VERBATIM
115 COMMENT "Generating ${qrc_file}"
116 COMMAND ${CMAKE_COMMAND} -P ${CMAKE_SOURCE_DIR}/cmake/GenerateQrc.cmake "${qrc_filepath}" "${ARG_PREFIX}" "${ARG_PATTERNS}"
117 DEPENDS ${ARG_DEPENDS}
118 BYPRODUCTS ${qrc_filepath}
119 WORKING_DIRECTORY ${basedir}
121 set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${qrc_filepath})
123 # RCC sucks and expects the data files relative to the qrc file, with no way to configure it differently.
124 # Only when reading from stdin ("-") it takes the working directory as a base, so we have to use this if
125 # we want to use generated qrc files (which obviously cannot be placed in the source directory).
126 # Since neither autorcc nor qt5_add_resources() support this, we have to invoke rcc manually :(
128 # On Windows, input redirection apparently doesn't work, however piping does. Use this for all platforms for
129 # consistency, accommodating for the fact that the 'cat' equivalent on Windows is 'type'.
135 add_custom_command(VERBATIM
136 COMMENT "Generating ${qrc_src}"
137 COMMAND ${cat_cmd} "$<SHELL_PATH:${qrc_filepath}>"
138 | "$<SHELL_PATH:$<TARGET_FILE:Qt5::rcc>>" --name "${lower_name}" --output "$<SHELL_PATH:${qrc_srcpath}>" -
139 DEPENDS ${qrc_target}
140 MAIN_DEPENDENCY ${qrc_filepath}
141 OUTPUT ${qrc_srcpath}
142 WORKING_DIRECTORY ${basedir}
145 # Generate library target that can be referenced elsewhere. Force static, because
146 # we can't easily export symbols from the generated sources.
147 quassel_add_module(Resource::${_name} STATIC)
148 target_sources(${TARGET} PRIVATE ${qrc_srcpath})
149 set_target_properties(${TARGET} PROPERTIES AUTOMOC OFF AUTOUIC OFF AUTORCC OFF)
151 # Set variable for referencing the target from outside
152 set(RESOURCE_TARGET ${TARGET} PARENT_SCOPE)
155 ###################################################################################################
156 # target_link_if_exists(Target
157 # [PUBLIC dep1 dep2...]
158 # [PRIVATE dep3 dep4...]
161 # Convenience function to add dependencies to a target only if they exist. This is useful when
162 # handling targets that are conditionally created, e.g. resource libraries depending on -DEMBED_DATA.
164 # NOTE: In order to link a given target, it must already have been created, i.e its subdirectory
165 # must already have been added. This is also true for globally visible ALIAS targets that
166 # can otherwise be linked to regardless of creation order; "if (TARGET...)" does not
167 # support handling this case correctly.
169 function(target_link_if_exists _target)
172 set(multiValueArgs PUBLIC PRIVATE)
173 cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
176 foreach(dep ${ARG_PUBLIC})
178 target_link_libraries(${_target} PUBLIC ${dep})
184 foreach(dep ${ARG_PRIVATE})
186 target_link_libraries(${_target} PRIVATE ${dep})