summaryrefslogtreecommitdiffstats
path: root/cmake/QtFrameworkHelpers.cmake
blob: 750caf2cb8bf01ee567614eedb4bcc3775af126d (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
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause

macro(qt_find_apple_system_frameworks)
    if(APPLE)
        qt_internal_find_apple_system_framework(FWAppKit AppKit)
        qt_internal_find_apple_system_framework(FWCFNetwork CFNetwork)
        qt_internal_find_apple_system_framework(FWAssetsLibrary AssetsLibrary)
        qt_internal_find_apple_system_framework(FWPhotos Photos)
        qt_internal_find_apple_system_framework(FWAudioToolbox AudioToolbox)
        qt_internal_find_apple_system_framework(FWApplicationServices ApplicationServices)
        qt_internal_find_apple_system_framework(FWCarbon Carbon)
        qt_internal_find_apple_system_framework(FWCoreFoundation CoreFoundation)
        qt_internal_find_apple_system_framework(FWCoreServices CoreServices)
        qt_internal_find_apple_system_framework(FWCoreGraphics CoreGraphics)
        qt_internal_find_apple_system_framework(FWCoreText CoreText)
        qt_internal_find_apple_system_framework(FWCoreVideo CoreVideo)
        qt_internal_find_apple_system_framework(FWCryptoTokenKit CryptoTokenKit)
        qt_internal_find_apple_system_framework(FWDiskArbitration DiskArbitration)
        qt_internal_find_apple_system_framework(FWFoundation Foundation)
        qt_internal_find_apple_system_framework(FWIOBluetooth IOBluetooth)
        qt_internal_find_apple_system_framework(FWIOKit IOKit)
        qt_internal_find_apple_system_framework(FWIOSurface IOSurface)
        qt_internal_find_apple_system_framework(FWImageIO ImageIO)
        qt_internal_find_apple_system_framework(FWMetal Metal)
        qt_internal_find_apple_system_framework(FWMobileCoreServices MobileCoreServices)
        qt_internal_find_apple_system_framework(FWQuartzCore QuartzCore)
        qt_internal_find_apple_system_framework(FWSecurity Security)
        qt_internal_find_apple_system_framework(FWSystemConfiguration SystemConfiguration)
        qt_internal_find_apple_system_framework(FWUIKit UIKit)
        qt_internal_find_apple_system_framework(FWCoreLocation CoreLocation)
        qt_internal_find_apple_system_framework(FWCoreMotion CoreMotion)
        qt_internal_find_apple_system_framework(FWWatchKit WatchKit)
        qt_internal_find_apple_system_framework(FWGameController GameController)
        qt_internal_find_apple_system_framework(FWCoreBluetooth CoreBluetooth)
        qt_internal_find_apple_system_framework(FWAVFoundation AVFoundation)
        qt_internal_find_apple_system_framework(FWContacts Contacts)
        qt_internal_find_apple_system_framework(FWEventKit EventKit)
        qt_internal_find_apple_system_framework(FWHealthKit HealthKit)
        qt_internal_find_apple_system_framework(FWUniformTypeIdentifiers UniformTypeIdentifiers)
    endif()
endmacro()

# Given framework_name == 'IOKit', sets non-cache variable 'FWIOKit' to '-framework IOKit' in
# the calling directory scope if the framework is found, or 'IOKit-NOTFOUND'.
function(qt_internal_find_apple_system_framework out_var framework_name)
    # To avoid creating many FindFoo.cmake files for each apple system framework, populate each
    # FWFoo variable with '-framework Foo' instead of an absolute path to the framework. This makes
    # the generated CMake target files relocatable, so that Xcode SDK absolute paths are not
    # hardcoded, like with Xcode11.app on the CI.
    # We might revisit this later.
    set(cache_var_name "${out_var}Internal")

    find_library(${cache_var_name} "${framework_name}")

    if(${cache_var_name} AND ${cache_var_name} MATCHES ".framework$")
        set(${out_var} "-framework ${framework_name}" PARENT_SCOPE)
    else()
        set(${out_var} "${out_var}-NOTFOUND" PARENT_SCOPE)
    endif()
endfunction()

# Copy header files to the framework's Headers directory
# Use this function for header files that
#   - are not added as source files to the target
#   - are not marked as PUBLIC_HEADER
#   - or are private and supposed to end up in the 6.7.8/QtXYZ/private subdir.
function(qt_copy_framework_headers target)
    get_target_property(is_fw ${target} FRAMEWORK)
    if(NOT "${is_fw}")
        return()
    endif()

    set(options)
    set(oneValueArgs)
    set(multiValueArgs PUBLIC PRIVATE QPA RHI SSG)
    cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

    qt_internal_get_framework_info(fw ${target})
    get_target_property(output_dir ${target} LIBRARY_OUTPUT_DIRECTORY)
    set(output_dir_PUBLIC "${output_dir}/${fw_versioned_header_dir}")
    set(output_dir_PRIVATE "${output_dir}/${fw_private_module_header_dir}/private")
    set(output_dir_QPA "${output_dir}/${fw_private_module_header_dir}/qpa")
    set(output_dir_RHI "${output_dir}/${fw_private_module_header_dir}/rhi")
    set(output_dir_SSG "${output_dir}/${fw_private_module_header_dir}/ssg")

    qt_internal_module_info(module "${target}")

    set(out_files "")
    set(in_files "")
    set(out_dirs "")
    set(copy_commands "")
    foreach(type IN ITEMS PUBLIC PRIVATE QPA RHI SSG)
        set(in_files_${type} "")
        set(fw_output_header_dir "${output_dir_${type}}")
        list(APPEND out_dirs "${fw_output_header_dir}")
        foreach(hdr IN LISTS arg_${type})
            get_filename_component(in_file_path ${hdr} ABSOLUTE)
            get_filename_component(in_file_name ${hdr} NAME)
            set(out_file_path "${fw_output_header_dir}/${in_file_name}")
            list(APPEND out_files ${out_file_path})
            list(APPEND in_files_${type} "${in_file_path}")
        endforeach()
        if(in_files_${type})
            list(APPEND copy_commands
                COMMAND ${CMAKE_COMMAND} -E copy ${in_files_${type}} "${fw_output_header_dir}")
            list(APPEND in_files ${in_files_${type}})
        endif()
    endforeach()

    list(REMOVE_DUPLICATES out_files)
    list(REMOVE_DUPLICATES in_files)

    set(copy_fw_sync_headers_command
        "${CMAKE_COMMAND}" -E copy_directory
        "${module_build_interface_include_dir}/.syncqt_staging"
        "${output_dir}/${fw_versioned_header_dir}"
    )

    if(CMAKE_GENERATOR MATCHES "^Ninja")
        add_custom_command(
            OUTPUT "${output_dir}/${fw_versioned_header_dir}"
            DEPENDS ${target}_sync_headers
            COMMAND ${copy_fw_sync_headers_command}
            VERBATIM
        )
        add_custom_target(${target}_copy_fw_sync_headers
            DEPENDS "${output_dir}/${fw_versioned_header_dir}")
    else()
        add_custom_target(${target}_copy_fw_sync_headers
            COMMAND ${copy_fw_sync_headers_command})
    endif()

    if(out_files)
        add_custom_command(
            OUTPUT ${out_files}
            DEPENDS ${target}_copy_fw_sync_headers ${in_files}
            COMMAND
                ${CMAKE_COMMAND} -E make_directory ${out_dirs}
            ${copy_commands}
            VERBATIM
            COMMENT "Copy the ${target} header files to the framework directory"
        )
        set_property(TARGET ${target} APPEND PROPERTY
            QT_COPIED_FRAMEWORK_HEADERS "${out_files}")
    endif()
endfunction()

function(qt_internal_generate_fake_framework_header target)
    # Hack to create the "Headers" symlink in the framework:
    # Create a fake header file and copy it into the framework by marking it as PUBLIC_HEADER.
    # CMake now takes care of creating the symlink.
    set(fake_header "${CMAKE_CURRENT_BINARY_DIR}/${target}_fake_header.h")
    qt_internal_get_main_cmake_configuration(main_config)
    file(GENERATE OUTPUT "${fake_header}" CONTENT "// ignore this file\n"
        CONDITION "$<CONFIG:${main_config}>")
    target_sources(${target} PRIVATE "${fake_header}")
    set_source_files_properties("${fake_header}" PROPERTIES GENERATED ON)
    set_property(TARGET ${target} APPEND PROPERTY PUBLIC_HEADER "${fake_header}")
endfunction()

function(qt_finalize_framework_headers_copy target)
    get_target_property(target_type ${target} TYPE)
    if(${target_type} STREQUAL "INTERFACE_LIBRARY")
        return()
    endif()
    get_target_property(is_fw ${target} FRAMEWORK)
    if(NOT "${is_fw}")
        return()
    endif()
    get_target_property(headers ${target} QT_COPIED_FRAMEWORK_HEADERS)
    if(headers)
        qt_internal_generate_fake_framework_header(${target})

        # Add a target, e.g. Core_framework_headers, that triggers the header copy.
        add_custom_target(${target}_framework_headers DEPENDS ${headers})
        add_dependencies(${target} ${target}_framework_headers)
    endif()
endfunction()

# Collects the framework related information and paths from the target properties.
# Output variables:
#    <out_var>_name framework base name, e.g. 'QtCore'.
#    <out_var>_dir framework base directory, e.g. 'QtCore.framework'.
#    <out_var>_version framework version, e.g. 'A', 'B' etc.
#    <out_var>_bundle_version framework bundle version, same as the PROJECT_VERSION, e.g. '6.0.0'.
#    <out_var>_header_dir top-level header directory, e.g. 'QtCore.framework/Headers'.
#    <out_var>_versioned_header_dir header directory for specific framework version,
#        e.g. 'QtCore.framework/Versions/A/Headers'
#    <out_var>_private_header_dir header directory for the specific framework version and
#       framework bundle version e.g. 'QtCore.framework/Versions/A/Headers/6.0.0'
#    <out_var>_private_module_header_dir private header directory for the specific framework
#       version, framework bundle version and tailing module name, e.g.
#       'QtCore.framework/Versions/A/Headers/6.0.0/Core'
function(qt_internal_get_framework_info out_var target)
    get_target_property(${out_var}_version ${target} FRAMEWORK_VERSION)
    get_target_property(${out_var}_bundle_version ${target} MACOSX_FRAMEWORK_BUNDLE_VERSION)

    # The module name might be different of the actual target name
    # and we want to use the Qt'fied module name as a framework identifier.
    get_target_property(module_interface_name ${target} _qt_module_interface_name)
    if(module_interface_name)
        qt_internal_qtfy_target(module ${module_interface_name})
    else()
        qt_internal_qtfy_target(module ${target})
    endif()

    set(${out_var}_name "${module}")
    set(${out_var}_dir "${${out_var}_name}.framework")
    set(${out_var}_header_dir "${${out_var}_dir}/Headers")
    if(UIKIT)
        # iOS frameworks do not version their headers
        set(${out_var}_versioned_header_dir "${${out_var}_header_dir}")
    else()
        set(${out_var}_versioned_header_dir "${${out_var}_dir}/Versions/${${out_var}_version}/Headers")
    endif()
    set(${out_var}_private_header_dir "${${out_var}_versioned_header_dir}/${${out_var}_bundle_version}")
    set(${out_var}_private_module_header_dir "${${out_var}_private_header_dir}/${module}")

    set(${out_var}_name "${${out_var}_name}" PARENT_SCOPE)
    set(${out_var}_dir "${${out_var}_dir}" PARENT_SCOPE)
    set(${out_var}_header_dir "${${out_var}_header_dir}" PARENT_SCOPE)
    set(${out_var}_version "${${out_var}_version}" PARENT_SCOPE)
    set(${out_var}_bundle_version "${${out_var}_bundle_version}" PARENT_SCOPE)
    set(${out_var}_versioned_header_dir "${${out_var}_versioned_header_dir}" PARENT_SCOPE)
    set(${out_var}_private_header_dir "${${out_var}_private_header_dir}" PARENT_SCOPE)
    set(${out_var}_private_module_header_dir "${${out_var}_private_module_header_dir}" PARENT_SCOPE)
endfunction()