Skip to content

Commit e215616

Browse files
committed
Produce QMake config files (.pri) for each module
1 parent 2296250 commit e215616

File tree

7 files changed

+428
-17
lines changed

7 files changed

+428
-17
lines changed

CMakeLists.txt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,6 @@ include(GNUInstallDirs)
99
include(CTest)
1010
include(FeatureSummary)
1111

12-
# Custom includes
13-
include(GenerateHeaders)
14-
include(AddQCoroLibrary)
15-
1612
#-----------------------------------------------------------#
1713
# Options
1814
#-----------------------------------------------------------#

LICENSES/BSD-3-Clause.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
Copyright (c) <year> <owner>.
2+
3+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
4+
5+
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
6+
7+
2. 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.
8+
9+
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
10+
11+
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.

cmake/AddQCoroLibrary.cmake

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
include(GenerateHeaders)
66
include(GenerateModuleConfigFile)
7+
include(ECMGeneratePriFile)
78

89
function(add_qcoro_library)
910
function(prefix_libraries)
@@ -23,6 +24,28 @@ function(add_qcoro_library)
2324
set(${prf_OUTPUT} ${_libs} PARENT_SCOPE)
2425
endfunction()
2526

27+
function(process_qmake_deps)
28+
set(oneValueArgs PREFIX OUTPUT)
29+
set(multiValueArgs LIBRARIES)
30+
cmake_parse_arguments(pqd "" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
31+
32+
set(_libs_priv FALSE)
33+
set(_deps)
34+
foreach (dep ${pqd_LIBRARIES})
35+
if ("${dep}" MATCHES "PUBLIC|INTERFACE|public|interface")
36+
set(_libs_priv FALSE)
37+
continue()
38+
elseif ("${dep}" MATCHES "PRIVATE|private")
39+
set(_libs_priv TRUE)
40+
continue()
41+
endif()
42+
if (NOT _libs_priv)
43+
set(_deps "${_deps} ${pqd_PREFIX}${dep}")
44+
endif()
45+
endforeach()
46+
set(${pqd_OUTPUT} ${_deps} PARENT_SCOPE)
47+
endfunction()
48+
2649
set(params INTERFACE NO_CMAKE_CONFIG)
2750
set(oneValueArgs NAME)
2851
set(multiValueArgs SOURCES CAMELCASE_HEADERS HEADERS QCORO_LINK_LIBRARIES QT_LINK_LIBRARIES)
@@ -90,14 +113,40 @@ function(add_qcoro_library)
90113
)
91114

92115
if (NOT LIB_NO_CMAKE_CONFIG)
93-
generate_module_config_file(
116+
generate_cmake_module_config_file(
117+
NAME ${LIB_NAME}
94118
TARGET_NAME ${target_name}
95-
LIB_NAME ${LIB_NAME}
96119
QT_DEPENDENCIES ${LIB_QT_LINK_LIBRARIES}
97120
QCORO_DEPENDENCIES ${LIB_QCORO_LINK_LIBRARIES}
98121
)
99122
endif()
100123

124+
string(TOLOWER "${LIB_QT_LINK_LIBRARIES}" lc_qt_link_libraries)
125+
process_qmake_deps(
126+
OUTPUT qmake_qt_deps
127+
LIBRARIES ${lc_qt_link_libraries}
128+
)
129+
130+
process_qmake_deps(
131+
PREFIX QCoro
132+
OUTPUT qmake_qcoro_deps
133+
LIBRARIES ${LIB_QCORO_LINK_LIBRARIES}
134+
)
135+
136+
set(egp_INTERFACE)
137+
if (LIB_INTERFACE)
138+
set(egp_INTERFACE "INTERFACE")
139+
endif()
140+
141+
ecm_generate_pri_file(
142+
${egp_INTERFACE}
143+
BASE_NAME QCoro${LIB_NAME}
144+
LIB_NAME ${target_name}
145+
VERSION ${qcoro_VERSION}
146+
INCLUDE_INSTALL_DIRS ${QCORO_INSTALL_INCLUDEDIR}/qcoro;${QCORO_INSTALL_INCLUDEDIR}/QCoro
147+
DEPS "${qmake_qt_deps} ${qmake_qcoro_deps}"
148+
)
149+
101150
install(
102151
TARGETS ${target_name}
103152
EXPORT ${target_name}Targets
@@ -125,4 +174,9 @@ function(add_qcoro_library)
125174
NAMESPACE ${QCORO_TARGET_PREFIX}::
126175
COMPONENT Devel
127176
)
177+
install(
178+
FILES "${CMAKE_CURRENT_BINARY_DIR}/qt_QCoro${LIB_NAME}.pri"
179+
DESTINATION "${ECM_MKSPECS_INSTALL_DIR}"
180+
COMPONENT Devel
181+
)
128182
endfunction()

cmake/ECMGeneratePriFile.cmake

Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
# SPDX-FileCopyrightText: 2014 David Faure <faure@kde.org>
2+
#
3+
# SPDX-License-Identifier: BSD-3-Clause
4+
5+
#[=======================================================================[.rst:
6+
ECMGeneratePriFile
7+
------------------
8+
9+
Generate a ``.pri`` file for the benefit of qmake-based projects.
10+
11+
As well as the function below, this module creates the cache variable
12+
``ECM_MKSPECS_INSTALL_DIR`` and sets the default value to ``mkspecs/modules``.
13+
This assumes Qt and the current project are both installed to the same
14+
non-system prefix. Packagers who use ``-DCMAKE_INSTALL_PREFIX=/usr`` will
15+
certainly want to set ``ECM_MKSPECS_INSTALL_DIR`` to something like
16+
``share/qt5/mkspecs/modules``.
17+
18+
The main thing is that this should be the ``modules`` subdirectory of either
19+
the default qmake ``mkspecs`` directory or of a directory that will be in the
20+
``$QMAKEPATH`` environment variable when qmake is run.
21+
22+
::
23+
24+
ecm_generate_pri_file(BASE_NAME <baseName>
25+
LIB_NAME <libName>
26+
[VERSION <version>] # since 5.83
27+
[DEPS "<dep> [<dep> [...]]"]
28+
[FILENAME_VAR <filename_variable>]
29+
[INCLUDE_INSTALL_DIRS <dir> [<dir> [...]]] # since 5.92
30+
[INCLUDE_INSTALL_DIR <dir>] # deprecated since 5.92
31+
[LIB_INSTALL_DIR <dir>])
32+
33+
If your CMake project produces a Qt-based library, you may expect there to be
34+
applications that wish to use it that use a qmake-based build system, rather
35+
than a CMake-based one. Creating a ``.pri`` file will make use of your
36+
library convenient for them, in much the same way that CMake config files make
37+
things convenient for CMake-based applications. ``ecm_generate_pri_file()``
38+
generates just such a file.
39+
40+
VERSION specifies the version of the library the ``.pri`` file describes. If
41+
not set, the value is taken from the context variable ``PROJECT_VERSION``.
42+
This variable is usually set by the ``project(... VERSION ...)`` command or,
43+
if CMake policy CMP0048 is not NEW, by :module:`ECMSetupVersion`.
44+
For backward-compatibility with older ECM versions the
45+
``PROJECT_VERSION_STRING`` variable as set by :module:`ECMSetupVersion`
46+
will be preferred over ``PROJECT_VERSION`` if set, unless the minimum
47+
required version of ECM is 5.83 and newer. Since 5.83.
48+
49+
BASE_NAME specifies the name qmake project (.pro) files should use to refer to
50+
the library (eg: KArchive). LIB_NAME is the name of the actual library to
51+
link to (ie: the first argument to add_library()). DEPS is a space-separated
52+
list of the base names of other libraries (for Qt libraries, use the same
53+
names you use with the ``QT`` variable in a qmake project file, such as "core"
54+
for QtCore). FILENAME_VAR specifies the name of a variable to store the path
55+
to the generated file in.
56+
57+
INCLUDE_INSTALL_DIRS are the paths (relative to ``CMAKE_INSTALL_PREFIX``) that
58+
include files will be installed to. It defaults to
59+
``${INCLUDE_INSTALL_DIR}/<baseName>`` if the ``INCLUDE_INSTALL_DIR`` variable
60+
is set. If that variable is not set, the ``CMAKE_INSTALL_INCLUDEDIR`` variable
61+
is used instead, and if neither are set ``include`` is used. LIB_INSTALL_DIR
62+
operates similarly for the installation location for libraries; it defaults to
63+
``${LIB_INSTALL_DIR}``, ``${CMAKE_INSTALL_LIBDIR}`` or ``lib``, in that order.
64+
65+
INCLUDE_INSTALL_DIR is the old variant of INCLUDE_INSTALL_DIRS, taking only one
66+
directory.
67+
68+
Example usage:
69+
70+
.. code-block:: cmake
71+
72+
ecm_generate_pri_file(
73+
BASE_NAME KArchive
74+
LIB_NAME KF5KArchive
75+
DEPS "core"
76+
FILENAME_VAR pri_filename
77+
VERSION 4.2.0
78+
)
79+
install(FILES ${pri_filename} DESTINATION ${ECM_MKSPECS_INSTALL_DIR})
80+
81+
A qmake-based project that wished to use this would then do::
82+
83+
QT += KArchive
84+
85+
in their ``.pro`` file.
86+
87+
Since pre-1.0.0.
88+
#]=======================================================================]
89+
90+
# Replicate the logic from KDEInstallDirs.cmake as we can't depend on it
91+
# Ask qmake if we're using the same prefix as Qt
92+
set(_should_query_qt OFF)
93+
if(NOT DEFINED KDE_INSTALL_USE_QT_SYS_PATHS)
94+
include(ECMQueryQt)
95+
ecm_query_qt(qt_install_prefix_dir QT_INSTALL_PREFIX TRY)
96+
if(qt_install_prefix_dir STREQUAL "${CMAKE_INSTALL_PREFIX}")
97+
set(_should_query_qt ON)
98+
endif()
99+
endif()
100+
101+
if(KDE_INSTALL_USE_QT_SYS_PATHS OR _should_query_qt)
102+
include(ECMQueryQt)
103+
ecm_query_qt(qt_install_prefix_dir QT_INSTALL_PREFIX)
104+
ecm_query_qt(qt_host_data_dir QT_HOST_DATA)
105+
if(qt_install_prefix_dir STREQUAL "${CMAKE_INSTALL_PREFIX}")
106+
file(RELATIVE_PATH qt_host_data_dir ${qt_install_prefix_dir} ${qt_host_data_dir})
107+
endif()
108+
if(qt_host_data_dir STREQUAL "")
109+
set(mkspecs_install_dir mkspecs/modules)
110+
else()
111+
set(mkspecs_install_dir ${qt_host_data_dir}/mkspecs/modules)
112+
endif()
113+
set(ECM_MKSPECS_INSTALL_DIR ${mkspecs_install_dir} CACHE PATH "The directory where mkspecs will be installed to.")
114+
else()
115+
set(ECM_MKSPECS_INSTALL_DIR mkspecs/modules CACHE PATH "The directory where mkspecs will be installed to.")
116+
endif()
117+
118+
function(ECM_GENERATE_PRI_FILE)
119+
set(options INTERFACE)
120+
set(oneValueArgs BASE_NAME LIB_NAME DEPS FILENAME_VAR INCLUDE_INSTALL_DIR LIB_INSTALL_DIR VERSION)
121+
set(multiValueArgs INCLUDE_INSTALL_DIRS)
122+
123+
cmake_parse_arguments(EGPF "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
124+
125+
if(EGPF_UNPARSED_ARGUMENTS)
126+
message(FATAL_ERROR "Unknown keywords given to ECM_GENERATE_PRI_FILE(): \"${EGPF_UNPARSED_ARGUMENTS}\"")
127+
endif()
128+
129+
if(ECM_GLOBAL_FIND_VERSION VERSION_LESS 5.83.0)
130+
set(_support_backward_compat_version_string_var TRUE)
131+
else()
132+
set(_support_backward_compat_version_string_var FALSE)
133+
endif()
134+
135+
if(NOT EGPF_BASE_NAME)
136+
message(FATAL_ERROR "Required argument BASE_NAME missing in ECM_GENERATE_PRI_FILE() call")
137+
endif()
138+
if(NOT EGPF_LIB_NAME)
139+
message(FATAL_ERROR "Required argument LIB_NAME missing in ECM_GENERATE_PRI_FILE() call")
140+
endif()
141+
if(NOT EGPF_VERSION)
142+
if(_support_backward_compat_version_string_var)
143+
if(NOT PROJECT_VERSION_STRING AND NOT PROJECT_VERSION)
144+
message(FATAL_ERROR "Required variable PROJECT_VERSION_STRING or PROJECT_VERSION not set before ECM_GENERATE_PRI_FILE() call. Missing call of ecm_setup_version() or project(VERSION)?")
145+
endif()
146+
else()
147+
if(NOT PROJECT_VERSION)
148+
message(FATAL_ERROR "Required variable PROJECT_VERSION not set before ECM_GENERATE_PRI_FILE() call. Missing call of ecm_setup_version() or project(VERSION)?")
149+
endif()
150+
endif()
151+
endif()
152+
if(EGPF_INCLUDE_INSTALL_DIR)
153+
if(EGPF_INCLUDE_INSTALL_DIRS)
154+
message(FATAL_ERROR "Only one argument of INCLUDE_INSTALL_DIR & INCLUDE_INSTALL_DIRS can be used in ECM_GENERATE_PRI_FILE() call")
155+
endif()
156+
set(EGPF_INCLUDE_INSTALL_DIRS ${EGPF_INCLUDE_INSTALL_DIR})
157+
endif()
158+
if(NOT EGPF_INCLUDE_INSTALL_DIRS)
159+
if(INCLUDE_INSTALL_DIR)
160+
set(EGPF_INCLUDE_INSTALL_DIRS "${INCLUDE_INSTALL_DIR}/${EGPF_BASE_NAME}")
161+
elseif(CMAKE_INSTALL_INCLUDEDIR)
162+
set(EGPF_INCLUDE_INSTALL_DIRS "${CMAKE_INSTALL_INCLUDEDIR}/${EGPF_BASE_NAME}")
163+
else()
164+
set(EGPF_INCLUDE_INSTALL_DIRS "include/${EGPF_BASE_NAME}")
165+
endif()
166+
endif()
167+
if(NOT EGPF_LIB_INSTALL_DIR)
168+
if(LIB_INSTALL_DIR)
169+
set(EGPF_LIB_INSTALL_DIR "${LIB_INSTALL_DIR}")
170+
elseif(CMAKE_INSTALL_LIBDIR)
171+
set(EGPF_LIB_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}")
172+
else()
173+
set(EGPF_LIB_INSTALL_DIR "lib")
174+
endif()
175+
endif()
176+
177+
if(EGPF_VERSION)
178+
set(PRI_VERSION "${EGPF_VERSION}")
179+
else()
180+
if(_support_backward_compat_version_string_var AND PROJECT_VERSION_STRING)
181+
set(PRI_VERSION "${PROJECT_VERSION_STRING}")
182+
if(NOT PROJECT_VERSION_STRING STREQUAL PROJECT_VERSION)
183+
message(DEPRECATION "ECM_GENERATE_PRI_FILE() will no longer support PROJECT_VERSION_STRING when the required minimum version of ECM is 5.83 or newer. Set VERSION parameter or use PROJECT_VERSION instead.")
184+
endif()
185+
else()
186+
set(PRI_VERSION "${PROJECT_VERSION}")
187+
endif()
188+
endif()
189+
190+
string(REGEX REPLACE "^([0-9]+)\\.[0-9]+\\.[0-9]+.*" "\\1" PRI_VERSION_MAJOR "${PRI_VERSION}")
191+
string(REGEX REPLACE "^[0-9]+\\.([0-9]+)\\.[0-9]+.*" "\\1" PRI_VERSION_MINOR "${PRI_VERSION}")
192+
string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" PRI_VERSION_PATCH "${PRI_VERSION}")
193+
194+
# Prepare the right number of "../.." to go from ECM_MKSPECS_INSTALL_DIR to the install prefix
195+
# This allows to make the generated pri files relocatable (no absolute paths)
196+
if (IS_ABSOLUTE ${ECM_MKSPECS_INSTALL_DIR})
197+
set(BASEPATH ${CMAKE_INSTALL_PREFIX})
198+
else()
199+
string(REGEX REPLACE "[^/]+" ".." PRI_ROOT_RELATIVE_TO_MKSPECS ${ECM_MKSPECS_INSTALL_DIR})
200+
set(BASEPATH "$$PWD/${PRI_ROOT_RELATIVE_TO_MKSPECS}")
201+
endif()
202+
203+
set(PRI_TARGET_BASENAME ${EGPF_BASE_NAME})
204+
set(PRI_TARGET_LIBNAME ${EGPF_LIB_NAME})
205+
set(PRI_TARGET_QTDEPS ${EGPF_DEPS})
206+
set(PRI_TARGET_INCLUDES)
207+
foreach(_dir ${EGPF_INCLUDE_INSTALL_DIRS})
208+
# separate list entries with space
209+
if(IS_ABSOLUTE "${_dir}")
210+
string(APPEND PRI_TARGET_INCLUDES " ${_dir}")
211+
else()
212+
string(APPEND PRI_TARGET_INCLUDES " ${BASEPATH}/${_dir}")
213+
endif()
214+
endforeach()
215+
if(IS_ABSOLUTE "${EGPF_LIB_INSTALL_DIR}")
216+
set(PRI_TARGET_LIBS "${EGPF_LIB_INSTALL_DIR}")
217+
else()
218+
set(PRI_TARGET_LIBS "${BASEPATH}/${EGPF_LIB_INSTALL_DIR}")
219+
endif()
220+
set(PRI_TARGET_DEFINES "")
221+
222+
set(PRI_FILENAME ${CMAKE_CURRENT_BINARY_DIR}/qt_${PRI_TARGET_BASENAME}.pri)
223+
if (EGPF_FILENAME_VAR)
224+
set(${EGPF_FILENAME_VAR} ${PRI_FILENAME} PARENT_SCOPE)
225+
endif()
226+
227+
set(PRI_TARGET_MODULE_CONFIG "")
228+
# backward compat: it was not obvious LIB_NAME needs to be a target name,
229+
# and some projects where the target name was not the actual library output name
230+
# passed the output name for LIB_NAME, so .name & .module prperties are correctly set.
231+
# TODO: improve API dox, allow control over module name if target name != output name
232+
if(TARGET ${EGPF_LIB_NAME})
233+
get_target_property(target_type ${EGPF_LIB_NAME} TYPE)
234+
if (target_type STREQUAL "STATIC_LIBRARY")
235+
set(PRI_TARGET_MODULE_CONFIG "staticlib")
236+
endif()
237+
endif()
238+
239+
if (EGPF_INTERFACE)
240+
set(PRI_TARGET_MODULE "")
241+
else()
242+
set(PRI_TARGET_MODULE "${PRI_TARGET_LIBNAME}")
243+
endif()
244+
245+
246+
file(GENERATE
247+
OUTPUT ${PRI_FILENAME}
248+
CONTENT
249+
"QT.${PRI_TARGET_BASENAME}.VERSION = ${PRI_VERSION}
250+
QT.${PRI_TARGET_BASENAME}.MAJOR_VERSION = ${PRI_VERSION_MAJOR}
251+
QT.${PRI_TARGET_BASENAME}.MINOR_VERSION = ${PRI_VERSION_MINOR}
252+
QT.${PRI_TARGET_BASENAME}.PATCH_VERSION = ${PRI_VERSION_PATCH}
253+
QT.${PRI_TARGET_BASENAME}.name = ${PRI_TARGET_LIBNAME}
254+
QT.${PRI_TARGET_BASENAME}.module = ${PRI_TARGET_MODULE}
255+
QT.${PRI_TARGET_BASENAME}.defines = ${PRI_TARGET_DEFINES}
256+
QT.${PRI_TARGET_BASENAME}.includes = ${PRI_TARGET_INCLUDES}
257+
QT.${PRI_TARGET_BASENAME}.private_includes =
258+
QT.${PRI_TARGET_BASENAME}.libs = ${PRI_TARGET_LIBS}
259+
QT.${PRI_TARGET_BASENAME}.depends = ${PRI_TARGET_QTDEPS}
260+
QT.${PRI_TARGET_BASENAME}.module_config = ${PRI_TARGET_MODULE_CONFIG}
261+
"
262+
)
263+
endfunction()

0 commit comments

Comments
 (0)