summaryrefslogtreecommitdiffstats
path: root/cmake/QtSetup.cmake
blob: 5fc6ed8d98ed76720ac37472479abe84a789fd87 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause

## Set a default build type if none was specified

# Set the QT_IS_BUILDING_QT variable so we can verify whether we are building
# Qt from source
set(QT_BUILDING_QT TRUE CACHE
    TYPE STRING "When this is present and set to true, it signals that we are building Qt from source.")

# Pre-calculate the developer_build feature if it's set by the user via INPUT_developer_build
if(NOT FEATURE_developer_build AND INPUT_developer_build
        AND NOT "${INPUT_developer_build}" STREQUAL "undefined")
    set(FEATURE_developer_build ON)
endif()

# Pre-calculate the no_prefix feature if it's set by configure via INPUT_no_prefix.
# This needs to be done before qtbase/configure.cmake is processed.
if(NOT FEATURE_no_prefix AND INPUT_no_prefix
        AND NOT "${INPUT_no_prefix}" STREQUAL "undefined")
    set(FEATURE_no_prefix ON)
endif()

set(_default_build_type "Release")
if(FEATURE_developer_build)
    set(_default_build_type "Debug")
endif()

function(qt_internal_set_message_log_level out_var)
    # Decide whether output should be verbose or not.
    # Default to verbose (--log-level=STATUS) in a developer-build and
    # non-verbose (--log-level=NOTICE) otherwise.
    # If a custom CMAKE_MESSAGE_LOG_LEVEL was specified, it takes priority.
    # Passing an explicit --log-level=Foo has the highest priority.
    if(NOT CMAKE_MESSAGE_LOG_LEVEL)
        if(FEATURE_developer_build OR QT_FEATURE_developer_build)
            set(CMAKE_MESSAGE_LOG_LEVEL "STATUS")
        else()
            set(CMAKE_MESSAGE_LOG_LEVEL "NOTICE")
        endif()
        set(${out_var} "${CMAKE_MESSAGE_LOG_LEVEL}" PARENT_SCOPE)
    endif()
endfunction()
qt_internal_set_message_log_level(CMAKE_MESSAGE_LOG_LEVEL)

# Reset content of extra build internal vars for each inclusion of QtSetup.
unset(QT_EXTRA_BUILD_INTERNALS_VARS)

# Save the global property in a variable to make it available to feature conditions.
get_property(QT_GENERATOR_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)

if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
  message(STATUS "Setting build type to '${_default_build_type}' as none was specified.")
  set(CMAKE_BUILD_TYPE "${_default_build_type}" CACHE STRING "Choose the type of build." FORCE)
  set_property(CACHE CMAKE_BUILD_TYPE
      PROPERTY STRINGS
      "Debug" "Release" "MinSizeRel" "RelWithDebInfo") # Set the possible values for cmake-gui.
elseif(CMAKE_CONFIGURATION_TYPES)
    message(STATUS "Building for multiple configurations: ${CMAKE_CONFIGURATION_TYPES}.")
    message(STATUS "Main configuration is: ${QT_MULTI_CONFIG_FIRST_CONFIG}.")
    if(CMAKE_NINJA_MULTI_DEFAULT_BUILD_TYPE)
        message(STATUS
            "Default build configuration set to '${CMAKE_NINJA_MULTI_DEFAULT_BUILD_TYPE}'.")
    endif()
    if(CMAKE_GENERATOR STREQUAL "Ninja")
        message(FATAL_ERROR
            "It's not possible to build multiple configurations with the single config Ninja "
            "generator. Consider configuring with -G\"Ninja Multi-Config\" instead of -GNinja."
        )
    endif()
else()
    message(STATUS "CMAKE_BUILD_TYPE was set to: '${CMAKE_BUILD_TYPE}'")
endif()

# Append a config-specific postfix to library names to ensure distinct names
# in a multi-config build.
# e.g. lib/libQt6DBus_relwithdebinfo.6.3.0.dylib
# Don't apply the postfix to the first encountered release-like config, so we have at least one
# config without a postifx.
if(QT_GENERATOR_IS_MULTI_CONFIG AND CMAKE_CONFIGURATION_TYPES)
    set(__qt_setup_release_configs Release RelWithDebInfo MinSizeRel)
    set(__qt_setup_found_first_release_config FALSE)
    foreach(__qt_setup_config_type IN LISTS CMAKE_CONFIGURATION_TYPES)
        # Skip assigning postfix for the first release-like config.
        if(NOT __qt_setup_found_first_release_config
                AND __qt_setup_config_type IN_LIST __qt_setup_release_configs)
            set(__qt_setup_found_first_release_config TRUE)
            continue()
        endif()

        string(TOLOWER "${__qt_setup_config_type}" __qt_setup_config_type_lower)
        string(TOUPPER "${__qt_setup_config_type}" __qt_setup_config_type_upper)
        set(CMAKE_${__qt_setup_config_type_upper}_POSTFIX "_${__qt_setup_config_type_lower}")
        if(APPLE)
            set(CMAKE_FRAMEWORK_MULTI_CONFIG_POSTFIX_${__qt_setup_config_type_upper}
                "_${__qt_setup_config_type_lower}")
        endif()
    endforeach()
endif()

# Override the generic debug postfixes above with custom debug postfixes (even in a single config
# build) to follow the conventions we had since Qt 5.
# e.g. lib/libQt6DBus_debug.6.3.0.dylib
if(WIN32)
    if(MINGW)
        # On MinGW we don't have "d" suffix for debug libraries like on Linux,
        # unless we're building debug and release libraries in one go.
        if(QT_GENERATOR_IS_MULTI_CONFIG)
            set(CMAKE_DEBUG_POSTFIX "d")
        endif()
    else()
        set(CMAKE_DEBUG_POSTFIX "d")
    endif()
elseif(APPLE)
    set(CMAKE_DEBUG_POSTFIX "_debug")
    set(CMAKE_FRAMEWORK_MULTI_CONFIG_POSTFIX_DEBUG "_debug")
endif()

## Position independent code:
set(CMAKE_POSITION_INDEPENDENT_CODE ON)

# Do not relink dependent libraries when no header has changed:
set(CMAKE_LINK_DEPENDS_NO_SHARED ON)

# Detect non-prefix builds: either when the qtbase install prefix is set to the binary dir
# or when a developer build is explicitly enabled and no install prefix (or staging prefix)
# is specified.
# This detection only happens when building qtbase, and later is propagated via the generated
# QtBuildInternalsExtra.cmake file.
if (PROJECT_NAME STREQUAL "QtBase" AND NOT QT_BUILD_STANDALONE_TESTS)
    if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
        # Handle both FEATURE_ and QT_FEATURE_ cases when they are specified on the command line
        # explicitly. It's possible for one to be set, but not the other, because
        # qtbase/configure.cmake is not processed by this point.
        if((FEATURE_developer_build
            OR QT_FEATURE_developer_build
            OR FEATURE_no_prefix
            OR QT_FEATURE_no_prefix
            )
            AND NOT CMAKE_STAGING_PREFIX)
            # Handle non-prefix builds by setting the CMake install prefix to point to qtbase's
            # build dir. While building another repo (like qtsvg) the CMAKE_PREFIX_PATH should be
            # set on the command line to point to the qtbase build dir.
            set(__qt_default_prefix "${QtBase_BINARY_DIR}")
        else()
            if(CMAKE_HOST_WIN32)
                set(__qt_default_prefix "C:/Qt/")
            else()
                set(__qt_default_prefix "/usr/local/")
            endif()
            string(APPEND __qt_default_prefix
                "Qt-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
        endif()
        set(CMAKE_INSTALL_PREFIX ${__qt_default_prefix} CACHE PATH
            "Install path prefix, prepended onto install directories." FORCE)
        unset(__qt_default_prefix)
    endif()
    if(CMAKE_STAGING_PREFIX)
        set(__qt_prefix "${CMAKE_STAGING_PREFIX}")
    else()
        set(__qt_prefix "${CMAKE_INSTALL_PREFIX}")
    endif()
    if(__qt_prefix STREQUAL QtBase_BINARY_DIR)
        set(__qt_will_install_value OFF)
    else()
        set(__qt_will_install_value ON)
    endif()
    set(QT_WILL_INSTALL ${__qt_will_install_value} CACHE BOOL
        "Boolean indicating if doing a Qt prefix build (vs non-prefix build)." FORCE)
    unset(__qt_prefix)
    unset(__qt_will_install_value)
endif()

# Specify the QT_SOURCE_TREE only when building qtbase. Needed by some tests when the tests are
# built as part of the project, and not standalone. For standalone tests, the value is set in
# QtBuildInternalsExtra.cmake.
if(PROJECT_NAME STREQUAL "QtBase")
    set(QT_SOURCE_TREE "${QtBase_SOURCE_DIR}" CACHE PATH
        "A path to the source tree of the previously configured QtBase project." FORCE)
endif()

if(FEATURE_developer_build)
    if(DEFINED QT_CMAKE_EXPORT_COMPILE_COMMANDS)
        set(CMAKE_EXPORT_COMPILE_COMMANDS ${QT_CMAKE_EXPORT_COMPILE_COMMANDS})
    else()
        set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
    endif()
    set(_qt_build_tests_default ON)
    set(__build_benchmarks ON)

    # Tests are not built by default with qmake for iOS and friends, and thus the overall build
    # tends to fail. Disable them by default when targeting uikit.
    if(UIKIT OR ANDROID)
        set(_qt_build_tests_default OFF)
    endif()

    # Disable benchmarks for single configuration generators which do not build
    # with release configuration.
    if (CMAKE_BUILD_TYPE AND CMAKE_BUILD_TYPE STREQUAL Debug)
        set(__build_benchmarks OFF)
    endif()
else()
    set(_qt_build_tests_default OFF)
    set(__build_benchmarks OFF)
endif()

# Build Benchmarks
option(QT_BUILD_BENCHMARKS "Build Qt Benchmarks" ${__build_benchmarks})
if(QT_BUILD_BENCHMARKS)
    set(_qt_build_tests_default ON)
endif()

## Set up testing
option(QT_BUILD_TESTS "Build the testing tree." ${_qt_build_tests_default})
unset(_qt_build_tests_default)
option(QT_BUILD_TESTS_BY_DEFAULT "Should tests be built as part of the default 'all' target." ON)
if(QT_BUILD_STANDALONE_TESTS)
    # BuildInternals might have set it to OFF on initial configuration. So force it to ON when
    # building standalone tests.
    set(QT_BUILD_TESTS ON CACHE BOOL "Build the testing tree." FORCE)

    # Also force the tests to be built as part of the default build target.
    set(QT_BUILD_TESTS_BY_DEFAULT ON CACHE BOOL
        "Should tests be built as part of the default 'all' target." FORCE)
endif()
set(BUILD_TESTING ${QT_BUILD_TESTS} CACHE INTERNAL "")

if (WASM)
    set(_qt_batch_tests ON)
else()
    set(_qt_batch_tests OFF)
endif()

if(DEFINED INPUT_batch_tests)
    if (${INPUT_batch_tests})
        set(_qt_batch_tests ON)
    else()
        set(_qt_batch_tests OFF)
    endif()
endif()

option(QT_BUILD_TESTS_BATCHED "Link all tests into a single binary." ${_qt_batch_tests})

if(QT_BUILD_TESTS AND QT_BUILD_TESTS_BATCHED AND CMAKE_VERSION VERSION_LESS "3.18")
    message(FATAL_ERROR
        "Test batching requires at least CMake 3.18, due to requiring per-source "
        "TARGET_DIRECTORY assignments.")
endif()

# QT_BUILD_TOOLS_WHEN_CROSSCOMPILING -> QT_FORCE_BUILD_TOOLS
# pre-6.4 compatibility flag (remove sometime in the future)
if(CMAKE_CROSSCOMPILING AND QT_BUILD_TOOLS_WHEN_CROSSCOMPILING)
    message(WARNING "QT_BUILD_TOOLS_WHEN_CROSSCOMPILING is deprecated. "
        "Please use QT_FORCE_BUILD_TOOLS instead.")
    set(QT_FORCE_BUILD_TOOLS TRUE CACHE INTERNAL "" FORCE)
endif()

# When cross-building, we don't build tools by default. Sometimes this also covers Qt apps as well.
# Like in qttools/assistant/assistant.pro, load(qt_app), which is guarded by a qtNomakeTools() call.

set(_qt_build_tools_by_default_default ON)
if(CMAKE_CROSSCOMPILING AND NOT QT_FORCE_BUILD_TOOLS)
    set(_qt_build_tools_by_default_default OFF)
endif()
option(QT_BUILD_TOOLS_BY_DEFAULT "Should tools be built as part of the default 'all' target."
       "${_qt_build_tools_by_default_default}")
unset(_qt_build_tools_by_default_default)

include(CTest)
enable_testing()

option(QT_BUILD_EXAMPLES "Build Qt examples" OFF)
option(QT_BUILD_EXAMPLES_BY_DEFAULT "Should examples be built as part of the default 'all' target." ON)

# FIXME: Support prefix builds as well QTBUG-96232
if(QT_WILL_INSTALL)
    set(_qt_build_examples_as_external OFF)
else()
    set(_qt_build_examples_as_external ON)
endif()
option(QT_BUILD_EXAMPLES_AS_EXTERNAL "Should examples be built as ExternalProjects."
       ${_qt_build_examples_as_external})
unset(_qt_build_examples_as_external)

option(QT_BUILD_MANUAL_TESTS "Build Qt manual tests" OFF)

if(WASM)
    option(QT_BUILD_MINIMAL_STATIC_TESTS "Build minimal subset of tests for static Qt builds" ON)
else()
    option(QT_BUILD_MINIMAL_STATIC_TESTS "Build minimal subset of tests for static Qt builds" OFF)
endif()

option(QT_BUILD_MINIMAL_ANDROID_MULTI_ABI_TESTS
    "Build minimal subset of tests for Android multi-ABI Qt builds" OFF)

## Path used to find host tools, either when cross-compiling or just when using the tools from
## a different host build.
set(QT_HOST_PATH "$ENV{QT_HOST_PATH}" CACHE PATH
    "Installed Qt host directory path, used for cross compiling.")

## Android platform settings
if(ANDROID)
    include(QtPlatformAndroid)
endif()

## qt_add_module and co.:
include(QtBuild)

## Qt Feature support:
include(QtBuildInformation)
include(QtFeature)

## Compiler optimization flags:
include(QtCompilerOptimization)

## Compiler flags:
include(QtCompilerFlags)

qt_set_language_standards()

option(QT_USE_CCACHE "Enable the use of ccache")
if(QT_USE_CCACHE)
    find_program(CCACHE_PROGRAM ccache)
    if(CCACHE_PROGRAM)
        set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_PROGRAM}")
        set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}")
        set(CMAKE_OBJC_COMPILER_LAUNCHER "${CCACHE_PROGRAM}")
        set(CMAKE_OBJCXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}")
    else()
        message(FATAL_ERROR "Ccache use was requested, but the program was not found.")
    endif()
endif()

# We need to clean up QT_FEATURE_*, but only once per configuration cycle
get_property(qt_feature_clean GLOBAL PROPERTY _qt_feature_clean)
if(NOT qt_feature_clean)
    message(STATUS "Check for feature set changes")
    set_property(GLOBAL PROPERTY _qt_feature_clean TRUE)
    foreach(feature ${QT_KNOWN_FEATURES})
        if(DEFINED "FEATURE_${feature}" AND
            NOT "${QT_FEATURE_${feature}}" STREQUAL "${FEATURE_${feature}}")
            message("    '${feature}' is changed from ${QT_FEATURE_${feature}} \
to ${FEATURE_${feature}}")
            set(dirty_build TRUE)
        endif()
        unset("QT_FEATURE_${feature}" CACHE)
    endforeach()

    set(QT_KNOWN_FEATURES "" CACHE INTERNAL "" FORCE)

    if(dirty_build)
        set_property(GLOBAL PROPERTY _qt_dirty_build TRUE)
        message(WARNING "Re-configuring in existing build folder. \
Some features will be re-evaluated automatically.")
    endif()
endif()