File: FindGI.cmake

package info (click to toggle)
webkit2gtk 2.42.2-1~deb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 362,452 kB
  • sloc: cpp: 2,881,971; javascript: 282,447; ansic: 134,088; python: 43,789; ruby: 18,308; perl: 15,872; asm: 14,389; xml: 4,395; yacc: 2,350; sh: 2,074; java: 1,734; lex: 1,323; makefile: 288; pascal: 60
file content (404 lines) | stat: -rw-r--r-- 15,383 bytes parent folder | download | duplicates (5)
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
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
# Copyright (C) 2022 Igalia S.L.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1.  Redistributions of source code must retain the above copyright
#     notice, this list of conditions and the following disclaimer.
# 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.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS 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 ITS
# 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.
#
#[=======================================================================[.rst:
FindGI
------

Finds the GObject-Introspection tools and adds the :command:`GI_INTROSPECT`
command. The following variables will also be set:

``GI_FOUND``
  True if the GObject-Introspection tools are available.
``GI_VERSION``
  Version of the GObject-Introspection tools.
``GI_SCANNER_EXE``
  Path to the ``g-ir-scanner`` program.
``GI_COMPILER_EXE``
  Path to the ``g-ir-compiler`` program.
``GI_GIRDIR``
  Path where to install ``.gir`` files in the target system.
``GI_TYPELIBDIR``
  Path where to install ``.typelib`` files in the target system.
``GI_HAVE_SOURCES_TOP_DIRS``
  Whether the introspection scannner supports the ``--sources-top-dirs=``
  command line flag.

#]=======================================================================]

# Add a dummy command in case introspection is disabled. This allows
# always use it and automatically have it be a noop in that case, instead
# of having a check next to each invocation.
if (NOT ENABLE_INTROSPECTION)
    function(GI_INTROSPECT)
    endfunction()
    return()
endif ()

find_package(PkgConfig QUIET)

if (PKG_CONFIG_FOUND)
    if (PACKAGE_FIND_VERSION_COUNT GREATER 0)
        set(_gi_version_cmp ">=${PACKAGE_FIND_VERSION}")
    endif ()
    pkg_check_modules(PC_GI gobject-introspection-1.0${_gi_version_cmp})
    if (PC_GI_FOUND)
        pkg_get_variable(_GI_SCANNER_EXE gobject-introspection-1.0 g_ir_scanner)
        pkg_get_variable(_GI_COMPILER_EXE gobject-introspection-1.0 g_ir_compiler)
        pkg_get_variable(_GI_GIRDIR gobject-introspection-1.0 girdir)
        pkg_get_variable(_GI_TYPELIBDIR gobject-introspection-1.0 typelibdir)
        pkg_get_variable(_GI_PREFIX gobject-introspection-1.0 prefix)
        set(GI_VERSION ${PC_GI_VERSION})
    endif ()
endif ()

find_program(GI_SCANNER_EXE NAMES ${_GI_SCANNER_EXE} g-ir-scanner)
find_program(GI_COMPILER_EXE NAMES ${_GI_COMPILER_EXE} g-ir-compiler)

include(GNUInstallDirs)
if (_GI_GIRDIR AND _GI_PREFIX)
    string(FIND "${_GI_GIRDIR}" "${_GI_PREFIX}" _idx)
    if (_idx EQUAL 0)
        string(LENGTH "${_GI_PREFIX}" _idx)
        string(SUBSTRING "${_GI_GIRDIR}" ${_idx} -1 _GI_GIRDIR)
        set(_GI_GIRDIR "${CMAKE_INSTALL_PREFIX}/${_GI_GIRDIR}")
    else ()
        unset(_GI_GIRDIR)
    endif ()
endif ()

if (NOT _GI_GIRDIR)
    set(_GI_GIRDIR "${CMAKE_INSTALL_DATADIR}/gir-1.0")
endif ()

if (_GI_TYPELIBDIR AND _GI_PREFIX)
    string(FIND "${_GI_TYPELIBDIR}" "${_GI_PREFIX}" _idx)
    if (_idx EQUAL 0)
        string(LENGTH "${_GI_PREFIX}" _idx)
        string(SUBSTRING "${_GI_TYPELIBDIR}" ${_idx} -1 _GI_TYPELIBDIR)
        set(_GI_TYPELIBDIR "${CMAKE_INSTALL_PREFIX}/${_GI_TYPELIBDIR}")
    else ()
        unset(_GI_TYPELIBDIR)
    endif ()
endif ()

if (NOT _GI_TYPELIBDIR)
    set(_GI_TYPELIBDIR "${CMAKE_INSTALL_LIBDIR}/girepository-1.0")
endif ()

set(GI_GIRDIR "${_GI_GIRDIR}" CACHE PATH "Path to installed .gir files")
set(GI_TYPELIBDIR "${_GI_TYPELIBDIR}" CACHE PATH "Path to installed .typelib files")

if (NOT GI_VERSION AND GI_SCANNER_EXE)
    execute_process(
        COMMAND "${GI_SCANNER_EXE}" --version
        OUTPUT_VARIABLE GI_VERSION
        OUTPUT_STRIP_TRAILING_WHITESPACE
        COMMAND_ERROR_IS_FATAL ANY
        ERROR_QUIET
    )
    if (GI_VERSION MATCHES "^g-ir-scanner[[:space:]]+([0-9.]+)")
        set(GI_VERSION ${CMAKE_MATCH_1})
    else ()
        unset(GI_VERSION)
    endif ()
endif ()

if (GI_VERSION VERSION_GREATER_EQUAL 1.59.1)
    set(GI_HAVE_SOURCES_TOP_DIRS TRUE)
else ()
    set(GI_HAVE_SOURCES_TOP_DIRS FALSE)
endif ()

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(GI
    REQUIRED_VARS GI_SCANNER_EXE GI_COMPILER_EXE GI_GIRDIR GI_TYPELIBDIR
    VERSION_VAR GI_VERSION
)

if (NOT GI_FOUND)
    return()
endif ()

define_property(TARGET
    PROPERTY GI_GIR_PATH
    BRIEF_DOCS "Path to .gir file"
    FULL_DOCS "Path to .gir file generated by the target"
)
define_property(TARGET
    PROPERTY GI_PACKAGE
    BRIEF_DOCS "Exported package"
    FULL_DOCS "Name of the pkg-config package for the target"
)


#[=======================================================================[.rst:

.. command:: GI_INTROSPECT

  .. code-block:: cmake

    GI_INTROSPECT(<namespace> <nsversion> <header>
                  [TARGET <target>]
                  [SYMBOL_PREFIX <string>]
                  [IDENTIFIER_PREFIX <string>]
                  [PACKAGE <pkgname>]
                  [DEPENDENCIES <dependency>...]
                  [SOURCES <file>...
                  [NO_IMPLICIT_SOURCES])

  Enables generating introspection data for a library ``<target>``, which
  will make the introspected API available in the ``<namespace>-<nsversion>``
  module. Both ``.gir`` and ``.typelib`` will be built and configured for
  installation.

  The ``<header>`` argument indicates how to include the top-level *public*
  API header for the library, for example ``gtk/gtk.h``.

  ``TARGET`` specifies the name of the CMake used to build the library to scan
  for introspection data. If not specified, the default value is the same as
  the ``<namespace>``.

  ``SYMBOL_PREFIX`` specifies the prefix of symbols (functions) to scan for.
  If not specified, the default value is the ``<namespace>`` converted to
  lowercase.

  ``IDENTIFIER_PREFIX`` specifies the prefix of identifiers (types) to scan
  for. If not specified, the default value is the ``<namespace>`` converted
  to uppercase.

  ``PACKAGE`` indicates the ``pkg-config`` package exported by the generated
  ``.gir``. If not specified, the default value is the ``<namespace>``
  converted to lowercase.

  ``DEPENDENCIES`` specifies an optional list of dependencies of the library
  being scanned for introspection data. Each dependecy can be one of:

  * A GObject-Introspection module name, e.g. ``GObject-2.0``.
  * A GObject-Introspection module name, a colon, and the name of its
    ``pkg-config`` package, e.g. ``Gtk-4.0:gtk4``. This is useful for
    those modules where both names don't match.
  * Another ``<namespace>`` from a previous usage of the command. This
    will add its ``.gir`` as an uninstalled dependency and ensure that
    dependencies are built beforehand.

  By default the sources scanned for introspection documentation comments
  are those used to build the ``<target>`` library, plus those specified
  with ``SOURCES``. Adding the ``NO_IMPLICIT_SOURCES`` flag uses only the
  latter.

  The command creates a target named ``gir-<namespace>`` to build the
  ``.gir`` file, with two properties: ``GI_GIR_PATH`` contains the path
  to the generated (uninstalled) file, and ``GI_PACKAGE`` containing the
  string ``<pkgname>-<nsversion>``.

  A target named ``typelib-<namespace>`` is created as well to build the
  ``.typelib`` file.

  Targets ``gir-all`` and ``typelib-all`` can be used to build all the
  ``.gir`` and ``.typelib`` files for a project.

#]=======================================================================]

function(GI_INTROSPECT namespace nsversion header)
    cmake_parse_arguments(PARSE_ARGV 2 opt
        "NO_IMPLICIT_SOURCES"
        "IDENTIFIER_PREFIX;PACKAGE;SYMBOL_PREFIX;TARGET"
        "DEPENDENCIES;SOURCES;OPTIONS"
    )
    if (NOT opt_PACKAGE)
        string(TOLOWER "${namespace}" opt_PACKAGE)
    endif ()
    if (NOT opt_SYMBOL_PREFIX)
        string(TOLOWER "${namespace}" opt_SYMBOL_PREFIX)
    endif ()
    if (NOT opt_IDENTIFIER_PREFIX)
        string(TOUPPER "${opt_SYMBOL_PREFIX}" opt_IDENTIFIER_PREFIX)
    endif ()
    if (NOT opt_TARGET)
        set(opt_TARGET "${namespace}")
    endif ()

    if (NOT TARGET ${opt_TARGET})
        message(FATAL_ERROR "Target '${opt_TARGET}' was not defined")
    endif ()

    set(gir_deps)
    set(gir_name "${namespace}-${nsversion}")
    set(gir_path "${CMAKE_BINARY_DIR}/${gir_name}.gir")
    set(typ_path "${CMAKE_BINARY_DIR}/${gir_name}.typelib")

    set(scanner_flags)
    if (GI_HAVE_SOURCES_TOP_DIRS)
        list(APPEND scanner_flags "--sources-top-dirs=${CMAKE_SOURCE_DIR}")
    endif ()

    # Each dependency can be:
    #   * GI include, i.e. "GObject-2.0", implies --include=GObject-2.0, --pkg=gobject-2.0
    #   * GI include ":" pkgconfig module, i.e. "Gtk-4.0:gtk4", implies --include=Gtk-4.0, --pkg=gtk4
    #   * CMake target, i.e. "JavaScriptCore", implies --include-uninstalled=<girfile>. The target
    #     must have been previously used with GI_INTROSPECT(), and for each use on the target the
    #     corresponding <girfile> will be picked automatically.
    foreach (dep IN LISTS opt_DEPENDENCIES)
        if (TARGET "gir-${dep}")
            get_property(dep_gir_path TARGET "gir-${dep}" PROPERTY GI_GIR_PATH)
            get_property(dep_gir_lib TARGET "gir-${dep}" PROPERTY GI_GIR_LIBRARY)
            if (dep_gir_path)
                list(APPEND scanner_flags "--include-uninstalled=${dep_gir_path}")
                list(APPEND gir_deps "${dep_gir_path}")
            else ()
                message(AUTHOR_WARNING
                    "Target '${dep}' listed as a dependency but it has not "
                    "been previously configured with GI_INTROSPECT()"
                )
            endif ()
            if (dep_gir_lib)
                list(APPEND scanner_flags "--library=${dep_gir_lib}")
            endif ()
        elseif (dep MATCHES "^([a-zA-Z0-9._-]+):([a-z0-9._\\+-]+)$")
            list(APPEND scanner_flags
                "--include=${CMAKE_MATCH_1}"
                "--pkg=${CMAKE_MATCH_2}"
            )
        else ()
            string(TOLOWER "${dep}" dep_pkg)
            list(APPEND scanner_flags
                "--include=${dep}"
                "--pkg=${dep_pkg}"
            )
        endif ()
    endforeach ()

    get_property(target_srcdir TARGET ${opt_TARGET} PROPERTY SOURCE_DIR)
    foreach (incdir IN LISTS ${opt_TARGET}_INTERFACE_INCLUDE_DIRECTORIES)
        if (NOT IS_ABSOLUTE "${incdir}")
            get_filename_component(incdir "${incdir}" REALPATH BASE_DIR "${target_srcdir}")
        endif ()
        list(APPEND scanner_flags "-I${incdir}")
    endforeach ()

    set(gir_srcs "")
    foreach (src IN LISTS opt_SOURCES)
        if (NOT IS_ABSOLUTE "${src}")
            get_filename_component(src "${src}" REALPATH BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
        endif ()
        if (IS_DIRECTORY "${src}")
            if (EXISTS "${src}")
                file(GLOB src_files LIST_DIRECTORIES FALSE CONFIGURE_DEPENDS "${src}/*.c" "${src}/*.cpp")
                if (src_files)
                    list(APPEND gir_srcs ${src_files})
                else ()
                    message(AUTHOR_WARNING "Directory '${src}' specified as source, but contains no source files")
                endif ()
            else ()
                message(AUTHOR_WARNING "Directory '${src}' specified as source, but it does not exist")
            endif ()
        else ()
            list(APPEND gir_srcs "${src}")
        endif ()
    endforeach ()

    if (NOT opt_NO_IMPLICIT_SOURCES)
        foreach (src IN LISTS ${opt_TARGET}_INSTALLED_HEADERS ${opt_TARGET}_SOURCES)
            if (NOT IS_ABSOLUTE "${src}")
                get_filename_component(src "${src}" REALPATH BASE_DIR "${target_srcdir}")
            endif ()
            list(APPEND gir_srcs "${src}")
        endforeach ()
    endif ()

    if (NOT gir_srcs)
        message(FATAL_ERROR "No sources to scan specified")
    endif ()

    # Generate .gir
    set(target_def "$<TARGET_PROPERTY:${opt_TARGET},COMPILE_DEFINITIONS>")
    set(target_inc "$<TARGET_PROPERTY:${opt_TARGET},INTERFACE_INCLUDE_DIRECTORIES>")
    add_custom_command(
        OUTPUT "${gir_path}"
        COMMENT "Generating ${gir_name}.gir"
        WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
        DEPENDS ${gir_deps} ${gir_srcs}
        VERBATIM
        COMMAND_EXPAND_LISTS
        COMMAND ${CMAKE_COMMAND} -E env "CC=${CMAKE_C_COMPILER}" "CFLAGS=${CMAKE_C_FLAGS}"
            "${GI_SCANNER_EXE}" --quiet --warn-all --warn-error --no-libtool
            "--output=${gir_path}"
            "--library=$<TARGET_FILE_BASE_NAME:${opt_TARGET}>"
            "--library-path=$<TARGET_FILE_DIR:${opt_TARGET}>"
            "--namespace=${namespace}"
            "--nsversion=${nsversion}"
            "--c-include=${header}"
            "--identifier-prefix=${opt_IDENTIFIER_PREFIX}"
            "--symbol-prefix=${opt_SYMBOL_PREFIX}"
            "--pkg-export=${opt_PACKAGE}-${nsversion}"
            "$<$<BOOL:${target_def}>:-D$<JOIN:${target_def},;-D>>"
            "$<$<BOOL:${target_inc}>:-I$<JOIN:${target_inc},;-I>>"
            ${scanner_flags}
            ${opt_OPTIONS}
            ${gir_srcs}
    )

    add_custom_target("gir-${namespace}" DEPENDS "${gir_path}")

    if (NOT TARGET gir-all)
        add_custom_target(gir-all COMMENT "All GI .gir targets")
    endif ()
    add_dependencies(gir-all "gir-${namespace}")

    install(
        FILES "${gir_path}"
        DESTINATION "${GI_GIRDIR}"
        COMPONENT runtime
    )

    # Generate .typelib
    add_custom_command(
        OUTPUT "${typ_path}"
        COMMENT "Generating ${gir_name}.typelib"
        DEPENDS "${gir_path}"
        VERBATIM
        COMMAND "${GI_COMPILER_EXE}"
            "--includedir=${CMAKE_BINARY_DIR}"
            "--output=${typ_path}"
            "${gir_path}"
    )

    add_custom_target("typelib-${namespace}" DEPENDS "${typ_path}")

    if (NOT TARGET typelib-all)
        add_custom_target(typelib-all ALL COMMENT "All GI .typelib targets")
    endif ()
    add_dependencies(typelib-all "typelib-${namespace}")

    install(
        FILES "${typ_path}"
        DESTINATION "${GI_TYPELIBDIR}"
        COMPONENT runtime
    )

    # Record in targets to use later on e.g. with gi-docgen.
    set_property(TARGET "gir-${namespace}" PROPERTY GI_GIR_PATH "${gir_path}")
    set_property(TARGET "gir-${namespace}" PROPERTY GI_GIR_LIBRARY "$<TARGET_FILE_BASE_NAME:${opt_TARGET}>")
    set_property(TARGET "gir-${namespace}" PROPERTY GI_PACKAGE "${opt_PACKAGE}-${nsversion}")
endfunction()