summaryrefslogtreecommitdiffstats
path: root/cmake/QtBuildPathsHelpers.cmake
blob: 6431fa19375bbe8a6ba89f0e00a5a92b35ae17e5 (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
# Copyright (C) 2023 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause

macro(qt_internal_setup_default_install_prefix)
    # 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_INTERNAL_BUILD_STANDALONE_PARTS)
        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()
endmacro()

function(qt_internal_setup_build_and_install_paths)
    # Compute the values of QT_BUILD_DIR, QT_INSTALL_DIR, QT_CONFIG_BUILD_DIR, QT_CONFIG_INSTALL_DIR
    # taking into account whether the current build is a prefix build or a non-prefix build,
    # and whether it is a superbuild or non-superbuild.
    # A third case is when another module or standalone tests/examples are built against a
    # super-built Qt.
    # The layout for the third case is the same as for non-superbuilds.
    #
    # These values should be prepended to file paths in commands or properties,
    # in order to correctly place generated Config files, generated Targets files,
    # executables / libraries, when copying / installing files, etc.
    #
    # The build dir variables will always be absolute paths.
    # The QT_INSTALL_DIR variable will have a relative path in a prefix build,
    # which means that it can be empty, so use qt_join_path to prevent accidental absolute paths.
    if(QT_SUPERBUILD)
        # In this case, we always copy all the build products in qtbase/{bin,lib,...}
        if(QT_WILL_INSTALL)
            set(QT_BUILD_DIR "${QtBase_BINARY_DIR}")
            set(QT_INSTALL_DIR "")
        else()
            if("${CMAKE_STAGING_PREFIX}" STREQUAL "")
                set(QT_BUILD_DIR "${QtBase_BINARY_DIR}")
                set(QT_INSTALL_DIR "${QtBase_BINARY_DIR}")
            else()
                set(QT_BUILD_DIR "${CMAKE_STAGING_PREFIX}")
                set(QT_INSTALL_DIR "${CMAKE_STAGING_PREFIX}")
            endif()
        endif()
    else()
        if(QT_WILL_INSTALL)
            # In the usual prefix build case, the build dir is the current module build dir,
            # and the install dir is the prefix, so we don't set it.
            set(QT_BUILD_DIR "${CMAKE_BINARY_DIR}")
            set(QT_INSTALL_DIR "")
        else()
            # When doing a non-prefix build, both the build dir and install dir are the same,
            # pointing to the qtbase build dir.
            set(QT_BUILD_DIR "${QT_STAGING_PREFIX}")
            set(QT_INSTALL_DIR "${QT_BUILD_DIR}")
        endif()
    endif()

    set(__config_path_part "${INSTALL_LIBDIR}/cmake")
    set(QT_CONFIG_BUILD_DIR "${QT_BUILD_DIR}/${__config_path_part}")
    set(QT_CONFIG_INSTALL_DIR "${QT_INSTALL_DIR}")
    if(QT_CONFIG_INSTALL_DIR)
        string(APPEND QT_CONFIG_INSTALL_DIR "/")
    endif()
    string(APPEND QT_CONFIG_INSTALL_DIR ${__config_path_part})

    set(QT_BUILD_DIR "${QT_BUILD_DIR}" PARENT_SCOPE)
    set(QT_INSTALL_DIR "${QT_INSTALL_DIR}" PARENT_SCOPE)
    set(QT_CONFIG_BUILD_DIR "${QT_CONFIG_BUILD_DIR}" PARENT_SCOPE)
    set(QT_CONFIG_INSTALL_DIR "${QT_CONFIG_INSTALL_DIR}" PARENT_SCOPE)
endfunction()

function(qt_configure_process_path name default docstring)
    # Values are computed once for qtbase, and then exported and reused for other projects.
    if(NOT PROJECT_NAME STREQUAL "QtBase")
        return()
    endif()

    # No value provided, set the default.
    if(NOT DEFINED "${name}")
        set("${name}" "${default}" CACHE STRING "${docstring}")
    else()
        get_filename_component(given_path_as_abs "${${name}}" ABSOLUTE BASE_DIR
                               "${CMAKE_INSTALL_PREFIX}")
        file(RELATIVE_PATH rel_path "${CMAKE_INSTALL_PREFIX}"
                                    "${given_path_as_abs}")

        # If absolute path given, check that it's inside the prefix (error out if not).
        # TODO: Figure out if we need to support paths that are outside the prefix.
        #
        # If relative path given, it's relative to the install prefix (rather than the binary dir,
        # which is what qmake does for some reason).
        # In both cases, store the value as a relative path.
        if("${rel_path}" STREQUAL "")
            # file(RELATIVE_PATH) returns an empty string if the given absolute paths are equal
            set(rel_path ".")
        elseif(rel_path MATCHES "^\.\./")
            # INSTALL_SYSCONFDIR is allowed to be outside the prefix.
            if(NOT name STREQUAL "INSTALL_SYSCONFDIR")
                message(FATAL_ERROR
                    "Path component '${name}' is outside computed install prefix: ${rel_path} ")
                return()
            endif()
            set("${name}" "${${name}}" CACHE STRING "${docstring}" FORCE)
        else()
            set("${name}" "${rel_path}" CACHE STRING "${docstring}" FORCE)
        endif()
    endif()
endfunction()

macro(qt_internal_setup_configure_install_paths)
    # Install locations:
    qt_configure_process_path(INSTALL_BINDIR "bin" "Executables [PREFIX/bin]")
    qt_configure_process_path(INSTALL_INCLUDEDIR "include" "Header files [PREFIX/include]")
    qt_configure_process_path(INSTALL_LIBDIR "lib" "Libraries [PREFIX/lib]")
    qt_configure_process_path(INSTALL_MKSPECSDIR "mkspecs" "Mkspecs files [PREFIX/mkspecs]")
    qt_configure_process_path(INSTALL_ARCHDATADIR "." "Arch-dependent data [PREFIX]")
    qt_configure_process_path(INSTALL_PLUGINSDIR
                              "${INSTALL_ARCHDATADIR}/plugins"
                              "Plugins [ARCHDATADIR/plugins]")

    if(NOT INSTALL_MKSPECSDIR MATCHES "(^|/)mkspecs")
        message(FATAL_ERROR "INSTALL_MKSPECSDIR must end with '/mkspecs'")
    endif()

    if (WIN32)
        set(_default_libexec "${INSTALL_ARCHDATADIR}/bin")
    else()
        set(_default_libexec "${INSTALL_ARCHDATADIR}/libexec")
    endif()

    qt_configure_process_path(
        INSTALL_LIBEXECDIR
        "${_default_libexec}"
        "Helper programs [ARCHDATADIR/bin on Windows, ARCHDATADIR/libexec otherwise]")
    qt_configure_process_path(INSTALL_QMLDIR
                              "${INSTALL_ARCHDATADIR}/qml"
                               "QML imports [ARCHDATADIR/qml]")
    qt_configure_process_path(INSTALL_DATADIR "." "Arch-independent data [PREFIX]")
    qt_configure_process_path(INSTALL_DOCDIR "${INSTALL_DATADIR}/doc" "Documentation [DATADIR/doc]")
    qt_configure_process_path(INSTALL_TRANSLATIONSDIR "${INSTALL_DATADIR}/translations"
        "Translations [DATADIR/translations]")
    if(APPLE)
        set(QT_DEFAULT_SYS_CONF_DIR "/Library/Preferences/Qt")
    else()
        set(QT_DEFAULT_SYS_CONF_DIR "etc/xdg")
    endif()
    qt_configure_process_path(
        INSTALL_SYSCONFDIR
        "${QT_DEFAULT_SYS_CONF_DIR}"
        "Settings used by Qt programs [PREFIX/etc/xdg]/[/Library/Preferences/Qt]")
    qt_configure_process_path(INSTALL_EXAMPLESDIR "examples" "Examples [PREFIX/examples]")
    qt_configure_process_path(INSTALL_TESTSDIR "tests" "Tests [PREFIX/tests]")
    qt_configure_process_path(INSTALL_DESCRIPTIONSDIR
                             "${INSTALL_ARCHDATADIR}/modules"
                              "Module description files directory")
endmacro()

macro(qt_internal_set_cmake_install_libdir)
    # Ensure that GNUInstallDirs's CMAKE_INSTALL_LIBDIR points to the same lib dir that Qt was
    # configured with. Currently this is important for QML plugins, which embed an rpath based
    # on that value.
    set(CMAKE_INSTALL_LIBDIR "${INSTALL_LIBDIR}")
endmacro()

macro(qt_internal_set_qt_cmake_dir)
    set(QT_CMAKE_DIR "${CMAKE_CURRENT_LIST_DIR}")
endmacro()

macro(qt_internal_set_qt_apple_support_files_path)
    # This is analogous to what we have in QtConfig.cmake.in. It's copied here so that iOS
    # tests can be built in tree.
    if(APPLE)
        if(NOT CMAKE_SYSTEM_NAME OR CMAKE_SYSTEM_NAME STREQUAL "Darwin")
            set(__qt_internal_cmake_apple_support_files_path "${QT_CMAKE_DIR}/macos")
        elseif(CMAKE_SYSTEM_NAME STREQUAL "iOS")
            set(__qt_internal_cmake_apple_support_files_path "${QT_CMAKE_DIR}/ios")
        elseif(CMAKE_SYSTEM_NAME STREQUAL "visionOS")
            set(__qt_internal_cmake_apple_support_files_path "${QT_CMAKE_DIR}/visionos")
        endif()
    endif()
endmacro()

macro(qt_internal_set_qt_staging_prefix)
    if(NOT "${CMAKE_STAGING_PREFIX}" STREQUAL "")
        set(QT_STAGING_PREFIX "${CMAKE_STAGING_PREFIX}")
    else()
        set(QT_STAGING_PREFIX "${CMAKE_INSTALL_PREFIX}")
    endif()
endmacro()

macro(qt_internal_setup_paths_and_prefixes)
    qt_internal_setup_configure_install_paths()

    qt_internal_set_qt_staging_prefix()

    # Depends on QT_STAGING_PREFIX being set.
    qt_internal_setup_build_and_install_paths()

    qt_get_relocatable_install_prefix(QT_BUILD_INTERNALS_RELOCATABLE_INSTALL_PREFIX)

    # Depends on INSTALL_LIBDIR being set.
    qt_internal_set_cmake_install_libdir()

    qt_internal_set_qt_cmake_dir()

    qt_internal_set_qt_apple_support_files_path()
endmacro()