3b9>QA@FɥTKB+ϜyurP5o2v!լY̰%Ʈ97>Z;.>ڱ0       SqmHQiGCL9#~cE[                usr/share/ECM/cmake/ECMConfig.cmake                                                                                                                                                                                                                             SYA{]Ͽ!g`.0      C        usr/share/ECM/cmake/ECMConfigVersion.cmake                                                                                                                                                                                                                      R!*v85_41z[E9
d9"]^      I         usr/share/ECM/find-modules/ECMFindModuleHelpersStub.cmake                                                                                                                                                                                                       3]"%lυ_FL]]#C.      D        usr/share/ECM/find-modules/Find7Zip.cmake                                                                                                                                                                                                                       <O'XŖ&^<WI5      I        usr/share/ECM/find-modules/Find7z.cmake                                                                                                                                                                                                                         $gsRQ?X@?_빅4      -        usr/share/ECM/find-modules/FindCanberra.cmake                                                                                                                                                                                                                   .2noR%it)a%      k        usr/share/ECM/find-modules/FindEGL.cmake                                                                                                                                                                                                                        .|#UA&թ"W3O#nIk֛Sn7              usr/share/ECM/find-modules/FindGLIB2.cmake                                                                                                                                                                                                                      B1
Ot 	{kKI{fJ              usr/share/ECM/find-modules/FindGperf.cmake                                                                                                                                                                                                                      ٫bSdҟK]cVΦ*C}\V1Z      *        usr/share/ECM/find-modules/FindGradle.cmake                                                                                                                                                                                                                     mnꢇ xݢr:G=J;[Tٯz k      T        usr/share/ECM/find-modules/FindIcoTool.cmake                                                                                                                                                                                                                    2!I]o2a,ja1=Tq      	        usr/share/ECM/find-modules/FindInotify.cmake                                                                                                                                                                                                                    et"*)3Ezz              usr/share/ECM/find-modules/FindIsoCodes.cmake                                                                                                                                                                                                                   ХÜ#li- jR FtJfc      x        usr/share/ECM/find-modules/FindKF5.cmake                                                                                                                                                                                                                        EYAdP&6Ork              usr/share/ECM/find-modules/FindKF6.cmake                                                                                                                                                                                                                        ,ZYt>ڤ+= fN+d              usr/share/ECM/find-modules/FindLibExiv2.cmake                                                                                                                                                                                                                   e5TEvIx'1˔ޭxzT)$3              usr/share/ECM/find-modules/FindLibGit2.cmake                                                                                                                                                                                                                    jHӚC$*k]e@      	        usr/share/ECM/find-modules/FindLibMount.cmake                                                                                                                                                                                                                   4{:ʎL4XDURVXw              usr/share/ECM/find-modules/FindLibcap.cmake                                                                                                                                                                                                                     qnhPWnKHBVD&9iZ              usr/share/ECM/find-modules/FindOpenEXR.cmake                                                                                                                                                                                                                    $֔,pȳ҅@~u(er߹9      	        usr/share/ECM/find-modules/FindPhoneNumber.cmake                                                                                                                                                                                                                fd0wJG35ۢ	P߇g              usr/share/ECM/find-modules/FindPoppler.cmake                                                                                                                                                                                                                    5A}K;hBƣx06glUe              usr/share/ECM/find-modules/FindPulseAudio.cmake                                                                                                                                                                                                                 }mUKixljFw2	ew             usr/share/ECM/find-modules/FindQHelpGenerator.cmake                                                                                                                                                                                                             db` ڱ	'i*|I%w䳩f;             usr/share/ECM/find-modules/FindQtWaylandScanner.cmake                                                                                                                                                                                                           }/_y2}h
;ě.[a!
*             usr/share/ECM/find-modules/FindReuseTool.cmake                                                                                                                                                                                                                  _vyjnZK9@E -     6        usr/share/ECM/find-modules/FindSasl2.cmake                                                                                                                                                                                                                      dr~rnbf+`ȓ?D8'oU0-1:x%9             usr/share/ECM/find-modules/FindSeccomp.cmake                                                                                                                                                                                                                    _-j| OAwH=F@             usr/share/ECM/find-modules/FindSharedMimeInfo.cmake                                                                                                                                                                                                             N~!ʽ?uHQS#},L             usr/share/ECM/find-modules/FindTaglib.cmake                                                                                                                                                                                                                     n$YNKhapQKBPEY8	X             usr/share/ECM/find-modules/FindUDev.cmake                                                                                                                                                                                                                       A2##ia|n@&mbJ8Q;_             usr/share/ECM/find-modules/FindWayland.cmake                                                                                                                                                                                                                    ~d/:0*di%Byqr             usr/share/ECM/find-modules/FindWaylandProtocols.cmake                                                                                                                                                                                                           Of%WgJ?\4QJw             usr/share/ECM/find-modules/FindWaylandScanner.cmake                                                                                                                                                                                                             -xxۭx ulrYJ.oTxWq             usr/share/ECM/find-modules/FindX11_XCB.cmake                                                                                                                                                                                                                    
6`E!94i738Do#3p             usr/share/ECM/find-modules/FindXCB.cmake                                                                                                                                                                                                                        ieG e.iZubH"3     .
        usr/share/ECM/find-modules/Findepoxy.cmake                                                                                                                                                                                                                      t,Vt$vn0)00za     2        usr/share/ECM/find-modules/Findgzip.cmake                                                                                                                                                                                                                       `":@t:E<*8M6W              usr/share/ECM/find-modules/local.properties.cmake                                                                                                                                                                                                               )z[٧sGqʝJ8A               usr/share/ECM/find-modules/settings.gradle.cmake                                                                                                                                                                                                                祡Gz"+5ΤϽ:gOnb     =        usr/share/ECM/kde-modules/KDECMakeSettings.cmake                                                                                                                                                                                                                 d{2y^VRFn#             usr/share/ECM/kde-modules/KDEClangFormat.cmake                                                                                                                                                                                                                  :#kȀRu(Gh Wr؃             usr/share/ECM/kde-modules/KDECompilerSettings.cmake                                                                                                                                                                                                             -ϟe0+$gfeR
>     W        usr/share/ECM/kde-modules/KDEFrameworkCompilerLegacySettings.cmake                                                                                                                                                                                              oBOҐ!14eg5rA>@uu     
        usr/share/ECM/kde-modules/KDEFrameworkCompilerSettings.cmake                                                                                                                                                                                                    B
-ဎzYHAo<`7ěgRUa             usr/share/ECM/kde-modules/KDEGitCommitHooks.cmake                                                                                                                                                                                                               ?9ٓ_T	L;ɣ #^     :        usr/share/ECM/kde-modules/KDEInstallDirs.cmake                                                                                                                                                                                                                  3Z$)p_*`1یe6E-     x?        usr/share/ECM/kde-modules/KDEInstallDirs5.cmake                                                                                                                                                                                                                 b@1<kq1el2d]=sdA$L     &0        usr/share/ECM/kde-modules/KDEInstallDirs6.cmake                                                                                                                                                                                                                 l;ǈv8^NMըp
Ȳ8k |=     |9        usr/share/ECM/kde-modules/KDEInstallDirsCommon.cmake                                                                                                                                                                                                            gC-4G 	62%'g[xGw     A        usr/share/ECM/kde-modules/KDEMetaInfoPlatformCheck.cmake                                                                                                                                                                                                        0u߹cE"H_?8:cB     C        usr/share/ECM/kde-modules/KDEPackageAppTemplates.cmake                                                                                                                                                                                                          `7Ӹ+?G,$+ ˛             usr/share/ECM/kde-modules/KDESetupPrefixScript.cmake                                                                                                                                                                                                            ThHhXm>fN:Q.לޣʄ             usr/share/ECM/kde-modules/appstreamtest.cmake                                                                                                                                                                                                                   ZezDb1޴'ڟ5ʱDgCxP%     a
        usr/share/ECM/kde-modules/clang-format.cmake                                                                                                                                                                                                                    QZުk[3je
$yyb             usr/share/ECM/kde-modules/kde-git-commit-hooks/clang-format.sh                                                                                                                                                                                                  *\ڣ3ecVR"b              usr/share/ECM/kde-modules/kde-git-commit-hooks/combined.schema.json.in                                                                                                                                                                                          huW	l]i7[dd4Sc              usr/share/ECM/kde-modules/kde-git-commit-hooks/combined.schema.json.in.license                                                                                                                                                                                  V}S$-?SRrV*	vWE             usr/share/ECM/kde-modules/kde-git-commit-hooks/json-schema.py                                                                                                                                                                                                   idS))6>g̝a}˕۲     +         usr/share/ECM/kde-modules/kde-git-commit-hooks/pre-commit.in                                                                                                                                                                                                    ᔗZTO}Q[ qզ5mvη             usr/share/ECM/kde-modules/prefix.sh.cmake                                                                                                                                                                                                                       -ݚb9ǚ:̨inG%c\1     |        usr/share/ECM/kde-modules/prefix.sh.fish.cmake                                                                                                                                                                                                                  %b	J(kJU)D-x*"N             usr/share/ECM/modules/CheckAtomic.cmake                                                                                                                                                                                                                         DZ	y~-GD|qoX             usr/share/ECM/modules/ECMAddAndroidApk.cmake                                                                                                                                                                                                                    XMaV񸰔<YO9t$Jg     lD        usr/share/ECM/modules/ECMAddAppIcon.cmake                                                                                                                                                                                                                       `n=QzuV;IT<͔'_37     '        usr/share/ECM/modules/ECMAddQch.cmake                                                                                                                                                                                                                           LpY?b*PXIȡZ     Y        usr/share/ECM/modules/ECMAddQtDesignerPlugin.cmake                                                                                                                                                                                                              a칾=125Y)yMEv4dF             usr/share/ECM/modules/ECMAddTests.cmake                                                                                                                                                                                                                         i*TL{7kD1y^+8F렟3             usr/share/ECM/modules/ECMCheckOutboundLicense.cmake                                                                                                                                                                                                             8!OTөq
|2
L     	        usr/share/ECM/modules/ECMConfiguredInstall.cmake                                                                                                                                                                                                                g|d)@դP(y8o ["#pV     *        usr/share/ECM/modules/ECMCoverageOption.cmake                                                                                                                                                                                                                   >@Aݻ]j;&{Qm\ĀcZ     "        usr/share/ECM/modules/ECMCreateQmFromPoFiles.cmake                                                                                                                                                                                                              V[V7^wTI
Knv@ְ*4Vv;f}             usr/share/ECM/modules/ECMDeprecationSettings.cmake                                                                                                                                                                                                              .]#@I5Rmk5wPsLq     %        usr/share/ECM/modules/ECMEnableSanitizers.cmake                                                                                                                                                                                                                 >ugyz]昩[φ5             usr/share/ECM/modules/ECMFeatureSummary.cmake                                                                                                                                                                                                                   ;pspf8wE.     /        usr/share/ECM/modules/ECMFindModuleHelpers.cmake                                                                                                                                                                                                                $E>-faIG&SmVDs\tF     	        usr/share/ECM/modules/ECMFindQmlModule.cmake                                                                                                                                                                                                                    ?e'FoSL 	{\㢨|X^f     "        usr/share/ECM/modules/ECMFindQmlModule.cmake.in                                                                                                                                                                                                                 :0PSnsNuܴ             usr/share/ECM/modules/ECMGenerateDBusServiceFile.cmake                                                                                                                                                                                                          Y86(ڏâwci]4(qڦdSt             usr/share/ECM/modules/ECMGenerateExportHeader.cmake                                                                                                                                                                                                             ,H6q>I,줩1(U+     #        usr/share/ECM/modules/ECMGenerateHeaders.cmake                                                                                                                                                                                                                  \Vs_$|x~=_* t$F 	w     *        usr/share/ECM/modules/ECMGeneratePkgConfigFile.cmake                                                                                                                                                                                                            ګP	W&}$1?60M     *        usr/share/ECM/modules/ECMGeneratePriFile.cmake                                                                                                                                                                                                                  )("m>/7ZE64TC}x]˄             usr/share/ECM/modules/ECMGeneratePythonBindings.cmake                                                                                                                                                                                                           [̱w9=P,ہ7T&B@U(             usr/share/ECM/modules/ECMGeneratePythonBindings.toml.in                                                                                                                                                                                                         }35./,!$,Ks*     r         usr/share/ECM/modules/ECMGeneratePythonBindings.toml.in.license                                                                                                                                                                                                 jldaoL*[po&(Beٿ=M+     A	        usr/share/ECM/modules/ECMGenerateQmlTypes.cmake                                                                                                                                                                                                                 )'_qan1V(Ȗbt܎4     ,        usr/share/ECM/modules/ECMInstallIcons.cmake                                                                                                                                                                                                                     W0fp^r;R̆se:\`             usr/share/ECM/modules/ECMMarkAsTest.cmake                                                                                                                                                                                                                       xeNq>9[^͎@״F=e             usr/share/ECM/modules/ECMMarkNonGuiExecutable.cmake                                                                                                                                                                                                             LNuEؖN$;Bh             usr/share/ECM/modules/ECMOptionalAddSubdirectory.cmake                                                                                                                                                                                                          ylei]]^#лy;o             usr/share/ECM/modules/ECMPackageConfigHelpers.cmake                                                                                                                                                                                                             FI_,bǴa%׭Y     $        usr/share/ECM/modules/ECMPoQmTools.cmake                                                                                                                                                                                                                        xCg_y:a'fc@fkد     C        usr/share/ECM/modules/ECMQMLModules.cmake                                                                                                                                                                                                                       cvh>,v̈́c&a     K)        usr/share/ECM/modules/ECMQchDoxygen.config.in                                                                                                                                                                                                                   mzP$oܞ.&?2E}j	f             usr/share/ECM/modules/ECMQchDoxygenLayout.xml                                                                                                                                                                                                                   OR[zqگ@Xt	ɲG{     w        usr/share/ECM/modules/ECMQmLoader.cpp.in                                                                                                                                                                                                                        {cBC09[Zb5싶ȕ     !        usr/share/ECM/modules/ECMQmlModule.cmake                                                                                                                                                                                                                        _;I β-AN)UK#
e'              usr/share/ECM/modules/ECMQmlModule.cpp.in                                                                                                                                                                                                                       +$4ay㹩(7|V8`b,$(     b         usr/share/ECM/modules/ECMQmlModule.cpp.in.license                                                                                                                                                                                                               g0V`D2ҖBqE`e2*r-s(     d        usr/share/ECM/modules/ECMQmlModule.h.in                                                                                                                                                                                                                         +$4ay㹩(7|V8`b,$)     b         usr/share/ECM/modules/ECMQmlModule.h.in.license                                                                                                                                                                                                                 5A&i5g̎o nz%O鍯9*     7        usr/share/ECM/modules/ECMQmlModule5.cmake                                                                                                                                                                                                                       >3N^QAS^9gߝV_рa     >'        usr/share/ECM/modules/ECMQmlModule6.cmake                                                                                                                                                                                                                       ̡d&H&`\?v9AbwjK->6     V@        usr/share/ECM/modules/ECMQtDeclareLoggingCategory.cmake                                                                                                                                                                                                         m\7;y2mC6?ꡓw@.              usr/share/ECM/modules/ECMQtDeclareLoggingCategory.cpp.in                                                                                                                                                                                                        A;hX{;%'MT,;wo              usr/share/ECM/modules/ECMQtDeclareLoggingCategory.h.in                                                                                                                                                                                                          >zЇcj)S!kx\U}|[     u        usr/share/ECM/modules/ECMQueryQmake.cmake                                                                                                                                                                                                                       (m>vgbpJ՜O8hXoIEDuN             usr/share/ECM/modules/ECMQueryQt.cmake                                                                                                                                                                                                                          Ԗ9A?BZ=BKygr     A!        usr/share/ECM/modules/ECMSetupQtPluginMacroNames.cmake                                                                                                                                                                                                          ͩǒoiԼ
ӶjUuQӉ	     "        usr/share/ECM/modules/ECMSetupVersion.cmake                                                                                                                                                                                                                     T":v8o|طZ+F4s	Ce$	     )        usr/share/ECM/modules/ECMSourceVersionControl.cmake                                                                                                                                                                                                             O&pVCig[+q3n|'	             usr/share/ECM/modules/ECMUninstallTarget.cmake                                                                                                                                                                                                                  +`u.M X|Ij~r6b#!0#=:	S.	             usr/share/ECM/modules/ECMUseFindModules.cmake                                                                                                                                                                                                                   \$x#&ĘN\̺+0:	             usr/share/ECM/modules/ECMVersionHeader.h.in                                                                                                                                                                                                                     N/{]k>46n	6;%en#<	             usr/share/ECM/modules/ECMWinResolveSymlinks.cmake                                                                                                                                                                                                               -gvyTFmyo~k}@C7L	             usr/share/ECM/modules/QtVersionOption.cmake                                                                                                                                                                                                                     bVERj
mYsҌ;RbeQ	             usr/share/ECM/modules/check-outbound-license.py                                                                                                                                                                                                                 B{24Gh/DaZ\"n3)pb	     ,        usr/share/ECM/modules/ecm_uninstall.cmake.in                                                                                                                                                                                                                    <ODJZA&

" ,/o4e	     (        usr/share/ECM/test-modules/test_execute_and_compare.cmake                                                                                                                                                                                                       4]kȜ%kaLYl^$Pd5\g	     7        usr/share/ECM/toolchain/Android.cmake                                                                                                                                                                                                                           @",.$kXwp"yr	             usr/share/ECM/toolchain/ECMAndroidDeployQt5.cmake                                                                                                                                                                                                               )u#V~3&;
qs(^>f|	     p        usr/share/ECM/toolchain/deployment-file-qt514.json.in                                                                                                                                                                                                           ħ0	ۧ(AEQ?,	             usr/share/ECM/toolchain/deployment-file-qt6.json.in                                                                                                                                                                                                             +cF*0ȁ!$BJSӾL	     g         usr/share/ECM/toolchain/deployment-file-qt6.json.in.license                                                                                                                                                                                                     fЎ#'&+ R]KF	             usr/share/ECM/toolchain/deployment-file.json.in                                                                                                                                                                                                                 u.B' 50(:sPK׬iJ	     N        usr/share/ECM/toolchain/generate-fastlane-metadata.py                                                                                                                                                                                                           [&毚Z`;9'7ih8cx
     l        usr/share/ECM/toolchain/hasMainSymbol.cmake                                                                                                                                                                                                                     Vh^Vѐk'pz'n
     k        usr/share/ECM/toolchain/specifydependencies.cmake                                                                                                                                                                                                               
####### Expanded from @PACKAGE_INIT@ by configure_package_config_file() #######
####### Any changes to this file will be overwritten by the next CMake run ####
####### The input file was ECMConfig.cmake.in                            ########

get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE)

macro(set_and_check _var _file)
  set(${_var} "${_file}")
  if(NOT EXISTS "${_file}")
    message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !")
  endif()
endmacro()

macro(check_required_components _NAME)
  foreach(comp ${${_NAME}_FIND_COMPONENTS})
    if(NOT ${_NAME}_${comp}_FOUND)
      if(${_NAME}_FIND_REQUIRED_${comp})
        set(${_NAME}_FOUND FALSE)
      endif()
    endif()
  endforeach()
endmacro()

####################################################################################

set(ECM_FIND_MODULE_DIR "${PACKAGE_PREFIX_DIR}/share/ECM/find-modules/")

set(ECM_MODULE_DIR "${PACKAGE_PREFIX_DIR}/share/ECM/modules/")

set(ECM_KDE_MODULE_DIR "${PACKAGE_PREFIX_DIR}/share/ECM/kde-modules/")

set(ECM_PREFIX "/usr")

set(ECM_MODULE_PATH "${ECM_MODULE_DIR}" "${ECM_FIND_MODULE_DIR}" "${ECM_KDE_MODULE_DIR}")

set(ECM_GLOBAL_FIND_VERSION "${ECM_FIND_VERSION}")

include("${ECM_MODULE_DIR}/ECMUseFindModules.cmake")
# This is a basic version file for the Config-mode of find_package().
# It is used by write_basic_package_version_file() as input file for configure_file()
# to create a version-file which can be installed along a config.cmake file.
#
# The created file sets PACKAGE_VERSION_EXACT if the current version string and
# the requested version string are exactly the same and it sets
# PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version.
# The variable CVF_VERSION must be set before calling configure_file().

set(PACKAGE_VERSION "6.10.0")

if (PACKAGE_FIND_VERSION_RANGE)
  # Package version must be in the requested version range
  if ((PACKAGE_FIND_VERSION_RANGE_MIN STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION_MIN)
      OR ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_GREATER PACKAGE_FIND_VERSION_MAX)
        OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND PACKAGE_VERSION VERSION_GREATER_EQUAL PACKAGE_FIND_VERSION_MAX)))
    set(PACKAGE_VERSION_COMPATIBLE FALSE)
  else()
    set(PACKAGE_VERSION_COMPATIBLE TRUE)
  endif()
else()
  if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
    set(PACKAGE_VERSION_COMPATIBLE FALSE)
  else()
    set(PACKAGE_VERSION_COMPATIBLE TRUE)
    if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
      set(PACKAGE_VERSION_EXACT TRUE)
    endif()
  endif()
endif()


# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it:
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "" STREQUAL "")
  return()
endif()

# check that the installed version has the same 32/64bit-ness as the one which is currently searching:
if(NOT CMAKE_SIZEOF_VOID_P STREQUAL "")
  math(EXPR installedBits " * 8")
  set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)")
  set(PACKAGE_VERSION_UNSUITABLE TRUE)
endif()
include(${CMAKE_CURRENT_LIST_DIR}/../modules/ECMFindModuleHelpers.cmake)
# SPDX-FileCopyrightText: 2019, 2021, 2023 Friedrich W. H. Kossebau <kossebau@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
Find7Zip
--------

Try to find 7-Zip.

If the 7-Zip executable is not in your PATH, you can provide
an alternative name or full path location with the ``7Zip_EXECUTABLE``
variable.

This will define the following variables:

``7Zip_FOUND``
    TRUE if 7-Zip is available

``7Zip_EXECUTABLE``
    Path to 7-Zip executable

If ``7Zip_FOUND`` is TRUE, it will also define the following imported
target:

``7Zip::7Zip``
    Path to 7-Zip executable

.. note::
    It will see to only find the original 7-Zip, not one of the  p7zip forks.

Since 5.113.0.
#]=======================================================================]

if(WIN32)
    find_program(7Zip_EXECUTABLE NAMES 7z 7za)
else()
    # Some p7zip used to be a fork for Linux of older 7-Zip,
    # just supporting the 7z format, and occupied the 7z binary name.
    # When 7-Zip got its official Linux support, it chose 7zz to not conflict,
    # given it also has another set of arguments.
    # Later p7zip was forked once more into some p7zip-zstd, using a newer copy of 7-Zip,
    # supporting more than 7z format, therefore also many of the arguments known from 7-Zip.
    # Being a different project though and now a real fork due to 7-Zip supporting Linux,
    # we try to only find the original here, so consumers can rely on the original 7-Zip documentation.
    find_program(7Zip_EXECUTABLE NAMES 7zz)
endif()

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(7Zip
    FOUND_VAR
        7Zip_FOUND
    REQUIRED_VARS
        7Zip_EXECUTABLE
)
mark_as_advanced(7Zip_EXECUTABLE)

if(NOT TARGET 7Zip::7Zip AND 7Zip_FOUND)
    add_executable(7Zip::7Zip IMPORTED)
    set_target_properties(7Zip::7Zip PROPERTIES
        IMPORTED_LOCATION "${7Zip_EXECUTABLE}"
    )
endif()

include(FeatureSummary)
set_package_properties(7Zip PROPERTIES
    URL "https://www.7-zip.org/"
    DESCRIPTION "Data (de)compression program"
)
# SPDX-FileCopyrightText: 2019, 2021 Friedrich W. H. Kossebau <kossebau@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
Find7z
------

Try to find 7z.

If the 7z executable is not in your PATH, you can provide
an alternative name or full path location with the ``7z_EXECUTABLE``
variable.

This will define the following variables:

``7z_FOUND``
    TRUE if 7z is available

``7z_EXECUTABLE``
    Path to 7z executable

If ``7z_FOUND`` is TRUE, it will also define the following imported
target:

``7z::7z``
    Path to 7z executable

.. note::
    Only works on Windows.

Deprecated: since 5.113, use  :find-module:`Find7Zip`.

Since 5.85.0.
#]=======================================================================]

find_program(7z_EXECUTABLE NAMES 7z.exe 7za.exe)

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(7z
    FOUND_VAR
        7z_FOUND
    REQUIRED_VARS
        7z_EXECUTABLE
)
mark_as_advanced(7z_EXECUTABLE)

if(NOT TARGET 7z::7z AND 7z_FOUND)
    add_executable(7z::7z IMPORTED)
    set_target_properties(7z::7z PROPERTIES
        IMPORTED_LOCATION "${7z_EXECUTABLE}"
    )
endif()

include(FeatureSummary)
set_package_properties(7z PROPERTIES
    URL "https://www.7-zip.org/"
    DESCRIPTION "Data (de)compression program"
)
# SPDX-FileCopyrightText: 2012 Raphael Kubo da Costa <rakuco@FreeBSD.org>
# SPDX-FileCopyrightText: 2019 Harald Sitter <sitter@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
FindCanberra
------------

Try to find Canberra event sound library.

This will define the following variables:

``Canberra_FOUND``
    True if (the requested version of) Canberra is available
``Canberra_VERSION``
    The version of Canberra
``Canberra_LIBRARIES``
    The libraries of Canberra for use with target_link_libraries()
``Canberra_INCLUDE_DIRS``
    The include dirs of Canberra for use with target_include_directories()

If ``Canberra_FOUND`` is TRUE, it will also define the following imported
target:

``Canberra::Canberra``
    The Canberra library

In general we recommend using the imported target, as it is easier to use.
Bear in mind, however, that if the target is in the link interface of an
exported library, it must be made available by the package config file.

Since 5.56.0.
#]=======================================================================]

find_package(PkgConfig QUIET)
pkg_check_modules(PC_Canberra QUIET IMPORTED_TARGET libcanberra)

find_library(Canberra_LIBRARIES
    NAMES canberra
    HINTS ${PC_Canberra_LIBRARY_DIRS}
)

find_path(Canberra_INCLUDE_DIRS
    NAMES canberra.h
    HINTS ${PC_Canberra_INCLUDE_DIRS}
)

set(Canberra_VERSION ${PC_Canberra_VERSION})

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Canberra
    FOUND_VAR
        Canberra_FOUND
    REQUIRED_VARS
        Canberra_LIBRARIES
        Canberra_INCLUDE_DIRS
    VERSION_VAR
        Canberra_VERSION
)

if(Canberra_FOUND AND NOT TARGET Canberra::Canberra)
    add_library(Canberra::Canberra UNKNOWN IMPORTED)
    set_target_properties(Canberra::Canberra PROPERTIES
        IMPORTED_LOCATION "${Canberra_LIBRARIES}"
        INTERFACE_COMPILE_OPTIONS "${PC_Canberra_CFLAGS}"
        INTERFACE_INCLUDE_DIRECTORIES "${Canberra_INCLUDE_DIRS}"
    )
    if (TARGET PkgConfig::PC_Canberra)
        target_link_libraries(Canberra::Canberra INTERFACE PkgConfig::PC_Canberra)
    endif()
endif()

mark_as_advanced(Canberra_LIBRARIES Canberra_INCLUDE_DIRS Canberra_VERSION)

include(FeatureSummary)
set_package_properties(Canberra PROPERTIES
    DESCRIPTION "Event sound library"
    URL "https://0pointer.de/lennart/projects/libcanberra"
)

# Compatibility variables. In a previous life FindCanberra lived
# in a number of different repos: don't break them if they use ECM but have not
# been updated for this finder.
set(CANBERRA_FOUND ${Canberra_FOUND})
set(CANBERRA_VERSION ${Canberra_VERSION})
set(CANBERRA_LIBRARIES ${Canberra_LIBRARIES})
set(CANBERRA_INCLUDE_DIRS ${Canberra_INCLUDE_DIRS})
mark_as_advanced(CANBERRA_VERSION CANBERRA_LIBRARIES CANBERRA_INCLUDE_DIRS)
# SPDX-FileCopyrightText: 2014 Alex Merry <alex.merry@kde.org>
# SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
FindEGL
-------

Try to find EGL.

This will define the following variables:

``EGL_FOUND``
    True if (the requested version of) EGL is available
``EGL_VERSION``
    The version of EGL; note that this is the API version defined in the
    headers, rather than the version of the implementation (eg: Mesa)
``EGL_LIBRARIES``
    This can be passed to target_link_libraries() instead of the ``EGL::EGL``
    target
``EGL_INCLUDE_DIRS``
    This should be passed to target_include_directories() if the target is not
    used for linking
``EGL_DEFINITIONS``
    This should be passed to target_compile_options() if the target is not
    used for linking

If ``EGL_FOUND`` is TRUE, it will also define the following imported target:

``EGL::EGL``
    The EGL library

In general we recommend using the imported target, as it is easier to use.
Bear in mind, however, that if the target is in the link interface of an
exported library, it must be made available by the package config file.

Since pre-1.0.0.
#]=======================================================================]

include(${CMAKE_CURRENT_LIST_DIR}/ECMFindModuleHelpersStub.cmake)
include(CheckCXXSourceCompiles)
include(CMakePushCheckState)

ecm_find_package_version_check(EGL)

# Use pkg-config to get the directories and then use these values
# in the FIND_PATH() and FIND_LIBRARY() calls
find_package(PkgConfig QUIET)
pkg_check_modules(PKG_EGL QUIET egl)

set(EGL_DEFINITIONS ${PKG_EGL_CFLAGS_OTHER})

find_path(EGL_INCLUDE_DIR
    NAMES
        EGL/egl.h
    HINTS
        ${PKG_EGL_INCLUDE_DIRS}
)
find_library(EGL_LIBRARY
    NAMES
        EGL
        libEGL
    HINTS
        ${PKG_EGL_LIBRARY_DIRS}
)

# NB: We do *not* use the version information from pkg-config, as that
#     is the implementation version (eg: the Mesa version)
if(EGL_INCLUDE_DIR)
    # egl.h has defines of the form EGL_VERSION_x_y for each supported
    # version; so the header for EGL 1.1 will define EGL_VERSION_1_0 and
    # EGL_VERSION_1_1.  Finding the highest supported version involves
    # finding all these defines and selecting the highest numbered.
    file(READ "${EGL_INCLUDE_DIR}/EGL/egl.h" _EGL_header_contents)
    string(REGEX MATCHALL
        "[ \t]EGL_VERSION_[0-9_]+"
        _EGL_version_lines
        "${_EGL_header_contents}"
    )
    unset(_EGL_header_contents)
    foreach(_EGL_version_line ${_EGL_version_lines})
        string(REGEX REPLACE
            "[ \t]EGL_VERSION_([0-9_]+)"
            "\\1"
            _version_candidate
            "${_EGL_version_line}"
        )
        string(REPLACE "_" "." _version_candidate "${_version_candidate}")
        if(NOT DEFINED EGL_VERSION OR EGL_VERSION VERSION_LESS _version_candidate)
            set(EGL_VERSION "${_version_candidate}")
        endif()
    endforeach()
    unset(_EGL_version_lines)
endif()

cmake_push_check_state(RESET)
list(APPEND CMAKE_REQUIRED_LIBRARIES "${EGL_LIBRARY}")
list(APPEND CMAKE_REQUIRED_INCLUDES "${EGL_INCLUDE_DIR}")

check_cxx_source_compiles("
#include <EGL/egl.h>

int main(int argc, char *argv[]) {
    EGLint x = 0; EGLDisplay dpy = 0; EGLContext ctx = 0;
    eglDestroyContext(dpy, ctx);
}" HAVE_EGL)

cmake_pop_check_state()

set(required_vars EGL_INCLUDE_DIR HAVE_EGL)
if(NOT EMSCRIPTEN)
    list(APPEND required_vars EGL_LIBRARY)
endif()

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(EGL
    FOUND_VAR
        EGL_FOUND
    REQUIRED_VARS
        ${required_vars}
    VERSION_VAR
        EGL_VERSION
)

if(EGL_FOUND AND NOT TARGET EGL::EGL)
    if (EMSCRIPTEN)
        add_library(EGL::EGL INTERFACE IMPORTED)
        # Nothing further to be done, system include paths have headers and linkage is implicit.
    else()
        add_library(EGL::EGL UNKNOWN IMPORTED)
        set_target_properties(EGL::EGL PROPERTIES
            IMPORTED_LOCATION "${EGL_LIBRARY}"
            INTERFACE_COMPILE_OPTIONS "${EGL_DEFINITIONS}"
            INTERFACE_INCLUDE_DIRECTORIES "${EGL_INCLUDE_DIR}"
        )
    endif()
endif()

mark_as_advanced(EGL_LIBRARY EGL_INCLUDE_DIR HAVE_EGL)

# compatibility variables
set(EGL_LIBRARIES ${EGL_LIBRARY})
set(EGL_INCLUDE_DIRS ${EGL_INCLUDE_DIR})
set(EGL_VERSION_STRING ${EGL_VERSION})

include(FeatureSummary)
set_package_properties(EGL PROPERTIES
    URL "https://www.khronos.org/egl/"
    DESCRIPTION "A platform-agnostic mechanism for creating rendering surfaces for use with other graphics libraries, such as OpenGL|ES and OpenVG."
)
# SPDX-FileCopyrightText: 2008 Laurent Montel <montel@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause


#[=======================================================================[.rst:
FindGLIB2
---------

Try to locate the GLib2 library.
If found, this will define the following variables:

``GLIB2_FOUND``
    True if the GLib2 library is available
``GLIB2_INCLUDE_DIRS``
    The GLib2 include directories
``GLIB2_LIBRARIES``
    The GLib2 libraries for linking
``GLIB2_INCLUDE_DIR``
    Deprecated, use ``GLIB2_INCLUDE_DIRS``
``GLIB2_LIBRARY``
    Deprecated, use ``GLIB2_LIBRARIES``

If ``GLIB2_FOUND`` is TRUE, it will also define the following
imported target:

``GLIB2::GLIB2``
    The GLIB2 library
``GLIB2::GTHREAD2``
    The GThread2 library (since 6.7.0)
``GLIB2::GOBJECT``
    The GObject library (since 6.7.0)
``GLIB2::GIO``
    The GIO library (since 6.7.0)

Since 5.41.0.
#]=======================================================================]

find_package(PkgConfig QUIET)
pkg_check_modules(PC_GLIB2 QUIET glib-2.0)

find_path(GLIB2_INCLUDE_DIRS
          NAMES glib.h
          HINTS ${PC_GLIB2_INCLUDEDIR}
          PATH_SUFFIXES glib-2.0)

find_library(GLIB2_LIBRARIES
             NAMES glib-2.0
             HINTS ${PC_GLIB2_LIBDIR}
)

pkg_check_modules(PC_GTHREAD2 QUIET gthread-2.0)

find_library(GTHREAD2_LIBRARIES
             NAMES gthread-2.0
             HINTS ${PC_GTHREAD2_LIBDIR}
)

pkg_check_modules(PC_GOBJECT QUIET gobject-2.0)

find_path(GLIB2_GOBJECT_INCLUDE_DIRS
          NAMES glib-object.h
          HINTS ${PC_GOBJECT_INCLUDEDIR}
          PATH_SUFFIXES glib-2.0)

find_library(GLIB2_GOBJECT_LIBRARIES
             NAMES gobject-2.0
             HINTS ${PC_GOBJECT_LIBDIR}
)

pkg_check_modules(PC_GIO QUIET gio-2.0)

find_path(GLIB2_GIO_INCLUDE_DIRS
          NAMES gio/gio.h
          HINTS ${PC_GIO_INCLUDEDIR}
          PATH_SUFFIXES glib-2.0)

find_library(GLIB2_GIO_LIBRARIES
             NAMES gio-2.0
             HINTS ${PC_GIO_LIBDIR}
)

# search the glibconfig.h include dir under the same root where the library is found
get_filename_component(glib2LibDir "${GLIB2_LIBRARIES}" PATH)

find_path(GLIB2_INTERNAL_INCLUDE_DIR glibconfig.h
          PATH_SUFFIXES glib-2.0/include
          HINTS ${PC_GLIB2_INCLUDEDIR} "${glib2LibDir}" ${CMAKE_SYSTEM_LIBRARY_PATH})

# not sure if this include dir is optional or required
# for now it is optional
if(GLIB2_INTERNAL_INCLUDE_DIR)
  list(APPEND GLIB2_INCLUDE_DIRS "${GLIB2_INTERNAL_INCLUDE_DIR}")
  list(APPEND GLIB2_GOBJECT_INCLUDE_DIRS "${GLIB2_INTERNAL_INCLUDE_DIR}")
  list(APPEND GLIB2_GIO_INCLUDE_DIRS "${GLIB2_INTERNAL_INCLUDE_DIR}")
endif()

# Deprecated synonyms
set(GLIB2_INCLUDE_DIR "${GLIB2_INCLUDE_DIRS}")
set(GLIB2_LIBRARY "${GLIB2_LIBRARIES}")
set(GLIB2_GOBJECT_INCLUDE_DIR "${GLIB2_GOBJECT_INCLUDE_DIRS}")
set(GLIB2_GOBJECT_LIBRARY "${GLIB2_GOBJECT_LIBRARIES}")
set(GLIB2_GIO_INCLUDE_DIR "${GLIB2_GIO_INCLUDE_DIRS}")
set(GLIB2_GIO_LIBRARY "${GLIB2_GIO_LIBRARIES}")

if(GLIB2_GOBJECT_LIBRARIES AND GLIB2_GOBJECT_INCLUDE_DIRS)
  set(GLIB2_GOBJECT_FOUND TRUE)
endif()

if(GLIB2_GIO_LIBRARIES AND GLIB2_GIO_INCLUDE_DIRS)
  set(GLIB2_GIO_FOUND TRUE)
endif()

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(GLIB2
                                  REQUIRED_VARS GLIB2_LIBRARIES GTHREAD2_LIBRARIES GLIB2_INCLUDE_DIRS
                                  HANDLE_COMPONENTS)

if(GLIB2_FOUND AND NOT TARGET GLIB2::GLIB2)
  add_library(GLIB2::GLIB2 UNKNOWN IMPORTED)
  set_target_properties(GLIB2::GLIB2 PROPERTIES
                        IMPORTED_LOCATION "${GLIB2_LIBRARIES}"
                        INTERFACE_LINK_LIBRARIES "${GTHREAD2_LIBRARIES}"
                        INTERFACE_INCLUDE_DIRECTORIES "${GLIB2_INCLUDE_DIRS}")
endif()

if(GLIB2_GOBJECT_FOUND AND NOT TARGET GLIB2::GOBJECT)
  add_library(GLIB2::GOBJECT UNKNOWN IMPORTED)
  set_target_properties(GLIB2::GOBJECT PROPERTIES
                        IMPORTED_LOCATION "${GLIB2_GOBJECT_LIBRARIES}"
                        INTERFACE_INCLUDE_DIRECTORIES "${GLIB2_GOBJECT_INCLUDE_DIRS}")
endif()

if(GLIB2_GIO_FOUND AND NOT TARGET GLIB2::GIO)
  add_library(GLIB2::GIO UNKNOWN IMPORTED)
  set_target_properties(GLIB2::GIO PROPERTIES
                        IMPORTED_LOCATION "${GLIB2_GIO_LIBRARIES}"
                        INTERFACE_INCLUDE_DIRECTORIES "${GLIB2_GIO_INCLUDE_DIRS}")
endif()

mark_as_advanced(GLIB2_INCLUDE_DIRS GLIB2_INCLUDE_DIR
                 GLIB2_LIBRARIES GLIB2_LIBRARY
                 GLIB2_GOBJECT_INCLUDE_DIRS GLIB2_GOBJECT_INCLUDE_DIR
                 GLIB2_GOBJECT_LIBRARIES GLIB2_GOBJECT_LIBRARY
                 GLIB2_GIO_INCLUDE_DIRS GLIB2_GIO_INCLUDE_DIR
                 GLIB2_GIO_LIBRARIES GLIB2_GIO_LIBRARY)

include(FeatureSummary)
set_package_properties(GLIB2 PROPERTIES
  URL "https://wiki.gnome.org/Projects/GLib"
  DESCRIPTION "Event loop and utility library")
# SPDX-FileCopyrightText: 2016-2017 Pino Toscano <pino@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
FindGperf
-----------

Try to find GNU gperf.

If the gperf executable is not in your PATH, you can provide
an alternative name or full path location with the ``Gperf_EXECUTABLE``
variable.

This will define the following variables:

``Gperf_FOUND``
    True if gperf is available.

``Gperf_EXECUTABLE``
    The gperf executable.

``Gperf_VERSION``
    The gperf version. (since 5.85)

If ``Gperf_FOUND`` is TRUE, it will also define the following imported
target:

``GPerf::Gperf``
    The gperf executable.

and the following public function:
::

  ecm_gperf_generate(<GperfInput> <OutputFile> <OutputVariable(|target (since 5.83))>
                     [GENERATION_FLAGS <flags>])

Run ``gperf`` on ``<GperfInput>`` to generate ``<OutputFile>``, adding it to
the ``<OutputVariable>`` variable which contains the source for the target
where ``<OutputFile>`` is going to be built or, since KF 5.83, if the given
argument is a target, to the list of private sources of that target. The
target must not be an alias. The optional ``GENERATION_FLAGS`` argument is
needed to pass extra parameters to ``gperf`` (note you cannot override that
way the output file).

A simple invocation would be:

.. code-block:: cmake

  ecm_gperf_generate(simple.gperf ${CMAKE_CURRENT_BINARY_DIR}/simple.h MySources)

Since 5.35.0.
#]=======================================================================]

include(${CMAKE_CURRENT_LIST_DIR}/ECMFindModuleHelpersStub.cmake)

ecm_find_package_version_check(Gperf)

# Find gperf
find_program(Gperf_EXECUTABLE NAMES gperf)

if(Gperf_EXECUTABLE)
    execute_process(COMMAND ${Gperf_EXECUTABLE} -v
        OUTPUT_VARIABLE _version_string
        ERROR_QUIET
        OUTPUT_STRIP_TRAILING_WHITESPACE)
    if(_version_string MATCHES "^GNU gperf ([-0-9\\.]+)")
        set(Gperf_VERSION "${CMAKE_MATCH_1}")
    endif()
    unset(_version_string)
else()
    set(Gperf_VERSION)
endif()

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Gperf
    FOUND_VAR
        Gperf_FOUND
    REQUIRED_VARS
        Gperf_EXECUTABLE
    VERSION_VAR
        Gperf_VERSION
)

mark_as_advanced(Gperf_EXECUTABLE)

if (Gperf_FOUND)
    if (NOT TARGET GPerf::Gperf)
        add_executable(GPerf::Gperf IMPORTED)
        set_target_properties(GPerf::Gperf PROPERTIES
            IMPORTED_LOCATION "${Gperf_EXECUTABLE}"
        )
    endif()
endif()

include(FeatureSummary)
set_package_properties(Gperf PROPERTIES
    URL "https://www.gnu.org/software/gperf/"
    DESCRIPTION "Perfect hash function generator"
)

function(ecm_gperf_generate input_file output_file _target_or_sources_var)
    # Parse arguments
    set(oneValueArgs GENERATION_FLAGS)
    cmake_parse_arguments(ARGS "" "${oneValueArgs}" "" ${ARGN})

    if(ARGS_UNPARSED_ARGUMENTS)
        message(FATAL_ERROR "Unknown keywords given to ecm_gperf_generate(): \"${ARGS_UNPARSED_ARGUMENTS}\"")
    endif()
    if (TARGET ${_target_or_sources_var})
        get_target_property(aliased_target ${_target_or_sources_var} ALIASED_TARGET)
        if(aliased_target)
            message(FATAL_ERROR "Target argument passed to ecm_gperf_generate must not be an alias: ${_target_or_sources_var}")
        endif()
    endif()

    get_filename_component(_infile ${input_file} ABSOLUTE)
    set(_extraopts "${ARGS_GENERATION_FLAGS}")
    separate_arguments(_extraopts)
    add_custom_command(OUTPUT ${output_file}
        COMMAND ${Gperf_EXECUTABLE} ${_extraopts} --output-file=${output_file} ${_infile}
        DEPENDS ${_infile}
        WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
        VERBATIM
    )
    set_property(SOURCE ${output_file} PROPERTY SKIP_AUTOMOC ON)

    if (TARGET ${_target_or_sources_var})
        target_sources(${_target_or_sources_var} PRIVATE ${output_file})
    else()
        set(${_target_or_sources_var} ${${_target_or_sources_var}} ${output_file} PARENT_SCOPE)
    endif()
endfunction()
# SPDX-FileCopyrightText: 2019 Volker Krause <vkrause@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
FindGradle
----------

Provides the ability to build Android AAR libraries using Gradle.

This relies on the Qt provided Gradle, so a Qt for Android installation
is required.
::

  gradle_add_aar(<target>
                 BUIDLFILE build.gradle
                 NAME <aar-name>)

This builds an Android AAR library using the given ``build.gradle`` file.
::

  gradle_install_aar(<target>
                     DESTINATION <dest>)

Installs a Android AAR library that has been created with ``gradle_add_aar``.

Since 5.76.0.
#]=======================================================================]

include(${CMAKE_CURRENT_LIST_DIR}/../modules/QtVersionOption.cmake)
include(FindPackageHandleStandardArgs)

find_package(Qt${QT_MAJOR_VERSION}Core REQUIRED)

set (Gradle_PRECOMMAND "")
if (NOT WIN32)
    set(Gradle_EXECUTABLE ${CMAKE_BINARY_DIR}/gradle/gradlew)
    # the gradlew script installed by Qt6 is not executable, so running it directly fails
    if (QT_MAJOR_VERSION EQUAL "6")
        set(Gradle_PRECOMMAND "sh")
    endif()
else()
    set(Gradle_EXECUTABLE ${CMAKE_BINARY_DIR}/gradle/gradlew.bat)
endif()

get_target_property(_qt_core_location Qt${QT_MAJOR_VERSION}::Core LOCATION)
get_filename_component(_qt_install_root ${_qt_core_location} DIRECTORY)
get_filename_component(_qt_install_root ${_qt_install_root}/../ ABSOLUTE)

set(_gradle_template_dir ${CMAKE_CURRENT_LIST_DIR})

add_custom_command(OUTPUT ${Gradle_EXECUTABLE}
    COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/gradle
    COMMAND ${CMAKE_COMMAND} -E copy_directory ${_qt_install_root}/src/3rdparty/gradle ${CMAKE_BINARY_DIR}/gradle
)
add_custom_target(gradle DEPENDS ${Gradle_EXECUTABLE})

# Android Gradle plugin version (not the Gradle version!) used by Qt, for use in our own build.gradle files
file(READ ${_qt_install_root}/src/android/templates/build.gradle _build_grade_template)
string(REGEX MATCH "[0-9]+\.[0-9]+\.[0-9]+" Gradle_ANDROID_GRADLE_PLUGIN_VERSION ${_build_grade_template})

find_package_handle_standard_args(Gradle DEFAULT_MSG Gradle_EXECUTABLE)

function(gradle_add_aar target)
    cmake_parse_arguments(ARG "" "BUILDFILE;NAME" "" ${ARGN})

    set(_build_root ${CMAKE_CURRENT_BINARY_DIR}/gradle_build/${ARG_NAME})
    configure_file(${_gradle_template_dir}/local.properties.cmake ${_build_root}/local.properties)
    configure_file(${_gradle_template_dir}/settings.gradle.cmake ${_build_root}/settings.gradle)
    configure_file(${ARG_BUILDFILE} ${_build_root}/build.gradle)

    if (CMAKE_BUILD_TYPE MATCHES "[Dd][Ee][Bb][Uu][Gg]")
        set(_aar_suffix "-debug")
        set(_aar_gradleCmd "assembleDebug")
    else()
        set(_aar_suffix "-release")
        set(_aar_gradleCmd "assembleRelease")
    endif()

    file(GLOB_RECURSE _src_files CONFIGURE_DEPENDS "*")
    add_custom_command(
        OUTPUT ${_build_root}/build/outputs/aar/${ARG_NAME}${_aar_suffix}.aar
        COMMAND ${Gradle_PRECOMMAND} ${Gradle_EXECUTABLE} ${_aar_gradleCmd}
        # this allows make create-apk to work without installations for apps with AAR libs in the same repository
        COMMAND ${CMAKE_COMMAND} -E copy ${_build_root}/build/outputs/aar/${ARG_NAME}${_aar_suffix}.aar ${CMAKE_BINARY_DIR}/jar/${ARG_NAME}.aar
        DEPENDS ${Gradle_EXECUTABLE} ${_src_files}
        DEPENDS gradle
        WORKING_DIRECTORY ${_build_root}
    )
    add_custom_target(${target} ALL DEPENDS ${_build_root}/build/outputs/aar/${ARG_NAME}${_aar_suffix}.aar)
    set_target_properties(${target} PROPERTIES LOCATION ${_build_root}/build/outputs/aar/${ARG_NAME}${_aar_suffix}.aar)
    set_target_properties(${target} PROPERTIES OUTPUT_NAME ${ARG_NAME})
endfunction()

function(gradle_install_aar target)
    cmake_parse_arguments(ARG "" "DESTINATION" "" ${ARGN})
    get_target_property(_loc ${target} LOCATION)
    get_target_property(_name ${target} OUTPUT_NAME)
    install(FILES ${_loc} DESTINATION ${ARG_DESTINATION} RENAME ${_name}.aar)
endfunction()
# SPDX-FileCopyrightText: 2017 Vincent Pinon <vpinon@kde.org>
# SPDX-FileCopyrightText: 2014 Alex Merry <alex.merry@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
FindIcoTool
-----------

Try to find icotool.

If the icotool executable is not in your PATH, you can provide
an alternative name or full path location with the ``IcoTool_EXECUTABLE``
variable.

This will define the following variables:

``IcoTool_FOUND``
    True if icotool is available.

``IcoTool_EXECUTABLE``
    The icotool executable.

If ``IcoTool_FOUND`` is TRUE, it will also define the following imported
target:

``IcoTool::IcoTool``
    The icotool executable.

Since 5.49.
#]=======================================================================]

include(${CMAKE_CURRENT_LIST_DIR}/ECMFindModuleHelpersStub.cmake)
ecm_find_package_version_check(IcoTool)
find_program(IcoTool_EXECUTABLE NAMES icotool)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(IcoTool
    FOUND_VAR
        IcoTool_FOUND
    REQUIRED_VARS
        IcoTool_EXECUTABLE
)
mark_as_advanced(IcoTool_EXECUTABLE)

if (IcoTool_FOUND)
    if (NOT TARGET IcoTool::IcoTool)
        add_executable(IcoTool::IcoTool IMPORTED)
        set_target_properties(IcoTool::IcoTool PROPERTIES
            IMPORTED_LOCATION "${IcoTool_EXECUTABLE}"
        )
    endif()
endif()

include(FeatureSummary)
set_package_properties(IcoTool PROPERTIES
    URL "https://www.nongnu.org/icoutils/"
    DESCRIPTION "Executable that converts a collection of PNG files into a Windows icon file"
)
# SPDX-FileCopyrightText: 2016 Tobias C. Berner <tcberner@FreeBSD.org>
# SPDX-FileCopyrightText: 2017 Adriaan de Groot <groot@kde.org>
#
# SPDX-License-Identifier: BSD-2-Clause

#[=======================================================================[.rst:
FindInotify
--------------

Try to find inotify on this system. This finds:
 - libinotify on Unix like systems, or
 - the kernel's inotify on Linux systems.

This will define the following variables:

``Inotify_FOUND``
   True if inotify is available
``Inotify_LIBRARIES``
   This has to be passed to target_link_libraries()
``Inotify_INCLUDE_DIRS``
   This has to be passed to target_include_directories()

On Linux and SunOS, the libraries and include directories are empty,
even though ``Inotify_FOUND`` may be set to TRUE. This is because
no special includes or libraries are needed. On other systems
these may be needed to use inotify.

Since 5.32.0.
#]=======================================================================]

find_path(Inotify_INCLUDE_DIRS sys/inotify.h)

if(Inotify_INCLUDE_DIRS)
# On Linux and SunOS, there is no library to link against, on the BSDs there is.
# On the BSD's, inotify is implemented through a library, libinotify.
    if(CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_SYSTEM_NAME MATCHES "SunOS")
        set(Inotify_FOUND TRUE)
        set(Inotify_LIBRARIES "")
        set(Inotify_INCLUDE_DIRS "")
    else()
        find_library(Inotify_LIBRARIES NAMES inotify)
        include(FindPackageHandleStandardArgs)
        find_package_handle_standard_args(Inotify
            FOUND_VAR
                Inotify_FOUND
            REQUIRED_VARS
                Inotify_LIBRARIES
                Inotify_INCLUDE_DIRS
        )
        mark_as_advanced(Inotify_LIBRARIES Inotify_INCLUDE_DIRS)
        include(FeatureSummary)
        set_package_properties(Inotify PROPERTIES
            URL "https://github.com/libinotify-kqueue/"
            DESCRIPTION "inotify API on the *BSD family of operating systems."
        )
    endif()
    if(NOT TARGET Inotify::Inotify)
        add_library(Inotify::Inotify INTERFACE IMPORTED)
        set_property(TARGET Inotify::Inotify PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${Inotify_INCLUDE_DIRS}")
        set_property(TARGET Inotify::Inotify PROPERTY INTERFACE_LINK_LIBRARIES "${Inotify_LIBRARIES}")
    endif()
else()
    set(Inotify_FOUND FALSE)
endif()

mark_as_advanced(Inotify_LIBRARIES Inotify_INCLUDE_DIRS) 
# SPDX-FileCopyrightText: 2016 Pino Toscano <pino@kde.org>
# SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
FindIsoCodes
------------

Try to find iso-codes data files.
Once done this will define:

``IsoCodes_FOUND``
      Whether the system has iso-codes
``IsoCodes_PREFIX``
      The location in which the iso-codes data files are found
``IsoCodes_DOMAINS``
      The available domains provided by iso-codes

Since 5.80.0.
#]=======================================================================]

find_package(PkgConfig QUIET)
pkg_check_modules(PKG_iso_codes QUIET iso-codes)

set(IsoCodes_VERSION ${PKG_iso_codes_VERSION})
set(IsoCodes_PREFIX ${PKG_iso_codes_PREFIX})
pkg_get_variable(IsoCodes_DOMAINS iso-codes domains)

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(IsoCodes
    FOUND_VAR IsoCodes_FOUND
    REQUIRED_VARS IsoCodes_DOMAINS IsoCodes_PREFIX
    VERSION_VAR IsoCodes_VERSION
)

include(FeatureSummary)
set_package_properties(IsoCodes PROPERTIES
  URL "https://salsa.debian.org/iso-codes-team/iso-codes"
  DESCRIPTION "Data about various ISO standards (e.g. country, language, language scripts, and currency names)"
)
# SPDX-FileCopyrightText: 2014 Alex Merry <alex.merry@kde.org>
# SPDX-FileCopyrightText: 2013 Stephen Kelly <steveire@gmail.com>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
FindKF5
-------

Find KDE Frameworks 5 with a single find_package() call.

This will use the package config files provided by the individual frameworks.
For example, if you wish to find KArchive, which presents itself to CMake as
KF5Archive (ie: you would do ``find_package(KF5Archive)`` to find it
directly), you can do

.. code-block:: cmake

  find_package(KF5 COMPONENTS Archive)

If all the required components (those given in the COMPONENTS argument, but
not those given in the OPTIONAL_COMPONENTS argument) are found, ``KF5_FOUND``
will be set to true. Otherwise, it will be set to false.

Since pre-1.0.0.
#]=======================================================================]

include(${CMAKE_CURRENT_LIST_DIR}/ECMFindModuleHelpersStub.cmake)

ecm_find_package_version_check(KF5)

if (NOT KF5_FIND_COMPONENTS)
    set(KF5_NOT_FOUND_MESSAGE "The KF5 package requires at least one component")
    set(KF5_FOUND False)
    return()
endif()

set(_quiet_arg)
if (KF5_FIND_QUIETLY)
    set(_quiet_arg QUIET)
endif()
set(_exact_arg)
if (KF5_FIND_EXACT)
    set(_exact_arg EXACT)
endif()

include(FindPackageHandleStandardArgs)
include(FeatureSummary)

set(KF5_VERSION)
foreach(_module ${KF5_FIND_COMPONENTS})
    find_package(KF5${_module} ${KF5_FIND_VERSION}
        ${_exact_arg} ${_quiet_arg}
        CONFIG
    )
    # CMake >= 3.17 wants to be explicitly told we are fine with name mismatch here
    set(_name_mismatched_arg)
    if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.17)
       set(_name_mismatched_arg NAME_MISMATCHED)
    endif()
    find_package_handle_standard_args(KF5${_module} CONFIG_MODE ${_name_mismatched_arg})
    if (KF5_FIND_REQUIRED AND KF5_FIND_REQUIRED_${_module})
        # If the component was required, we tell FeatureSummary so that it
        # will be displayed in the correct list. We do not use the REQUIRED
        # argument of find_package() to allow all the missing frameworks
        # to be listed at once (fphsa will error out at the end of this file
        # anyway).
        set_package_properties(KF5${_module} PROPERTIES TYPE REQUIRED)
    endif()

    # Component-based find modules are expected to set
    # <module>_<component>_FOUND and <module>_<component>_VERSION variables,
    # but the find_package calls above will have set KF5<component>_*
    # variables.
    set(KF5_${_module}_FOUND ${KF5${_module}_FOUND})
    if(KF5${_module}_FOUND)
        set(KF5_${_module}_VERSION ${KF5${_module}_VERSION})

        # make KF5_VERSION the minimum found version
        if(NOT KF5_VERSION OR KF5_VERSION VERSION_GREATER KF5${_module}_VERSION)
            set(KF5_VERSION ${KF5${_module}_VERSION})
        endif()
    endif()
endforeach()

# Annoyingly, find_package_handle_standard_args requires you to provide
# REQUIRED_VARS even when using HANDLE_COMPONENTS, but all we actually
# care about is whether the required components were found. So we provide
# a dummy variable that is just set to something that will be printed
# on success.
set(_dummy_req_var "success")

find_package_handle_standard_args(KF5
    FOUND_VAR
        KF5_FOUND
    REQUIRED_VARS
        _dummy_req_var
    VERSION_VAR
        KF5_VERSION
    HANDLE_COMPONENTS
)

# SPDX-FileCopyrightText: 2014 Alex Merry <alex.merry@kde.org>
# SPDX-FileCopyrightText: 2013 Stephen Kelly <steveire@gmail.com>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
FindKF6
-------

Find KDE Frameworks 6 with a single find_package() call.

This will use the package config files provided by the individual frameworks.
For example, if you wish to find KArchive, which presents itself to CMake as
KF6Archive (ie: you would do ``find_package(KF6Archive)`` to find it
directly), you can do

.. code-block:: cmake

  find_package(KF6 COMPONENTS Archive)

If all the required components (those given in the COMPONENTS argument, but
not those given in the OPTIONAL_COMPONENTS argument) are found, ``KF6_FOUND``
will be set to true. Otherwise, it will be set to false.

Since 6.0.0.
#]=======================================================================]

include(${CMAKE_CURRENT_LIST_DIR}/ECMFindModuleHelpersStub.cmake)

ecm_find_package_version_check(KF6)

if (NOT KF6_FIND_COMPONENTS)
    set(KF6_NOT_FOUND_MESSAGE "The KF6 package requires at least one component")
    set(KF6_FOUND False)
    return()
endif()

set(_quiet_arg)
if (KF6_FIND_QUIETLY)
    set(_quiet_arg QUIET)
endif()
set(_exact_arg)
if (KF6_FIND_EXACT)
    set(_exact_arg EXACT)
endif()

include(FindPackageHandleStandardArgs)
include(FeatureSummary)

set(KF6_VERSION)
set(KF6_MISSING_REQUIRED_COMPONENTS)
foreach(_module ${KF6_FIND_COMPONENTS})
    find_package(KF6${_module} ${KF6_FIND_VERSION}
        ${_exact_arg} ${_quiet_arg}
        CONFIG
    )
    # CMake >= 3.17 wants to be explicitly told we are fine with name mismatch here
    set(_name_mismatched_arg)
    if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.17)
       set(_name_mismatched_arg NAME_MISMATCHED)
    endif()
    find_package_handle_standard_args(KF6${_module} CONFIG_MODE ${_name_mismatched_arg})
    if (KF6_FIND_REQUIRED AND KF6_FIND_REQUIRED_${_module})
        # If the component was required, we tell FeatureSummary so that it
        # will be displayed in the correct list. We do not use the REQUIRED
        # argument of find_package() to allow all the missing frameworks
        # to be listed at once (fphsa will error out at the end of this file
        # anyway).
        set_package_properties(KF6${_module} PROPERTIES TYPE REQUIRED)
    endif()

    # Component-based find modules are expected to set
    # <module>_<component>_FOUND and <module>_<component>_VERSION variables,
    # but the find_package calls above will have set KF6<component>_*
    # variables.
    set(KF6_${_module}_FOUND ${KF6${_module}_FOUND})
    if(KF6${_module}_FOUND)
        set(KF6_${_module}_VERSION ${KF6${_module}_VERSION})

        # make KF6_VERSION the minimum found version
        if(NOT KF6_VERSION OR KF6_VERSION VERSION_GREATER KF6${_module}_VERSION)
            set(KF6_VERSION ${KF6${_module}_VERSION})
        endif()
    elseif(KF6_FIND_REQUIRED_${_module})
        list(APPEND KF6_MISSING_REQUIRED_COMPONENTS ${_module})
    endif()
endforeach()

# Annoyingly, find_package_handle_standard_args requires you to provide
# REQUIRED_VARS even when using HANDLE_COMPONENTS, but all we actually
# care about is whether the required components were found. So we provide
# a dummy variable that is just set to something that will be printed
# on success.
set(_dummy_req_var "success")

list(JOIN KF6_MISSING_REQUIRED_COMPONENTS " " MISSING_COMPONENTS_STRING)

find_package_handle_standard_args(KF6
    FOUND_VAR
        KF6_FOUND
    REQUIRED_VARS
        _dummy_req_var
    VERSION_VAR
        KF6_VERSION
    HANDLE_COMPONENTS
    REASON_FAILURE_MESSAGE "Missing the following required components: ${MISSING_COMPONENTS_STRING}"
)

unset(MISSING_COMPONENTS_STRING)
unset(KF6_MISSING_REQUIRED_COMPONENTS)
# SPDX-FileCopyrightText: 2018 Christophe Giboudeaux <christophe@krop.fr>
# SPDX-FileCopyrightText: 2010 Alexander Neundorf <neundorf@kde.org>
# SPDX-FileCopyrightText: 2008 Gilles Caulier <caulier.gilles@gmail.com>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
FindLibExiv2
------------

Try to find the Exiv2 library.

This will define the following variables:

``LibExiv2_FOUND``
    True if (the requested version of) Exiv2 is available

``LibExiv2_VERSION``
    The version of Exiv2

``LibExiv2_INCLUDE_DIRS``
    The include dirs of Exiv2 for use with target_include_directories()

``LibExiv2_LIBRARIES``
    The Exiv2 library for use with target_link_libraries().
    This can be passed to target_link_libraries() instead of
    the ``LibExiv2::LibExiv2`` target

If ``LibExiv2_FOUND`` is TRUE, it will also define the following imported
target:

``LibExiv2::LibExiv2``
    The Exiv2 library

In general we recommend using the imported target, as it is easier to use.
Bear in mind, however, that if the target is in the link interface of an
exported library, it must be made available by the package config file.

Since 5.53.0.
#]=======================================================================]

find_package(PkgConfig QUIET)
pkg_check_modules(PC_EXIV2 QUIET exiv2)

find_path(LibExiv2_INCLUDE_DIRS NAMES exiv2/exif.hpp
    HINTS ${PC_EXIV2_INCLUDEDIR}
)

find_library(LibExiv2_LIBRARIES NAMES exiv2 libexiv2
    HINTS ${PC_EXIV2_LIBRARY_DIRS}
)

set(LibExiv2_VERSION ${PC_EXIV2_VERSION})

if(NOT LibExiv2_VERSION AND DEFINED LibExiv2_INCLUDE_DIRS)
    # With exiv >= 0.27, the version #defines are in exv_conf.h instead of version.hpp
    foreach(_exiv2_version_file "version.hpp" "exv_conf.h")
        if(EXISTS "${LibExiv2_INCLUDE_DIRS}/exiv2/${_exiv2_version_file}")
            file(READ "${LibExiv2_INCLUDE_DIRS}/exiv2/${_exiv2_version_file}" _exiv_version_file_content)
            string(REGEX MATCH "#define EXIV2_MAJOR_VERSION[ ]+\\([0-9]+U?\\)" EXIV2_MAJOR_VERSION_MATCH ${_exiv_version_file_content})
            string(REGEX MATCH "#define EXIV2_MINOR_VERSION[ ]+\\([0-9]+U?\\)" EXIV2_MINOR_VERSION_MATCH ${_exiv_version_file_content})
            string(REGEX MATCH "#define EXIV2_PATCH_VERSION[ ]+\\([0-9]+U?\\)" EXIV2_PATCH_VERSION_MATCH ${_exiv_version_file_content})
            if(EXIV2_MAJOR_VERSION_MATCH)
                string(REGEX REPLACE ".*_MAJOR_VERSION[ ]+\\(([0-9]*)U?\\)" "\\1" EXIV2_MAJOR_VERSION ${EXIV2_MAJOR_VERSION_MATCH})
                string(REGEX REPLACE ".*_MINOR_VERSION[ ]+\\(([0-9]*)U?\\)" "\\1" EXIV2_MINOR_VERSION ${EXIV2_MINOR_VERSION_MATCH})
                string(REGEX REPLACE ".*_PATCH_VERSION[ ]+\\(([0-9]*)U?\\)" "\\1"  EXIV2_PATCH_VERSION  ${EXIV2_PATCH_VERSION_MATCH})
            endif()
        endif()
    endforeach()

    set(LibExiv2_VERSION "${EXIV2_MAJOR_VERSION}.${EXIV2_MINOR_VERSION}.${EXIV2_PATCH_VERSION}")
endif()

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(LibExiv2
    FOUND_VAR LibExiv2_FOUND
    REQUIRED_VARS  LibExiv2_LIBRARIES LibExiv2_INCLUDE_DIRS
    VERSION_VAR  LibExiv2_VERSION
)

mark_as_advanced(LibExiv2_INCLUDE_DIRS LibExiv2_LIBRARIES)

if(LibExiv2_FOUND AND NOT TARGET LibExiv2::LibExiv2)
    add_library(LibExiv2::LibExiv2 UNKNOWN IMPORTED)
    set_target_properties(LibExiv2::LibExiv2 PROPERTIES
        IMPORTED_LOCATION "${LibExiv2_LIBRARIES}"
        INTERFACE_INCLUDE_DIRECTORIES "${LibExiv2_INCLUDE_DIRS}"
    )
    if (LibExiv2_VERSION VERSION_LESS 0.28.0)
        # exiv2 0.27 or older still uses std::auto_ptr, which is no longer available
        # by default when using newer C++ versions
        set_target_properties(LibExiv2::LibExiv2 PROPERTIES
            INTERFACE_COMPILE_DEFINITIONS "_LIBCPP_ENABLE_CXX17_REMOVED_AUTO_PTR=1;_HAS_AUTO_PTR_ETC=1"
        )
    endif()
endif()

include(FeatureSummary)
set_package_properties(LibExiv2 PROPERTIES
    URL "https://www.exiv2.org"
    DESCRIPTION "Image metadata support"
)
# SPDX-FileCopyrightText: 2014 Alex Merry <alex.merry@kde.org>
# SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
# SPDX-FileCopyrightText: 2014 Christoph Cullmann <cullmann@kde.org>
# SPDX-FileCopyrightText: 2023 Louis Moureaux <m_louis30@yahoo.com>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
FindLibGit2
-----------

Try to find libgit2 on a Unix system.

This will define the following variables:

``LIBGIT2_FOUND``
    True if (the requested version of) libgit2 is available
``LIBGIT2_VERSION``
    The version of libgit2
``LIBGIT2_LIBRARIES``
    This can be passed to target_link_libraries() instead of the ``LibGit2::LibGit2``
    target
``LIBGIT2_INCLUDE_DIRS``
    This should be passed to target_include_directories() if the target is not
    used for linking
``LIBGIT2_DEFINITIONS``
    This should be passed to target_compile_options() if the target is not
    used for linking

If ``LIBGIT2_FOUND`` is TRUE, it will also define the following imported target:

``LibGit2::LibGit2``
    The libgit2 library

In general we recommend using the imported target, as it is easier to use.
Bear in mind, however, that if the target is in the link interface of an
exported library, it must be made available by the package config file.

Since 1.3.0.
#]=======================================================================]

include(${CMAKE_CURRENT_LIST_DIR}/ECMFindModuleHelpersStub.cmake)

ecm_find_package_version_check(LibGit2)

# Use pkg-config to get the directories and then use these values
# in the FIND_PATH() and FIND_LIBRARY() calls
find_package(PkgConfig QUIET)
pkg_check_modules(PKG_GIT2 QUIET libgit2)

set(LIBGIT2_DEFINITIONS ${PKG_GIT2_CFLAGS_OTHER})

find_path(LIBGIT2_INCLUDE_DIR
    NAMES
        git2.h
    HINTS
        ${PKG_GIT2_INCLUDE_DIRS}
)
find_library(LIBGIT2_LIBRARY
    NAMES
        git2
    HINTS
        ${PKG_GIT2_LIBRARY_DIRS}
)

# get version from header, should work on windows, too
if(LIBGIT2_INCLUDE_DIR)
    file(STRINGS "${LIBGIT2_INCLUDE_DIR}/git2/version.h" LIBGIT2_H REGEX "^#define LIBGIT2_VERSION +\"[^\"]*\"$")

    string(REGEX REPLACE "^.*LIBGIT2_VERSION +\"([0-9]+).*$" "\\1" LIBGIT2_VERSION_MAJOR "${LIBGIT2_H}")
    string(REGEX REPLACE "^.*LIBGIT2_VERSION +\"[0-9]+\\.([0-9]+).*$" "\\1" LIBGIT2_VERSION_MINOR  "${LIBGIT2_H}")
    string(REGEX REPLACE "^.*LIBGIT2_VERSION +\"[0-9]+\\.[0-9]+\\.([0-9]+).*$" "\\1" LIBGIT2_VERSION_PATCH "${LIBGIT2_H}")
    set(LIBGIT2_VERSION "${LIBGIT2_VERSION_MAJOR}.${LIBGIT2_VERSION_MINOR}.${LIBGIT2_VERSION_PATCH}")

    set(LIBGIT2_MAJOR_VERSION "${LIBGIT2_VERSION_MAJOR}")
    set(LIBGIT2_MINOR_VERSION "${LIBGIT2_VERSION_MINOR}")
    set(LIBGIT2_PATCH_VERSION "${LIBGIT2_VERSION_PATCH}")

    unset(LIBGIT2_H)
endif()

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(LibGit2
    FOUND_VAR
        LIBGIT2_FOUND
    REQUIRED_VARS
        LIBGIT2_LIBRARY
        LIBGIT2_INCLUDE_DIR
    VERSION_VAR
        LIBGIT2_VERSION
)

if(LIBGIT2_FOUND AND NOT TARGET LibGit2::LibGit2)
    add_library(LibGit2::LibGit2 UNKNOWN IMPORTED)
    set_target_properties(LibGit2::LibGit2 PROPERTIES
        IMPORTED_LOCATION "${LIBGIT2_LIBRARY}"
        INTERFACE_COMPILE_OPTIONS "${LIBGIT2_DEFINITIONS}"
        INTERFACE_INCLUDE_DIRECTORIES "${LIBGIT2_INCLUDE_DIR}"
    )
endif()

mark_as_advanced(LIBGIT2_LIBRARY LIBGIT2_INCLUDE_DIR)

set(LIBGIT2_LIBRARIES ${LIBGIT2_LIBRARY})
set(LIBGIT2_INCLUDE_DIRS ${LIBGIT2_INCLUDE_DIR})

include(FeatureSummary)
set_package_properties(LibGit2 PROPERTIES
    URL "https://libgit2.github.com/"
    DESCRIPTION "A plain C library to interface with the git version control system."
)
# SPDX-FileCopyrightText: 2021 Ahmad Samir <a.samirh78@gmail.com>
#
# SPDX-License-Identifier: BSD-3-Clause

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

FindLibMount
------------

Try to find the libmount library (part of util-linux), once done this will define:

``LibMount_FOUND``
    LibMount was found on the system.

``LibMount_INCLUDE_DIRS``
    The libmount include directory.

``LibMount_LIBRARIES``
    The libmount libraries.

``LibMount_VERSION``
    The libmount version.

If ``LibMount_FOUND`` is TRUE, it will also define the following imported target:

``LibMount::LibMount``
    The libmount library

Since 5.83.0
#]=======================================================================]

find_package(PkgConfig QUIET)
pkg_check_modules(PC_LIBMOUNT QUIET IMPORTED_TARGET mount)

find_path(LibMount_INCLUDE_DIRS NAMES libmount.h PATH_SUFFIXES libmount HINTS ${PC_LIBMOUNT_INCLUDE_DIRS})
find_library(LibMount_LIBRARIES NAMES mount HINTS ${PC_LIBMOUNT_LIBRARY_DIRS})

set(LibMount_VERSION ${PC_LIBMOUNT_VERSION})

if(LibMount_INCLUDE_DIRS AND NOT LibMount_VERSION)
    file(READ "${LibMount_INCLUDE_DIRS}/libmount.h" _LibMount_header_contents)
    string(REGEX MATCHALL "#define[ \t]+LIBMOUNT_VERSION[ \t]+\"*[0-9.]+" _LibMount_version_line "${_LibMount_header_contents}")
    unset(_LibMount_header_contents)
    string(REGEX REPLACE ".*LIBMOUNT_VERSION[ \t]+\"*([0-9.]+)\"*" "\\1" _version "${_LibMount_version_line}")
    set(LibMount_VERSION "${_version}")
    unset(_LibMount_version_line)
endif()

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(LibMount
    FOUND_VAR LibMount_FOUND
    REQUIRED_VARS LibMount_INCLUDE_DIRS LibMount_LIBRARIES
    VERSION_VAR LibMount_VERSION
)

mark_as_advanced(LibMount_INCLUDE_DIRS LibMount_LIBRARIES)

if(LibMount_FOUND AND NOT TARGET LibMount::LibMount)
    add_library(LibMount::LibMount UNKNOWN IMPORTED)
    set_target_properties(LibMount::LibMount PROPERTIES
        IMPORTED_LOCATION "${LibMount_LIBRARIES}"
        INTERFACE_INCLUDE_DIRECTORIES "${LibMount_INCLUDE_DIRS}"
        INTERFACE_COMPILE_DEFINITIONS "${PC_LIBMOUNT_CFLAGS_OTHER}"
    )
    if (TARGET PkgConfig::PC_LIBMOUNT)
        target_link_libraries(LibMount::LibMount INTERFACE PkgConfig::PC_LIBMOUNT)
    endif()
endif()

include(FeatureSummary)
set_package_properties(LibMount PROPERTIES
    DESCRIPTION "API for getting info about mounted filesystems (part of util-linux)"
    URL "https://www.kernel.org/pub/linux/utils/util-linux/"
)
# SPDX-FileCopyrightText: 2014 Hrvoje Senjan <hrvoje.senjan@gmail.com>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
FindLibcap
----------
Try to find the setcap binary and cap libraries

This will define:

``Libcap_FOUND``
    system has the cap library and setcap binary
``Libcap_LIBRARIES``
    cap libraries to link against
``SETCAP_EXECUTABLE``
    path of the setcap binary

In addition, the following targets are defined:
  ``Libcap::SetCapabilities``

Since 5.80.0
#]=======================================================================]

find_program(SETCAP_EXECUTABLE NAMES setcap DOC "The setcap executable")

find_library(Libcap_LIBRARIES NAMES cap DOC "The cap (capabilities) library")

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Libcap FOUND_VAR Libcap_FOUND
                                      REQUIRED_VARS SETCAP_EXECUTABLE Libcap_LIBRARIES)

if(Libcap_FOUND AND NOT TARGET Libcap::SetCapabilities)
    add_executable(Libcap::SetCapabilities IMPORTED)
    set_target_properties(Libcap::SetCapabilities PROPERTIES
        IMPORTED_LOCATION "${SETCAP_EXECUTABLE}"
    )
endif()

mark_as_advanced(SETCAP_EXECUTABLE Libcap_LIBRARIES)

include(FeatureSummary)
set_package_properties(Libcap PROPERTIES
    URL https://sites.google.com/site/fullycapable/
    DESCRIPTION "Capabilities are a measure to limit the omnipotence of the superuser.")
# SPDX-FileCopyrightText: 2013-2014 Alex Merry <alex.merry@kdemail.net>
# SPDX-FileCopyrightText: 2006 Alexander Neundorf <neundorf@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
FindOpenEXR
-----------

Try to find the OpenEXR libraries.

This will define the following variables:

``OpenEXR_FOUND``
    True if OpenEXR is available
``OpenEXR_LIBRARIES``
    Link to these to use OpenEXR
``OpenEXR_INCLUDE_DIRS``
    Include directory for OpenEXR
``OpenEXR_DEFINITIONS``
    Compiler flags required to link against OpenEXR

and the following imported targets:

``OpenEXR::IlmImf``
    The OpenEXR core library

In general we recommend using the imported target, as it is easier to use.
Bear in mind, however, that if the target is in the link interface of an
exported library, it must be made available by the package config file.

Since pre-1.0.0.
#]=======================================================================]

include(${CMAKE_CURRENT_LIST_DIR}/ECMFindModuleHelpersStub.cmake)

ecm_find_package_version_check(OpenEXR)

# use pkg-config to get the directories and then use these values
# in the FIND_PATH() and FIND_LIBRARY() calls
find_package(PkgConfig QUIET)
pkg_check_modules(PC_OpenEXR QUIET OpenEXR)

set(OpenEXR_DEFINITIONS ${PC_OpenEXR_CFLAGS_OTHER})

find_path(OpenEXR_INCLUDE_DIR ImfRgbaFile.h
   PATHS
   ${PC_OpenEXR_INCLUDEDIR}
   ${PC_OpenEXR_INCLUDE_DIRS}
   PATH_SUFFIXES OpenEXR
)

# Required libraries for OpenEXR
find_library(OpenEXR_HALF_LIBRARY NAMES Half
   PATHS
   ${PC_OpenEXR_LIBDIR}
   ${PC_OpenEXR_LIBRARY_DIRS}
)
find_library(OpenEXR_IEX_LIBRARY NAMES Iex
   PATHS
   ${PC_OpenEXR_LIBDIR}
   ${PC_OpenEXR_LIBRARY_DIRS}
)
find_library(OpenEXR_IMATH_LIBRARY NAMES Imath
   PATHS
   ${PC_OpenEXR_LIBDIR}
   ${PC_OpenEXR_LIBRARY_DIRS}
)
find_library(OpenEXR_ILMTHREAD_LIBRARY NAMES IlmThread
   PATHS
   ${PC_OpenEXR_LIBDIR}
   ${PC_OpenEXR_LIBRARY_DIRS}
)
# This is the actual OpenEXR library
find_library(OpenEXR_ILMIMF_LIBRARY NAMES IlmImf
   PATHS
   ${PC_OpenEXR_LIBDIR}
   ${PC_OpenEXR_LIBRARY_DIRS}
)

set(_OpenEXR_deps
   ${OpenEXR_HALF_LIBRARY}
   ${OpenEXR_IEX_LIBRARY}
   ${OpenEXR_IMATH_LIBRARY}
   ${OpenEXR_ILMTHREAD_LIBRARY})

set(OpenEXR_LIBRARIES
   ${_OpenEXR_deps}
   ${OpenEXR_ILMIMF_LIBRARY})

if (OpenEXR_INCLUDE_DIR AND EXISTS "${OpenEXR_INCLUDE_DIR}/OpenEXRConfig.h")
    file(STRINGS "${OpenEXR_INCLUDE_DIR}/OpenEXRConfig.h" openexr_version_str
         REGEX "^#define[\t ]+OPENEXR_VERSION_STRING[\t ]+\"[^\"]*\"")
    string(REGEX REPLACE "^#define[\t ]+OPENEXR_VERSION_STRING[\t ]+\"([^\"]*).*"
           "\\1" OpenEXR_VERSION_STRING "${openexr_version_str}")
    unset(openexr_version_str)
endif ()

include(FindPackageHandleStandardArgs)
# find_package_handle_standard_args reports the value of the first variable
# on success, so make sure this is the actual OpenEXR library
find_package_handle_standard_args(OpenEXR
   FOUND_VAR OpenEXR_FOUND
   REQUIRED_VARS
      OpenEXR_ILMIMF_LIBRARY
      OpenEXR_HALF_LIBRARY
      OpenEXR_IEX_LIBRARY
      OpenEXR_IMATH_LIBRARY
      OpenEXR_ILMTHREAD_LIBRARY
      OpenEXR_INCLUDE_DIR
   VERSION_VAR OpenEXR_VERSION_STRING)

set(OpenEXR_INCLUDE_DIRS ${OpenEXR_INCLUDE_DIR})

include(FeatureSummary)
set_package_properties(OpenEXR PROPERTIES
   URL https://www.openexr.com/
   DESCRIPTION "A library for handling OpenEXR high dynamic-range image files")

mark_as_advanced(
   OpenEXR_INCLUDE_DIR
   OpenEXR_LIBRARIES
   OpenEXR_DEFINITIONS
   OpenEXR_ILMIMF_LIBRARY
   OpenEXR_ILMTHREAD_LIBRARY
   OpenEXR_IMATH_LIBRARY
   OpenEXR_IEX_LIBRARY
   OpenEXR_HALF_LIBRARY
)

if(OpenEXR_FOUND AND NOT TARGET OpenEXR::IlmImf)
    add_library(OpenEXR::IlmImf UNKNOWN IMPORTED)
    set_target_properties(OpenEXR::IlmImf PROPERTIES
        IMPORTED_LOCATION "${OpenEXR_ILMIMF_LIBRARY}"
        INTERFACE_COMPILE_OPTIONS "${OpenEXR_DEFINITIONS}"
        INTERFACE_INCLUDE_DIRECTORIES "${OpenEXR_INCLUDE_DIR}"
        INTERFACE_LINK_LIBRARIES "${_OpenEXR_deps}"
    )
endif()
# SPDX-FileCopyrightText: 2017 Klaralvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
# SPDX-FileCopyrightText: 2018 Volker Krause <vkrause@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
FindPhoneNumber
---------------

Try to find PhoneNumber.

This is a component-based find module, which makes use of the COMPONENTS and
OPTIONAL_COMPONENTS arguments to find_module.  The following components are
available::

  PhoneNumber  GeoCoding

If no components are specified, this module will act as though all components
were passed to OPTIONAL_COMPONENTS.

This module will define the following variables, independently of the
components searched for or found:

``PhoneNumber_FOUND``
    True if (the requestion version of) PhoneNumber is available

For each searched-for components, ``PhoneNumber_<component>_FOUND`` will be set to
TRUE if the corresponding library was found, and FALSE otherwise.  If
``PhoneNumber_<component>_FOUND`` is TRUE, the imported target ``PhoneNumber::<component>``
will be defined.

Since 5.54.0.
#]=======================================================================]

include(ECMFindModuleHelpersStub)

ecm_find_package_version_check(PhoneNumber)

set(PhoneNumber_known_components
    PhoneNumber
    GeoCoding
)
set(PhoneNumber_default_components ${PhoneNumber_known_components})

set(PhoneNumber_PhoneNumber_lib phonenumber)
set(PhoneNumber_PhoneNumber_header phonenumbers/phonenumberutil.h)
set(PhoneNumber_GeoCoding_lib geocoding)
set(PhoneNumber_GeoCoding_header phonenumbers/geocoding/phonenumber_offline_geocoder.h)

ecm_find_package_parse_components(PhoneNumber
    RESULT_VAR PhoneNumber_components
    KNOWN_COMPONENTS ${PhoneNumber_known_components}
    DEFAULT_COMPONENTS ${PhoneNumber_default_components}
)
ecm_find_package_handle_library_components(PhoneNumber
    COMPONENTS ${PhoneNumber_components}
)
find_package_handle_standard_args(PhoneNumber
    FOUND_VAR
        PhoneNumber_FOUND
    REQUIRED_VARS
        PhoneNumber_LIBRARIES
    VERSION_VAR
        PhoneNumber_VERSION
    HANDLE_COMPONENTS
)
set(PhoneNumber_VERSION 0) # there is no observable version number in the installed files

include(FeatureSummary)
set_package_properties(PhoneNumber PROPERTIES
  URL "https://github.com/googlei18n/libphonenumber"
  DESCRIPTION "Library for parsing, formatting, and validating international phone numbers")
# SPDX-FileCopyrightText: 2015 Alex Richardson <arichardson.kde@gmail.com>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
FindPoppler
-----------

Try to find Poppler.

This is a component-based find module, which makes use of the COMPONENTS
and OPTIONAL_COMPONENTS arguments to find_module.  The following components
are available::

  Core  Cpp  Qt5  Qt4  Glib

If no components are specified, this module will act as though all components
were passed to OPTIONAL_COMPONENTS.

This module will define the following variables, independently of the
components searched for or found:

``Poppler_FOUND``
    TRUE if (the requested version of) Poppler is available
``Poppler_VERSION``
    Found Poppler version
``Poppler_TARGETS``
    A list of all targets imported by this module (note that there may be more
    than the components that were requested)
``Poppler_LIBRARIES``
    This can be passed to target_link_libraries() instead of the imported
    targets
``Poppler_INCLUDE_DIRS``
    This should be passed to target_include_directories() if the targets are
    not used for linking
``Poppler_DEFINITIONS``
    This should be passed to target_compile_options() if the targets are not
    used for linking

For each searched-for components, ``Poppler_<component>_FOUND`` will be set to
TRUE if the corresponding Poppler library was found, and FALSE otherwise.  If
``Poppler_<component>_FOUND`` is TRUE, the imported target
``Poppler::<component>`` will be defined.  This module will also attempt to
determine ``Poppler_*_VERSION`` variables for each imported target, although
``Poppler_VERSION`` should normally be sufficient.

In general we recommend using the imported targets, as they are easier to use
and provide more control.  Bear in mind, however, that if any target is in the
link interface of an exported library, it must be made available by the
package config file.

Since 5.19
#]=======================================================================]

include(${CMAKE_CURRENT_LIST_DIR}/ECMFindModuleHelpersStub.cmake)

ecm_find_package_version_check(Poppler)

set(Poppler_known_components
    Cpp
    Qt4
    Qt5
    Qt6
    Glib
)
foreach(_comp ${Poppler_known_components})
    string(TOLOWER "${_comp}" _lc_comp)
    set(Poppler_${_comp}_component_deps "Core")
    set(Poppler_${_comp}_pkg_config "poppler-${_lc_comp}")
    set(Poppler_${_comp}_lib "poppler-${_lc_comp}")
    set(Poppler_${_comp}_header_subdir "poppler/${_lc_comp}")
endforeach()
set(Poppler_known_components Core ${Poppler_known_components})

set(Poppler_Core_component_deps "")
set(Poppler_Core_pkg_config "poppler")
# poppler-config.h header is only installed with --enable-xpdf-headers
# fall back to using any header from a submodule with a path to make it work in that case too
set(Poppler_Core_header "poppler-config.h" "cpp/poppler-version.h" "qt6/poppler-qt6.h" "qt5/poppler-qt5.h" "qt4/poppler-qt4.h" "glib/poppler.h")
set(Poppler_Core_header_subdir "poppler")
set(Poppler_Core_lib "poppler")

set(Poppler_Cpp_header "poppler-version.h")
set(Poppler_Qt6_header "poppler-qt6.h")
set(Poppler_Qt5_header "poppler-qt5.h")
set(Poppler_Qt4_header "poppler-qt4.h")
set(Poppler_Glib_header "poppler.h")

ecm_find_package_parse_components(Poppler
    RESULT_VAR Poppler_components
    KNOWN_COMPONENTS ${Poppler_known_components}
)
ecm_find_package_handle_library_components(Poppler
    COMPONENTS ${Poppler_components}
)

# If pkg-config didn't provide us with version information,
# try to extract it from poppler-version.h or poppler-config.h
if(NOT Poppler_VERSION)
    find_file(Poppler_VERSION_HEADER
        NAMES "poppler-config.h" "cpp/poppler-version.h"
        HINTS ${Poppler_INCLUDE_DIRS}
        PATH_SUFFIXES ${Poppler_Core_header_subdir}
    )
    mark_as_advanced(Poppler_VERSION_HEADER)
    if(Poppler_VERSION_HEADER)
        file(READ ${Poppler_VERSION_HEADER} _poppler_version_header_contents)
        string(REGEX REPLACE
            "^.*[ \t]+POPPLER_VERSION[ \t]+\"([0-9d.]*)\".*$"
            "\\1"
            Poppler_VERSION
            "${_poppler_version_header_contents}"
        )
        unset(_poppler_version_header_contents)
    endif()
endif()

find_package_handle_standard_args(Poppler
    FOUND_VAR
        Poppler_FOUND
    REQUIRED_VARS
        Poppler_LIBRARIES
    VERSION_VAR
        Poppler_VERSION
    HANDLE_COMPONENTS
)

include(FeatureSummary)
set_package_properties(Poppler PROPERTIES
    DESCRIPTION "A PDF rendering library"
    URL "https://poppler.freedesktop.org/"
)
# SPDX-FileCopyrightText: 2008 Matthias Kretz <kretz@kde.org>
# SPDX-FileCopyrightText: 2009 Marcus Hufgard <Marcus.Hufgard@hufgard.de>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
FindPulseAudio
--------------

Try to locate the PulseAudio library.
If found, this will define the following variables:

``PulseAudio_FOUND``
     True if the system has the PulseAudio library of at least
     the minimum version specified by either the version parameter
     to find_package() or the variable PulseAudio_MINIMUM_VERSION
``PulseAudio_INCLUDE_DIRS``
     The PulseAudio include directory
``PulseAudio_LIBRARIES``
     The PulseAudio libraries for linking
``PulseAudio_MAINLOOP_LIBRARY``
     The libraries needed to use PulseAudio Mainloop
``PulseAudio_VERSION``
     The version of PulseAudio that was found
``PulseAudio_INCLUDE_DIR``
    Deprecated, use ``PulseAudio_INCLUDE_DIRS``
``PulseAudio_LIBRARY``
    Deprecated, use ``PulseAudio_LIBRARIES``

If ``PulseAudio_FOUND`` is TRUE, it will also define the following
imported target:

``PulseAudio::PulseAudio``
    The PulseAudio library

Since 5.41.0.
#]=======================================================================]

# Support PulseAudio_MINIMUM_VERSION for compatibility:
if(NOT PulseAudio_FIND_VERSION)
  set(PulseAudio_FIND_VERSION "${PulseAudio_MINIMUM_VERSION}")
endif()

# the minimum version of PulseAudio we require
if(NOT PulseAudio_FIND_VERSION)
  set(PulseAudio_FIND_VERSION "0.9.9")
endif()

find_package(PkgConfig QUIET)
pkg_check_modules(PC_PulseAudio QUIET libpulse>=${PulseAudio_FIND_VERSION})
pkg_check_modules(PC_PulseAudio_MAINLOOP QUIET libpulse-mainloop-glib)

find_path(PulseAudio_INCLUDE_DIRS pulse/pulseaudio.h
   HINTS
   ${PC_PulseAudio_INCLUDEDIR}
   ${PC_PulseAudio_INCLUDE_DIRS}
   )

find_library(PulseAudio_LIBRARIES NAMES pulse libpulse
   HINTS
   ${PC_PulseAudio_LIBDIR}
   ${PC_PulseAudio_LIBRARY_DIRS}
   )

find_library(PulseAudio_MAINLOOP_LIBRARY NAMES pulse-mainloop pulse-mainloop-glib libpulse-mainloop-glib
   HINTS
   ${PC_PulseAudio_LIBDIR}
   ${PC_PulseAudio_LIBRARY_DIRS}
   )

# Store the version number in the cache, so we don't have to search every time again:
if (PulseAudio_INCLUDE_DIRS AND NOT PulseAudio_VERSION)

   # get PulseAudio's version from its version.h
   file(STRINGS "${PulseAudio_INCLUDE_DIRS}/pulse/version.h" pulse_version_h
        REGEX ".*pa_get_headers_version\\(\\).*")
   string(REGEX REPLACE ".*pa_get_headers_version\\(\\)\ \\(\"([0-9]+\\.[0-9]+\\.[0-9]+)[^\"]*\"\\).*" "\\1"
                         _PulseAudio_VERSION "${pulse_version_h}")

   set(PulseAudio_VERSION "${_PulseAudio_VERSION}" CACHE STRING "Version number of PulseAudio" FORCE)
endif()

# Use the new extended syntax of find_package_handle_standard_args(), which also handles version checking:
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(PulseAudio REQUIRED_VARS PulseAudio_LIBRARIES PulseAudio_INCLUDE_DIRS
                                             VERSION_VAR PulseAudio_VERSION)

# Deprecated synonyms
set(PULSEAUDIO_INCLUDE_DIR "${PulseAudio_INCLUDE_DIRS}")
set(PULSEAUDIO_LIBRARY "${PulseAudio_LIBRARIES}")
set(PULSEAUDIO_MAINLOOP_LIBRARY "${PulseAudio_MAINLOOP_LIBRARY}")
set(PULSEAUDIO_FOUND "${PulseAudio_FOUND}")

if(PulseAudio_FOUND AND NOT TARGET PulseAudio::PulseAudio)
  add_library(PulseAudio::PulseAudio UNKNOWN IMPORTED)
  set_target_properties(PulseAudio::PulseAudio PROPERTIES
                        IMPORTED_LOCATION "${PulseAudio_LIBRARIES}"
			INTERFACE_INCLUDE_DIRECTORIES "${PulseAudio_INCLUDE_DIRS}")
endif()

mark_as_advanced(PulseAudio_INCLUDE_DIRS PULSEAUDIO_INCLUDE_DIR
                 PulseAudio_LIBRARIES PULSEAUDIO_LIBRARY
		 PulseAudio_MAINLOOP_LIBRARY PULSEAUDIO_MAINLOOP_LIBRARY)

include(FeatureSummary)
set_package_properties(PulseAudio PROPERTIES
  URL "https://www.freedesktop.org/wiki/Software/PulseAudio"
  DESCRIPTION "Sound server, for sound stream routing and mixing")
# SPDX-FileCopyrightText: 2016 Friedrich W. H. Kossebau <kossebau@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
WARNING: FOR ECM-INTERNAL USE ONLY, DO NOT USE IN OWN PROJECTS
THIS FILE MIGHT DISAPPEAR IN FUTURE VERSIONS OF ECM.

Finds the Qt5 QHelpGenerator

 QHelpGenerator_FOUND     - True if QHelpGenerator found.
 QHelpGenerator_EXECUTABLE - Path to executable
#]=======================================================================]

include(${CMAKE_CURRENT_LIST_DIR}/../modules/QtVersionOption.cmake)
find_package(Qt${QT_MAJOR_VERSION}Help QUIET)
if (TARGET Qt5::qhelpgenerator)
    get_target_property(QHelpGenerator_EXECUTABLE Qt5::qhelpgenerator LOCATION)
else()
    # assume same folder as qmake executable
    if (TARGET Qt5::qmake)
        get_target_property(_qmake_EXECUTABLE Qt5::qmake LOCATION)
        get_filename_component(_path ${_qmake_EXECUTABLE} DIRECTORY)
    else()
        set(_path)
    endif()
    find_program(QHelpGenerator_EXECUTABLE
        NAMES
            qhelpgenerator-qt5
            qhelpgenerator
        PATHS
            ${_path}
        NO_DEFAULT_PATH
    )
endif()
mark_as_advanced(QHelpGenerator_EXECUTABLE)

if(QHelpGenerator_EXECUTABLE)
    set(QHelpGenerator_FOUND TRUE)
else()
    set(QHelpGenerator_FOUND FALSE)
endif()

if(QHelpGenerator_FOUND)
  if(NOT QHelpGenerator_FIND_QUIETLY )
    message( STATUS "Found QHelpGenerator executable: ${QHelpGenerator_EXECUTABLE}")
  endif()
else()
  if(QHelpGenerator_FIND_REQUIRED)
    message( FATAL_ERROR "Could not find QHelpGenerator executable" )
  else()
    message( STATUS "Optional QHelpGenerator executable was not found" )
  endif()
endif()

# SPDX-FileCopyrightText: 2012-2014 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
FindQtWaylandScanner
--------------------

Try to find qtwaylandscanner.

If the qtwaylandscanner executable is not in your PATH, you can provide
an alternative name or full path location with the ``QtWaylandScanner_EXECUTABLE``
variable.

This will define the following variables:

``QtWaylandScanner_FOUND``
    True if qtwaylandscanner is available

``QtWaylandScanner_EXECUTABLE``
    The qtwaylandscanner executable.

If ``QtWaylandScanner_FOUND`` is TRUE, it will also define the following imported
target:

``Wayland::QtScanner``
    The qtwaylandscanner executable.

This module provides the following functions to generate C++ protocol
implementations:

  - ``ecm_add_qtwayland_client_protocol``
  - ``ecm_add_qtwayland_server_protocol``

::

  ecm_add_qtwayland_client_protocol(<target>
                                    PROTOCOL <xmlfile>
                                    BASENAME <basename>
                                    [PREFIX <prefix>]
                                    [PRIVATE_CODE])

  ecm_add_qtwayland_client_protocol(<source_files_var>
                                    PROTOCOL <xmlfile>
                                    BASENAME <basename>
                                    [PREFIX <prefix>]
                                    [PRIVATE_CODE])

Generate C++ wrapper to Wayland client protocol files from ``<xmlfile>``
XML definition for the ``<basename>`` interface and append those files
to ``<source_files_var>`` or ``<target>``.  Pass the ``<prefix>`` argument if the interface
names don't start with ``qt_`` or ``wl_``.
``PRIVATE_CODE`` instructs wayland-scanner to hide marshalling code
from the compiled DSO for use in other DSOs. The default is to
export this code.

WaylandScanner is required and will be searched for.

::

  ecm_add_qtwayland_server_protocol(<target>
                                    PROTOCOL <xmlfile>
                                    BASENAME <basename>
                                    [PREFIX <prefix>]
                                    [PRIVATE_CODE])

  ecm_add_qtwayland_server_protocol(<source_files_var>
                                    PROTOCOL <xmlfile>
                                    BASENAME <basename>
                                    [PREFIX <prefix>]
                                    [PRIVATE_CODE])

Generate C++ wrapper to Wayland server protocol files from ``<xmlfile>``
XML definition for the ``<basename>`` interface and append those files
to ``<source_files_var>`` or ``<target>``.  Pass the ``<prefix>`` argument if the interface
names don't start with ``qt_`` or ``wl_``.
``PRIVATE_CODE`` instructs wayland-scanner to hide marshalling code
from the compiled DSO for use in other DSOs. The default is to
export this code.

WaylandScanner is required and will be searched for.

Since 1.4.0.
#]=======================================================================]

include(${CMAKE_CURRENT_LIST_DIR}/ECMFindModuleHelpersStub.cmake)
include("${ECM_MODULE_DIR}/ECMQueryQt.cmake")

ecm_find_package_version_check(QtWaylandScanner)

if (QT_MAJOR_VERSION STREQUAL "5")
    ecm_query_qt(qtwaylandscanner_dir QT_HOST_BINS)
else()
    ecm_query_qt(qtwaylandscanner_dir QT_HOST_LIBEXECS)
endif()

# Find qtwaylandscanner
find_program(QtWaylandScanner_EXECUTABLE NAMES qtwaylandscanner HINTS ${qtwaylandscanner_dir})

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(QtWaylandScanner
    FOUND_VAR
        QtWaylandScanner_FOUND
    REQUIRED_VARS
        QtWaylandScanner_EXECUTABLE
)

mark_as_advanced(QtWaylandScanner_EXECUTABLE)

if(NOT TARGET Wayland::QtScanner AND QtWaylandScanner_FOUND)
    add_executable(Wayland::QtScanner IMPORTED)
    set_target_properties(Wayland::QtScanner PROPERTIES
        IMPORTED_LOCATION "${QtWaylandScanner_EXECUTABLE}"
    )
endif()

include(FeatureSummary)
set_package_properties(QtWaylandScanner PROPERTIES
    URL "https://qt.io/"
    DESCRIPTION "Executable that converts XML protocol files to C++ code"
)

function(ecm_add_qtwayland_client_protocol target_or_sources_var)
    # Parse arguments
    set(oneValueArgs PROTOCOL BASENAME PREFIX)
    set(options PRIVATE_CODE)
    cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "" ${ARGN})

    if(ARGS_UNPARSED_ARGUMENTS)
        message(FATAL_ERROR "Unknown keywords given to ecm_add_qtwayland_client_protocol(): \"${ARGS_UNPARSED_ARGUMENTS}\"")
    endif()

    set(_prefix "${ARGS_PREFIX}")
    if(ARGS_PRIVATE_CODE)
        set(_private_code_option PRIVATE_CODE)
    endif()

    find_package(WaylandScanner REQUIRED QUIET)
    ecm_add_wayland_client_protocol(${target_or_sources_var}
                                    PROTOCOL ${ARGS_PROTOCOL}
                                    BASENAME ${ARGS_BASENAME}
                                    ${_private_code_option})

    get_filename_component(_infile ${ARGS_PROTOCOL} ABSOLUTE)
    set(_header "${CMAKE_CURRENT_BINARY_DIR}/qwayland-${ARGS_BASENAME}.h")
    set(_code "${CMAKE_CURRENT_BINARY_DIR}/qwayland-${ARGS_BASENAME}.cpp")

    set_source_files_properties(${_header} ${_code} GENERATED)

    add_custom_command(OUTPUT "${_header}"
        COMMAND ${QtWaylandScanner_EXECUTABLE} client-header ${_infile} "" ${_prefix} > ${_header}
        DEPENDS ${_infile} ${_cheader} VERBATIM)

    add_custom_command(OUTPUT "${_code}"
        COMMAND ${QtWaylandScanner_EXECUTABLE} client-code ${_infile} "" ${_prefix} > ${_code}
        DEPENDS ${_infile} ${_header} VERBATIM)

    set_property(SOURCE ${_header} ${_code} PROPERTY SKIP_AUTOMOC ON)

    if (TARGET ${target_or_sources_var})
        target_sources(${target_or_sources_var} PRIVATE "${_code}")
    else()
        list(APPEND ${target_or_sources_var} "${_code}")
        set(${target_or_sources_var} ${${target_or_sources_var}} PARENT_SCOPE)
    endif()
endfunction()


function(ecm_add_qtwayland_server_protocol target_or_sources_var)
    # Parse arguments
    set(oneValueArgs PROTOCOL BASENAME PREFIX)
    set(options PRIVATE_CODE)
    cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "" ${ARGN})

    if(ARGS_UNPARSED_ARGUMENTS)
        message(FATAL_ERROR "Unknown keywords given to ecm_add_qtwayland_server_protocol(): \"${ARGS_UNPARSED_ARGUMENTS}\"")
    endif()

    set(_prefix "${ARGS_PREFIX}")
    if(ARGS_PRIVATE_CODE)
        set(_private_code_option PRIVATE_CODE)
    endif()

    find_package(WaylandScanner REQUIRED QUIET)
    ecm_add_wayland_server_protocol(${target_or_sources_var}
                                    PROTOCOL ${ARGS_PROTOCOL}
                                    BASENAME ${ARGS_BASENAME}
                                    ${_private_code_option})

    get_filename_component(_infile ${ARGS_PROTOCOL} ABSOLUTE)
    set(_header "${CMAKE_CURRENT_BINARY_DIR}/qwayland-server-${ARGS_BASENAME}.h")
    set(_code "${CMAKE_CURRENT_BINARY_DIR}/qwayland-server-${ARGS_BASENAME}.cpp")

    set_source_files_properties(${_header} ${_code} GENERATED)

    add_custom_command(OUTPUT "${_header}"
        COMMAND ${QtWaylandScanner_EXECUTABLE} server-header ${_infile} "" ${_prefix} > ${_header}
        DEPENDS ${_infile} VERBATIM)

    add_custom_command(OUTPUT "${_code}"
        COMMAND ${QtWaylandScanner_EXECUTABLE} server-code ${_infile} "" ${_prefix} > ${_code}
        DEPENDS ${_infile} ${_header} VERBATIM)

    set_property(SOURCE ${_header} ${_code} PROPERTY SKIP_AUTOMOC ON)

    if (TARGET ${target_or_sources_var})
        target_sources(${target_or_sources_var} PRIVATE "${_code}")
    else()
        list(APPEND ${target_or_sources_var} "${_code}")
        set(${target_or_sources_var} ${${target_or_sources_var}} PARENT_SCOPE)
    endif()
endfunction()
# SPDX-FileCopyrightText: 2020 Andreas Cord-Landwehr <cordlandwehr@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
WARNING: FOR ECM-INTERNAL USE ONLY, DO NOT USE IN OWN PROJECTS
THIS FILE MIGHT DISAPPEAR IN FUTURE VERSIONS OF ECM.

Finds the REUSE Tool by FSFE: https://github.com/fsfe/reuse-tool

 REUSETOOL_FOUND      - True if REUSE tool is found.
 REUSETOOL_EXECUTABLE - Path to executable
#]=======================================================================]

find_program(REUSETOOL_EXECUTABLE NAMES reuse)

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(ReuseTool
    FOUND_VAR
        REUSETOOL_FOUND
    REQUIRED_VARS
        REUSETOOL_EXECUTABLE
)
# SPDX-FileCopyrightText: 2006, 2007 Laurent Montel <montel@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
FindSasl2
---------

Try to find the SASL2 library.

This will define the following variables:

``Sasl2_FOUND``
    System has SASL2.

``Sasl2_VERSION``
    The version of SASL2.

``Sasl2_INCLUDE_DIRS``
    This should be passed to target_include_directories() if
    the target is not used for linking.

``Sasl2_LIBRARIES``
    The SASL2 library.
    This can be passed to target_link_libraries() instead of
    the ``Sasl2::Sasl2`` target

If ``Sasl2_FOUND`` is TRUE, the following imported target
will be available:

``Sasl2::Sasl2``
    The SASL2 library

Since 5.41.0.
#]=======================================================================]

# NOTE: libsasl2.pc doesn't export the include dir.
find_package(PkgConfig QUIET)
pkg_check_modules(PC_Sasl2 libsasl2)

find_path(Sasl2_INCLUDE_DIRS NAMES sasl/sasl.h)

# libsasl2 add for windows, because the windows package of cyrus-sasl2
# contains a libsasl2 also for msvc which is not standard conform
find_library(Sasl2_LIBRARIES
  NAMES sasl2 libsasl2
  HINTS ${PC_Sasl2_LIBRARY_DIRS}
)

set(Sasl2_VERSION "${PC_Sasl2_VERSION}")

if(NOT Sasl2_VERSION)
  if(EXISTS "${Sasl2_INCLUDE_DIRS}/sasl/sasl.h")
    file(READ "${Sasl2_INCLUDE_DIRS}/sasl/sasl.h" SASL2_H_CONTENT)
    string(REGEX MATCH "#define SASL_VERSION_MAJOR[ ]+[0-9]+" SASL2_VERSION_MAJOR_MATCH ${SASL2_H_CONTENT})
    string(REGEX MATCH "#define SASL_VERSION_MINOR[ ]+[0-9]+" SASL2_VERSION_MINOR_MATCH ${SASL2_H_CONTENT})
    string(REGEX MATCH "#define SASL_VERSION_STEP[ ]+[0-9]+" SASL2_VERSION_STEP_MATCH ${SASL2_H_CONTENT})

    string(REGEX REPLACE ".*_MAJOR[ ]+(.*)" "\\1" SASL2_VERSION_MAJOR ${SASL2_VERSION_MAJOR_MATCH})
    string(REGEX REPLACE ".*_MINOR[ ]+(.*)" "\\1" SASL2_VERSION_MINOR ${SASL2_VERSION_MINOR_MATCH})
    string(REGEX REPLACE ".*_STEP[ ]+(.*)" "\\1"  SASL2_VERSION_STEP  ${SASL2_VERSION_STEP_MATCH})

    set(Sasl2_VERSION "${SASL2_VERSION_MAJOR}.${SASL2_VERSION_MINOR}.${SASL2_VERSION_STEP}")
  else()
  # Could not find the version
  set(Sasl2_VERSION "0.0.0")
  endif()
endif()

include(FindPackageHandleStandardArgs)

find_package_handle_standard_args(Sasl2
    FOUND_VAR Sasl2_FOUND
    REQUIRED_VARS Sasl2_LIBRARIES Sasl2_INCLUDE_DIRS
    VERSION_VAR Sasl2_VERSION
)
if(Sasl2_FOUND AND NOT TARGET Sasl2::Sasl2)
  add_library(Sasl2::Sasl2 UNKNOWN IMPORTED)
  set_target_properties(Sasl2::Sasl2 PROPERTIES
  IMPORTED_LOCATION "${Sasl2_LIBRARIES}"
  INTERFACE_INCLUDE_DIRECTORIES "${Sasl2_INCLUDE_DIRS}")
endif()

mark_as_advanced(Sasl2_LIBRARIES Sasl2_INCLUDE_DIRS Sasl2_VERSION)

include(FeatureSummary)
set_package_properties(Sasl2 PROPERTIES
  URL "https://www.cyrusimap.org/sasl/"
  DESCRIPTION "The Cyrus-sasl library."
)

# SPDX-FileCopyrightText: 2017 Martin Flöser <mgraesslin@kde.org>
# SPDX-FileCopyrightText: 2017 David Kahles <david.kahles96@gmail.com>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
FindSeccomp
-----------

Try to locate the libseccomp library.

This will define the following variables:

``Seccomp_FOUND``
    True if the seccomp library is available
``Seccomp_INCLUDE_DIRS``
    The seccomp include directories
``Seccomp_LIBRARIES``
    The seccomp libraries for linking

If ``Seccomp_FOUND`` is TRUE, it will also define the following
imported target:

``Seccomp::Seccomp``
    The Seccomp library

Since 5.44.0.
#]=======================================================================]

find_package(PkgConfig QUIET)
pkg_check_modules(PKG_Libseccomp QUIET libseccomp)

find_path(Seccomp_INCLUDE_DIRS
    NAMES
        seccomp.h
    HINTS
        ${PKG_Libseccomp_INCLUDE_DIRS}
)
find_library(Seccomp_LIBRARIES
    NAMES
        seccomp
    HINTS
        ${PKG_Libseccomp_LIBRARY_DIRS}
)

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Seccomp
    FOUND_VAR
        Seccomp_FOUND
    REQUIRED_VARS
        Seccomp_LIBRARIES
        Seccomp_INCLUDE_DIRS
)

if (Seccomp_FOUND AND NOT TARGET Seccomp::Seccomp)
    add_library(Seccomp::Seccomp UNKNOWN IMPORTED)
    set_target_properties(Seccomp::Seccomp PROPERTIES
        IMPORTED_LOCATION "${Seccomp_LIBRARIES}"
        INTERFACE_INCLUDE_DIRECTORIES "${Seccomp_INCLUDE_DIRS}"
    )
endif()

mark_as_advanced(Seccomp_LIBRARIES Seccomp_INCLUDE_DIRS)

include(FeatureSummary)
set_package_properties(Seccomp PROPERTIES
    URL "https://github.com/seccomp/libseccomp"
    DESCRIPTION "The enhanced seccomp library."
)
# SPDX-FileCopyrightText: 2013-2014 Alex Merry <alex.merry@kdemail.net>
# SPDX-FileCopyrightText: 2007 Pino Toscano <toscano.pino@tiscali.it>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
FindSharedMimeInfo
------------------

Try to find the shared-mime-info package.

This will define the following variables:

``SharedMimeInfo_FOUND``
    True if system has the shared-mime-info package
``UPDATE_MIME_DATABASE_EXECUTABLE``
    The update-mime-database executable

and the following imported targets:

``SharedMimeInfo::UpdateMimeDatabase``
    The update-mime-database executable

The follow macro is available::

  update_xdg_mimetypes(<path>)

Updates the XDG mime database at install time (unless the ``$DESTDIR``
environment variable is set, in which case it is up to package managers to
perform this task).

Since pre-1.0.0.
#]=======================================================================]

include(${CMAKE_CURRENT_LIST_DIR}/ECMFindModuleHelpersStub.cmake)

ecm_find_package_version_check(SharedMimeInfo)

find_program (UPDATE_MIME_DATABASE_EXECUTABLE NAMES update-mime-database)

if (UPDATE_MIME_DATABASE_EXECUTABLE)
    execute_process(
        COMMAND "${UPDATE_MIME_DATABASE_EXECUTABLE}" -v
        OUTPUT_VARIABLE _smiVersionRaw
        ERROR_VARIABLE _smiVersionRaw)

    string(REGEX REPLACE "update-mime-database \\([a-zA-Z\\-]+\\) ([0-9]\\.[0-9]+).*"
           "\\1" SharedMimeInfo_VERSION_STRING "${_smiVersionRaw}")
endif()

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(SharedMimeInfo
    FOUND_VAR
        SharedMimeInfo_FOUND
    REQUIRED_VARS
        UPDATE_MIME_DATABASE_EXECUTABLE
    VERSION_VAR
        SharedMimeInfo_VERSION_STRING)

if(SharedMimeInfo_FOUND AND NOT TARGET SharedMimeInfo::UpdateMimeDatabase)
    add_executable(SharedMimeInfo::UpdateMimeDatabase IMPORTED)
    set_target_properties(SharedMimeInfo::UpdateMimeDatabase PROPERTIES
        IMPORTED_LOCATION "${UPDATE_MIME_DATABASE_EXECUTABLE}"
    )
endif()

mark_as_advanced(UPDATE_MIME_DATABASE_EXECUTABLE)

function(UPDATE_XDG_MIMETYPES _path)
    get_filename_component(_xdgmimeDir "${_path}" NAME)
    if("${_xdgmimeDir}" STREQUAL packages )
        get_filename_component(_xdgmimeDir "${_path}" PATH)
    else()
        set(_xdgmimeDir "${_path}")
    endif()

    # Note that targets and most variables are not available to install code
    install(CODE "
set(DESTDIR_VALUE \"\$ENV{DESTDIR}\")
if (NOT DESTDIR_VALUE)
    # under Windows relative paths are used, that's why it runs from CMAKE_INSTALL_PREFIX
    message(STATUS \"Updating MIME database at \${CMAKE_INSTALL_PREFIX}/${_xdgmimeDir}\")
    execute_process(COMMAND \"${UPDATE_MIME_DATABASE_EXECUTABLE}\" -n \"${_xdgmimeDir}\"
                    WORKING_DIRECTORY \"\${CMAKE_INSTALL_PREFIX}\")
endif (NOT DESTDIR_VALUE)
")
endfunction()

include(FeatureSummary)
set_package_properties(SharedMimeInfo PROPERTIES
    URL https://freedesktop.org/wiki/Software/shared-mime-info/
    DESCRIPTION "A database of common MIME types")
# SPDX-FileCopyrightText: 2006 Laurent Montel <montel@kde.org>
# SPDX-FileCopyrightText: 2019 Heiko Becker <heirecka@exherbo.org>
# SPDX-FileCopyrightText: 2020 Elvis Angelaccio <elvis.angelaccio@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
FindTaglib
----------

Try to find the Taglib library.

This will define the following variables:

``Taglib_FOUND``
      True if the system has the taglib library of at least the minimum
      version specified by the version parameter to find_package()
``Taglib_INCLUDE_DIRS``
      The taglib include dirs for use with target_include_directories
``Taglib_LIBRARIES``
      The taglib libraries for use with target_link_libraries()
``Taglib_VERSION``
      The version of taglib that was found

If ``Taglib_FOUND`` is TRUE, it will also define the following imported
target:

``Taglib::Taglib``
      The Taglib library

Since 5.72.0
#]=======================================================================]

find_package(PkgConfig QUIET)

pkg_check_modules(PC_TAGLIB QUIET taglib)

find_path(Taglib_INCLUDE_DIRS
    NAMES tag.h
    PATH_SUFFIXES taglib
    HINTS ${PC_TAGLIB_INCLUDEDIR}
)

find_library(Taglib_LIBRARIES
    NAMES tag
    HINTS ${PC_TAGLIB_LIBDIR}
)

set(Taglib_VERSION ${PC_TAGLIB_VERSION})

if (Taglib_INCLUDE_DIRS AND NOT Taglib_VERSION)
    if(EXISTS "${Taglib_INCLUDE_DIRS}/taglib.h")
        file(READ "${Taglib_INCLUDE_DIRS}/taglib.h" TAGLIB_H)

        string(REGEX MATCH "#define TAGLIB_MAJOR_VERSION[ ]+[0-9]+" TAGLIB_MAJOR_VERSION_MATCH ${TAGLIB_H})
        string(REGEX MATCH "#define TAGLIB_MINOR_VERSION[ ]+[0-9]+" TAGLIB_MINOR_VERSION_MATCH ${TAGLIB_H})
        string(REGEX MATCH "#define TAGLIB_PATCH_VERSION[ ]+[0-9]+" TAGLIB_PATCH_VERSION_MATCH ${TAGLIB_H})

        string(REGEX REPLACE ".*_MAJOR_VERSION[ ]+(.*)" "\\1" TAGLIB_MAJOR_VERSION "${TAGLIB_MAJOR_VERSION_MATCH}")
        string(REGEX REPLACE ".*_MINOR_VERSION[ ]+(.*)" "\\1" TAGLIB_MINOR_VERSION "${TAGLIB_MINOR_VERSION_MATCH}")
        string(REGEX REPLACE ".*_PATCH_VERSION[ ]+(.*)" "\\1" TAGLIB_PATCH_VERSION "${TAGLIB_PATCH_VERSION_MATCH}")

        set(Taglib_VERSION "${TAGLIB_MAJOR_VERSION}.${TAGLIB_MINOR_VERSION}.${TAGLIB_PATCH_VERSION}")
    endif()
endif()

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Taglib
    FOUND_VAR
        Taglib_FOUND
    REQUIRED_VARS
        Taglib_LIBRARIES
        Taglib_INCLUDE_DIRS
    VERSION_VAR
        Taglib_VERSION
)

if (Taglib_FOUND AND NOT TARGET Taglib::Taglib)
    add_library(Taglib::Taglib UNKNOWN IMPORTED)
    set_target_properties(Taglib::Taglib PROPERTIES
        IMPORTED_LOCATION "${Taglib_LIBRARIES}"
        INTERFACE_INCLUDE_DIRECTORIES "${Taglib_INCLUDE_DIRS}"
    )
endif()

mark_as_advanced(Taglib_LIBRARIES Taglib_INCLUDE_DIRS)

include(FeatureSummary)
set_package_properties(Taglib PROPERTIES
    URL "https://taglib.org/"
    DESCRIPTION "A library for reading and editing the meta-data of audio formats"
)
# SPDX-FileCopyrightText: 2010 Rafael Fernández López <ereslibre@kde.org>
# SPDX-FileCopyrightText: 2019 Volker Krause <vkrause@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
FindUDev
--------

Try to find the UDev library.

This will define the following variables:

``UDev_FOUND``
    System has UDev.

``UDev_INCLUDE_DIRS``
    The libudev include directory.

``UDev_LIBRARIES``
    The libudev libraries.

``UDev_VERSION``
    The libudev version.

If ``UDev_FOUND`` is TRUE, it will also define the following imported
target:

``UDev::UDev``
    The UDev library

Since 5.57.0.
#]=======================================================================]

find_package(PkgConfig QUIET)
pkg_check_modules(PC_UDEV QUIET libudev)

find_path(UDev_INCLUDE_DIRS NAMES libudev.h HINTS ${PC_UDEV_INCLUDE_DIRS})
find_library(UDev_LIBRARIES NAMES udev HINTS ${PC_UDEV_LIBRARY_DIRS})

set(UDev_VERSION ${PC_UDEV_VERSION})

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(UDev
    FOUND_VAR UDev_FOUND
    REQUIRED_VARS UDev_INCLUDE_DIRS UDev_LIBRARIES
    VERSION_VAR UDev_VERSION
)

mark_as_advanced(UDev_INCLUDE_DIRS UDev_LIBRARIES)

if(UDev_FOUND AND NOT TARGET UDev::UDev)
    add_library(UDev::UDev UNKNOWN IMPORTED)
    set_target_properties(UDev::UDev PROPERTIES
        IMPORTED_LOCATION "${UDev_LIBRARIES}"
        INTERFACE_INCLUDE_DIRECTORIES "${UDev_INCLUDE_DIRS}"
        INTERFACE_COMPILE_DEFINITIONS "${PC_UDEV_CFLAGS_OTHER}"
    )
endif()

# backward compat variables, remove for KF6
set(UDEV_FOUND ${UDev_FOUND})
set(UDEV_LIBS ${UDev_LIBRARIES})
set(UDEV_INCLUDE_DIR ${UDev_INCLUDE_DIRS})
mark_as_advanced(UDEV_FOUND UDEV_LIBS UDEV_INCLUDE_DIR)

include(FeatureSummary)
set_package_properties(UDev PROPERTIES
    DESCRIPTION "API for enumerating and introspecting local devices (part of systemd)"
    URL "https://www.freedesktop.org/wiki/Software/systemd/"
)
# SPDX-FileCopyrightText: 2014 Alex Merry <alex.merry@kde.org>
# SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
FindWayland
-----------

Try to find Wayland.

This is a component-based find module, which makes use of the COMPONENTS
and OPTIONAL_COMPONENTS arguments to find_module.  The following components
are available::

  Client  Server  Cursor  Egl

If no components are specified, this module will act as though all components
were passed to OPTIONAL_COMPONENTS.

This module will define the following variables, independently of the
components searched for or found:

``Wayland_FOUND``
    TRUE if (the requested version of) Wayland is available
``Wayland_VERSION``
    Found Wayland version
``Wayland_TARGETS``
    A list of all targets imported by this module (note that there may be more
    than the components that were requested)
``Wayland_LIBRARIES``
    This can be passed to target_link_libraries() instead of the imported
    targets
``Wayland_INCLUDE_DIRS``
    This should be passed to target_include_directories() if the targets are
    not used for linking
``Wayland_DEFINITIONS``
    This should be passed to target_compile_options() if the targets are not
    used for linking
``Wayland_DATADIR``
    The core wayland protocols data directory
    Since 5.73.0

For each searched-for components, ``Wayland_<component>_FOUND`` will be set to
TRUE if the corresponding Wayland library was found, and FALSE otherwise.  If
``Wayland_<component>_FOUND`` is TRUE, the imported target
``Wayland::<component>`` will be defined.  This module will also attempt to
determine ``Wayland_*_VERSION`` variables for each imported target, although
``Wayland_VERSION`` should normally be sufficient.

In general we recommend using the imported targets, as they are easier to use
and provide more control.  Bear in mind, however, that if any target is in the
link interface of an exported library, it must be made available by the
package config file.

Since pre-1.0.0.
#]=======================================================================]

include(${CMAKE_CURRENT_LIST_DIR}/ECMFindModuleHelpersStub.cmake)

ecm_find_package_version_check(Wayland)

set(Wayland_known_components
    Client
    Server
    Cursor
    Egl
)
foreach(_comp ${Wayland_known_components})
    string(TOLOWER "${_comp}" _lc_comp)
    set(Wayland_${_comp}_component_deps)
    set(Wayland_${_comp}_pkg_config "wayland-${_lc_comp}")
    set(Wayland_${_comp}_lib "wayland-${_lc_comp}")
    set(Wayland_${_comp}_header "wayland-${_lc_comp}.h")
endforeach()
set(Wayland_Egl_component_deps Client)

ecm_find_package_parse_components(Wayland
    RESULT_VAR Wayland_components
    KNOWN_COMPONENTS ${Wayland_known_components}
)
ecm_find_package_handle_library_components(Wayland
    COMPONENTS ${Wayland_components}
)

# If pkg-config didn't provide us with version information,
# try to extract it from wayland-version.h
# (Note that the version from wayland-egl.pc will probably be
# the Mesa version, rather than the Wayland version, but that
# version will be ignored as we always find wayland-client.pc
# first).
if(NOT Wayland_VERSION)
    find_file(Wayland_VERSION_HEADER
        NAMES wayland-version.h
        HINTS ${Wayland_INCLUDE_DIRS}
    )
    mark_as_advanced(Wayland_VERSION_HEADER)
    if(Wayland_VERSION_HEADER)
        file(READ ${Wayland_VERSION_HEADER} _wayland_version_header_contents)
        string(REGEX REPLACE
            "^.*[ \t]+WAYLAND_VERSION[ \t]+\"([0-9.]*)\".*$"
            "\\1"
            Wayland_VERSION
            "${_wayland_version_header_contents}"
        )
        unset(_wayland_version_header_contents)
    endif()
endif()

find_package_handle_standard_args(Wayland
    FOUND_VAR
        Wayland_FOUND
    REQUIRED_VARS
        Wayland_LIBRARIES
    VERSION_VAR
        Wayland_VERSION
    HANDLE_COMPONENTS
)

pkg_get_variable(Wayland_DATADIR wayland-scanner pkgdatadir)
if (CMAKE_CROSSCOMPILING AND (NOT EXISTS "${Wayland_DATADIR}/wayland.xml"))
    # PKG_CONFIG_SYSROOT_DIR only applies to -I and -L flags, so pkg-config
    # does not prepend CMAKE_SYSROOT when cross-compiling unless you pass
    # --define-prefix explicitly. Therefore we have to  manually do prepend
    # it here when cross-compiling.
    # See https://gitlab.kitware.com/cmake/cmake/-/issues/16647#note_844761
    set(Wayland_DATADIR ${CMAKE_SYSROOT}${Wayland_DATADIR})
endif()
if (NOT EXISTS "${Wayland_DATADIR}/wayland.xml")
    message(WARNING "Could not find wayland.xml in ${Wayland_DATADIR}")
endif()

include(FeatureSummary)
set_package_properties(Wayland PROPERTIES
    URL "https://wayland.freedesktop.org/"
    DESCRIPTION "C library implementation of the Wayland protocol: a protocol for a compositor to talk to its clients"
)
# SPDX-FileCopyrightText: 2019 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
FindWaylandProtocols
--------------------

Try to find wayland-protocols on a Unix system.

This will define the following variables:

``WaylandProtocols_FOUND``
    True if (the requested version of) wayland-protocols is available
``WaylandProtocols_VERSION``
    The version of wayland-protocols
``WaylandProtocols_DATADIR``
    The wayland protocols data directory
#]=======================================================================]

find_package(PkgConfig QUIET)
pkg_check_modules(PKG_wayland_protocols QUIET wayland-protocols)

set(WaylandProtocols_VERSION ${PKG_wayland_protocols_VERSION})
pkg_get_variable(WaylandProtocols_DATADIR wayland-protocols pkgdatadir)

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(WaylandProtocols
    FOUND_VAR WaylandProtocols_FOUND
    REQUIRED_VARS WaylandProtocols_DATADIR
    VERSION_VAR WaylandProtocols_VERSION
)

include(FeatureSummary)
set_package_properties(WaylandProtocols PROPERTIES
    DESCRIPTION "Specifications of extended Wayland protocols"
    URL "https://wayland.freedesktop.org/"
)
# SPDX-FileCopyrightText: 2012-2014 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
FindWaylandScanner
------------------

Try to find wayland-scanner.

If the wayland-scanner executable is not in your PATH, you can provide
an alternative name or full path location with the ``WaylandScanner_EXECUTABLE``
variable.

This will define the following variables:

``WaylandScanner_FOUND``
    True if wayland-scanner is available.

``WaylandScanner_EXECUTABLE``
    The wayland-scanner executable.

If ``WaylandScanner_FOUND`` is TRUE, it will also define the following imported
target:

``Wayland::Scanner``
    The wayland-scanner executable.

This module provides the following functions to generate C protocol
implementations:

  - ``ecm_add_wayland_client_protocol``
  - ``ecm_add_wayland_server_protocol``

::

  ecm_add_wayland_client_protocol(<target>
                                  PROTOCOL <xmlfile>
                                  BASENAME <basename>
                                  [PRIVATE_CODE])

  ecm_add_wayland_client_protocol(<source_files_var>
                                  PROTOCOL <xmlfile>
                                  BASENAME <basename>
                                  [PRIVATE_CODE])

Generate Wayland client protocol files from ``<xmlfile>`` XML
definition for the ``<basename>`` interface and append those files
to ``<source_files_var>`` or ``<target>``.

``PRIVATE_CODE`` instructs wayland-scanner to hide marshalling code
from the compiled DSO for use in other DSOs. The default is to
export this code.

::

  ecm_add_wayland_server_protocol(<target>
                                  PROTOCOL <xmlfile>
                                  BASENAME <basename>
                                  [PRIVATE_CODE])

  ecm_add_wayland_server_protocol(<source_files_var>
                                  PROTOCOL <xmlfile>
                                  BASENAME <basename>
                                  [PRIVATE_CODE])

Generate Wayland server protocol files from ``<xmlfile>`` XML
definition for the ``<basename>`` interface and append those files
to ``<source_files_var>`` or ``<target>``.

``PRIVATE_CODE`` instructs wayland-scanner to hide marshalling code
from the compiled DSO for use in other DSOs. The default is to
export this code.

Since 1.4.0.
#]=======================================================================]

include(${CMAKE_CURRENT_LIST_DIR}/ECMFindModuleHelpersStub.cmake)

ecm_find_package_version_check(WaylandScanner)

# Find wayland-scanner
find_program(WaylandScanner_EXECUTABLE NAMES wayland-scanner)

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(WaylandScanner
    FOUND_VAR
        WaylandScanner_FOUND
    REQUIRED_VARS
        WaylandScanner_EXECUTABLE
)

mark_as_advanced(WaylandScanner_EXECUTABLE)

if(NOT TARGET Wayland::Scanner AND WaylandScanner_FOUND)
    add_executable(Wayland::Scanner IMPORTED)
    set_target_properties(Wayland::Scanner PROPERTIES
        IMPORTED_LOCATION "${WaylandScanner_EXECUTABLE}"
    )
endif()

include(FeatureSummary)
set_package_properties(WaylandScanner PROPERTIES
    URL "https://wayland.freedesktop.org/"
    DESCRIPTION "Executable that converts XML protocol files to C code"
)

function(ecm_add_wayland_client_protocol target_or_sources_var)
    # Parse arguments
    set(options PRIVATE_CODE)
    set(oneValueArgs PROTOCOL BASENAME)
    cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "" ${ARGN})

    if(ARGS_UNPARSED_ARGUMENTS)
        message(FATAL_ERROR "Unknown keywords given to ecm_add_wayland_client_protocol(): \"${ARGS_UNPARSED_ARGUMENTS}\"")
    endif()

    get_filename_component(_infile ${ARGS_PROTOCOL} ABSOLUTE)
    set(_client_header "${CMAKE_CURRENT_BINARY_DIR}/wayland-${ARGS_BASENAME}-client-protocol.h")
    set(_code "${CMAKE_CURRENT_BINARY_DIR}/wayland-${ARGS_BASENAME}-protocol.c")
    if(ARGS_PRIVATE_CODE)
        set(_code_type private-code)
    else()
        set(_code_type public-code)
    endif()

    set_source_files_properties(${_client_header} GENERATED)
    set_source_files_properties(${_code} GENERATED)
    set_property(SOURCE ${_client_header} ${_code} PROPERTY SKIP_AUTOMOC ON)

    add_custom_command(OUTPUT "${_client_header}"
        COMMAND ${WaylandScanner_EXECUTABLE} client-header ${_infile} ${_client_header}
        DEPENDS ${_infile} VERBATIM)

    add_custom_command(OUTPUT "${_code}"
        COMMAND ${WaylandScanner_EXECUTABLE} ${_code_type} ${_infile} ${_code}
        DEPENDS ${_infile} ${_client_header} VERBATIM)

    if (TARGET ${target_or_sources_var})
        target_sources(${target_or_sources_var} PRIVATE "${_client_header}" "${_code}")
    else()
        list(APPEND ${target_or_sources_var} "${_client_header}" "${_code}")
        set(${target_or_sources_var} ${${target_or_sources_var}} PARENT_SCOPE)
    endif()
endfunction()


function(ecm_add_wayland_server_protocol target_or_sources_var)
    # Parse arguments
    set(options PRIVATE_CODE)
    set(oneValueArgs PROTOCOL BASENAME)
    cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "" ${ARGN})

    if(ARGS_UNPARSED_ARGUMENTS)
        message(FATAL_ERROR "Unknown keywords given to ecm_add_wayland_server_protocol(): \"${ARGS_UNPARSED_ARGUMENTS}\"")
    endif()

    if(ARGS_PRIVATE_CODE)
        set(_private_code_option PRIVATE_CODE)
    endif()

    ecm_add_wayland_client_protocol(${target_or_sources_var}
                                    PROTOCOL ${ARGS_PROTOCOL}
                                    BASENAME ${ARGS_BASENAME}
                                    ${_private_code_option})

    get_filename_component(_infile ${ARGS_PROTOCOL} ABSOLUTE)
    set(_server_header "${CMAKE_CURRENT_BINARY_DIR}/wayland-${ARGS_BASENAME}-server-protocol.h")
    set(_server_code "${CMAKE_CURRENT_BINARY_DIR}/wayland-${ARGS_BASENAME}-protocol.c")
    set_property(SOURCE ${_server_header} ${_server_code} PROPERTY SKIP_AUTOMOC ON)
    set_source_files_properties(${_server_header} GENERATED)

    add_custom_command(OUTPUT "${_server_header}"
        COMMAND ${WaylandScanner_EXECUTABLE} server-header ${_infile} ${_server_header}
        DEPENDS ${_infile} VERBATIM)

    if (TARGET ${target_or_sources_var})
        target_sources(${target_or_sources_var} PRIVATE "${_server_header}")
    else()
        list(APPEND ${target_or_sources_var} "${_server_header}")
        set(${target_or_sources_var} ${${target_or_sources_var}} PARENT_SCOPE)
    endif()
endfunction()
# SPDX-FileCopyrightText: 2014 Alex Merry <alex.merry@kde.org>
# SPDX-FileCopyrightText: 2011 Fredrik Höglund <fredrik@kde.org>
# SPDX-FileCopyrightText: 2008 Helio Chissini de Castro <helio@kde.org>
# SPDX-FileCopyrightText: 2007 Matthias Kretz <kretz@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
FindX11_XCB
-----------

Try to find the X11 XCB compatibility library.

This will define the following variables:

``X11_XCB_FOUND``
    True if (the requested version of) libX11-xcb is available
``X11_XCB_VERSION``
    The version of libX11-xcb (this is not guaranteed to be set even when
    X11_XCB_FOUND is true)
``X11_XCB_LIBRARIES``
    This can be passed to target_link_libraries() instead of the ``EGL::EGL``
    target
``X11_XCB_INCLUDE_DIR``
    This should be passed to target_include_directories() if the target is not
    used for linking
``X11_XCB_DEFINITIONS``
    This should be passed to target_compile_options() if the target is not
    used for linking

If ``X11_XCB_FOUND`` is TRUE, it will also define the following imported
target:

``X11::XCB``
    The X11 XCB compatibility library

In general we recommend using the imported target, as it is easier to use.
Bear in mind, however, that if the target is in the link interface of an
exported library, it must be made available by the package config file.

Since pre-1.0.0.
#]=======================================================================]

include(${CMAKE_CURRENT_LIST_DIR}/ECMFindModuleHelpersStub.cmake)

ecm_find_package_version_check(X11_XCB)

# use pkg-config to get the directories and then use these values
# in the FIND_PATH() and FIND_LIBRARY() calls
find_package(PkgConfig QUIET)
pkg_check_modules(PKG_X11_XCB QUIET x11-xcb)

set(X11_XCB_DEFINITIONS ${PKG_X11_XCB_CFLAGS_OTHER})
set(X11_XCB_VERSION ${PKG_X11_XCB_VERSION})

find_path(X11_XCB_INCLUDE_DIR
    NAMES X11/Xlib-xcb.h
    HINTS ${PKG_X11_XCB_INCLUDE_DIRS}
)
find_library(X11_XCB_LIBRARY
    NAMES X11-xcb
    HINTS ${PKG_X11_XCB_LIBRARY_DIRS}
)

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(X11_XCB
    FOUND_VAR
        X11_XCB_FOUND
    REQUIRED_VARS
        X11_XCB_LIBRARY
        X11_XCB_INCLUDE_DIR
    VERSION_VAR
        X11_XCB_VERSION
)

if(X11_XCB_FOUND AND NOT TARGET X11::XCB)
    add_library(X11::XCB UNKNOWN IMPORTED)
    set_target_properties(X11::XCB PROPERTIES
        IMPORTED_LOCATION "${X11_XCB_LIBRARY}"
        INTERFACE_COMPILE_OPTIONS "${X11_XCB_DEFINITIONS}"
        INTERFACE_INCLUDE_DIRECTORIES "${X11_XCB_INCLUDE_DIR}"
    )
endif()

mark_as_advanced(X11_XCB_INCLUDE_DIR X11_XCB_LIBRARY)

# compatibility variables
set(X11_XCB_LIBRARIES ${X11_XCB_LIBRARY})
set(X11_XCB_INCLUDE_DIRS ${X11_XCB_INCLUDE_DIR})
set(X11_XCB_VERSION_STRING ${X11_XCB_VERSION})

include(FeatureSummary)
set_package_properties(X11_XCB PROPERTIES
    URL "https://xorg.freedesktop.org/"
    DESCRIPTION "A compatibility library for code that translates Xlib API calls into XCB calls"
)
# SPDX-FileCopyrightText: 2011 Fredrik Höglund <fredrik@kde.org>
# SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org>
# SPDX-FileCopyrightText: 2014-2015 Alex Merry <alex.merry@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
FindXCB
-------

Try to find XCB.

This is a component-based find module, which makes use of the COMPONENTS and
OPTIONAL_COMPONENTS arguments to find_module.  The following components are
available::

  XCB
  ATOM         AUX          COMPOSITE    CURSOR       DAMAGE
  DPMS         DRI2         DRI3         EVENT        EWMH
  GLX          ICCCM        IMAGE        KEYSYMS      PRESENT
  RANDR        RECORD       RENDER       RENDERUTIL   RES
  SCREENSAVER  SHAPE        SHM          SYNC         UTIL
  XF86DRI      XFIXES       XINERAMA     XINPUT       XKB
  XTEST        XV           XVMC

If no components are specified, this module will act as though all components
were passed to OPTIONAL_COMPONENTS. Before 5.82 this excluded XINPUT. Since 5.82
all components are searched for.

This module will define the following variables, independently of the
components searched for or found:

``XCB_FOUND``
    True if (the requestion version of) xcb is available
``XCB_VERSION``
    Found xcb version
``XCB_TARGETS``
    A list of all targets imported by this module (note that there may be more
    than the components that were requested)
``XCB_LIBRARIES``
    This can be passed to target_link_libraries() instead of the imported
    targets
``XCB_INCLUDE_DIRS``
    This should be passed to target_include_directories() if the targets are
    not used for linking
``XCB_DEFINITIONS``
    This should be passed to target_compile_options() if the targets are not
    used for linking

For each searched-for components, ``XCB_<component>_FOUND`` will be set to
true if the corresponding xcb library was found, and false otherwise.  If
``XCB_<component>_FOUND`` is true, the imported target ``XCB::<component>``
will be defined.  This module will also attempt to determine
``XCB_*_VERSION`` variables for each imported target, although
``XCB_VERSION`` should normally be sufficient.

In general we recommend using the imported targets, as they are easier to use
and provide more control.  Bear in mind, however, that if any target is in the
link interface of an exported library, it must be made available by the
package config file.

Since pre-1.0.0.
#]=======================================================================]

include(${CMAKE_CURRENT_LIST_DIR}/ECMFindModuleHelpersStub.cmake)

ecm_find_package_version_check(XCB)

# Note that this list needs to be ordered such that any component
# appears after its dependencies
set(XCB_known_components
    XCB
    RENDER
    SHAPE
    XFIXES
    SHM
    ATOM
    AUX
    COMPOSITE
    CURSOR
    DAMAGE
    DPMS
    DRI2
    DRI3
    EVENT
    EWMH
    GLX
    ICCCM
    IMAGE
    KEYSYMS
    PRESENT
    RANDR
    RECORD
    RENDERUTIL
    RES
    SCREENSAVER
    SYNC
    UTIL
    XF86DRI
    XINERAMA
    XINPUT
    XKB
    XTEST
    XV
    XVMC
)

# default component info: xcb components have fairly predictable
# header files, library names and pkg-config names
foreach(_comp ${XCB_known_components})
    string(TOLOWER "${_comp}" _lc_comp)
    set(XCB_${_comp}_component_deps XCB)
    set(XCB_${_comp}_pkg_config "xcb-${_lc_comp}")
    set(XCB_${_comp}_lib "xcb-${_lc_comp}")
    set(XCB_${_comp}_header "xcb/${_lc_comp}.h")
endforeach()
# exceptions
set(XCB_XCB_component_deps)
set(XCB_COMPOSITE_component_deps XCB XFIXES)
set(XCB_DAMAGE_component_deps XCB XFIXES)
set(XCB_IMAGE_component_deps XCB SHM)
set(XCB_RENDERUTIL_component_deps XCB RENDER)
set(XCB_XFIXES_component_deps XCB RENDER SHAPE)
set(XCB_XVMC_component_deps XCB XV)
set(XCB_XV_component_deps XCB SHM)
set(XCB_XCB_pkg_config "xcb")
set(XCB_XCB_lib "xcb")
set(XCB_ATOM_header "xcb/xcb_atom.h")
set(XCB_ATOM_lib "xcb-util")
set(XCB_AUX_header "xcb/xcb_aux.h")
set(XCB_AUX_lib "xcb-util")
set(XCB_CURSOR_header "xcb/xcb_cursor.h")
set(XCB_EVENT_header "xcb/xcb_event.h")
set(XCB_EVENT_lib "xcb-util")
set(XCB_EWMH_header "xcb/xcb_ewmh.h")
set(XCB_ICCCM_header "xcb/xcb_icccm.h")
set(XCB_IMAGE_header "xcb/xcb_image.h")
set(XCB_KEYSYMS_header "xcb/xcb_keysyms.h")
set(XCB_PIXEL_header "xcb/xcb_pixel.h")
set(XCB_RENDERUTIL_header "xcb/xcb_renderutil.h")
set(XCB_RENDERUTIL_lib "xcb-render-util")
set(XCB_UTIL_header "xcb/xcb_util.h")

ecm_find_package_parse_components(XCB
    RESULT_VAR XCB_components
    KNOWN_COMPONENTS ${XCB_known_components}
    DEFAULT_COMPONENTS ${XCB_default_components}
)

ecm_find_package_handle_library_components(XCB
    COMPONENTS ${XCB_components}
)

find_package_handle_standard_args(XCB
    FOUND_VAR
        XCB_FOUND
    REQUIRED_VARS
        XCB_LIBRARIES
    VERSION_VAR
        XCB_VERSION
    HANDLE_COMPONENTS
)

include(FeatureSummary)
set_package_properties(XCB PROPERTIES
    URL "https://xcb.freedesktop.org/"
    DESCRIPTION "X protocol C-language Binding"
)
# SPDX-FileCopyrightText: 2014 Fredrik Höglund <fredrik@kde.org>
# SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
Findepoxy
---------

Try to find libepoxy on a Unix system.

This will define the following variables:

``epoxy_FOUND``
    True if (the requested version of) libepoxy is available
``epoxy_VERSION``
    The version of libepoxy
``epoxy_LIBRARIES``
    This should be passed to target_link_libraries() if the target is not
    used for linking
``epoxy_INCLUDE_DIRS``
    This should be passed to target_include_directories() if the target is not
    used for linking
``epoxy_DEFINITIONS``
    This should be passed to target_compile_options() if the target is not
    used for linking
``epoxy_HAS_GLX``
    True if GLX support is available

If ``epoxy_FOUND`` is TRUE, it will also define the following imported target:

``epoxy::epoxy``
    The epoxy library

In general we recommend using the imported target, as it is easier to use.
Bear in mind, however, that if the target is in the link interface of an
exported library, it must be made available by the package config file.
#]=======================================================================]

find_package(PkgConfig QUIET)
pkg_check_modules(PKG_epoxy QUIET epoxy)

set(epoxy_VERSION ${PKG_epoxy_VERSION})
set(epoxy_DEFINITIONS ${PKG_epoxy_CFLAGS})

find_path(epoxy_INCLUDE_DIRS
    NAMES epoxy/gl.h
    HINTS ${PKG_epoxy_INCLUDEDIR} ${PKG_epoxy_INCLUDE_DIRS}
)
find_library(epoxy_LIBRARIES
    NAMES epoxy
    HINTS ${PKG_epoxy_LIBDIR} ${PKG_epoxy_LIBRARY_DIRS}
)
find_file(epoxy_GLX_HEADER NAMES epoxy/glx.h HINTS ${epoxy_INCLUDE_DIR})

if (epoxy_GLX_HEADER STREQUAL "epoxy_GLX_HEADER-NOTFOUND")
    set(epoxy_HAS_GLX FALSE CACHE BOOL "whether glx is available")
else ()
    set(epoxy_HAS_GLX TRUE CACHE BOOL "whether glx is available")
endif()

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(epoxy
    FOUND_VAR epoxy_FOUND
    REQUIRED_VARS epoxy_LIBRARIES epoxy_INCLUDE_DIRS
    VERSION_VAR epoxy_VERSION
)

if (epoxy_FOUND AND NOT TARGET epoxy::epoxy)
    add_library(epoxy::epoxy UNKNOWN IMPORTED)
    set_target_properties(epoxy::epoxy PROPERTIES
        IMPORTED_LOCATION "${epoxy_LIBRARIES}"
        INTERFACE_COMPILE_OPTIONS "${epoxy_DEFINITIONS}"
        INTERFACE_INCLUDE_DIRECTORIES "${epoxy_INCLUDE_DIRS}"
    )
endif()

mark_as_advanced(
    epoxy_DEFINITIONS
    epoxy_HAS_GLX
    epoxy_INCLUDE_DIRS
    epoxy_LIBRARIES
    epoxy_VERSION
)
# SPDX-FileCopyrightText: 2019, 2021 Friedrich W. H. Kossebau <kossebau@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
Findgzip
--------

Try to find gzip.

If the gzip executable is not in your PATH, you can provide
an alternative name or full path location with the ``gzip_EXECUTABLE``
variable.

This will define the following variables:

``gzip_FOUND``
    TRUE if gzip is available

``gzip_EXECUTABLE``
    Path to gzip executable

If ``gzip_FOUND`` is TRUE, it will also define the following imported
target:

``gzip::gzip``
    Path to gzip executable

Since 5.85.0.
#]=======================================================================]

find_program(gzip_EXECUTABLE NAMES gzip)

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(gzip
    FOUND_VAR
        gzip_FOUND
    REQUIRED_VARS
        gzip_EXECUTABLE
)
mark_as_advanced(gzip_EXECUTABLE)

if(NOT TARGET gzip::gzip AND gzip_FOUND)
    add_executable(gzip::gzip IMPORTED)
    set_target_properties(gzip::gzip PROPERTIES
        IMPORTED_LOCATION "${gzip_EXECUTABLE}"
    )
endif()

include(FeatureSummary)
set_package_properties(gzip PROPERTIES
    URL "https://www.gnu.org/software/gzip"
    DESCRIPTION "Data compression program for the gzip format"
)
sdk.dir=@ANDROID_SDK_ROOT@
rootProject.name = '@ARG_NAME@'
# SPDX-FileCopyrightText: 2014 Alex Merry <alex.merry@kde.org>
# SPDX-FileCopyrightText: 2013 Aleix Pol <aleixpol@kde.org>
# SPDX-FileCopyrightText: 2012-2013 Stephen Kelly <steveire@gmail.com>
# SPDX-FileCopyrightText: 2007 Matthias Kretz <kretz@kde.org>
# SPDX-FileCopyrightText: 2006-2007 Laurent Montel <montel@kde.org>
# SPDX-FileCopyrightText: 2006-2013 Alex Neundorf <neundorf@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
KDECMakeSettings
----------------

Changes various CMake settings to what the KDE community views as more
sensible defaults.

It is recommended to include this module with the ``NO_POLICY_SCOPE`` flag,
otherwise you may get spurious warnings with some versions of CMake.

It is split into three parts, which can be independently disabled if desired.

Runtime Paths
~~~~~~~~~~~~~

The default runtime path (used on Unix systems to search for
dynamically-linked libraries) is set to include the location that libraries
will be installed to (as set in ``LIB_INSTALL_DIR`` or, if the former is not set,
``KDE_INSTALL_LIBDIR``), and also the linker search path.

.. note::
  ``LIB_INSTALL_DIR`` or alternatively ``KDE_INSTALL_LIBDIR`` needs
  to be set before including this module.
  Typically, this is done by including the :kde-module:`KDEInstallDirs` module.

This section can be disabled by setting ``KDE_SKIP_RPATH_SETTINGS`` to ``TRUE``
before including this module.


Testing
~~~~~~~

Testing is enabled by default, and an option ``BUILD_TESTING`` is provided for
users to control this. See the CTest module documentation in the CMake manual
for more details.

This section can be disabled by setting ``KDE_SKIP_TEST_SETTINGS`` to ``TRUE``
before including this module.


Build Settings
~~~~~~~~~~~~~~

Various CMake build defaults are altered, such as searching source and build
directories for includes first, enabling automoc by default.

When ``find_package(ECM 5.38)`` or higher is called, this also selects
a layout for the build dir that helps running executables without installing:
all executables are built into a toplevel "bin" dir, making it possible to find
helper binaries, and to find uninstalled plugins (provided that you use
``kcoreaddons_add_plugin()`` or set ``LIBRARY_OUTPUT_DIRECTORY`` as documented on
https://community.kde.org/Guidelines_and_HOWTOs/Making_apps_run_uninstalled).

This section can be disabled by setting ``KDE_SKIP_BUILD_SETTINGS`` to ``TRUE``
before including this module.

This section also provides an ``uninstall`` target that can be individually
disabled by setting ``KDE_SKIP_UNINSTALL_TARGET`` to ``TRUE`` before including
this module.

By default on OS X, X11 and XCB related detections are disabled. However if
the need would arise to use these technologies, the detection can be enabled
by setting ``APPLE_FORCE_X11`` to ``ON``.

A warning is printed for the developer to know that the detection is disabled on OS X.
This message can be turned off by setting ``APPLE_SUPPRESS_X11_WARNING`` to ``ON``.

Since pre-1.0.0.

``ENABLE_CLAZY`` option is added (``OFF`` by default) when clang is being used.
Turning this option on will force clang to load the clazy plugins for richer
warnings on Qt-related code.

If clang is not being used, this won't have an effect.
See https://commits.kde.org/clazy?path=README.md

Since 5.17.0

- ``uninstall`` target functionality since 1.7.0
- ``APPLE_FORCE_X11`` option since 5.14.0 (detecting X11 was previously the default behavior)
- ``APPLE_SUPPRESS_X11_WARNING`` option since 5.14.0
- ``CMAKE_AUTORCC`` enabled by default when supported by CMake (>= 3.0) since 5.62.0

Translations (deprecated)
~~~~~~~~~~~~~~~~~~~~~~~~~
A fetch-translations target will be set up that will download translations
for projects using l10n.kde.org.

``KDE_L10N_BRANCH`` will be responsible for choosing which l10n branch to use
for the translations.

``KDE_L10N_AUTO_TRANSLATIONS`` (``OFF`` by default) will indicate whether translations
should be downloaded when building the project.

Since 5.34.0

``KDE_L10N_SYNC_TRANSLATIONS`` (``OFF`` by default) will download the translations at configuration
time instead of build time.

Since 5.50.0

All ``KDE_L10N_*`` options have been deprecated since 5.102.0, as translations
are meanwhile present inside the source code repositories.
#]=======================================================================]

################# RPATH handling ##################################

if(NOT KDE_SKIP_RPATH_SETTINGS)

   # Set the default RPATH to point to useful locations, namely where the
   # libraries will be installed and the linker search path

   # First look for the old LIB_INSTALL_DIR, then fallback to newer KDE_INSTALL_LIBDIR
   if(NOT LIB_INSTALL_DIR)
      if(NOT KDE_INSTALL_LIBDIR)
         message(FATAL_ERROR "Neither KDE_INSTALL_LIBDIR nor LIB_INSTALL_DIR is set. Setting one is necessary for using the RPATH settings.")
      else()
         set(_abs_LIB_INSTALL_DIR "${KDE_INSTALL_LIBDIR}")
      endif()
   else()
      set(_abs_LIB_INSTALL_DIR "${LIB_INSTALL_DIR}")
   endif()

   if (NOT IS_ABSOLUTE "${_abs_LIB_INSTALL_DIR}")
      set(_abs_LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/${_abs_LIB_INSTALL_DIR}")
   endif()

   if (UNIX)
      # for macOS: add install name dir in addition
      # check: is the rpath stuff below really required on macOS? at least it seems so to use a stock qt from qt.io
      if (APPLE)
         set(CMAKE_INSTALL_NAME_DIR ${_abs_LIB_INSTALL_DIR})
      endif ()

      # add our LIB_INSTALL_DIR to the RPATH (but only when it is not one of
      # the standard system link directories - such as /usr/lib on UNIX)
      list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${_abs_LIB_INSTALL_DIR}" _isSystemLibDir)
      list(FIND CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES      "${_abs_LIB_INSTALL_DIR}" _isSystemCxxLibDir)
      list(FIND CMAKE_C_IMPLICIT_LINK_DIRECTORIES        "${_abs_LIB_INSTALL_DIR}" _isSystemCLibDir)
      if("${_isSystemLibDir}" STREQUAL "-1"  AND  "${_isSystemCxxLibDir}" STREQUAL "-1"  AND  "${_isSystemCLibDir}" STREQUAL "-1")
         set(CMAKE_INSTALL_RPATH "${_abs_LIB_INSTALL_DIR}")
      endif()

      # Append directories in the linker search path (but outside the project)
      set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
   endif (UNIX)

endif()

################ Testing setup ####################################

find_program(APPSTREAMCLI appstreamcli)
function(appstreamtest)
    cmake_policy(PUSH)
    cmake_policy(SET CMP0064 NEW) # enable TEST operator
    if(TEST appstreamtest)
        # already configured
    elseif(APPSTREAMCLI)
        add_test(NAME appstreamtest COMMAND ${CMAKE_COMMAND} -DAPPSTREAMCLI=${APPSTREAMCLI} -DINSTALL_FILES=${CMAKE_BINARY_DIR}/install_manifest.txt -P ${CMAKE_CURRENT_LIST_DIR}/appstreamtest.cmake)
    else()
        message(STATUS "Could not set up the appstream test. appstreamcli is missing.")
    endif()
    cmake_policy(POP)
endfunction()

if(NOT KDE_SKIP_TEST_SETTINGS)

   # If there is a CTestConfig.cmake, include CTest.
   # Otherwise, there will not be any useful settings, so just
   # fake the functionality we care about from CTest.

   if (EXISTS ${CMAKE_SOURCE_DIR}/CTestConfig.cmake)
      include(CTest)
   else()
      option(BUILD_TESTING "Build the testing tree." ON)
      if(BUILD_TESTING)
         enable_testing()
         appstreamtest()
      endif ()
   endif ()

endif()



################ Build-related settings ###########################

if(NOT KDE_SKIP_BUILD_SETTINGS)

   # Always include srcdir and builddir in include path
   # This saves typing ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} in about every subdir
   # since cmake 2.4.0
   set(CMAKE_INCLUDE_CURRENT_DIR ON)

   # put the include dirs which are in the source or build tree
   # before all other include dirs, so the headers in the sources
   # are preferred over the already installed ones
   # since cmake 2.4.1
   set(CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE ON)

   # Add the src and build dir to the BUILD_INTERFACE include directories
   # of all targets. Similar to CMAKE_INCLUDE_CURRENT_DIR, but transitive.
   # Since CMake 2.8.11
   set(CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE ON)

   # When a shared library changes, but its includes do not, don't relink
   # all dependencies. It is not needed.
   # Since CMake 2.8.11
   set(CMAKE_LINK_DEPENDS_NO_SHARED ON)

   # Default to shared libs for KDE, if no type is explicitly given to add_library():
   set(BUILD_SHARED_LIBS TRUE CACHE BOOL "If enabled, shared libs will be built by default, otherwise static libs")

   # Enable automoc in cmake
   # Since CMake 2.8.6
   set(CMAKE_AUTOMOC ON)

   # Enable autorcc and in cmake so qrc files get generated.
   # Since CMake 3.0
   # TODO KF6: discuss enabling AUTOUIC and note porting requirements. autouic
   #   acts on all #include "ui_*.h" assuming *.ui exists
   set(CMAKE_AUTORCC ON)

   # By default, create 'GUI' executables. This can be reverted on a per-target basis
   # using ECMMarkNonGuiExecutable
   # Since CMake 2.8.8
   set(CMAKE_WIN32_EXECUTABLE ON)
   set(CMAKE_MACOSX_BUNDLE ON)

   # By default, don't put a prefix on MODULE targets. add_library(MODULE) is basically for plugin targets,
   # and in KDE plugins don't have a prefix.
   set(CMAKE_SHARED_MODULE_PREFIX "")

   unset(EXECUTABLE_OUTPUT_PATH)
   unset(LIBRARY_OUTPUT_PATH)
   unset(CMAKE_ARCHIVE_OUTPUT_DIRECTORY)
   unset(CMAKE_LIBRARY_OUTPUT_DIRECTORY)
   unset(CMAKE_RUNTIME_OUTPUT_DIRECTORY)

   # under Windows, output all executables and dlls into
   # one common directory, and all static|import libraries and plugins
   # into another one. This way test executables can find their dlls
   # even without installation.

   # We do the same under Unix to make it possible to run tests and apps without installing
   if (WIN32 OR ECM_GLOBAL_FIND_VERSION VERSION_GREATER_EQUAL 5.38.0)
       set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
       set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
       set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
   endif()

   # For Android we need to put shared libraries into "lib" for androiddeployqt to work without prior installation.
   # That fact that this conflicts with the above isn't really an issue, as we can't run things while cross-compiling
   # for Android anyway.
   if (ANDROID)
      set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
   endif()

   if (APPLE)
       # Disable detection of X11 and related package on OS X because when using
       # brew or macports, X11 can be installed and thus is detected.
       option(APPLE_FORCE_X11 "Force enable X11 related detection on OS X" OFF)
       option(APPLE_SUPPRESS_X11_WARNING "Suppress X11 and related technologies search disabling warning on OS X" OFF)

       if(NOT APPLE_FORCE_X11)
           if (NOT APPLE_SUPPRESS_X11_WARNING)
               message(WARNING "Searching for X11 and related technologies is disabled on Apple systems. Set APPLE_FORCE_X11 to ON to change this behaviour. Set APPLE_SUPPRESS_X11_WARNING to ON to hide this warning.")
           endif()
           set(CMAKE_DISABLE_FIND_PACKAGE_X11 true)
           set(CMAKE_DISABLE_FIND_PACKAGE_XCB true)
           set(CMAKE_DISABLE_FIND_PACKAGE_Qt5X11Extras true)
       endif()
    endif()

    option(KDE_SKIP_UNINSTALL_TARGET "Prevent an \"uninstall\" target from being generated." OFF)
   if(NOT KDE_SKIP_UNINSTALL_TARGET)
       include("${ECM_MODULE_DIR}/ECMUninstallTarget.cmake")
   endif()

endif()

if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
    option(ENABLE_CLAZY "Enable Clazy warnings" OFF)

    if(ENABLE_CLAZY)
        find_library(CLAZY_v1_5_FOUND ClazyPlugin${CMAKE_SHARED_LIBRARY_SUFFIX})
        if(CLAZY_v1_5_FOUND) # clazy >= 1.5
            set(CMAKE_CXX_COMPILE_OBJECT "${CMAKE_CXX_COMPILE_OBJECT} -Xclang -load -Xclang ClazyPlugin${CMAKE_SHARED_LIBRARY_SUFFIX} -Xclang -add-plugin -Xclang clazy")
        else() # clazy < 1.5
            set(CMAKE_CXX_COMPILE_OBJECT "${CMAKE_CXX_COMPILE_OBJECT} -Xclang -load -Xclang ClangLazy${CMAKE_SHARED_LIBRARY_SUFFIX} -Xclang -add-plugin -Xclang clang-lazy")
        endif()
    endif()
endif()

###################################################################
# Download translations

function(_repository_name reponame dir)
    execute_process(COMMAND git rev-parse --symbolic-full-name @{u}
        OUTPUT_VARIABLE upstream_ref
        RESULT_VARIABLE exitCode
        WORKING_DIRECTORY "${dir}")
    if(exitCode EQUAL 0)
        string(REGEX REPLACE "refs/remotes/([^/]+)/.*" "\\1" gitorigin "${upstream_ref}")
        message(DEBUG "Git upstream inferred as ${gitorigin}, upstream ref was ${upstream_ref}")
    else()
        set(gitorigin "origin")
        message(DEBUG "Assuming origin as the git remote as we are in detached mode")
    endif()

    execute_process(COMMAND git remote get-url --all "${gitorigin}"
        OUTPUT_VARIABLE giturl
        RESULT_VARIABLE exitCode
        WORKING_DIRECTORY "${dir}")

    if(exitCode EQUAL 0)
        message(DEBUG "Git URL inferred as ${giturl}")
        string(REGEX MATCHALL ".+kde\\.org[:\\/]([-A-Za-z0-9\\/]+)(.git)?\\s*" "" ${giturl})
        set(${reponame} ${CMAKE_MATCH_1})
        message(DEBUG "Repository inferred as ${${reponame}}")
    endif()

    if(NOT ${reponame})
        set(${reponame} ${CMAKE_PROJECT_NAME})
    endif()
    set(${reponame} ${${reponame}} PARENT_SCOPE)
endfunction()

if(NOT EXISTS ${CMAKE_SOURCE_DIR}/po AND NOT TARGET fetch-translations)
    option(KDE_L10N_AUTO_TRANSLATIONS "Automatically 'make fetch-translations`" OFF)
    option(KDE_L10N_SYNC_TRANSLATIONS "Fetch translations when KDECMakeSettings.cmake is processed." OFF)
    set(KDE_L10N_BRANCH "trunk" CACHE STRING "Branch from l10n.kde.org to fetch from: trunk | stable | lts | trunk_kde4 | stable_kde4")

    if(KDE_L10N_AUTO_TRANSLATIONS AND NOT KDE_L10N_SYNC_TRANSLATIONS)
        set(_EXTRA_ARGS "ALL")
    else()
        set(_EXTRA_ARGS)
    endif()

    set(_reponame "")
    _repository_name(_reponame "${CMAKE_SOURCE_DIR}")

    set(releaseme_clone_commands
        COMMAND git clone --depth 1 https://invent.kde.org/sdk/releaseme.git
    )
    add_custom_command(
        OUTPUT "${CMAKE_BINARY_DIR}/releaseme"
        ${releaseme_clone_commands}
        WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
        COMMENT "Fetching releaseme scripts to download translations..."
    )

    set(_l10n_po_dir "${CMAKE_BINARY_DIR}/po")
    set(_l10n_poqm_dir "${CMAKE_BINARY_DIR}/poqm")

    set(extra BYPRODUCTS ${_l10n_po_dir} ${_l10n_poqm_dir})

    set(fetch_commands
        COMMAND ruby "${CMAKE_BINARY_DIR}/releaseme/fetchpo.rb"
            --origin ${KDE_L10N_BRANCH}
            --project "${_reponame}"
            --output-dir "${_l10n_po_dir}"
            --output-poqm-dir "${_l10n_poqm_dir}"
            "${CMAKE_CURRENT_SOURCE_DIR}"
    )

    add_custom_target(fetch-translations ${_EXTRA_ARGS}
        COMMENT "Downloading translations for ${_reponame} branch ${KDE_L10N_BRANCH}..."
        COMMAND git -C "${CMAKE_BINARY_DIR}/releaseme" pull
        COMMAND cmake -E remove_directory ${_l10n_po_dir}
        COMMAND cmake -E remove_directory ${_l10n_poqm_dir}
        ${fetch_commands}
        ${extra}
        DEPENDS "${CMAKE_BINARY_DIR}/releaseme"
    )

    if (KDE_L10N_SYNC_TRANSLATIONS AND (NOT EXISTS ${_l10n_po_dir} OR NOT EXISTS ${_l10n_poqm_dir}))
        execute_process(${releaseme_clone_commands})
        execute_process(${fetch_commands})
    endif()
endif()
# SPDX-FileCopyrightText: 2019 Christoph Cullmann <cullmann@kde.org>
# SPDX-FileCopyrightText: 2021 Alexander Lohnau <alexander.lohnau@gmx.de>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
KDEClangFormat
--------------------

This module provides a functionality to format the source
code of your repository according to a predefined KDE
clang-format file.

This module provides the following function:

::

  kde_clang_format(<files>)

Using this function will create a clang-format target that will format all
``<files>`` passed to the function with the predefined KDE clang-format style.
To format the files you have to invoke the target with ``make clang-format`` or ``ninja clang-format``.
Once the project is formatted it is recommended to enforce the formatting using a pre-commit hook,
this can be done using :kde-module:`KDEGitCommitHooks`.

The ``.clang-format`` file from ECM will be copied to the source directory. This file should not be
added to version control. It is recommended to add it to the ``.gitignore`` file: ``/.clang-format``.

Since 5.79: If the source folder already contains a .clang-format file it is not overwritten.
Since version 5.80 this function is called by default in :kde-module:`KDEFrameworkCompilerSettings`. If directories should be excluded from
the formatting a .clang-format file with ``DisableFormat: true`` and ``SortIncludes: false`` should be created.

Example usage:

.. code-block:: cmake

  include(KDEClangFormat)
  file(GLOB_RECURSE ALL_CLANG_FORMAT_SOURCE_FILES *.cpp *.h *.hpp *.c)
  kde_clang_format(${ALL_CLANG_FORMAT_SOURCE_FILES})

To exclude directories from the formatting add a ``.clang-format``
file in the directory with the following contents:

.. code-block:: yaml

   DisableFormat: true
   SortIncludes: false

Since 5.64
#]=======================================================================]

# try to find clang-format in path
find_program(KDE_CLANG_FORMAT_EXECUTABLE clang-format)

# instantiate our clang-format file, must be in source directory for tooling if we have the tool
if(KDE_CLANG_FORMAT_EXECUTABLE)
    set(CLANG_FORMAT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/.clang-format)
    if (EXISTS ${CLANG_FORMAT_FILE})
        file(READ ${CLANG_FORMAT_FILE} CLANG_FORMAT_CONTENTS LIMIT 1000)
        string(FIND "${CLANG_FORMAT_CONTENTS}" "This file got automatically created by ECM, do not edit" matchres)
        if(${matchres} EQUAL -1)
            message(WARNING "The .clang-format file already exists. Please remove it in order to use the file provided by ECM")
        else()
            configure_file(${CMAKE_CURRENT_LIST_DIR}/clang-format.cmake ${CLANG_FORMAT_FILE} @ONLY)
        endif()
    else()
        configure_file(${CMAKE_CURRENT_LIST_DIR}/clang-format.cmake ${CLANG_FORMAT_FILE} @ONLY)
    endif()
endif()

# formatting target
function(KDE_CLANG_FORMAT)
    if (TARGET clang-format)
        # We can only define one clang-format target
        return()
    endif()

    # add target without specific commands first, we add the real calls file-per-file to avoid command line length issues and enable parallelization
    add_custom_target(clang-format COMMENT "Formatting sources in ${CMAKE_CURRENT_SOURCE_DIR} with ${KDE_CLANG_FORMAT_EXECUTABLE}...")

    # run clang-format only if available, else signal the user what is missing
    if(KDE_CLANG_FORMAT_EXECUTABLE)
        get_filename_component(_binary_dir ${CMAKE_BINARY_DIR} REALPATH)
        set(_ci_install_dir "${CMAKE_SOURCE_DIR}/_install") # on the KDE-CI, we install dependencies in-source
        foreach(_file ${ARGV})
            # check if the file is inside the build directory => ignore such files
            get_filename_component(_full_file_path ${_file} REALPATH)
            string(FIND ${_full_file_path} ${_binary_dir} _binary_idx)
            string(FIND ${_full_file_path} ${_ci_install_dir} _dependency_idx)
            if(NOT _binary_idx EQUAL 0 AND NOT _dependency_idx EQUAL 0)
                get_filename_component(_file_name ${_file} NAME)
                file(RELATIVE_PATH _rel_file_path ${CMAKE_SOURCE_DIR} ${_full_file_path})
                string(REPLACE "/" "_" unique_target_name "clang-format-${_rel_file_path}")
                string(REPLACE "%" "_" unique_target_name ${unique_target_name}) # some imvalid cmake target names
                string(REPLACE "{" "_" unique_target_name ${unique_target_name})
                string(REPLACE "}" "_" unique_target_name ${unique_target_name})
                add_custom_target(${unique_target_name}
                    DEPENDS ${_full_file_path}
                )
                add_custom_command(TARGET ${unique_target_name}
                    POST_BUILD
                    COMMAND ${KDE_CLANG_FORMAT_EXECUTABLE} -style=file -i ${_full_file_path}
                    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
                )
                add_dependencies(clang-format ${unique_target_name})
            endif()
        endforeach()
    else()
        add_custom_command(TARGET clang-format
            COMMAND
                ${CMAKE_COMMAND} -E echo "Could not set up the clang-format target as the clang-format executable is missing."
            )
    endif()
endfunction()
# SPDX-FileCopyrightText: 2014 Alex Merry <alex.merry@kde.org>
# SPDX-FileCopyrightText: 2013 Stephen Kelly <steveire@gmail.com>
# SPDX-FileCopyrightText: 2012-2013 Raphael Kubo da Costa <rakuco@FreeBSD.org>
# SPDX-FileCopyrightText: 2007 Matthias Kretz <kretz@kde.org>
# SPDX-FileCopyrightText: 2006-2007 Laurent Montel <montel@kde.org>
# SPDX-FileCopyrightText: 2006-2013 Alex Neundorf <neundorf@kde.org>
# SPDX-FileCopyrightText: 2021 Friedrich W. H. Kossebau <kossebau@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
KDECompilerSettings
-------------------

Set useful compile and link flags for C++ (and C) code.

Enables many more warnings than the default, and sets stricter modes
for some compiler features.  By default, exceptions are disabled;
``kde_target_enable_exceptions()`` can be used to re-enable them for a
specific target.

.. note::
  It is recommended to include this module with the ``NO_POLICY_SCOPE``
  flag, otherwise you may get spurious warnings with some versions of CMake.

Since 5.85 newer settings are controlled by a variable
``KDE_COMPILERSETTINGS_LEVEL``, taking an ECM version as value. That
version can not be greater than the minimum required ECM version.
The settings which are default at that version will then be used,
but can be overridden by more fine-grained controls (see respective settings).
This variable needs to be set before including this module, otherwise
defaults to the minimum required ECM version.

Modern code
~~~~~~~~~~~

The following CMake C standard default variables are set:

For ``KDE_COMPILERSETTINGS_LEVEL`` >= 5.85:

- ``CMAKE_C_STANDARD``: ``99``
- ``CMAKE_C_STANDARD_REQUIRED``: ``TRUE``
- ``CMAKE_C_EXTENSIONS``: ``OFF``

Otherwise:

- ``CMAKE_C_STANDARD``: ``90``
- ``CMAKE_C_STANDARD_REQUIRED``: not modified
- ``CMAKE_C_EXTENSIONS``: not modified

If the variable ``CMAKE_C_STANDARD`` is already set when including this module,
none of the above variables will be modified.

The following CMake C++ standard default variables are set:

For ``KDE_COMPILERSETTINGS_LEVEL`` >= 5.85:

- ``CMAKE_CXX_STANDARD``: ``17``
- ``CMAKE_CXX_STANDARD_REQUIRED``: ``TRUE``
- ``CMAKE_CXX_EXTENSIONS``: ``OFF``

Otherwise:

- ``CMAKE_CXX_STANDARD``: ``11``
- ``CMAKE_CXX_STANDARD_REQUIRED``: ``TRUE``
- ``CMAKE_CXX_EXTENSIONS``: not modified.

If the variable ``CMAKE_CXX_STANDARD`` is already set when including this module,
none of the above variables will be modified.


The following C++ compiler flags are set:

- ``-pedantic`` (GNU and Clang compilers, since 5.85)

  Can be disabled by setting ``KDE_SKIP_PEDANTIC_WARNINGS_SETTINGS`` to ``TRUE``
  before including this module (default is ``FALSE`` for
  ``KDE_COMPILERSETTINGS_LEVEL`` >= 5.85, ``TRUE`` otherwise).

- ``-Wmissing-include-dirs`` (GNU compilers, since 5.85)

  Can be disabled by setting ``KDE_SKIP_MISSING_INCLUDE_DIRS_WARNINGS_SETTINGS`` to ``TRUE``
  before including this module (default is ``FALSE`` for
  ``KDE_COMPILERSETTINGS_LEVEL`` >= 5.85, ``TRUE`` otherwise).

- ``-Wzero-as-null-pointer-constant`` (GNU and Clang compilers, since 5.85)

  Can be disabled by setting ``KDE_SKIP_NULLPTR_WARNINGS_SETTINGS`` to ``TRUE``
  before including this module (default is ``FALSE`` for
  ``KDE_COMPILERSETTINGS_LEVEL`` >= 5.85, ``TRUE`` otherwise).

- ``-Werror=undef`` (GNU and Clang compilers, since 5.96.0)

- Qt related preprocessor definitions (since 5.85.0):

  - ``-DQT_NO_CAST_TO_ASCII``
  - ``-DQT_NO_CAST_FROM_ASCII``
  - ``-DQT_NO_URL_CAST_FROM_STRING``
  - ``-DQT_NO_CAST_FROM_BYTEARRAY``
  - ``-DQT_USE_QSTRINGBUILDER``
  - ``-DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT``
  - ``-DQT_NO_KEYWORDS``
  - ``-DQT_NO_FOREACH``
  - ``-DQT_STRICT_ITERATORS``

    Strict iterators are not enabled on Windows, because they lead
    to a link error when application code iterates over a QVector<QPoint> for
    instance, unless Qt itself was also built with strict iterators.
    See example at https://bugreports.qt.io/browse/AUTOSUITE-946

  Can be controlled by setting ``KDE_QT_MODERNCODE_DEFINITIONS_LEVEL`` to the
  version of ECM where the wanted set of definitions has been added
  before including this module (default is ``KDE_COMPILERSETTINGS_LEVEL``).
  To disable individual definitions instead use ``remove_definitions()`` directly
  after including this module.

Functions
~~~~~~~~~

This module provides the following functions::

  kde_source_files_enable_exceptions([file1 [file2 [...]]])

Enables exceptions for specific source files.  This should not be
used on source files in a language other than C++.

::

  kde_target_enable_exceptions(target <INTERFACE|PUBLIC|PRIVATE>)

Enables exceptions for a specific target.  This should not be used
on a target that has source files in a language other than C++.

::

  kde_enable_exceptions()

Enables exceptions for C++ source files compiled for the
CMakeLists.txt file in the current directory and all subdirectories.

Variables
~~~~~~~~~

Inclusion of this module defines the following variables:

``ENABLE_BSYMBOLICFUNCTIONS``
    indicates whether we make use of ``-Bsymbolic-functions`` for linking.
    It ensures libraries bind global function references locally rather than
    at runtime.
    This option only has an effect on ELF-based systems.

    The option is disabled by default except when using
    :kde-module:`KDEFrameworkCompilerSettings` where it's enabled. Projects can enable
    it by calling ``set(ENABLE_BSYMBOLICFUNCTIONS ON)`` or passing
    ``-DENABLE BSYMBOLICFUNCTIONS=ON`` when configuring the build directory.

    Since 5.85

Example usages:

.. code-block:: cmake

  # needing some macro/feature only available with ECM 5.80.0
  find_package(ECM 5.80.0 NO_MODULE)

  # requiring ECM 5.80.0 above will default KDE_COMPILERSETTINGS_LEVEL also to 5.80.0,
  # thus not activate any newer settings
  include(KDECompilerSettings NO_POLICY_SCOPE)

.. code-block:: cmake

  # needing some macro/feature only available with ECM 5.87.0
  find_package(ECM 5.87.0 NO_MODULE)

  # project uses settings default as of KDECompilerSettings in ECM 5.85.0
  set(KDE_COMPILERSETTINGS_LEVEL 5.85.0)
  include(KDECompilerSettings NO_POLICY_SCOPE)

.. code-block:: cmake

  # needing some macro/feature only available with ECM 5.87.0
  find_package(ECM 5.87.0 NO_MODULE)

  # project mainly uses settings default as of KDECompilerSettings in ECM 5.85.0
  # with some small twisting
  set(KDE_COMPILERSETTINGS_LEVEL 5.85.0)
  # not ready yet for pedantic compilers
  set(KDE_SKIP_PEDANTIC_WARNINGS_SETTINGS TRUE)
  # avoid any Qt definitions
  set(KDE_QT_MODERNCODE_DEFINITIONS_LEVEL 5.84.0)
  include(KDECompilerSettings NO_POLICY_SCOPE)

.. code-block:: cmake

  # needing some macro/feature only available with ECM 5.85.0
  find_package(ECM 5.85.0 NO_MODULE)

  # requiring ECM 5.85.0 above will default KDE_COMPILERSETTINGS_LEVEL also to 5.85.0,
  # which again defaults KDE_QT_MODERNCODE_DEFINITIONS_LEVEL also to 5.85.0
  include(KDECompilerSettings NO_POLICY_SCOPE)
  # project is fine with almost all added Qt definitions as of 5.85.0, but not these ones:
  remove_definitions(
      -DQT_NO_KEYWORDS
      -DQT_NO_FOREACH
  )

Since pre-1.0.0.
#]=======================================================================]

############################################################
# Select and check KDE_COMPILERSETTINGS_LEVEL
# For a specified version of KDE_COMPILERSETTINGS_LEVEL always the same set
# of settings needs to be used, to give that version a meaning, even more as
# the settings are usually more strict and can break builds which build fine
# without the setting.
# As at the time of version x it is usually unknown what future versions x+y
# will offer as settings, the minimum required version of ECM sets the upper
# limit then for the level version.
if(NOT DEFINED KDE_COMPILERSETTINGS_LEVEL)
    set(KDE_INTERNAL_COMPILERSETTINGS_LEVEL "${ECM_GLOBAL_FIND_VERSION}")
else()
    if(KDE_COMPILERSETTINGS_LEVEL VERSION_GREATER "${ECM_GLOBAL_FIND_VERSION}")
        message(FATAL_ERROR "KDE_COMPILERSETTINGS_LEVEL (${KDE_COMPILERSETTINGS_LEVEL}) cannot be newer than the min. required ECM version (${ECM_GLOBAL_FIND_VERSION}).")
    endif()
    set(KDE_INTERNAL_COMPILERSETTINGS_LEVEL "${KDE_COMPILERSETTINGS_LEVEL}")
endif()

include("${ECM_MODULE_DIR}/ECMSourceVersionControl.cmake")

############################################################
# Default build type
# If no build type was specified, default to using a debug build if the
# source directory is a git clone.
# Otherwise, leave it empty, to let distro packagers choose the flags.
############################################################
if (ECM_SOURCE_UNDER_VERSION_CONTROL AND NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
    set(default_build_type "Debug")
    message(STATUS "Setting build type to '${default_build_type}' as none was specified.")
    set_property(CACHE CMAKE_BUILD_TYPE PROPERTY VALUE "${default_build_type}")
    # Set the possible values of build type for cmake-gui
    set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
        "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()

############################################################
# Toolchain minimal requirements
#
# Note that only compilers officially supported by Qt are
# supported by this file; workarounds for older compilers
# will generally not be included.  See
# https://qt-project.org/doc/qt-5/supported-platforms.html
# and
# https://community.kde.org/Frameworks/Policies#Frameworks_compiler_requirements_and_C.2B.2B11
# for more details.
############################################################

macro(_kde_compiler_min_version min_version)
    if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${min_version})
        message(WARNING "Version ${CMAKE_CXX_COMPILER_VERSION} of the ${CMAKE_CXX_COMPILER_ID} C++ compiler is not supported. Please use version ${min_version} or later.")
    endif()
endmacro()

if (MSVC)
    # MSVC_VERSION 1600 = VS 10.0 = Windows SDK 7
    # See: cmake --help-variable MSVC_VERSION
    # and https://developer.mozilla.org/en-US/docs/Windows_SDK_versions
    if (${MSVC_VERSION} LESS 1600)
        message(WARNING "Your MSVC version (${MSVC_VERSION}) is not supported. Please use the Windows SDK version 7 or later (or Microsoft Visual Studio 2010 or later).")
    endif()
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
    if (WIN32)
        _kde_compiler_min_version("4.7")
    elseif (APPLE)
        # FIXME: Apple heavily modifies GCC, so checking the
        # GCC version on OS/X is not very useful.
    else()
        _kde_compiler_min_version("4.5")
    endif()
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
    _kde_compiler_min_version("3.1")
else()
    message(WARNING "${CMAKE_CXX_COMPILER_ID} is not a supported C++ compiler.")
endif()



############################################################
# System API features
############################################################

# This macro is for adding definitions that affect the underlying
# platform API.  It makes sure that configure checks will also have
# the same defines, so that the checks match compiled code.
macro (_KDE_ADD_PLATFORM_DEFINITIONS)
    add_definitions(${ARGV})
    set(CMAKE_REQUIRED_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} ${ARGV})
endmacro()

include(CheckSymbolExists)
check_symbol_exists("__GLIBC__" "stdlib.h" LIBC_IS_GLIBC)
if (LIBC_IS_GLIBC)
    # Enable everything in GNU libc.  Any code using non-portable features
    # needs to perform feature tests, but this ensures that any such features
    # will be found if they exist.
    #
    # NB: we do NOT define _BSD_SOURCE, as with GNU libc that requires linking
    # against the -lbsd-compat library (it changes the behaviour of some
    # functions).  This, however, means that strlcat and strlcpy are not
    # provided by glibc.
    _kde_add_platform_definitions(-D_GNU_SOURCE)
endif ()

if (UNIX)
    # Enable extra API for using 64-bit file offsets on 32-bit systems.
    # FIXME: this is included in _GNU_SOURCE in glibc; do other libc
    # implementation recognize it?
    _kde_add_platform_definitions(-D_LARGEFILE64_SOURCE)

    include(CheckCXXSourceCompiles)

    # By default (in glibc, at least), on 32bit platforms off_t is 32 bits,
    # which causes a SIGXFSZ when trying to manipulate files larger than 2Gb
    # using libc calls (note that this issue does not occur when using QFile).
    check_cxx_source_compiles("
#include <sys/types.h>
 /* Check that off_t can represent 2**63 - 1 correctly.
    We can't simply define LARGE_OFF_T to be 9223372036854775807,
    since some C++ compilers masquerading as C compilers
    incorrectly reject 9223372036854775807.  */
#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
  int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1];
  int main() { return 0; }
" _OFFT_IS_64BIT)

    if (NOT _OFFT_IS_64BIT)
        _kde_add_platform_definitions(-D_FILE_OFFSET_BITS=64)
    endif ()
endif()

if (WIN32)
    # Speeds up compile times by not including everything with windows.h
    # See http://msdn.microsoft.com/en-us/library/windows/desktop/aa383745%28v=vs.85%29.aspx
    _kde_add_platform_definitions(-DWIN32_LEAN_AND_MEAN)

    if (KDE_INTERNAL_COMPILERSETTINGS_LEVEL VERSION_GREATER_EQUAL 5.240.0 OR QT_MAJOR_VERSION STREQUAL "6")
        # Target Windows 10
        # This enables various bits of new API
        # See http://msdn.microsoft.com/en-us/library/windows/desktop/aa383745%28v=vs.85%29.aspx
        # Windows 10 is the default by Qt6 hence we do not need the next line, but we keep it disabled
        # to not to start from scratch in case we want to target a different version in the future
        # _kde_add_platform_definitions(-D_WIN32_WINNT=0x0A00 -DWINVER=0x0A00 -D_WIN32_IE=0x0A00)
    else()
        # Target Windows Vista
        # This enables various bits of new API
        # See http://msdn.microsoft.com/en-us/library/windows/desktop/aa383745%28v=vs.85%29.aspx
        _kde_add_platform_definitions(-D_WIN32_WINNT=0x0600 -DWINVER=0x0600 -D_WIN32_IE=0x0600)
    endif()

    # Use the Unicode versions of Windows API by default
    # See http://msdn.microsoft.com/en-us/library/windows/desktop/dd317766%28v=vs.85%29.aspx
    _kde_add_platform_definitions(-DUNICODE -D_UNICODE)

    # As stated in http://msdn.microsoft.com/en-us/library/4hwaceh6.aspx M_PI only gets defined
    # if _USE_MATH_DEFINES is defined, with mingw this has a similar effect as -D_GNU_SOURCE on math.h
    _kde_add_platform_definitions(-D_USE_MATH_DEFINES)

    # Don't define MIN and MAX in windows.h
    # the defines break the use of std::max
    _kde_add_platform_definitions(-DNOMINMAX)
endif()



############################################################
# Language and toolchain features
############################################################

# Pick sensible versions of the C and C++ standards.
if (NOT CMAKE_C_STANDARD)
    if (KDE_INTERNAL_COMPILERSETTINGS_LEVEL VERSION_GREATER_EQUAL 5.85.0)
        set(CMAKE_C_STANDARD 99)
        set(CMAKE_C_STANDARD_REQUIRED TRUE)
        set(CMAKE_C_EXTENSIONS OFF)
    else()
        set(CMAKE_C_STANDARD 90)
    endif()
endif()
if (NOT CMAKE_CXX_STANDARD)
    if (KDE_INTERNAL_COMPILERSETTINGS_LEVEL VERSION_GREATER_EQUAL 5.85.0)
        set(CMAKE_CXX_STANDARD 17)
        set(CMAKE_CXX_EXTENSIONS OFF)
    else()
        set(CMAKE_CXX_STANDARD 11)
    endif()
    set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
endif()

# Do not merge uninitialized global variables.
# This is mostly a "principle of least surprise" thing, but also
# has performance benefits.
# See https://www.ibm.com/developerworks/community/blogs/zTPF/entry/benefits_of_the_fnocommon_compile_option_peter_lemieszewski?lang=en
# Note that this only applies to C code; C++ already behaves like this.
if (CMAKE_C_COMPILER_ID STREQUAL "GNU" OR
        CMAKE_C_COMPILER_ID MATCHES "Clang" OR
        (CMAKE_C_COMPILER_ID STREQUAL "Intel" AND NOT WIN32))
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-common")
endif()

# Do not treat the operator name keywords and, bitand, bitor, compl, not, or and xor as synonyms as keywords.
# They're not supported under Visual Studio out of the box thus using them limits the portability of code
if (CMAKE_C_COMPILER_ID STREQUAL "GNU" OR
        CMAKE_C_COMPILER_ID MATCHES "Clang" OR
        (CMAKE_C_COMPILER_ID STREQUAL "Intel" AND NOT WIN32))
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-operator-names")
endif()

# Default to hidden visibility for symbols
set(CMAKE_C_VISIBILITY_PRESET hidden)
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
set(CMAKE_VISIBILITY_INLINES_HIDDEN 1)
if (POLICY CMP0063)
    # No sane project should be affected by CMP0063, so suppress the warnings
    # generated by the above visibility settings in CMake >= 3.3
    cmake_policy(SET CMP0063 NEW)
endif()

if (UNIX AND NOT APPLE AND NOT CYGWIN)
    # Enable adding DT_RUNPATH, which means that LD_LIBRARY_PATH takes precedence
    # over the built-in rPath
    set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--enable-new-dtags ${CMAKE_SHARED_LINKER_FLAGS}")
    set(CMAKE_MODULE_LINKER_FLAGS "-Wl,--enable-new-dtags ${CMAKE_MODULE_LINKER_FLAGS}")
    set(CMAKE_EXE_LINKER_FLAGS    "-Wl,--enable-new-dtags ${CMAKE_EXE_LINKER_FLAGS}")
endif()

if (CMAKE_SYSTEM_NAME STREQUAL GNU)
    # Enable multithreading with the pthread library
    # FIXME: Is this actually necessary to have here?
    #        Can CMakeLists.txt files that require it use FindThreads.cmake
    #        instead?
    set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -pthread")
    set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -pthread")
endif()

if (MSVC)
    # Our source files are UTF-8 encoded, and assuming that is also the
    # default behavior of GCC/Clang. Not so for MSVC though, so force
    # that to UTF-8 explicitly, as that will otherwise cause compile-time
    # and runtime issues when dealing with string literals outside of 7-bit ASCII.
    add_compile_options(/utf-8)
endif()


############################################################
# Turn off exceptions by default
#
# This involves enough code to be separate from the
# previous section.
############################################################

# TODO: Deal with QT_NO_EXCEPTIONS for non-gnu compilers?
#       This should be defined if and only if exceptions are disabled.
#       qglobal.h has some magic to set it when exceptions are disabled
#       with gcc, but other compilers are unaccounted for.

# Turn off exceptions by default
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions")
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions")
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Intel" AND NOT WIN32)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions")
#elseif (MSVC OR (WIN32 AND CMAKE_CXX_COMPILER_ID STREQUAL "Intel"))
    # Exceptions appear to be disabled by default for MSVC
    # http://msdn.microsoft.com/en-us/library/1deeycx5.aspx

    # FIXME: are exceptions disabled by default for Intel?
endif()

macro(_kdecompilersettings_append_exception_flag VAR)
    if (MSVC)
        set(${VAR} "${${VAR}} -EHsc")
    elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
        if (WIN32)
            set(${VAR} "${${VAR}} -EHsc")
        else()
            set(${VAR} "${${VAR}} -fexceptions")
        endif()
    elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
        set(${VAR} "${${VAR}} -fexceptions")
    elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
        set(${VAR} "${${VAR}} -fexceptions")
    endif()
    string(STRIP "${${VAR}}" ${VAR})
endmacro()

function(KDE_SOURCE_FILES_ENABLE_EXCEPTIONS)
    foreach(source_file ${ARGV})
        get_source_file_property(flags ${source_file} COMPILE_FLAGS)
        if(NOT flags)
            # If COMPILE_FLAGS is not set, get_source_file_property() sets it to
            # NOTFOUND, which breaks build if we concatenate anything to
            # the "NOTFOUND" string.
            # Note that NOTFOUND evaluates to False, so we do enter the if.
            set(flags "")
        endif()
        _kdecompilersettings_append_exception_flag(flags)
        set_source_files_properties(${source_file} COMPILE_FLAGS "${flags}")
    endforeach()
endfunction()

function(KDE_TARGET_ENABLE_EXCEPTIONS target mode)
    target_compile_options(${target} ${mode} "$<$<CXX_COMPILER_ID:MSVC>:-EHsc>")
    if (WIN32)
        target_compile_options(${target} ${mode} "$<$<CXX_COMPILER_ID:Intel>:-EHsc>")
    else()
        target_compile_options(${target} ${mode} "$<$<CXX_COMPILER_ID:Intel>:-fexceptions>")
    endif()
    target_compile_options(${target} ${mode}
        "$<$<OR:$<CXX_COMPILER_ID:GNU>,$<CXX_COMPILER_ID:Clang>,$<CXX_COMPILER_ID:AppleClang>>:-fexceptions>")
endfunction()

function(KDE_ENABLE_EXCEPTIONS)
    # We set CMAKE_CXX_FLAGS, rather than add_compile_options(), because
    # we only want to affect the compilation of C++ source files.

    # strip any occurrences of -DQT_NO_EXCEPTIONS; this should only be defined
    # if exceptions are disabled
    # the extra spaces mean we will not accentially mangle any other options
    string(REPLACE " -DQT_NO_EXCEPTIONS " " " CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} ")
    # this option is common to several compilers, so just always remove it
    string(REPLACE " -fno-exceptions " " " CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
    # strip undoes the extra spaces we put in above
    string(STRIP "${CMAKE_CXX_FLAGS}" CMAKE_CXX_FLAGS)

    _kdecompilersettings_append_exception_flag(CMAKE_CXX_FLAGS)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}" PARENT_SCOPE)
endfunction()



############################################################
# Better diagnostics (warnings, errors)
############################################################

if ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT APPLE) OR
        (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND NOT APPLE) OR
        (CMAKE_CXX_COMPILER_ID STREQUAL "Intel" AND NOT WIN32))
    # Linker warnings should be treated as errors
    set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--fatal-warnings ${CMAKE_SHARED_LINKER_FLAGS}")
    set(CMAKE_MODULE_LINKER_FLAGS "-Wl,--fatal-warnings ${CMAKE_MODULE_LINKER_FLAGS}")

    string(TOUPPER "CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}" compileflags)
    if("${CMAKE_CXX_FLAGS} ${${compileflags}}" MATCHES "-fsanitize")
        set(sanitizers_enabled TRUE)
    else()
        set(sanitizers_enabled FALSE)
    endif()

    # Do not allow undefined symbols, even in non-symbolic shared libraries
    # On OpenBSD we must disable this to allow the stuff to properly compile without explicit libc specification
    if (NOT CMAKE_SYSTEM_NAME MATCHES "OpenBSD" AND (NOT sanitizers_enabled OR NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
        set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--no-undefined ${CMAKE_SHARED_LINKER_FLAGS}")
        set(CMAKE_MODULE_LINKER_FLAGS "-Wl,--no-undefined ${CMAKE_MODULE_LINKER_FLAGS}")
    endif()
endif()

set(_KDE_GCC_COMMON_WARNING_FLAGS "-Wall -Wextra -Wcast-align -Wchar-subscripts -Wformat-security -Wno-long-long -Wpointer-arith -Wundef")
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
    # -Wgnu-zero-variadic-macro-arguments (part of -pedantic) is triggered by every qCDebug() call and therefore results
    # in a lot of noise. This warning is only notifying us that clang is emulating the GCC behaviour
    # instead of the exact standard wording so we can safely ignore it
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-gnu-zero-variadic-macro-arguments")
endif()
if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang")
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${_KDE_GCC_COMMON_WARNING_FLAGS} -Wmissing-format-attribute -Wwrite-strings")
    # Make some warnings errors
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror=implicit-function-declaration")
endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${_KDE_GCC_COMMON_WARNING_FLAGS} -Wnon-virtual-dtor -Woverloaded-virtual")
    # Make some warnings errors
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=return-type -Werror=init-self")
    if (KDE_INTERNAL_COMPILERSETTINGS_LEVEL VERSION_GREATER_EQUAL 5.96.0)
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=undef")
    endif()
elseif(MSVC)
  # similar to -Werror=return-type
  # https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-1-c4715?view=msvc-170
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /we4715")
endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR
    (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 3.5))
    # -Wvla: use of variable-length arrays (an extension to C++)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wvla")
endif()
if ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 5.0) OR
    (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 3.5))
    include(CheckCXXCompilerFlag)
    check_cxx_compiler_flag(-Wdate-time HAVE_DATE_TIME)
    if (HAVE_DATE_TIME)
        # -Wdate-time: warn if we use __DATE__ or __TIME__ (we want to be able to reproduce the exact same binary)
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wdate-time")
    endif()
endif()

if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
   if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 5.0.0)
      set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsuggest-override -Wlogical-op" )
   endif()
endif()

# -w1 turns on warnings and errors
# FIXME: someone needs to have a closer look at the Intel compiler options
if (CMAKE_C_COMPILER_ID STREQUAL "Intel" AND NOT WIN32)
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -w1 -Wpointer-arith")
endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL "Intel" AND NOT WIN32)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -w1 -Wpointer-arith")
endif()

if (MSVC)
    # enable linter like warnings including deprecation warnings
    # https://learn.microsoft.com/en-us/cpp/build/reference/compiler-option-warning-level?view=msvc-170
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W3")
    # Disable warnings:
    # C4250: 'class1' : inherits 'class2::member' via dominance
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4250")
    # C4251: 'identifier' : class 'type' needs to have dll-interface to be
    #        used by clients of class 'type2'
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4251")
    # C4396: 'identifier' : 'function' the inline specifier cannot be used
    #        when a friend declaration refers to a specialization of a
    #        function template
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4396")
    # C4661: 'identifier' : no suitable definition provided for explicit
    #         template instantiation request
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4661")

    if (CMAKE_CXX_STANDARD GREATER_EQUAL 11)
        # Ensure __cplusplus is correct, otherwise it defaults to 199711L which isn't true
        # https://docs.microsoft.com/en-us/cpp/build/reference/zc-cplusplus?view=msvc-160
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zc:__cplusplus")
    endif()
endif()

option(ENABLE_BSYMBOLICFUNCTIONS "Make use of -Bsymbolic-functions" OFF)
if (ENABLE_BSYMBOLICFUNCTIONS)
    set(_SYMBOLIC_FUNCTIONS_COMPILER_OPTION "-Wl,-Bsymbolic-functions")
    list(APPEND CMAKE_REQUIRED_LIBRARIES "${_SYMBOLIC_FUNCTIONS_COMPILER_OPTION}")

    include(CheckCXXSourceCompiles)

    check_cxx_source_compiles( "int main () { return 0; }" BSYMBOLICFUNCTIONS_AVAILABLE )
    list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES "${_SYMBOLIC_FUNCTIONS_COMPILER_OPTION}")
    if (BSYMBOLICFUNCTIONS_AVAILABLE)
        set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${_SYMBOLIC_FUNCTIONS_COMPILER_OPTION}")
        set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${_SYMBOLIC_FUNCTIONS_COMPILER_OPTION}")
    endif()
endif()

if (WIN32)
    # Disable deprecation warnings for some API
    # FIXME: do we really want this?
    add_definitions(-D_CRT_SECURE_NO_DEPRECATE
                    -D_CRT_SECURE_NO_WARNINGS
                    -D_CRT_NONSTDC_NO_DEPRECATE
                    -D_SCL_SECURE_NO_WARNINGS
                   )
endif()

if (APPLE)
    #full Single Unix Standard v3 (SUSv3) conformance (the Unix API)
    _kde_add_platform_definitions(-D_DARWIN_C_SOURCE)
    #Cocoa is unconditional since we only support OS X 10.6 and above
    _kde_add_platform_definitions(-DQT_MAC_USE_COCOA)
endif()

############################################################
# Modern code
############################################################

function(_kde_set_default_skip_variable_by_min_ecm _var_name _ecm_version)
    if(NOT DEFINED ${_var_name})
        if (KDE_INTERNAL_COMPILERSETTINGS_LEVEL VERSION_LESS ${_ecm_version})
            set(${_var_name} TRUE PARENT_SCOPE)
        else()
            set(${_var_name} FALSE PARENT_SCOPE)
        endif()
    endif()
endfunction()

if(NOT DEFINED KDE_QT_MODERNCODE_DEFINITIONS_LEVEL)
    set(KDE_INTERNAL_QT_MODERNCODE_DEFINITIONS_LEVEL ${KDE_INTERNAL_COMPILERSETTINGS_LEVEL})
else()
    set(KDE_INTERNAL_QT_MODERNCODE_DEFINITIONS_LEVEL ${KDE_QT_MODERNCODE_DEFINITIONS_LEVEL})
endif()

if (KDE_INTERNAL_QT_MODERNCODE_DEFINITIONS_LEVEL VERSION_GREATER_EQUAL "5.85.0")
    add_definitions(
        -DQT_NO_CAST_TO_ASCII
        -DQT_NO_CAST_FROM_ASCII
        -DQT_NO_URL_CAST_FROM_STRING
        -DQT_NO_CAST_FROM_BYTEARRAY
        -DQT_USE_QSTRINGBUILDER
        -DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT
        -DQT_NO_KEYWORDS
        -DQT_NO_FOREACH
    )
    if (NOT WIN32)
        # Strict iterators can't be used on Windows, they lead to a link error
        # when application code iterates over a QVector<QPoint> for instance, unless
        # Qt itself was also built with strict iterators.
        # See example at https://bugreports.qt.io/browse/AUTOSUITE-946
        add_definitions(-DQT_STRICT_ITERATORS)
    endif()
endif()

_kde_set_default_skip_variable_by_min_ecm(KDE_SKIP_PEDANTIC_WARNINGS_SETTINGS "5.85.0")

if (NOT KDE_SKIP_PEDANTIC_WARNINGS_SETTINGS)
    if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic")
    endif()
endif()

_kde_set_default_skip_variable_by_min_ecm(KDE_SKIP_NULLPTR_WARNINGS_SETTINGS "5.85.0")

if (NOT KDE_SKIP_NULLPTR_WARNINGS_SETTINGS)
    if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
        if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "5.0.0")
            set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wzero-as-null-pointer-constant" )
        endif()
    endif()

    if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
        if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "5.0.0")
            set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wzero-as-null-pointer-constant" )
        endif()
    endif()
endif()

_kde_set_default_skip_variable_by_min_ecm(KDE_SKIP_MISSING_INCLUDE_DIRS_WARNINGS_SETTINGS "5.85.0")

if (NOT KDE_SKIP_MISSING_INCLUDE_DIRS_WARNINGS_SETTINGS)
    if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wmissing-include-dirs")
    endif()
endif()

############################################################
# Hacks
#
# Anything in this section should be thoroughly documented,
# including what problems it is supposed to fix and in what
# circumstances those problems occur.  Include links to any
# relevant bug reports.
############################################################

if (APPLE)
    # FIXME: why are these needed?  The commit log is unhelpful
    # (it was introduced in svn path=/trunk/KDE/kdelibs/; revision=503025 -
    # kdelibs git commit 4e4cb9cb9a2216b63d3eabf88b8fe94ee3c898cf -
    # with the message "mac os x fixes for the cmake build")
    set (CMAKE_SHARED_LINKER_FLAGS "-single_module -multiply_defined suppress ${CMAKE_SHARED_LINKER_FLAGS}")
    set (CMAKE_MODULE_LINKER_FLAGS "-multiply_defined suppress ${CMAKE_MODULE_LINKER_FLAGS}")
endif()

if (MINGW AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
    # This was copied from the Phonon build settings, where it had the comment
    # "otherwise undefined symbol in phononcore.dll errors occurs", with the commit
    # message "set linker flag --export-all-symbols for all targets, otherwise
    # some depending targets could not be build"
    # FIXME: do our export macros not deal with this properly?
    set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--export-all-symbols")
    set (CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,--export-all-symbols")
endif()

if (CMAKE_GENERATOR STREQUAL "Ninja" AND
    ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 4.9) OR
     (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 3.5)))
    # Force colored warnings in Ninja's output, if the compiler has -fdiagnostics-color support.
    # Rationale in https://github.com/ninja-build/ninja/issues/814
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color=always")
endif()

include("${ECM_MODULE_DIR}/ECMEnableSanitizers.cmake")
include("${ECM_MODULE_DIR}/ECMCoverageOption.cmake")

############################################################
# Clean-up
############################################################
# unset again, to not leak into caller scope and avoid usage there
set(KDE_INTERNAL_COMPILERSETTINGS_LEVEL)
set(KDE_INTERNAL_QT_MODERNCODE_DEFINITIONS_LEVEL)
# SPDX-FileCopyrightText: 2013 Albert Astals Cid <aacid@kde.org>
# SPDX-FileCopyrightText: 2007 Matthias Kretz <kretz@kde.org>
# SPDX-FileCopyrightText: 2006-2007 Laurent Montel <montel@kde.org>
# SPDX-FileCopyrightText: 2006-2013 Alex Neundorf <neundorf@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[
Backward-compatibility support
------------------------------

For all the non-KF projects which reused the KDEFrameworkCompilerSettings
module to get more strict settings.

Kept as is, to be removed on next backward-compatibility-breakage occasion.
#]=======================================================================]

if (NOT CMAKE_CXX_STANDARD)
    if (ECM_GLOBAL_FIND_VERSION VERSION_GREATER_EQUAL 5.84.0)
        set(CMAKE_CXX_STANDARD 17)
        set(CMAKE_CXX_STANDARD_REQUIRED ON)
        set(CMAKE_CXX_EXTENSIONS OFF)
    endif()
endif()

include(KDECompilerSettings NO_POLICY_SCOPE)

add_definitions(-DQT_NO_CAST_TO_ASCII
                -DQT_NO_CAST_FROM_ASCII
                -DQT_NO_URL_CAST_FROM_STRING
                -DQT_NO_CAST_FROM_BYTEARRAY
                -DQT_USE_QSTRINGBUILDER
                -DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT
               )

if (NOT WIN32)
    # Strict iterators can't be used on Windows, they lead to a link error
    # when application code iterates over a QVector<QPoint> for instance, unless
    # Qt itself was also built with strict iterators.
    # See example at https://bugreports.qt.io/browse/AUTOSUITE-946
    add_definitions(-DQT_STRICT_ITERATORS)
endif()

# Some non-KF projects make (ab)use of KDEFrameworkCompilerSettings currently,
# let them only hit this as well when bumping their min. ECM requirement to a newer version.
if (ECM_GLOBAL_FIND_VERSION VERSION_GREATER_EQUAL 5.79.0)
    add_definitions(
        -DQT_NO_KEYWORDS
        -DQT_NO_FOREACH
    )
else()
    add_definitions(-DQT_NO_SIGNALS_SLOTS_KEYWORDS)
endif()

add_definitions(
    -DQT_DEPRECATED_WARNINGS_SINCE=0x060000
    -DKF_DEPRECATED_WARNINGS_SINCE=0x060000
)

if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic")
endif()

if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
   if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 5.0.0)
      set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wzero-as-null-pointer-constant" )
   endif()
endif()

if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
   if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 5.0.0)
      set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wzero-as-null-pointer-constant" )
   endif()
endif()

if (ECM_GLOBAL_FIND_VERSION VERSION_GREATER_EQUAL 5.80.0)
    include(KDEClangFormat)
    # add clang-format target
    file(GLOB_RECURSE ALL_CLANG_FORMAT_SOURCE_FILES *.cpp *.h *.hpp *.c)
    kde_clang_format(${ALL_CLANG_FORMAT_SOURCE_FILES})
endif ()
# SPDX-FileCopyrightText: 2013 Albert Astals Cid <aacid@kde.org>
# SPDX-FileCopyrightText: 2007 Matthias Kretz <kretz@kde.org>
# SPDX-FileCopyrightText: 2006-2007 Laurent Montel <montel@kde.org>
# SPDX-FileCopyrightText: 2006-2013 Alex Neundorf <neundorf@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
KDEFrameworkCompilerSettings
----------------------------

Set stricter compile and link flags for KDE Frameworks modules.

.. warning::
   Do not use this module for software which is not part of KDE-Frameworks.
   There is no guarantee for backward-compatibility in newer versions.

The :kde-module:`KDECompilerSettings` module is included and, in addition, various
defines that affect the Qt libraries are set to enforce certain
conventions.

For example, constructions like ``QString("foo")`` are prohibited, instead
forcing the use of QLatin1String or QStringLiteral, and some
Qt-defined keywords like signals and slots will not be defined.

.. note::
  It is recommended to include this module with the NO_POLICY_SCOPE
  flag, otherwise you may get spurious warnings with some versions of CMake.

Since pre-1.0.0.
#]=======================================================================]

# No-one else should be using this module, at least by the time when requiring
# ECM 5.85 as minimum, where also settings levels had been introduced for
# KDECompilerSettings to satisfy the needs for stricter out-of-the-box
# settings.
# So making a clear cut here by that condition and providing backward-compat
# support from a separate file with the old code, avoiding the need for
# further if()-else() when changing the settings for current KDE Frameworks.
if (ECM_GLOBAL_FIND_VERSION VERSION_LESS 5.85.0)
    include(KDEFrameworkCompilerLegacySettings NO_POLICY_SCOPE)
    return()
endif()

# set ENABLE_BSYMBOLICFUNCTIONS default to ON when possible
# TODO: find a nice way to set an option default
# we can only use symbolic functions when everything is built with that
# otherwise we'll break function pointer based connects and method lookups
include(${CMAKE_CURRENT_LIST_DIR}/../modules/QtVersionOption.cmake)
if (QT_MAJOR_VERSION EQUAL "6")
    find_package(Qt6Core)
    set(ENABLE_BSYMBOLICFUNCTIONS ${QT_FEATURE_reduce_relocations})
    set(CMAKE_CXX_STANDARD 20)
    set(CMAKE_CXX_EXTENSIONS OFF)
    set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
else ()
    set(ENABLE_BSYMBOLICFUNCTIONS ON)
endif()

# Current defaults
include(KDECompilerSettings NO_POLICY_SCOPE)

# add clang-format target
include(KDEClangFormat)
file(GLOB_RECURSE ALL_CLANG_FORMAT_SOURCE_FILES *.cpp *.h *.hpp *.c)
kde_clang_format(${ALL_CLANG_FORMAT_SOURCE_FILES})

# add the metainfo platform check
include(KDEMetaInfoPlatformCheck)
# SPDX-FileCopyrightText: 2020-2023 Alexander Lohnau <alexander.lohnau@gmx.de>
# SPDX-FileCopyrightText: 2022 Ahmad Samir <a.samirh78@gmail.com>
# SPDX-FileCopyrightText: 2023 Johannes Zarl-Zierl <johannes@zarl-zierl.at>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
KDEGitCommitHooks
--------------------

This module provides a functionality to enforce formatting
or in the future other QS checks.

This module provides the following function:

::

  kde_configure_git_pre_commit_hook(
     CHECKS <check1> [<check2> [...]
     [CUSTOM_SCRIPTS [<script paths> [<script paths> ...]]] # since 5.109
  )

This function will create a pre-commit hook which contains all the given checks.
In addition to that, you can pass in paths to custom scripts that will be run as the pre-commit hook.
If a custom hooks directory is set via ``core.hooksPath``, a warning is issued.

Checks:

- ``CLANG_FORMAT`` With this check enabled the ``git clang-format`` tool will be used to make sure that
  the changed parts are properly formatted. In case the changes are not properly formatted an error
  message with the command to preview the formatting changes and to format the files in place
  will be displayed. This tool will reuse the exsting ``.clang-format`` file, in case you
  want to use the one provided by ECM you can include ``include(KDEClangFormat)`` which will copy
  the file to the source dir. It is also recommended to reformat the entire project before enforcing
  the formatting using this commit hook.
  - ``JSON_SCHEMA`` Since 5.110, uses the check-jsonschema CLI tool to ensure that all files are valid JSON and
  match the KPluginMetaData spec. This only applied if the JSON file has a "KPlugin" object in its root.
  To ignore invalid files, for example for testing error handling, given files can be exlcuded in the .kde-ci.yml file
  Define Options.json-validate-ignore with an array of the files you want to ignore

Example usage:

.. code-block:: cmake

  include(KDEGitCommitHooks)
  kde_configure_git_pre_commit_hook(CHECKS JSON_SCHEMA CLANG_FORMAT)

Since 5.79
#]=======================================================================]

# try to find clang-format in path
find_program(KDE_CLANG_FORMAT_EXECUTABLE clang-format)
find_program(KDE_CHECK_JSONSCHEMA_EXECUTABLE check-jsonschema)
set(PRE_COMMIT_HOOK_UNIX "${CMAKE_CURRENT_LIST_DIR}/kde-git-commit-hooks/pre-commit.in")
set(CLANG_FORMAT_UNIX "${CMAKE_CURRENT_LIST_DIR}/kde-git-commit-hooks/clang-format.sh")
set(JSON_SCHEMA_SCRIPT "${CMAKE_CURRENT_LIST_DIR}/kde-git-commit-hooks/json-schema.py")
set(JSON_SCHEMA_IN "${CMAKE_CURRENT_LIST_DIR}/kde-git-commit-hooks/combined.schema.json.in")
set(GIT_DIR "${CMAKE_SOURCE_DIR}/.git")
set(GIT_HOOKS_DIR "${GIT_DIR}/hooks")
set(JSON_SCHEMA_OUT "${GIT_HOOKS_DIR}/scripts/combined.schema.json")

function(KDE_CONFIGURE_GIT_PRE_COMMIT_HOOK)
    set(_oneValueArgs "")
    set(_multiValueArgs CHECKS CUSTOM_SCRIPTS)
    cmake_parse_arguments(ARG "" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN})

    if(NOT CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
        message(STATUS "Project is not top level project - pre-commit hook not installed")
        return()
    endif()

    if(NOT ARG_CHECKS)
        message(FATAL_ERROR "No checks were specified")
    endif()

    find_package(Git QUIET)

    if (NOT IS_DIRECTORY ${GIT_DIR} # In case of tarballs there is no .git directory
        OR NOT (UNIX OR WIN32)
        OR NOT GIT_FOUND
        )
        return()
    endif()

    execute_process(COMMAND "${GIT_EXECUTABLE}" config --get core.hooksPath
        WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
        RESULT_VARIABLE _gitresult
        OUTPUT_VARIABLE _gitoutput
        ERROR_QUIET
        OUTPUT_STRIP_TRAILING_WHITESPACE)

    if(_gitresult EQUAL 0 AND NOT ${GIT_HOOKS_DIR} EQUAL "${_gitoutput}")
        message(WARNING "Git is configured to use '${_gitoutput}' for hooks. The generated commit hooks will likely not be executed.")
    endif()

    string(REPLACE ";" "\n" PRE_COMMIT_SCRIPTS "${ARG_CUSTOM_SCRIPTS}")
    set(_write_hook FALSE)
    if(KDE_CLANG_FORMAT_EXECUTABLE)
        list(FIND ARG_CHECKS "CLANG_FORMAT" _index)
        # Used to configure clang-format.sh script
        if (COMMAND KDE_CLANG_FORMAT)
            set(HAS_CLANG_FORMAT_COMMAND_INCLUDED TRUE)
        else()
            set(HAS_CLANG_FORMAT_COMMAND_INCLUDED FALSE)
        endif()
        if (${_index} GREATER -1)
            # get version of clang-format
            execute_process(
                COMMAND "${KDE_CLANG_FORMAT_EXECUTABLE}" --version
                OUTPUT_VARIABLE _clang_format_version_raw
                ERROR_VARIABLE _clang_format_version_raw
            )
            if (_clang_format_version_raw MATCHES "clang-format version ([0-9]+)(\\.[0-9]+)*")
                set(KDE_CLANG_FORMAT_MAJOR_VERSION "${CMAKE_MATCH_1}")
            endif()
            unset(_clang_format_version_raw)
            message(STATUS "Found clang-format version ${KDE_CLANG_FORMAT_MAJOR_VERSION}")

            set(CLANG_FORMAT_SCRIPT "\"$(git rev-parse --git-common-dir)\"/hooks/scripts/clang-format.sh")
            configure_file(${CLANG_FORMAT_UNIX} "${GIT_HOOKS_DIR}/scripts/clang-format.sh" @ONLY)
            set(PRE_COMMIT_SCRIPTS "\"$(git rev-parse --git-common-dir)\"/hooks/scripts/clang-format.sh\n${PRE_COMMIT_SCRIPTS}")
            set(_write_hook TRUE)
        endif()
    endif()

    list(FIND ARG_CHECKS "JSON_SCHEMA" _index)
    if (${_index} GREATER -1)
      set(_write_hook TRUE)
      foreach(path ${CMAKE_PREFIX_PATH};${CMAKE_INCLUDE_PATH})
          file(GLOB files "${path}/${KDE_INSTALL_DATADIR}/kf6/jsonschema/*.json") 
          set(SCHEMA_FILES ${SCHEMA_FILES};${files})
      endforeach()
        foreach (SCHEMA ${SCHEMA_FILES})
            if (SCHEMA_INCLUDES)
                set(SCHEMA_INCLUDES "${SCHEMA_INCLUDES},")
            endif()
            set(SCHEMA_INCLUDES "${SCHEMA_INCLUDES}{\"$ref\": \"${SCHEMA}\"}")
        endforeach()
        configure_file(${JSON_SCHEMA_IN} ${JSON_SCHEMA_OUT} @ONLY)
        if (KDE_CHECK_JSONSCHEMA_EXECUTABLE)
            set(PRE_COMMIT_SCRIPTS "set -e\npython3 ${JSON_SCHEMA_SCRIPT} \"${JSON_SCHEMA_OUT}\"\n${PRE_COMMIT_SCRIPTS}")
        else()
            message(WARNING "check-jsonschema executable not found. Please install it using pip or using your package manager")
        endif()
    endif()


    set(_hook_file "${GIT_HOOKS_DIR}/pre-commit")
    # Appending to the file is quite ugly and causes edge cases. With the CUSTOM_SCRIPTS arg, this should not be needed though
    if (ECM_GLOBAL_FIND_VERSION VERSION_GREATER_EQUAL 5.109.0)
        set(PRE_COMMIT_SCRIPTS "# This file is autogenerated by kde_configure_git_pre_commit_hook, any changes will be lost! \n${PRE_COMMIT_SCRIPTS}")
        configure_file(${PRE_COMMIT_HOOK_UNIX} "${_hook_file}")
    else()
        if(NOT _write_hook)
            message(WARNING "No clang-format executable was found, skipping the formatting pre-commit hook")
            return()
        endif()
        # Doesn't exist? write away
        if(NOT EXISTS ${_hook_file})
            configure_file(${PRE_COMMIT_HOOK_UNIX} "${_hook_file}")
            return()
        endif()

        file(READ ${_hook_file} _contents)

        # For when CLANG_FORMAT_SCRIPT didn't have the 'git rev-parse --git-common-dir' part
        set(_old_cmd "./.git/hooks/scripts/clang-format.sh")
        string(FIND "${_contents}" "${_old_cmd}" _idx)
        if (${_idx} GREATER -1)
            string(REPLACE "${_old_cmd}" "${CLANG_FORMAT_SCRIPT}" _contents "${_contents}")
            file(WRITE ${_hook_file} "${_contents}")
            return()
        endif()

        string(FIND "${_contents}" "${CLANG_FORMAT_SCRIPT}" _idx)
        # File exists and doesn't have the clang-format.sh line, append it
        # so as to not overwrite users' customisations
        if (_idx EQUAL -1)
            file(APPEND ${_hook_file} "${CLANG_FORMAT_SCRIPT}")
        endif()
    endif()
endfunction()
# SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
KDEInstallDirs
--------------

Compatibility wrapper around :kde-module:`KDEInstallDirs5`.

Since 5.82.0, prior to that equivalent to :kde-module:`KDEInstallDirs5`.
#]=======================================================================]

include(${CMAKE_CURRENT_LIST_DIR}/../modules/QtVersionOption.cmake)
include(${CMAKE_CURRENT_LIST_DIR}/KDEInstallDirs${QT_MAJOR_VERSION}.cmake)
# SPDX-FileCopyrightText: 2014-2015 Alex Merry <alex.merry@kde.org>
# SPDX-FileCopyrightText: 2013 Stephen Kelly <steveire@gmail.com>
# SPDX-FileCopyrightText: 2012 David Faure <faure@kde.org>
# SPDX-FileCopyrightText: 2007 Matthias Kretz <kretz@kde.org>
# SPDX-FileCopyrightText: 2006-2007 Laurent Montel <montel@kde.org>
# SPDX-FileCopyrightText: 2006-2013 Alex Neundorf <neundorf@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
KDEInstallDirs5
---------------

Define KDE standard installation directories for Qt5/KF5 based software.

Note that none of the variables defined by this module provide any
information about the location of already-installed KDE software.

Also sets ``CMAKE_INSTALL_PREFIX`` to the installation prefix of ECM,
unless that variable has been already explicitly set by something else
(since 5.61 and with CMake >= 3.7).

Inclusion of this module defines the following variables:

``KDE_INSTALL_<dir>``
    destination for files of a given type
``KDE_INSTALL_FULL_<dir>``
    corresponding absolute path

where ``<dir>`` is one of (default values in parentheses and alternative,
deprecated variable name in square brackets):

``BUNDLEDIR``
    application bundles (``/Applications/KDE``) [``BUNDLE_INSTALL_DIR``]
``EXECROOTDIR``
    executables and libraries (``<empty>``) [``EXEC_INSTALL_PREFIX``]
``BINDIR``
    user executables (``EXECROOTDIR/bin``) [``BIN_INSTALL_DIR``]
``SBINDIR``
    system admin executables (``EXECROOTDIR/sbin``) [``SBIN_INSTALL_DIR``]
``LIBDIR``
    object code libraries (``EXECROOTDIR/lib``, ``EXECROOTDIR/lib64`` or
    ``EXECROOTDIR/lib/<multiarch-tuple`` on Debian) [``LIB_INSTALL_DIR``]
``LIBEXECDIR``
    executables for internal use by programs and libraries (``BINDIR`` on
    Windows, ``LIBDIR/libexec`` otherwise) [``LIBEXEC_INSTALL_DIR``]
``CMAKEPACKAGEDIR``
    CMake packages, including config files (``LIBDIR/cmake``)
    [``CMAKECONFIG_INSTALL_PREFIX``]
``QTPLUGINDIR``
    Qt plugins (``LIBDIR/plugins`` or qmake-qt5's ``QT_INSTALL_PLUGINS``) [``QT_PLUGIN_INSTALL_DIR``]
``PLUGINDIR``
    Plugins (``QTPLUGINDIR``) [``PLUGIN_INSTALL_DIR``]
``QTQUICKIMPORTSDIR``
    QtQuick1 imports (``QTPLUGINDIR/imports`` or qmake-qt5's ``QT_INSTALL_IMPORTS``) [``IMPORTS_INSTALL_DIR``]
``QMLDIR``
    QtQuick2 imports (``LIBDIR/qml`` or qmake-qt5's ``QT_INSTALL_QML``) [``QML_INSTALL_DIR``]
``INCLUDEDIR``
    C and C++ header files (``include``) [``INCLUDE_INSTALL_DIR``]
``LOCALSTATEDIR``
    modifiable single-machine data (``var``)
``SHAREDSTATEDIR``
    modifiable architecture-independent data (``com``)
``DATAROOTDIR``
    read-only architecture-independent data root (``BINDIR/data`` on
    Windows, ``share`` otherwise)
    [``SHARE_INSTALL_PREFIX``]
``DATADIR``
    read-only architecture-independent data (``DATAROOTDIR``)
    [``DATA_INSTALL_DIR``]
``DOCBUNDLEDIR``
    documentation bundles generated using kdoctools
    (``DATAROOTDIR/doc/HTML``) [``HTML_INSTALL_DIR``]
``KCFGDIR``
    kconfig description files (``DATAROOTDIR/config.kcfg``)
    [``KCFG_INSTALL_DIR``]
``KCONFUPDATEDIR``
    kconf_update scripts (``DATAROOTDIR/kconf_update``)
    [``KCONF_UPDATE_INSTALL_DIR``]
``KSERVICES5DIR`` or (since 5.89) ``KSERVICESDIR``
    services for KDE Frameworks 5 (``DATAROOTDIR/kservices5``)
    [``SERVICES_INSTALL_DIR``]
``KSERVICETYPES5DIR`` or (since 5.89) ``KSERVICETYPESDIR``
    service types for KDE Frameworks 5 (``DATAROOTDIR/kservicetypes5``)
    [``SERVICETYPES_INSTALL_DIR``]
``KXMLGUI5DIR`` or (since 5.89) ``KXMLGUIDIR``
    kxmlgui .rc files (``DATAROOTDIR/kxmlgui5``)
    [``KXMLGUI_INSTALL_DIR``]
``KAPPTEMPLATESDIR``
    KAppTemplate and KDevelop templates (``DATAROOTDIR/kdevappwizard/templates``)
    [``KDE_INSTALL_KTEMPLATESDIR``] Since 5.77.
``KFILETEMPLATESDIR``
    KDevelop file templates (``DATAROOTDIR/kdevfiletemplates/templates``) Since 5.77.
``KNOTIFY5RCDIR`` or (since 5.89) ``KNOTIFYRCDIR``
    knotify description files (``DATAROOTDIR/knotifications5``)
    [``KNOTIFYRC_INSTALL_DIR``]
``ICONDIR``
    icons (``DATAROOTDIR/icons``) [``ICON_INSTALL_DIR``]
``LOCALEDIR``
    locale-dependent data (``DATAROOTDIR/locale``)
    [``LOCALE_INSTALL_DIR``]
``SOUNDDIR``
    sound files (``DATAROOTDIR/sounds``) [``SOUND_INSTALL_DIR``]
``TEMPLATEDIR``
    templates (``DATAROOTDIR/templates``) [``TEMPLATES_INSTALL_DIR``]
``WALLPAPERDIR``
    desktop wallpaper images (``DATAROOTDIR/wallpapers``)
    [``WALLPAPER_INSTALL_DIR``]
``APPDIR``
    application desktop files (``DATAROOTDIR/applications``) Since 1.1.0.
    [``XDG_APPS_INSTALL_DIR``]
``DESKTOPDIR``
    desktop directories (``DATAROOTDIR/desktop-directories``)
    [``XDG_DIRECTORY_INSTALL_DIR``]
``MIMEDIR``
    mime description files (``DATAROOTDIR/mime/packages``)
    [``XDG_MIME_INSTALL_DIR``]
``METAINFODIR``
    AppStream component metadata files (``DATAROOTDIR/metainfo``)
``QTQCHDIR``
    documentation bundles in QCH format for Qt-extending libraries (``DATAROOTDIR/doc/qch`` or qmake-qt5's ``QT_INSTALL_DOCS``) Since 5.36.0.
``QCHDIR``
    documentation bundles in QCH format (``DATAROOTDIR/doc/qch``) Since 5.36.0.
``MANDIR``
    man documentation (``DATAROOTDIR/man``) [``MAN_INSTALL_DIR``]
``INFODIR``
    info documentation (``DATAROOTDIR/info``)
``DBUSDIR``
    D-Bus (``DATAROOTDIR/dbus-1``)
``DBUSINTERFACEDIR``
    D-Bus interfaces (``DBUSDIR/interfaces``)
    [``DBUS_INTERFACES_INSTALL_DIR``]
``DBUSSERVICEDIR``
    D-Bus session services (``DBUSDIR/services``)
    [``DBUS_SERVICES_INSTALL_DIR``]
``DBUSSYSTEMSERVICEDIR``
    D-Bus system services (``DBUSDIR/system-services``)
    [``DBUS_SYSTEM_SERVICES_INSTALL_DIR``]
``SYSCONFDIR``
    read-only single-machine data
    (``etc``, or ``/etc`` if ``CMAKE_INSTALL_PREFIX`` is ``/usr``)
    [``SYSCONF_INSTALL_DIR``]
``CONFDIR``
    application configuration files (``SYSCONFDIR/xdg``)
    [``CONFIG_INSTALL_DIR``]
``AUTOSTARTDIR``
    autostart files (``CONFDIR/autostart``) [``AUTOSTART_INSTALL_DIR``]
``LOGGINGCATEGORIESDIR``
    Qt logging categories files directory (``DATAROOTDIR/qlogging-categories5``) Since 5.59.0
``JARDIR``
    Java AAR/JAR files for Android. Since 5.62.0
``SYSTEMDUNITDIR``
    Systemd Units (``lib/systemd``)
    [``SYSTEMD_UNIT_INSTALL_DIR``]. Since 5.65
``SYSTEMDUSERUNITDIR``
    Systemd User Units (``lib/systemd/user``)
    [``SYSTEMD_USER_UNIT_INSTALL_DIR``]. Since 5.65
``ZSHAUTOCOMPLETEDIR``
    Zsh functions and autocompletion definitions (``zsh/site-functions``)
    Since 5.101

If ``KDE_INSTALL_USE_QT_SYS_PATHS`` is set to ``TRUE`` before including this
module, the default values for some variables are instead queried from
Qt5's qmake (where mentioned in the parentheses above).
If not set, it will default to ``TRUE`` if Qt5's qmake is found and
it's ``QT_INSTALL_PREFIX`` is the same as ``CMAKE_INSTALL_PREFIX``,
otherwise default to ``FALSE``.
This variable should NOT be set from within CMakeLists.txt files, instead
is intended to be set manually when configuring a project which uses
KDEInstallDirs (e.g. by packagers).

If ``KDE_INSTALL_DIRS_NO_DEPRECATED`` is set to ``TRUE`` before including this
module, the deprecated variables (listed in the square brackets above) are
not defined.

In addition, for each ``KDE_INSTALL_*`` variable, an equivalent
``CMAKE_INSTALL_*`` variable is defined. If
``KDE_INSTALL_DIRS_NO_DEPRECATED`` is set to ``TRUE``, only those variables
defined by the ``GNUInstallDirs`` module (shipped with CMake) are defined.
If ``KDE_INSTALL_DIRS_NO_CMAKE_VARIABLES`` is set to ``TRUE``, no variables with
a ``CMAKE_`` prefix will be defined by this module (other than
``CMAKE_INSTALL_DEFAULT_COMPONENT_NAME`` - see below).

The ``KDE_INSTALL_<dir>`` variables (or their ``CMAKE_INSTALL_<dir>`` or
deprecated counterparts) may be passed to the ``DESTINATION`` options of
``install()`` commands for the corresponding file type.  They are set in the
CMake cache, and so the defaults above can be overridden by users.

Note that the ``KDE_INSTALL_<dir>``, ``CMAKE_INSTALL_<dir>`` or deprecated
form of the variable can be changed using CMake command line variable
definitions; in either case, all forms of the variable will be affected. The
effect of passing multiple forms of the same variable on the command line
(such as ``KDE_INSTALL_BINDIR`` and ``CMAKE_INSTALL_BINDIR`` is undefined.

The variable ``KDE_INSTALL_TARGETS_DEFAULT_ARGS`` is also defined (along with
the deprecated form ``INSTALL_TARGETS_DEFAULT_ARGS``).  This should be used
when libraries or user-executable applications are installed, in the
following manner:

.. code-block:: cmake

  install(TARGETS mylib myapp ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})

It MUST NOT be used for installing plugins, system admin executables or
executables only intended for use internally by other code.  Those should use
``KDE_INSTALL_PLUGINDIR``, ``KDE_INSTALL_SBINDIR`` or
``KDE_INSTALL_LIBEXECDIR`` respectively.

Additionally, ``CMAKE_INSTALL_DEFAULT_COMPONENT_NAME`` will be set to
``${PROJECT_NAME}`` to provide a sensible default for this CMake option.

Note that mixing absolute and relative paths, particularly for ``BINDIR``,
``LIBDIR`` and ``INCLUDEDIR``, can cause issues with exported targets. Given
that the default values for these are relative paths, relative paths should
be used on the command line when possible (eg: use
``-DKDE_INSTALL_LIBDIR=lib64`` instead of
``-DKDE_INSTALL_LIBDIR=/usr/lib/lib64`` to override the library directory).

Since 5.82.0, prior to that available as :kde-module:`KDEInstallDirs`.

NB: The variables starting ``KDE_INSTALL_`` are available since 1.6.0,
unless otherwise noted with the variable.

The ``KDE_INSTALL_PREFIX_SCRIPT`` option will install a ${CMAKE_INSTALL_PREFIX}/prefix.sh
file that allows to easily incorporate the necessary environment variables
for the prefix into a process.

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

include(${CMAKE_CURRENT_LIST_DIR}/KDEInstallDirsCommon.cmake)

if(WIN32)
    _define_non_cache(LIBEXECDIR_KF5 "${CMAKE_INSTALL_LIBEXECDIR}")
else()
    _define_non_cache(LIBEXECDIR_KF5 "${CMAKE_INSTALL_LIBEXECDIR}/kf5")
endif()
if(NOT KDE_INSTALL_DIRS_NO_DEPRECATED)
    set(KF5_LIBEXEC_INSTALL_DIR "${CMAKE_INSTALL_LIBEXECDIR_KF5}")
endif()

include("${ECM_MODULE_DIR}/ECMQueryQt.cmake")

set(_default_KDE_INSTALL_USE_QT_SYS_PATHS OFF)
if(NOT DEFINED KDE_INSTALL_USE_QT_SYS_PATHS)
    ecm_query_qt(qt_install_prefix_dir QT_INSTALL_PREFIX TRY)
    if(qt_install_prefix_dir STREQUAL "${CMAKE_INSTALL_PREFIX}")
        message(STATUS "Installing in the same prefix as Qt, adopting their path scheme.")
        set(_default_KDE_INSTALL_USE_QT_SYS_PATHS ON)
    endif()
endif()

option (KDE_INSTALL_USE_QT_SYS_PATHS "Install mkspecs files, QCH files for Qt-based libs, Plugins and Imports to the Qt 5 install dir" "${_default_KDE_INSTALL_USE_QT_SYS_PATHS}")
if(KDE_INSTALL_USE_QT_SYS_PATHS)
    # Qt-specific vars
    ecm_query_qt(qt_install_prefix_dir QT_INSTALL_PREFIX TRY)
    ecm_query_qt(qt_plugins_dir QT_INSTALL_PLUGINS)

    if(qt_install_prefix_dir STREQUAL "${CMAKE_INSTALL_PREFIX}")
        file(RELATIVE_PATH qt_plugins_dir ${qt_install_prefix_dir} ${qt_plugins_dir})
    endif()
    _define_absolute(QTPLUGINDIR ${qt_plugins_dir}
        "Qt plugins"
         QT_PLUGIN_INSTALL_DIR)

    ecm_query_qt(qt_imports_dir QT_INSTALL_IMPORTS)

    if(qt_install_prefix_dir STREQUAL "${CMAKE_INSTALL_PREFIX}")
        file(RELATIVE_PATH qt_imports_dir ${qt_install_prefix_dir} ${qt_imports_dir})
    endif()
    _define_absolute(QTQUICKIMPORTSDIR ${qt_imports_dir}
        "QtQuick1 imports"
        IMPORTS_INSTALL_DIR)

    ecm_query_qt(qt_qml_dir QT_INSTALL_QML)

    if(qt_install_prefix_dir STREQUAL "${CMAKE_INSTALL_PREFIX}")
        file(RELATIVE_PATH qt_qml_dir ${qt_install_prefix_dir} ${qt_qml_dir})
    endif()
    _define_absolute(QMLDIR ${qt_qml_dir}
        "QtQuick2 imports"
        QML_INSTALL_DIR)
else()
    set(_pluginsDirParent LIBDIR)
    if (ANDROID)
        set(_pluginsDirParent)
        #androiddeployqt wants plugins right in the prefix
    endif()
    _define_relative(QTPLUGINDIR "${_pluginsDirParent}" "plugins"
        "Qt plugins"
        QT_PLUGIN_INSTALL_DIR)

    _define_relative(QTQUICKIMPORTSDIR QTPLUGINDIR "imports"
        "QtQuick1 imports"
        IMPORTS_INSTALL_DIR)

    _define_relative(QMLDIR LIBDIR "qml"
        "QtQuick2 imports"
        QML_INSTALL_DIR)
endif()

_define_relative(PLUGINDIR QTPLUGINDIR ""
    "Plugins"
    PLUGIN_INSTALL_DIR)

_define_non_cache(INCLUDEDIR_KF5 "${CMAKE_INSTALL_INCLUDEDIR}/KF5")
if(NOT KDE_INSTALL_DIRS_NO_DEPRECATED)
    set(KF5_INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_INCLUDEDIR_KF5}")
endif()


_define_non_cache(DATADIR_KF5 "${CMAKE_INSTALL_DATADIR}/kf5")
if(NOT KDE_INSTALL_DIRS_NO_DEPRECATED)
    set(KF5_DATA_INSTALL_DIR "${CMAKE_INSTALL_DATADIR_KF5}")
endif()

# Qt-specific data vars
if(KDE_INSTALL_USE_QT_SYS_PATHS)
    ecm_query_qt(qt_docs_dir QT_INSTALL_DOCS)

    _define_absolute(QTQCHDIR ${qt_docs_dir}
        "documentation bundles in QCH format for Qt-extending libraries")
else()
    _define_relative(QTQCHDIR DATAROOTDIR "doc/qch"
        "documentation bundles in QCH format for Qt-extending libraries")
endif()


# KDE Framework-specific things
_define_relative(KSERVICES5DIR DATAROOTDIR "kservices5"
    "services for KDE Frameworks 5"
    SERVICES_INSTALL_DIR KSERVICESDIR)
_define_relative(KSERVICETYPES5DIR DATAROOTDIR "kservicetypes5"
    "service types for KDE Frameworks 5"
    SERVICETYPES_INSTALL_DIR KSERVICETYPESDIR)
_define_relative(KNOTIFY5RCDIR DATAROOTDIR "knotifications5"
    "knotify description files"
    KNOTIFYRC_INSTALL_DIR KNOTIFYRCDIR)
_define_relative(KXMLGUI5DIR DATAROOTDIR "kxmlgui5"
    "kxmlgui .rc files"
    KXMLGUI_INSTALL_DIR KXMLGUIDIR)
_define_relative(LOGGINGCATEGORIESDIR DATAROOTDIR "qlogging-categories5"
    "Qt Logging categories files")


# For more documentation see above.
# Later on it will be possible to extend this for installing OSX frameworks
# The COMPONENT Devel argument has the effect that static libraries belong to the
# "Devel" install component. If we use this also for all install() commands
# for header files, it will be possible to install
#   -everything: make install OR cmake -P cmake_install.cmake
#   -only the development files: cmake -DCOMPONENT=Devel -P cmake_install.cmake
#   -everything except the development files: cmake -DCOMPONENT=Unspecified -P cmake_install.cmake
# This can then also be used for packaging with cpack.
set(KDE_INSTALL_TARGETS_DEFAULT_ARGS  RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
                                      LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
                                      ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT Devel
                                      INCLUDES DESTINATION "${KDE_INSTALL_INCLUDEDIR}"
)
if(APPLE)
    set(KDE_INSTALL_TARGETS_DEFAULT_ARGS  ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}
                                          BUNDLE DESTINATION "${BUNDLE_INSTALL_DIR}" )
endif()

set(KF5_INSTALL_TARGETS_DEFAULT_ARGS  RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
                                      LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
                                      ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT Devel
                                      INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR_KF5}"
)

# on macOS support an extra install directory for application bundles
if(APPLE)
    set(KF5_INSTALL_TARGETS_DEFAULT_ARGS  ${KF5_INSTALL_TARGETS_DEFAULT_ARGS}
                                          BUNDLE DESTINATION "${BUNDLE_INSTALL_DIR}" )
endif()

if(NOT KDE_INSTALL_DIRS_NO_DEPRECATED)
    set(INSTALL_TARGETS_DEFAULT_ARGS ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
endif()

# version-less forward compatibility variants, see also KDEInstallDirs6.cmake
set(KF_INSTALL_TARGETS_DEFAULT_ARGS ${KF5_INSTALL_TARGETS_DEFAULT_ARGS})
_define_non_cache(INCLUDEDIR_KF "${KDE_INSTALL_INCLUDEDIR_KF5}")
_define_non_cache(DATADIR_KF "${KDE_INSTALL_DATADIR_KF5}")
_define_non_cache(LIBEXECDIR_KF "${KDE_INSTALL_LIBEXECDIR_KF5}")

include(${CMAKE_CURRENT_LIST_DIR}/KDESetupPrefixScript.cmake)
# SPDX-FileCopyrightText: 2014-2015 Alex Merry <alex.merry@kde.org>
# SPDX-FileCopyrightText: 2013 Stephen Kelly <steveire@gmail.com>
# SPDX-FileCopyrightText: 2012 David Faure <faure@kde.org>
# SPDX-FileCopyrightText: 2007 Matthias Kretz <kretz@kde.org>
# SPDX-FileCopyrightText: 2006-2007 Laurent Montel <montel@kde.org>
# SPDX-FileCopyrightText: 2006-2013 Alex Neundorf <neundorf@kde.org>
# SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
# SPDX-FileCopyrightText: 2021 Ahmad Samir <a.samir78@gmail.com>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
KDEInstallDirs6
---------------

Define KDE standard installation directories for Qt6/KF6 based software.

Note that none of the variables defined by this module provide any
information about the location of already-installed KDE software.

Also sets ``CMAKE_INSTALL_PREFIX`` to the installation prefix of ECM,
unless that variable has been already explicitly set by something else.

Inclusion of this module defines the following variables:

``KDE_INSTALL_<dir>``
    destination for files of a given type
``KDE_INSTALL_FULL_<dir>``
    corresponding absolute path

where ``<dir>`` is one of (default values in parentheses):

``BUNDLEDIR``
    application bundles (``/Applications/KDE``)
``EXECROOTDIR``
    executables and libraries (``<empty>``)
``BINDIR``
    user executables (``EXECROOTDIR/bin``)
``SBINDIR``
    system admin executables (``EXECROOTDIR/sbin``)
``LIBDIR``
    object code libraries (``EXECROOTDIR/lib``, ``EXECROOTDIR/lib64`` or
    ``EXECROOTDIR/lib/<multiarch-tuple`` on Debian)
``LIBEXECDIR``
    executables for internal use by programs and libraries (``BINDIR`` on
    Windows, ``LIBDIR/libexec`` otherwise)
``CMAKEPACKAGEDIR``
    CMake packages, including config files (``LIBDIR/cmake``)
``QTPLUGINDIR``
    Qt plugins (``LIBDIR/plugins`` or qtpaths's ``QT_INSTALL_PLUGINS``)
``PLUGINDIR``
    Plugins (``QTPLUGINDIR``) [``PLUGIN_INSTALL_DIR``]
``QMLDIR``
    QtQuick2 imports (``LIBDIR/qml`` or qtpaths's ``QT_INSTALL_QML``)
``INCLUDEDIR``
    C and C++ header files (``include``)
``LOCALSTATEDIR``
    modifiable single-machine data (``var``)
``SHAREDSTATEDIR``
    modifiable architecture-independent data (``com``)
``DATAROOTDIR``
    read-only architecture-independent data root (``BINDIR/data`` on
    Windows, ``share`` otherwise)
``DATADIR``
    read-only architecture-independent data (``DATAROOTDIR``)
``DOCBUNDLEDIR``
    documentation bundles generated using kdoctools
    (``DATAROOTDIR/doc/HTML``)
``KCFGDIR``
    kconfig description files (``DATAROOTDIR/config.kcfg``)
``KCONFUPDATEDIR``
    kconf_update scripts (``DATAROOTDIR/kconf_update``)
``KXMLGUIDIR``
    kxmlgui .rc files (``DATAROOTDIR/kxmlgui5``)
``KAPPTEMPLATESDIR``
    KAppTemplate and KDevelop templates (``DATAROOTDIR/kdevappwizard/templates``)
``KFILETEMPLATESDIR``
    KDevelop file templates (``DATAROOTDIR/kdevfiletemplates/templates``)
``KNOTIFYRCDIR``
    knotify description files (``DATAROOTDIR/knotifications6``)
``ICONDIR``
    icons (``DATAROOTDIR/icons``)
``LOCALEDIR``
    locale-dependent data (``DATAROOTDIR/locale``)
``SOUNDDIR``
    sound files (``DATAROOTDIR/sounds``)
``TEMPLATEDIR``
    templates (``DATAROOTDIR/templates``)
``WALLPAPERDIR``
    desktop wallpaper images (``DATAROOTDIR/wallpapers``)
``APPDIR``
    application desktop files (``DATAROOTDIR/applications``)
``DESKTOPDIR``
    desktop directories (``DATAROOTDIR/desktop-directories``)
``MIMEDIR``
    mime description files (``DATAROOTDIR/mime/packages``)
``METAINFODIR``
    AppStream component metadata files (``DATAROOTDIR/metainfo``)
``QTQCHDIR``
    documentation bundles in QCH format for Qt-extending libraries (``DATAROOTDIR/doc/qch`` or qtpaths's ``QT_INSTALL_DOCS``)
``QCHDIR``
    documentation bundles in QCH format (``DATAROOTDIR/doc/qch``)
``MANDIR``
    man documentation (``DATAROOTDIR/man``)
``INFODIR``
    info documentation (``DATAROOTDIR/info``)
``DBUSDIR``
    D-Bus (``DATAROOTDIR/dbus-1``)
``DBUSINTERFACEDIR``
    D-Bus interfaces (``DBUSDIR/interfaces``)
``DBUSSERVICEDIR``
    D-Bus session services (``DBUSDIR/services``)
``DBUSSYSTEMSERVICEDIR``
    D-Bus system services (``DBUSDIR/system-services``)
``SYSCONFDIR``
    read-only single-machine data
    (``etc``, or ``/etc`` if ``CMAKE_INSTALL_PREFIX`` is ``/usr``)
``CONFDIR``
    application configuration files (``SYSCONFDIR/xdg``)
``AUTOSTARTDIR``
    autostart files (``CONFDIR/autostart``)
``LOGGINGCATEGORIESDIR``
    Qt logging categories files directory (``DATAROOTDIR/qlogging-categories6``)
``JARDIR``
    Java AAR/JAR files for Android.
``SYSTEMDUNITDIR``
    Systemd Units (``lib/systemd``)
``SYSTEMDUSERUNITDIR``
    Systemd User Units (``lib/systemd/user``)

If ``KDE_INSTALL_USE_QT_SYS_PATHS`` is set to ``TRUE`` before including this
module, the default values for some variables are instead queried from
Qt6's qmake (where mentioned in the parentheses above).
If not set, it will default to ``TRUE`` if Qt6's qmake is found and
it's ``QT_INSTALL_PREFIX`` is the same as ``CMAKE_INSTALL_PREFIX``,
otherwise default to ``FALSE``.
This variable should NOT be set from within CMakeLists.txt files, instead
is intended to be set manually when configuring a project which uses
KDEInstallDirs (e.g. by packagers).

In addition, for each ``KDE_INSTALL_*`` variable, an equivalent
``CMAKE_INSTALL_*`` variable is defined, if such a variable is also
defined by the ``GNUInstallDirs`` module (shipped with CMake).
If ``KDE_INSTALL_DIRS_NO_CMAKE_VARIABLES`` is set to ``TRUE``, no variables with
a ``CMAKE_`` prefix will be defined by this module (other than
``CMAKE_INSTALL_DEFAULT_COMPONENT_NAME`` - see below).

The ``KDE_INSTALL_<dir>`` variables may be passed to the ``DESTINATION`` options of
``install()`` commands for the corresponding file type.  They are set in the
CMake cache, and so the defaults above can be overridden by users.

Note that the ``KDE_INSTALL_<dir>`` or ``CMAKE_INSTALL_<dir>`` variables
can be changed using CMake command line variable definitions; in either case,
both forms of the variable will be affected. The effect of passing multiple
forms of the same variable on the command line
(such as ``KDE_INSTALL_BINDIR`` and ``CMAKE_INSTALL_BINDIR`` is undefined.

The variable ``KDE_INSTALL_TARGETS_DEFAULT_ARGS`` is also defined.
This should be used when libraries or user-executable applications are installed,
in the following manner:

.. code-block:: cmake

  install(TARGETS mylib myapp ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})

It MUST NOT be used for installing plugins, system admin executables or
executables only intended for use internally by other code.  Those should use
``KDE_INSTALL_PLUGINDIR``, ``KDE_INSTALL_SBINDIR`` or
``KDE_INSTALL_LIBEXECDIR`` respectively.

Additionally, ``CMAKE_INSTALL_DEFAULT_COMPONENT_NAME`` will be set to
``${PROJECT_NAME}`` to provide a sensible default for this CMake option.

Note that mixing absolute and relative paths, particularly for ``BINDIR``,
``LIBDIR`` and ``INCLUDEDIR``, can cause issues with exported targets. Given
that the default values for these are relative paths, relative paths should
be used on the command line when possible (eg: use
``-DKDE_INSTALL_LIBDIR=lib64`` instead of
``-DKDE_INSTALL_LIBDIR=/usr/lib/lib64`` to override the library directory).

The ``KDE_INSTALL_PREFIX_SCRIPT`` option will install a ${CMAKE_INSTALL_PREFIX}/prefix.sh
file that allows to easily incorporate the necessary environment variables
for the prefix into a process.
#]=======================================================================]

set(KDE_INSTALL_DIRS_NO_DEPRECATED TRUE)

include(${CMAKE_CURRENT_LIST_DIR}/KDEInstallDirsCommon.cmake)

if(WIN32)
    _define_non_cache(LIBEXECDIR_KF "${CMAKE_INSTALL_LIBEXECDIR}")
else()
    _define_non_cache(LIBEXECDIR_KF "${CMAKE_INSTALL_LIBEXECDIR}/kf6")
endif()

include(${ECM_MODULE_DIR}/ECMQueryQt.cmake)
ecm_query_qt(qt_install_prefix_dir QT_INSTALL_PREFIX)

set(_qt_prefix_is_cmake_install_prefix FALSE)
if(qt_install_prefix_dir STREQUAL "${CMAKE_INSTALL_PREFIX}")
    set(_qt_prefix_is_cmake_install_prefix TRUE)
endif()

set(_default_KDE_INSTALL_USE_QT_SYS_PATHS OFF)
if(NOT DEFINED KDE_INSTALL_USE_QT_SYS_PATHS)
    if(_qt_prefix_is_cmake_install_prefix)
       message(STATUS "Installing in the same prefix as Qt, adopting their path scheme.")
       set(_default_KDE_INSTALL_USE_QT_SYS_PATHS ON)
    endif()
endif()

option (KDE_INSTALL_USE_QT_SYS_PATHS
        "Install mkspecs files, QCH files for Qt-based libs, Plugins and Imports to the Qt 6 install dir"
        "${_default_KDE_INSTALL_USE_QT_SYS_PATHS}"
)

if(KDE_INSTALL_USE_QT_SYS_PATHS)
   # Qt-specific vars
    ecm_query_qt(qt_plugins_dir QT_INSTALL_PLUGINS)
    if(_qt_prefix_is_cmake_install_prefix)
        file(RELATIVE_PATH qt_plugins_dir ${qt_install_prefix_dir} ${qt_plugins_dir})
    endif()
    _define_absolute(QTPLUGINDIR ${qt_plugins_dir} "Qt plugins")

    ecm_query_qt(qt_qml_dir QT_INSTALL_QML)
    if(_qt_prefix_is_cmake_install_prefix)
        file(RELATIVE_PATH qt_qml_dir ${qt_install_prefix_dir} ${qt_qml_dir})
    endif()
   _define_absolute(QMLDIR ${qt_qml_dir} "QtQuick2 imports")
else()
    set(_pluginsDirParent LIBDIR)
    if (ANDROID)
        set(_pluginsDirParent)
        #androiddeployqt wants plugins right in the prefix
    endif()
    _define_relative(QTPLUGINDIR "${_pluginsDirParent}" "plugins"
        "Qt plugins")

    _define_relative(QMLDIR LIBDIR "qml"
        "QtQuick2 imports")
endif()

_define_relative(PLUGINDIR QTPLUGINDIR ""
    "Plugins")

_define_non_cache(INCLUDEDIR_KF "${CMAKE_INSTALL_INCLUDEDIR}/KF6")

_define_non_cache(DATADIR_KF "${CMAKE_INSTALL_DATADIR}/kf6")

# Qt-specific data vars
if(KDE_INSTALL_USE_QT_SYS_PATHS)
    ecm_query_qt(qt_docs_dir QT_INSTALL_DOCS)

   _define_absolute(QTQCHDIR ${qt_docs_dir} "documentation bundles in QCH format for Qt-extending libraries")
else()
    _define_relative(QTQCHDIR DATAROOTDIR "doc/qch"
        "documentation bundles in QCH format for Qt-extending libraries")
endif()


# KDE Framework-specific things
_define_relative(KNOTIFYRCDIR DATAROOTDIR "knotifications6"
    "knotify description files")
# TODO MOVE TO KXMLGUI
_define_relative(KXMLGUIDIR DATAROOTDIR "kxmlgui5"
    "kxmlgui .rc files")
_define_relative(LOGGINGCATEGORIESDIR DATAROOTDIR "qlogging-categories6"
    "Qt Logging categories files")

# For more documentation see above.
# Later on it will be possible to extend this for installing OSX frameworks
# The COMPONENT Devel argument has the effect that static libraries belong to the
# "Devel" install component. If we use this also for all install() commands
# for header files, it will be possible to install
#   -everything: make install OR cmake -P cmake_install.cmake
#   -only the development files: cmake -DCOMPONENT=Devel -P cmake_install.cmake
#   -everything except the development files: cmake -DCOMPONENT=Unspecified -P cmake_install.cmake
# This can then also be used for packaging with cpack.
set(KDE_INSTALL_TARGETS_DEFAULT_ARGS  RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
                                      LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
                                      ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
                                      OBJECTS DESTINATION "${CMAKE_INSTALL_LIBDIR}"
                                      COMPONENT Devel
)
if(APPLE)
    set(KDE_INSTALL_TARGETS_DEFAULT_ARGS  ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}
                                          BUNDLE DESTINATION "${KDE_INSTALL_BUNDLEDIR}" )
endif()

set(KF_INSTALL_TARGETS_DEFAULT_ARGS RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
                                    LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
                                    ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
                                    OBJECTS DESTINATION "${CMAKE_INSTALL_LIBDIR}"
                                    COMPONENT Devel
)

# on macOS support an extra install directory for application bundles
if(APPLE)
    set(KF_INSTALL_TARGETS_DEFAULT_ARGS  ${KF_INSTALL_TARGETS_DEFAULT_ARGS}
                                          BUNDLE DESTINATION "${KDE_INSTALL_BUNDLEDIR}" )
endif()

include(${CMAKE_CURRENT_LIST_DIR}/KDESetupPrefixScript.cmake)
# SPDX-FileCopyrightText: 2014-2015 Alex Merry <alex.merry@kde.org>
# SPDX-FileCopyrightText: 2013 Stephen Kelly <steveire@gmail.com>
# SPDX-FileCopyrightText: 2012 David Faure <faure@kde.org>
# SPDX-FileCopyrightText: 2007 Matthias Kretz <kretz@kde.org>
# SPDX-FileCopyrightText: 2006-2007 Laurent Montel <montel@kde.org>
# SPDX-FileCopyrightText: 2006-2013 Alex Neundorf <neundorf@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause
#
# Common implementation details of KDEInstallDirsX.cmake, not public API.
#

# Figure out what the default install directory for libraries should be.
# This is based on the logic in GNUInstallDirs, but simplified (the
# GNUInstallDirs code deals with re-configuring, but that is dealt with
# by the _define_* macros in this module).
set(_LIBDIR_DEFAULT "lib")
# Override this default 'lib' with 'lib64' if:
#  - we are on a Linux, kFreeBSD or Hurd system but NOT cross-compiling
#  - we are NOT on debian
#  - we are NOT on flatpak
#  - we are NOT on NixOS
#  - we are on a 64 bits system
# reason is: amd64 ABI: https://gitlab.com/x86-psABIs/x86-64-ABI/-/jobs/artifacts/master/raw/x86-64-ABI/abi.pdf?job=build
# For Debian with multiarch, use 'lib/${CMAKE_LIBRARY_ARCHITECTURE}' if
# CMAKE_LIBRARY_ARCHITECTURE is set (which contains e.g. "i386-linux-gnu"
# See https://wiki.debian.org/Multiarch
if((CMAKE_SYSTEM_NAME MATCHES "Linux|kFreeBSD" OR CMAKE_SYSTEM_NAME STREQUAL "GNU")
   AND NOT CMAKE_CROSSCOMPILING
   AND NOT EXISTS "/etc/arch-release"
   AND NOT DEFINED ENV{FLATPAK_ID}
   AND NOT EXISTS "/etc/NIXOS")
  if (EXISTS "/etc/debian_version") # is this a debian system ?
    if(CMAKE_LIBRARY_ARCHITECTURE)
      set(_LIBDIR_DEFAULT "lib/${CMAKE_LIBRARY_ARCHITECTURE}")
    endif()
  else() # not debian, rely on CMAKE_SIZEOF_VOID_P:
    if(NOT DEFINED CMAKE_SIZEOF_VOID_P)
      message(AUTHOR_WARNING
        "Unable to determine default LIB_INSTALL_LIBDIR directory because no target architecture is known. "
        "Please enable at least one language before including KDEInstallDirs.")
    else()
      if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
        set(_LIBDIR_DEFAULT "lib64")
      endif()
    endif()
  endif()
endif()

set(_gnu_install_dirs_vars
    BINDIR
    SBINDIR
    LIBEXECDIR
    SYSCONFDIR
    SHAREDSTATEDIR
    LOCALSTATEDIR
    LIBDIR
    INCLUDEDIR
    OLDINCLUDEDIR
    DATAROOTDIR
    DATADIR
    INFODIR
    LOCALEDIR
    MANDIR
    DOCDIR)

# Macro for variables that are relative to another variable. We store an empty
# value in the cache (for documentation/GUI cache editor purposes), and store
# the default value in a local variable. If the cache variable is ever set to
# something non-empty, the local variable will no longer be set. However, if
# the cache variable remains (or is set to be) empty, the value will be
# relative to that of the parent variable.
#
# varname:   the variable name suffix (eg: BINDIR for KDE_INSTALL_BINDIR)
# parent:    the variable suffix of the variable this is relative to
#            (eg: DATAROOTDIR for KDE_INSTALL_DATAROOTDIR)
# subdir:    the path of the default value of KDE_INSTALL_${varname}
#            relative to KDE_INSTALL_${parent}: no leading /
# docstring: documentation about the variable (not including the default value)
# oldstylename (optional): the old-style name of the variable
# alias (optional): alias for the variable (e.g. without '5' in the name)
macro(_define_relative varname parent subdir docstring)
    set(_oldstylename)
    if(NOT KDE_INSTALL_DIRS_NO_DEPRECATED AND ${ARGC} GREATER 4)
        set(_oldstylename "${ARGV4}")
    endif()
    set(_aliasname)
    if(${ARGC} GREATER 5)
        set(_aliasname "${ARGV5}")
    endif()
    set(_cmakename)
    if(NOT KDE_INSTALL_DIRS_NO_CMAKE_VARIABLES)
        list(FIND _gnu_install_dirs_vars "${varname}" _list_offset)
        set(_cmakename_is_deprecated FALSE)
        if(NOT KDE_INSTALL_DIRS_NO_DEPRECATED OR NOT _list_offset EQUAL -1)
            set(_cmakename CMAKE_INSTALL_${varname})
            if(_list_offset EQUAL -1)
                set(_cmakename_is_deprecated TRUE)
            endif()
        endif()
    endif()

    # Surprisingly complex logic to deal with joining paths.
    # Note that we cannot use arg vars directly in if() because macro args are
    # not proper variables.
    set(_parent "${parent}")
    set(_subdir "${subdir}")
    if(_parent AND _subdir)
        set(_docpath "${_parent}/${_subdir}")
        if(KDE_INSTALL_${_parent})
            set(_realpath "${KDE_INSTALL_${_parent}}/${_subdir}")
        else()
            set(_realpath "${_subdir}")
        endif()
    elseif(_parent)
        set(_docpath "${_parent}")
        set(_realpath "${KDE_INSTALL_${_parent}}")
    else()
        set(_docpath "${_subdir}")
        set(_realpath "${_subdir}")
    endif()

    if(KDE_INSTALL_${varname})
        # make sure the cache documentation is set correctly
        get_property(_iscached CACHE KDE_INSTALL_${varname} PROPERTY VALUE SET)
        if (_iscached)
            # make sure the docs are still set if it was passed on the command line
            set_property(CACHE KDE_INSTALL_${varname}
                PROPERTY HELPSTRING "${docstring} (${_docpath})")
            # make sure the type is correct if it was passed on the command line
            set_property(CACHE KDE_INSTALL_${varname}
                PROPERTY TYPE PATH)
        endif()
    elseif(${_oldstylename})
       message(DEPRECATION "${_oldstylename} is deprecated, use KDE_INSTALL_${varname} instead.")
        # The old name was given (probably on the command line): move
        # it to the new name
        set(KDE_INSTALL_${varname} "${${_oldstylename}}"
            CACHE PATH
                  "${docstring} (${_docpath})"
                  FORCE)
    elseif(${_aliasname})
        # The alias variable was given (probably on the command line): move
        # it to the new name
        set(KDE_INSTALL_${varname} "${${_aliasname}}"
            CACHE PATH
                  "${docstring} (${_docpath})"
                  FORCE)
    elseif(${_cmakename})
        if(_cmakename_is_deprecated)
            message(DEPRECATION "${_cmakename} is deprecated, use KDE_INSTALL_${varname} instead.")
        endif()
        # The CMAKE_ name was given (probably on the command line): move
        # it to the new name
        set(KDE_INSTALL_${varname} "${${_cmakename}}"
            CACHE PATH
                  "${docstring} (${_docpath})"
                  FORCE)
    else()
        # insert an empty value into the cache, indicating the default
        # should be used (including compatibility vars above)
        set(KDE_INSTALL_${varname} ""
            CACHE PATH "${docstring} (${_docpath})")
        set(KDE_INSTALL_${varname} "${_realpath}")
    endif()

    mark_as_advanced(KDE_INSTALL_${varname})

    if(NOT IS_ABSOLUTE ${KDE_INSTALL_${varname}})
        set(KDE_INSTALL_FULL_${varname}
            "${CMAKE_INSTALL_PREFIX}/${KDE_INSTALL_${varname}}")
    else()
        set(KDE_INSTALL_FULL_${varname} "${KDE_INSTALL_${varname}}")
    endif()

    # Override compatibility vars at runtime, even though we don't touch
    # them in the cache; this way, we keep the variables in sync where
    # KDEInstallDirs is included, but don't interfere with, say,
    # GNUInstallDirs in a parallel part of the CMake tree.
    if(_cmakename)
        set(${_cmakename} "${KDE_INSTALL_${varname}}")
        set(CMAKE_INSTALL_FULL_${varname} "${KDE_INSTALL_FULL_${varname}}")
    endif()

    if(_oldstylename)
        set(${_oldstylename} "${KDE_INSTALL_${varname}}")
    endif()
    if (_aliasname)
        set(KDE_INSTALL_${_aliasname} "${KDE_INSTALL_${varname}}")
        set(KDE_INSTALL_FULL_${_aliasname} "${KDE_INSTALL_FULL_${varname}}")
    endif()
endmacro()

# varname:   the variable name suffix (eg: BINDIR for KDE_INSTALL_BINDIR)
# dir:       the relative path of the default value of KDE_INSTALL_${varname}
#            relative to CMAKE_INSTALL_PREFIX: no leading /
# docstring: documentation about the variable (not including the default value)
# oldstylename (optional): the old-style name of the variable
macro(_define_absolute varname dir docstring)
    _define_relative("${varname}" "" "${dir}" "${docstring}" ${ARGN})
endmacro()

macro(_define_non_cache varname value)
    set(KDE_INSTALL_${varname} "${value}")
    if(NOT IS_ABSOLUTE ${KDE_INSTALL_${varname}})
        set(KDE_INSTALL_FULL_${varname}
            "${CMAKE_INSTALL_PREFIX}/${KDE_INSTALL_${varname}}")
    else()
        set(KDE_INSTALL_FULL_${varname} "${KDE_INSTALL_${varname}}")
    endif()

    if(NOT KDE_INSTALL_DIRS_NO_CMAKE_VARIABLES)
        list(FIND _gnu_install_dirs_vars "${varname}" _list_offset)
        if(NOT KDE_INSTALL_DIRS_NO_DEPRECATED OR NOT _list_offset EQUAL -1)
            set(CMAKE_INSTALL_${varname} "${KDE_INSTALL_${varname}}")
            set(CMAKE_INSTALL_FULL_${varname} "${KDE_INSTALL_FULL_${varname}}")
        endif()
    endif()
endmacro()

if(APPLE)
    _define_absolute(BUNDLEDIR "/Applications/KDE"
        "application bundles"
        BUNDLE_INSTALL_DIR)
endif()

# Only supported since cmake 3.7
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
    set(CMAKE_INSTALL_PREFIX "${ECM_PREFIX}" CACHE PATH "Install path prefix" FORCE)
endif()

_define_absolute(EXECROOTDIR ""
    "executables and libraries"
    EXEC_INSTALL_PREFIX)

_define_relative(BINDIR EXECROOTDIR "bin"
    "user executables"
    BIN_INSTALL_DIR)
_define_relative(SBINDIR EXECROOTDIR "sbin"
    "system admin executables"
    SBIN_INSTALL_DIR)
_define_relative(LIBDIR EXECROOTDIR "${_LIBDIR_DEFAULT}"
    "object code libraries"
    LIB_INSTALL_DIR)

if(WIN32)
    _define_relative(LIBEXECDIR BINDIR ""
        "executables for internal use by programs and libraries"
        LIBEXEC_INSTALL_DIR)
else()
    _define_relative(LIBEXECDIR LIBDIR "libexec"
        "executables for internal use by programs and libraries"
        LIBEXEC_INSTALL_DIR)
endif()

_define_relative(CMAKEPACKAGEDIR LIBDIR "cmake"
    "CMake packages, including config files"
    CMAKECONFIG_INSTALL_PREFIX)

_define_absolute(INCLUDEDIR "include"
    "C and C++ header files"
    INCLUDE_INSTALL_DIR)

_define_absolute(LOCALSTATEDIR "var"
    "modifiable single-machine data")

_define_absolute(SHAREDSTATEDIR "com"
    "modifiable architecture-independent data")

if (WIN32)
    _define_relative(DATAROOTDIR BINDIR "data"
        "read-only architecture-independent data root"
        SHARE_INSTALL_PREFIX)
else()
    _define_absolute(DATAROOTDIR "share"
        "read-only architecture-independent data root"
        SHARE_INSTALL_PREFIX)
endif()

_define_relative(DATADIR DATAROOTDIR ""
    "read-only architecture-independent data"
    DATA_INSTALL_DIR)

# KDE Framework-specific things
_define_relative(DOCBUNDLEDIR DATAROOTDIR "doc/HTML"
    "documentation bundles generated using kdoctools"
    HTML_INSTALL_DIR)
_define_relative(KCFGDIR DATAROOTDIR "config.kcfg"
    "kconfig description files"
    KCFG_INSTALL_DIR)
_define_relative(KCONFUPDATEDIR DATAROOTDIR "kconf_update"
    "kconf_update scripts"
    KCONF_UPDATE_INSTALL_DIR)
_define_relative(KAPPTEMPLATESDIR DATAROOTDIR "kdevappwizard/templates"
    "KAppTemplate and KDevelop templates"
    KDE_INSTALL_KTEMPLATESDIR
    )
_define_relative(KFILETEMPLATESDIR DATAROOTDIR "kdevfiletemplates/templates"
    "KDevelop file templates")
_define_relative(JARDIR "" "jar"
    "Java AAR/JAR files for Android")


# Cross-desktop or other system things
_define_relative(ICONDIR DATAROOTDIR "icons"
    "icons"
    ICON_INSTALL_DIR)
_define_relative(LOCALEDIR DATAROOTDIR "locale"
    "locale-dependent data"
    LOCALE_INSTALL_DIR)
_define_relative(SOUNDDIR DATAROOTDIR "sounds"
    "sound files"
    SOUND_INSTALL_DIR)
_define_relative(TEMPLATEDIR DATAROOTDIR "templates"
    "templates"
    TEMPLATES_INSTALL_DIR)
_define_relative(WALLPAPERDIR DATAROOTDIR "wallpapers"
    "desktop wallpaper images"
    WALLPAPER_INSTALL_DIR)
_define_relative(APPDIR DATAROOTDIR "applications"
    "application desktop files"
    XDG_APPS_INSTALL_DIR)
_define_relative(DESKTOPDIR DATAROOTDIR "desktop-directories"
    "desktop directories"
    XDG_DIRECTORY_INSTALL_DIR)
_define_relative(MIMEDIR DATAROOTDIR "mime/packages"
    "mime description files"
    XDG_MIME_INSTALL_DIR)
_define_relative(METAINFODIR DATAROOTDIR "metainfo"
    "AppStream component metadata")
_define_relative(QCHDIR DATAROOTDIR "doc/qch"
    "documentation bundles in QCH format")
_define_relative(MANDIR DATAROOTDIR "man"
    "man documentation"
    MAN_INSTALL_DIR)
_define_relative(INFODIR DATAROOTDIR "info"
    "info documentation")
_define_relative(DBUSDIR DATAROOTDIR "dbus-1"
    "D-Bus")
_define_relative(DBUSINTERFACEDIR DBUSDIR "interfaces"
    "D-Bus interfaces"
    DBUS_INTERFACES_INSTALL_DIR)
_define_relative(DBUSSERVICEDIR DBUSDIR "services"
    "D-Bus session services"
    DBUS_SERVICES_INSTALL_DIR)
_define_relative(DBUSSYSTEMSERVICEDIR DBUSDIR "system-services"
    "D-Bus system services"
    DBUS_SYSTEM_SERVICES_INSTALL_DIR)
_define_relative(SYSTEMDUNITDIR CMAKE_INSTALL_PREFIX "lib/systemd"
    "Systemd units"
    SYSTEMD_UNIT_INSTALL_DIR)
_define_relative(SYSTEMDUSERUNITDIR SYSTEMDUNITDIR "user"
    "Systemd user units"
    SYSTEMD_USER_UNIT_INSTALL_DIR)
_define_relative(ZSHAUTOCOMPLETEDIR DATAROOTDIR "zsh/site-functions"
    "Zsh functions and autocompletion definitions")

set(_default_sysconf_dir "etc")
if (CMAKE_INSTALL_PREFIX STREQUAL "/usr")
    set(_default_sysconf_dir "/etc")
endif()

_define_absolute(SYSCONFDIR "${_default_sysconf_dir}"
    "read-only single-machine data"
    SYSCONF_INSTALL_DIR)
_define_relative(CONFDIR SYSCONFDIR "xdg"
    "application configuration files"
    CONFIG_INSTALL_DIR)
_define_relative(AUTOSTARTDIR CONFDIR "autostart"
    "autostart files"
    AUTOSTART_INSTALL_DIR)


set(_mixed_core_path_styles FALSE)
if (IS_ABSOLUTE "${KDE_INSTALL_BINDIR}")
    if (NOT IS_ABSOLUTE "${KDE_INSTALL_LIBDIR}" OR NOT IS_ABSOLUTE "${KDE_INSTALL_INCLUDEDIR}")
        set(_mixed_core_path_styles )
    endif()
else()
    if (IS_ABSOLUTE "${KDE_INSTALL_LIBDIR}" OR IS_ABSOLUTE "${KDE_INSTALL_INCLUDEDIR}")
        set(_mixed_core_path_styles TRUE)
    endif()
endif()
if (_mixed_core_path_styles)
    message(WARNING "KDE_INSTALL_BINDIR, KDE_INSTALL_LIBDIR and KDE_INSTALL_INCLUDEDIR should either all be absolute paths or all be relative paths.")
endif()


# new in cmake 2.8.9: this is used for all installed files which do not have a component set
# so set the default component name to the name of the project, if a project name has been set:
if(NOT "${PROJECT_NAME}" STREQUAL "Project")
    set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME "${PROJECT_NAME}")
endif()
# SPDX-FileCopyrightText: 2022 Albert Astals Cid <aacid@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
KDEMetaInfoPlatformCheck
------------------------

By including this module there will be an automatic check between the supported
platforms listed in the metainfo.yaml file and the current platform
that is the target of the build

If the current platform that is the target of the build is not supported
a CMake ``FATAL_ERROR`` will be issued

The check can be ignored by setting ``KF_IGNORE_PLATFORM_CHECK`` to ``ON``.

Since 5.93
#]=======================================================================]

option(KF_IGNORE_PLATFORM_CHECK "Ignore the supported platform check against metainfo.yaml" OFF)
if ("$ENV{KF_IGNORE_PLATFORM_CHECK}" STREQUAL "ON")
    message(WARNING "KF_IGNORE_PLATFORM_CHECK set to ON from the environment")
    set(KF_IGNORE_PLATFORM_CHECK ON)
endif()

if (NOT "${KF_IGNORE_PLATFORM_CHECK}")
    file(STRINGS metainfo.yaml MetaInfoContents)
    set(_MetainfoParserInPlatforms false)
    set(_MetainfoFoundSupportedPlatform false)
    set(_MetainfoSupportedPlatforms "")
    foreach(MetaInfoString IN LISTS MetaInfoContents)
        if ("${MetaInfoString}" STREQUAL "platforms:")
            set(_MetainfoParserInPlatforms true)
        elseif(_MetainfoParserInPlatforms AND "${MetaInfoString}" MATCHES ".*name:[ \t\r\n]*(.*)")
            list(APPEND _MetainfoSupportedPlatforms ${CMAKE_MATCH_1})
            if (${CMAKE_MATCH_1} STREQUAL "Linux")
                if (CMAKE_SYSTEM_NAME MATCHES "Linux")
                    set(_MetainfoFoundSupportedPlatform true)
                endif()
            elseif (${CMAKE_MATCH_1} STREQUAL "FreeBSD")
                if (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
                    set(_MetainfoFoundSupportedPlatform true)
                endif()
            elseif (${CMAKE_MATCH_1} STREQUAL "OpenBSD")
                if (CMAKE_SYSTEM_NAME MATCHES "OpenBSD")
                    set(_MetainfoFoundSupportedPlatform true)
                endif()
            elseif (${CMAKE_MATCH_1} STREQUAL "Windows")
                if (WIN32)
                    set(_MetainfoFoundSupportedPlatform true)
                endif()
            elseif (${CMAKE_MATCH_1} STREQUAL "macOS")
                if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
                    set(_MetainfoFoundSupportedPlatform true)
                endif()
            elseif (${CMAKE_MATCH_1} STREQUAL "Android")
                if (ANDROID)
                    set(_MetainfoFoundSupportedPlatform true)
                endif()
            elseif (${CMAKE_MATCH_1} STREQUAL "iOS")
                if (IOS)
                    set(_MetainfoFoundSupportedPlatform true)
                endif()
            elseif (${CMAKE_MATCH_1} STREQUAL "All")
                set(_MetainfoFoundSupportedPlatform true)
            else()
                list(POP_BACK _MetainfoSupportedPlatforms)
                message(WARNING "Found platform not recognized by the metainfo platform parser: ${CMAKE_MATCH_1}")
            endif()
        elseif("${MetaInfoString}" MATCHES "^[A-Za-z0-9_]+:")
            set(_MetainfoParserInPlatforms false)
        endif()
    endforeach()

    if (NOT _MetainfoFoundSupportedPlatform)
        message(FATAL_ERROR "Your current platform '${CMAKE_SYSTEM_NAME}' is not supported. The list of supported platorms is '${_MetainfoSupportedPlatforms}'.If you think this is a mistake or you are working on enabling the platform please build with the KF_IGNORE_PLATFORM_CHECK variable set to true")
    endif()
endif()
# SPDX-FileCopyrightText: 2015 Marco Martin <mart@kde.org>
# SPDX-FileCopyrightText: 2014 Simon Wächter <waechter.simon@gmail.com>
# SPDX-FileCopyrightText: 2013 Nico Kruber <nico.kruber@gmail.com>
# SPDX-FileCopyrightText: 2012 Jeremy Whiting <jpwhiting@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
KDEPackageAppTemplates
----------------------

Packages KApptemplate/KDevelop compatible application templates

This module provides a functionality to package in a tarball and
install project templates compatible with the format used by
KApptemplate and KDevelop. Useful for providing minimal examples
for the usage of the KDE Frameworks.

This module provides the following function:

::

  kde_package_app_templates(TEMPLATES <template> [<template> [...]]
                            INSTALL_DIR <directory>)

``INSTALL_DIR`` is the directory to install the template package to.
In most cases you will want to use the variable ``KDE_INSTALL_KAPPTEMPLATESDIR``
from :kde-module:`KDEInstallDirs`.

``TEMPLATES`` lists subdirectories containing template files;
each ``<template>`` directory will be packaged into a file named
``<template>.tar.bz2`` and installed to the appropriate location.

The template is a minimal source tree of an application as if it was
an application project by itself, with names (file names or text inside)
the text files replaced by the following placeholders when needed:

``%{PROJECTDIRNAME}``
    name of generated project base folder ex: ``%{APPNAMELC}`` for KAppTemplate
``%{APPNAME}``
    project name as entered by user ex: MyKApp
``%{APPNAMELC}``
    project name in lower case ex: mykapp
``%{APPNAMEUC}``
    project name in upper case ex: MYKAPP

``%{CPP_TEMPLATE}``
    license header for cpp file
``%{H_TEMPLATE}``
    license header for h file

``%{AUTHOR}``
    author name ex: George Ignacious
``%{EMAIL}``
    author email ex: foo@bar.org
``%{VERSION}``
    project version ex: 0.1

Deprecated:

``%{dest}``
   path of generated project base folder, used in .kdevtemplate with the ``ShowFilesAfterGeneration`` entry
   KDevelop >= 5.1.1 supports relative paths with that entry, making this placeholder obsolete

Multiple templates can be passed at once.

This function does nothing when cross-compiling.


Since 5.18
#]=======================================================================]

function(kde_package_app_templates)
    if (CMAKE_CROSSCOMPILING)
        return()
    endif()

    set(_oneValueArgs INSTALL_DIR)
    set(_multiValueArgs TEMPLATES)
    cmake_parse_arguments(ARG "" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN} )

    if(NOT ARG_TEMPLATES)
        message(FATAL_ERROR "No TEMPLATES argument given to kde_package_app_templates")
    endif()

    if(NOT ARG_INSTALL_DIR)
        message(FATAL_ERROR "No INSTALL_DIR argument given to kde_package_app_templates")
    endif()

    find_program(_tar_executable NAMES gtar tar)
    if(_tar_executable)
        # NOTE: we also pass `--sort=name` here to check if the tar exe supports that
        #       this feature was only added in gnu tar v1.28
        execute_process(
            COMMAND ${_tar_executable} --sort=name --version
            TIMEOUT 3
            RESULT_VARIABLE _tar_exit
            OUTPUT_VARIABLE _tar_version
            ERROR_VARIABLE _tar_stderr
        )
        if("${_tar_exit}" EQUAL 0 AND "${_tar_version}" MATCHES "GNU tar")
            set(GNU_TAR_FOUND ON)
        else()
            set(GNU_TAR_FOUND OFF)
        endif()
    else()
        set(GNU_TAR_FOUND OFF)
    endif()

    foreach(_templateName ${ARG_TEMPLATES})
        get_filename_component(_tmp_file ${_templateName} ABSOLUTE)
        get_filename_component(_baseName ${_tmp_file} NAME_WE)
        set(_template ${CMAKE_CURRENT_BINARY_DIR}/${_baseName}.tar.bz2)

        # also enlist directories as deps to catch file removals
        file(GLOB_RECURSE _subdirs_entries LIST_DIRECTORIES true CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${_templateName}/*")

        add_custom_target(${_baseName}_kapptemplate ALL DEPENDS ${_template})

        if(GNU_TAR_FOUND)
            # Honour SOURCE_DATE_EPOCH if set
            if(DEFINED ENV{SOURCE_DATE_EPOCH})
                set(TIMESTAMP $ENV{SOURCE_DATE_EPOCH})
            else()
                execute_process(
                    COMMAND "date" "+%s"
                    OUTPUT_VARIABLE TIMESTAMP
                    OUTPUT_STRIP_TRAILING_WHITESPACE)
            endif()

            # Make tar archive reproducible, the arguments are only available with GNU tar
            add_custom_command(OUTPUT ${_template}
                COMMAND ${_tar_executable} ARGS
                   --exclude .kdev_ignore --exclude .svn
                   --sort=name
                   --mode=go=rX,u+rw,a-s
                   --numeric-owner --owner=0 --group=0
                   --mtime="@${TIMESTAMP}"
                   --pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime
                    -c -j -f ${_template} .
                WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${_templateName}
                DEPENDS ${_subdirs_entries}
            )
        else()
            add_custom_command(OUTPUT ${_template}
                COMMAND ${CMAKE_COMMAND} -E tar "cvfj" ${_template} .
                WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${_templateName}
                DEPENDS ${_subdirs_entries}
            )
        endif()

        install(FILES ${_template} DESTINATION ${ARG_INSTALL_DIR})
        set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${_template}")

    endforeach()
endfunction()
# SPDX-FileCopyrightText: 2014-2015 Alex Merry <alex.merry@kde.org>
# SPDX-FileCopyrightText: 2013 Stephen Kelly <steveire@gmail.com>
# SPDX-FileCopyrightText: 2012 David Faure <faure@kde.org>
# SPDX-FileCopyrightText: 2007 Matthias Kretz <kretz@kde.org>
# SPDX-FileCopyrightText: 2006-2007 Laurent Montel <montel@kde.org>
# SPDX-FileCopyrightText: 2006-2013 Alex Neundorf <neundorf@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause
#
# Prefix script setup code shared between KDEInstallDirsX.cmake, not public API.
#

if (CMAKE_CROSSCOMPILING)
    # we can't run anything when cross-compiling, so no need to even bother with a prefix script in this case
    return()
endif()

configure_file(${CMAKE_CURRENT_LIST_DIR}/prefix.sh.cmake ${CMAKE_CURRENT_BINARY_DIR}/prefix.sh @ONLY)

find_program(FISH_EXECUTABLE fish)
if(FISH_EXECUTABLE)
    configure_file(${CMAKE_CURRENT_LIST_DIR}/prefix.sh.fish.cmake ${CMAKE_CURRENT_BINARY_DIR}/prefix.sh.fish @ONLY)
endif()

option(KDE_INSTALL_PREFIX_SCRIPT "Installs ${CMAKE_INSTALL_PREFIX}/prefix.sh that sets up the necessary environment variables" OFF)
if(KDE_INSTALL_PREFIX_SCRIPT)
    install(FILES ${CMAKE_CURRENT_BINARY_DIR}/prefix.sh DESTINATION ${CMAKE_INSTALL_PREFIX} PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ)
endif()

if(NOT KDE_INSTALL_USE_QT_SYS_PATHS)
    message("Installing in ${CMAKE_INSTALL_PREFIX}. Run ${CMAKE_CURRENT_BINARY_DIR}/prefix.sh to set the environment for ${CMAKE_PROJECT_NAME}.")
endif()
file(GLOB install_done "${INSTALL_FILES}")
if (install_done)
    file(READ "${INSTALL_FILES}" out)
    string(REPLACE "\n" ";" out "${out}")
else()
    message("Not installed yet, skipping")
    set(out "")
endif()

set(metadatafiles)
foreach(file IN LISTS out)
    if(NOT (file MATCHES ".+\\.appdata.xml" OR file MATCHES ".+\\.metainfo.xml"))
        continue()
    endif()

    if(EXISTS ${file})
        list(APPEND metadatafiles ${file})
    else()
        message(WARNING "Could not find ${file}")
    endif()
endforeach()

if(metadatafiles)
    set(appstreamcliout "")
    execute_process(COMMAND ${APPSTREAMCLI} validate --no-net ${metadatafiles}
        ERROR_VARIABLE appstreamcliout
        OUTPUT_VARIABLE appstreamcliout
        RESULT_VARIABLE result
    )

    if(result EQUAL 0)
        set(msgType STATUS)
    else()
        set(msgType FATAL_ERROR)
    endif()
    message(${msgType} ${appstreamcliout})
endif()
---
# SPDX-FileCopyrightText: 2019 Christoph Cullmann <cullmann@kde.org>
# SPDX-FileCopyrightText: 2019 Gernot Gebhard <gebhard@absint.com>
#
# SPDX-License-Identifier: MIT

# This file got automatically created by ECM, do not edit
# See https://clang.llvm.org/docs/ClangFormatStyleOptions.html for the config options
# and https://community.kde.org/Policies/Frameworks_Coding_Style#Clang-format_automatic_code_formatting
# for clang-format tips & tricks
---
Language: JavaScript
DisableFormat: true
---

# Style for C++
Language: Cpp

# base is WebKit coding style: https://webkit.org/code-style-guidelines/
# below are only things set that diverge from this style!
BasedOnStyle: WebKit

# enforce C++11 (e.g. for std::vector<std::vector<lala>>
Standard: Cpp11

# 4 spaces indent
TabWidth: 4

# 2 * 80 wide lines
ColumnLimit: 160

# sort includes inside line separated groups
SortIncludes: true

# break before braces on function, namespace and class definitions.
BreakBeforeBraces: Linux

# CrlInstruction *a;
PointerAlignment: Right

# horizontally aligns arguments after an open bracket.
AlignAfterOpenBracket: Align

# don't move all parameters to new line
AllowAllParametersOfDeclarationOnNextLine: false

# no single line functions
AllowShortFunctionsOnASingleLine: None

# no single line enums
AllowShortEnumsOnASingleLine: false

# always break before you encounter multi line strings
AlwaysBreakBeforeMultilineStrings: true

# don't move arguments to own lines if they are not all on the same
BinPackArguments: false

# don't move parameters to own lines if they are not all on the same
BinPackParameters: false

# In case we have an if statement with multiple lines the operator should be at the beginning of the line
# but we do not want to break assignments
BreakBeforeBinaryOperators: NonAssignment

# format C++11 braced lists like function calls
Cpp11BracedListStyle: true

# do not put a space before C++11 braced lists
SpaceBeforeCpp11BracedList: false

# remove empty lines
KeepEmptyLinesAtTheStartOfBlocks: false

# no namespace indentation to keep indent level low
NamespaceIndentation: None

# we use template< without space.
SpaceAfterTemplateKeyword: false

# Always break after template declaration
AlwaysBreakTemplateDeclarations: true

# macros for which the opening brace stays attached.
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH, forever, Q_FOREVER, QBENCHMARK, QBENCHMARK_ONCE , wl_resource_for_each, wl_resource_for_each_safe ]

# keep lambda formatting multi-line if not empty
AllowShortLambdasOnASingleLine: Empty

# We do not want clang-format to put all arguments on a new line
AllowAllArgumentsOnNextLine: false
#!/usr/bin/env bash

# Based on okular/hooks/pre-commit, credits go to Albert Astals Cid

clang_format_major_version=@KDE_CLANG_FORMAT_MAJOR_VERSION@
if [[ ${clang_format_major_version:-1} -ge 14 ]]; then
    readonly output=$(git clang-format --staged --extensions 'cpp,h,hpp,c' -v --diff)
else
    readonly output=$(git clang-format --extensions 'cpp,h,hpp,c' -v --diff)
fi

if [[ ! -f .clang-format ]]; then
    if [[ @HAS_CLANG_FORMAT_COMMAND_INCLUDED@ = TRUE ]]; then
        echo "ERROR: no .clang-format file found in repository root, abort format"
        echo "       run cmake for this repository to generate it"
    else
        echo "ERROR: no .clang-format file found in repository root, abort format"
        echo "Make sure the KDEClangFormat CMake module is included, which will copy the KDE .clang-format file during the CMake configuration."
        echo "Alternatively you can manually copy a .clang-format file to the repository root directory."
    fi
    exit 1
fi
if [[ "$output" == *"no modified files to format"* ]]; then exit 0; fi
if [[ "$output" == *"clang-format did not modify any files"* ]]; then exit 0; fi

echo "ERROR: You have unformatted changes, please format your files. You can do this using the following commands:"
if [[ ${clang_format_major_version:-1} -ge 14 ]]; then
    echo "       git clang-format --staged --extensions 'cpp,h,hpp,c' # format the changed parts"
    echo "       git clang-format --staged --extensions 'cpp,h,hpp,c' --diff # preview the changes done by the formatter"
else
    echo "       git clang-format --extensions 'cpp,h,hpp,c' --force # format the changed parts"
    echo "       git clang-format --extensions 'cpp,h,hpp,c' --diff # preview the changes done by the formatter"
fi
exit 1
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "if": {
    "type": "object"
  },
  "then": {
    "allOf": [@SCHEMA_INCLUDES@]
  }
}
# Version in sysadmin/ci-utilities should be single source of truth
SPDX-FileCopyrightText: 2023 Alexander Lohnau <alexander.lohnau@gmx.de>
SPDX-License-Identifier: BSD-2-Clause
#!/usr/bin/python3
# Version in sysadmin/ci-utilities should be single source of truth
# SPDX-FileCopyrightText: 2023 Alexander Lohnau <alexander.lohnau@gmx.de>
# SPDX-License-Identifier: BSD-2-Clause

import os
import subprocess
import yaml
import sys

def get_changed_files():
    result = subprocess.run(['git', 'diff', '--name-only', 'HEAD'], capture_output=True, text=True)
    return [file for file in result.stdout.splitlines() if file.endswith('.json')]

def get_all_files():
    files = []
    for root, dirs, filenames in os.walk('.'):
        for filename in filenames:
            if filename.endswith('.json'):
                files.append(os.path.join(root, filename))
    return files

def filter_excluded_json_files(files):
    config_file = '.kde-ci.yml'
    # Check if the file exists
    if os.path.exists(config_file):
        with open(config_file, 'r') as file:
            config = yaml.safe_load(file)
    else:
        print(f'{config_file} does not exist in current directory')
        config = {}
    # Extract excluded files, used for tests that intentionally have broken files
    excluded_files = ['compile_commands.json', 'ci-utilities']
    if 'Options' in config and 'json-validate-ignore' in config['Options']:
        excluded_files += config['Options']['json-validate-ignore']

    # Find JSON files
    filtered_files = []
    for file_path in files:
        if not any(excluded_file in file_path for excluded_file in excluded_files):
            filtered_files.append(file_path)
    return filtered_files

is_kde_ci = "KDE_CI" in os.environ
if is_kde_ci:
    files = get_all_files()
else:
    files = get_changed_files()
files = filter_excluded_json_files(files)
if files:
    files_option = ' '.join(files)
    if len(sys.argv) > 1:
        schemafile = sys.argv[1]
    else:
        schemafile = os.path.join(os.path.dirname(__file__), 'resources', 'kpluginmetadata.schema.json')
    if is_kde_ci: # Only report files on CI, for pre-commit hook, we'd like to avoid verbose output in terminal sessions
        print(f"Validating {files_option} with {schemafile}")
    result = subprocess.run(['check-jsonschema', *files, '--schemafile', schemafile])
    # Fail the pipeline if command failed
    if result.returncode != 0:
        exit(1)

#!/usr/bin/env bash

${PRE_COMMIT_SCRIPTS}
export PATH=@KDE_INSTALL_FULL_BINDIR@:$PATH

# LD_LIBRARY_PATH only needed if you are building without rpath
# export LD_LIBRARY_PATH=@KDE_INSTALL_FULL_LIBDIR@:$LD_LIBRARY_PATH

export XDG_DATA_DIRS=@KDE_INSTALL_FULL_DATADIR@:${XDG_DATA_DIRS:-/usr/local/share:/usr/share}
export XDG_CONFIG_DIRS=@KDE_INSTALL_FULL_CONFDIR@:${XDG_CONFIG_DIRS:-/etc/xdg}

export QT_PLUGIN_PATH=@KDE_INSTALL_FULL_QTPLUGINDIR@:$QT_PLUGIN_PATH
export QML2_IMPORT_PATH=@KDE_INSTALL_FULL_QMLDIR@:$QML2_IMPORT_PATH

export QT_QUICK_CONTROLS_STYLE_PATH=@KDE_INSTALL_FULL_QMLDIR@/QtQuick/Controls.2/:$QT_QUICK_CONTROLS_STYLE_PATH

export MANPATH=@KDE_INSTALL_FULL_DATADIR@/man:${MANPATH:-/usr/local/share/man:/usr/share/man}

export SASL_PATH=@KDE_INSTALL_FULL_LIBDIR@/sasl2:${SASL_PATH:-/usr/@CMAKE_INSTALL_LIBDIR@/sasl2}
# SPDX-FileCopyrightText: 2021 Alexander Lohnau <alexander.lohnau@gmx.de>
# SPDX-License-Identifier: BSD-3-Clause

set PATH "@KDE_INSTALL_FULL_BINDIR@:$PATH"

# LD_LIBRARY_PATH only needed if you are building without rpath
# set -x LD_LIBRARY_PATH "@KDE_INSTALL_FULL_LIBDIR@:$LD_LIBRARY_PATH"

if test -z "$XDG_DATA_DIRS"
    set -x --path XDG_DATA_DIRS /usr/local/share/ /usr/share/
end
set -x --path XDG_DATA_DIRS "@KDE_INSTALL_FULL_DATADIR@" $XDG_DATA_DIRS

if test -z "$XDG_CONFIG_DIRS"
    set -x --path XDG_CONFIG_DIRS /etc/xdg
end
set -x --path XDG_CONFIG_DIRS "@KDE_INSTALL_FULL_CONFDIR@" $XDG_CONFIG_DIRS

set -x --path QT_PLUGIN_PATH "@KDE_INSTALL_FULL_QTPLUGINDIR@" $QT_PLUGIN_PATH
set -x --path QML2_IMPORT_PATH "@KDE_INSTALL_FULL_QMLDIR@" $QML2_IMPORT_PATH

set -x --path QT_QUICK_CONTROLS_STYLE_PATH "@KDE_INSTALL_FULL_QMLDIR@/QtQuick/Controls.2/" $QT_QUICK_CONTROLS_STYLE_PATH
# SPDX-FileCopyrightText: 2003-2018 University of Illinois at Urbana-Champaign.
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
CheckAtomic
-----------

Check if the compiler supports std:atomic out of the box or if libatomic is
needed for atomic support. If it is needed libatomicis added to
``CMAKE_REQUIRED_LIBRARIES``. So after running CheckAtomic you can use
std:atomic.

Since 5.75.0.
#]=======================================================================]

include(CheckCXXSourceCompiles)
include(CheckLibraryExists)

# Sometimes linking against libatomic is required for atomic ops, if
# the platform doesn't support lock-free atomics.

function(check_working_cxx_atomics varname)
  set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
  set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -std=c++11")
  check_cxx_source_compiles("
  #include <atomic>
  std::atomic<int> x;
  std::atomic<short> y;
  std::atomic<char> z;
  int main() {
    ++z;
    ++y;
    return ++x;
  }
  " ${varname})
  set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS})
endfunction()

function(check_working_cxx_atomics64 varname)
  set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
  set(CMAKE_REQUIRED_FLAGS "-std=c++11 ${CMAKE_REQUIRED_FLAGS}")
  check_cxx_source_compiles("
  #include <atomic>
  #include <cstdint>
  std::atomic<uint64_t> x (0);
  int main() {
    uint64_t i = x.load(std::memory_order_relaxed);
    return 0;
  }
  " ${varname})
  set(CMAKE_REQUIRED_FLAGS ${OLD_CMAKE_REQUIRED_FLAGS})
endfunction()

# Check for (non-64-bit) atomic operations.
if(MSVC)
  set(HAVE_CXX_ATOMICS_WITHOUT_LIB True)
elseif(LLVM_COMPILER_IS_GCC_COMPATIBLE)
  # First check if atomics work without the library.
  check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITHOUT_LIB)
  # If not, check if the library exists, and atomics work with it.
  if(NOT HAVE_CXX_ATOMICS_WITHOUT_LIB)
    check_library_exists(atomic __atomic_fetch_add_4 "" HAVE_LIBATOMIC)
    if(HAVE_LIBATOMIC)
      list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic")
      check_working_cxx_atomics(HAVE_CXX_ATOMICS_WITH_LIB)
      if (NOT HAVE_CXX_ATOMICS_WITH_LIB)
        message(FATAL_ERROR "Host compiler must support std::atomic!")
      endif()
    else()
      message(FATAL_ERROR "Host compiler appears to require libatomic, but cannot find it.")
    endif()
  endif()
endif()

# Check for 64 bit atomic operations.
if(MSVC)
  set(HAVE_CXX_ATOMICS64_WITHOUT_LIB True)
elseif(LLVM_COMPILER_IS_GCC_COMPATIBLE)
  # First check if atomics work without the library.
  check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITHOUT_LIB)
  # If not, check if the library exists, and atomics work with it.
  if(NOT HAVE_CXX_ATOMICS64_WITHOUT_LIB)
    check_library_exists(atomic __atomic_load_8 "" HAVE_CXX_LIBATOMICS64)
    if(HAVE_CXX_LIBATOMICS64)
      list(APPEND CMAKE_REQUIRED_LIBRARIES "atomic")
      check_working_cxx_atomics64(HAVE_CXX_ATOMICS64_WITH_LIB)
      if (NOT HAVE_CXX_ATOMICS64_WITH_LIB)
        message(FATAL_ERROR "Host compiler must support 64-bit std::atomic!")
      endif()
    else()
      message(FATAL_ERROR "Host compiler appears to require libatomic for 64-bit operations, but cannot find it.")
    endif()
  endif()
endif()
# SPDX-FileCopyrightText: 2018-2023 Aleix Pol <aleixpol@kde.org>
# SPDX-FileCopyrightText: 2023 Volker Krause <vkrause@kde.org>
# SPDX-License-Identifier: BSD-2-Clause

#[=======================================================================[.rst:
ECMAddAndroidApk
----------------

Functions for creating Android APK packages using Qt6's ``androiddeployqt`` tool
as well as the associated Fastlane metadata.

::

  ecm_add_android_apk(<target>
      [ANDROID_DIR <dir>]
      [PACKAGE_NAME <name>]
      # TODO extra args?
  )

Creates an Android APK for the given target.

If ``ANDROID_DIR`` is given, the Android manifest file as well as any potential
Gradle build system files or Java/Kotlin source files are taken from that directory.
If not set, the standard template shipped with Qt6 is used, which in usually not
what you want for production applications.

If ``PACKAGE_NAME`` is given, it is used as name for the Android APK.
If not set, the ``target`` name is used. Since 6.10.0

The use of this function creates a build target called ``create-apk-<target>``
which will run ``androiddeployqt`` to produce an (unsigned) APK, as well
as convert Appstream application metadata (if present) into the Fastlane format used
by F-Droid and Play store automation.

There's also a ``create-apk`` convenience target being created that
will build all APKs defined in a project.

When building for another platform than Android, this function does nothing.

The following variables impact the behavior:
``ECM_ADDITIONAL_FIND_ROOT_PATH``
    See documentation in the Android toolchain file.

``ECM_APK_STAGING_ROOT_PATH``
    For use with Craft's image directory. If set this is used as the source
    for all content of the APK rather than the search paths used for building.
    This allows to separate e.g. development files from what ends up in the APK.

Since 6.0.0
#]=======================================================================]

# make ExecuteCoreModules test pass on Qt5
include(${CMAKE_CURRENT_LIST_DIR}/../modules/QtVersionOption.cmake)
if (QT_MAJOR_VERSION EQUAL 5)
    message(WARNING "ECMAddAndroidApk is not compatible with Qt5 - skipping.")
    return()
endif()

find_package(Qt6Core REQUIRED) # required for the following to work stand-alone
find_package(Qt6CoreTools REQUIRED)
find_package(Python3 COMPONENTS Interpreter REQUIRED)

set(_ECM_TOOLCHAIN_DIR "${CMAKE_CURRENT_LIST_DIR}/../toolchain")

function (ecm_add_android_apk TARGET)
    set(oneValueArgs ANDROID_DIR PACKAGE_NAME)
    cmake_parse_arguments(ARGS "" "${oneValueArgs}" "" ${ARGN})
    if (NOT ANDROID)
        return()
    endif()

    set(APK_NAME "${TARGET}")
    if (ARGS_PACKAGE_NAME)
        set(APK_NAME "${ARGS_PACKAGE_NAME}")
    endif()

    set(APK_OUTPUT_DIR "${CMAKE_BINARY_DIR}/${TARGET}_build_apk/")
    set(APK_EXECUTABLE_PATH "${APK_OUTPUT_DIR}/libs/${CMAKE_ANDROID_ARCH_ABI}/lib${APK_NAME}_${CMAKE_ANDROID_ARCH_ABI}.so")

    set(QML_IMPORT_PATHS "")
    # add build directory to the search path as well, so this works without installation
    if (EXISTS ${CMAKE_BINARY_DIR}/lib)
        set(QML_IMPORT_PATHS ${CMAKE_BINARY_DIR}/lib)
    endif()
    if (ECM_APK_STAGING_ROOT_PATH)
        set(QML_IMPORT_PATHS "${ECM_APK_STAGING_ROOT_PATH}/lib/qml")
        set(ANDROID_QT6_INSTALL_PREFIX ${ECM_APK_STAGING_ROOT_PATH})
    else()
        foreach(prefix ${ECM_ADDITIONAL_FIND_ROOT_PATH})
            # qmlimportscanner chokes on symlinks, so we need to resolve those first
            get_filename_component(qml_path "${prefix}/lib/qml" REALPATH)
            if(EXISTS ${qml_path})
                if (QML_IMPORT_PATHS)
                    set(QML_IMPORT_PATHS "${QML_IMPORT_PATHS},${qml_path}")
                else()
                    set(QML_IMPORT_PATHS "${qml_path}")
                endif()
            endif()
        endforeach()
        set(ANDROID_QT6_INSTALL_PREFIX ${QT6_INSTALL_PREFIX})
    endif()
    if (QML_IMPORT_PATHS)
        set(DEFINE_QML_IMPORT_PATHS "\"qml-import-paths\": \"${QML_IMPORT_PATHS}\",")
    endif()

    set(EXTRA_PREFIX_DIRS "\"${CMAKE_BINARY_DIR}\"")
    set(EXTRA_LIB_DIRS "\"${CMAKE_BINARY_DIR}/lib\"")
    if (ECM_APK_STAGING_ROOT_PATH)
        set(EXTRA_PREFIX_DIRS "${EXTRA_PREFIX_DIRS}, \"${ECM_APK_STAGING_ROOT_PATH}\"")
        set(EXTRA_LIB_DIRS "${EXTRA_LIB_DIRS}, \"${ECM_APK_STAGING_ROOT_PATH}/lib\"")
    else()
        foreach(prefix ${ECM_ADDITIONAL_FIND_ROOT_PATH})
            set(EXTRA_PREFIX_DIRS "${EXTRA_PREFIX_DIRS}, \"${prefix}\"")
            set(EXTRA_LIB_DIRS "${EXTRA_LIB_DIRS}, \"${prefix}/lib\"")
        endforeach()
    endif()

    if (ARGS_ANDROID_DIR AND EXISTS ${ARGS_ANDROID_DIR}/AndroidManifest.xml)
        set(ANDROID_APK_DIR ${ARGS_ANDROID_DIR})
    else()
        message("Using default Qt APK template - this is often not intentional!")
        get_filename_component(_qtCore_install_prefix "${Qt6Core_DIR}/../../../" ABSOLUTE)
        set(ANDROID_APK_DIR "${_qtCore_install_prefix}/src/android/templates/")
    endif()

    get_target_property(QT6_RCC_BINARY Qt6::rcc LOCATION)
    string(TOLOWER "${CMAKE_HOST_SYSTEM_NAME}" _LOWER_CMAKE_HOST_SYSTEM_NAME)
    configure_file("${_ECM_TOOLCHAIN_DIR}/deployment-file-qt6.json.in" "${CMAKE_BINARY_DIR}/${APK_NAME}-deployment.json.in")

    if (NOT TARGET create-apk)
        add_custom_target(create-apk)
        if (NOT DEFINED ANDROID_FASTLANE_METADATA_OUTPUT_DIR)
            set(ANDROID_FASTLANE_METADATA_OUTPUT_DIR ${CMAKE_BINARY_DIR}/fastlane)
        endif()
        add_custom_target(create-fastlane
            COMMAND Python3::Interpreter ${_ECM_TOOLCHAIN_DIR}/generate-fastlane-metadata.py --output ${ANDROID_FASTLANE_METADATA_OUTPUT_DIR} --source ${CMAKE_SOURCE_DIR}
        )
    endif()

    if (NOT DEFINED ANDROID_APK_OUTPUT_DIR)
        set(ANDROID_APK_OUTPUT_DIR ${APK_OUTPUT_DIR})
    endif()

    if (CMAKE_GENERATOR STREQUAL "Unix Makefiles")
        set(arguments "\\$(ARGS)")
    endif()

    if (NOT ECM_APK_STAGING_ROOT_PATH)
        set(ECM_APK_STAGING_ROOT_PATH "${CMAKE_INSTALL_PREFIX}")
    endif()

    file(WRITE ${CMAKE_BINARY_DIR}/ranlib "${CMAKE_RANLIB}")
    set(CREATEAPK_TARGET_NAME "create-apk-${APK_NAME}")
    set(APK_NAME_FULL "${APK_NAME}-${CMAKE_ANDROID_ARCH_ABI}.apk")
    add_custom_target(${CREATEAPK_TARGET_NAME}
        WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
        COMMAND ${CMAKE_COMMAND} -E echo "Generating ${APK_NAME_FULL} with $<TARGET_FILE:Qt6::androiddeployqt>"
        COMMAND ${CMAKE_COMMAND} -E remove_directory "${APK_OUTPUT_DIR}"
        COMMAND ${CMAKE_COMMAND} -E copy "$<TARGET_FILE:${TARGET}>" "${APK_EXECUTABLE_PATH}"
        COMMAND LANG=C ${CMAKE_COMMAND} "-DTARGET=$<TARGET_FILE:${TARGET}>" -P ${_ECM_TOOLCHAIN_DIR}/hasMainSymbol.cmake
        COMMAND LANG=C ${CMAKE_COMMAND}
            -DINPUT_FILE="${CMAKE_BINARY_DIR}/${APK_NAME}-deployment.json.in"
            -DOUTPUT_FILE="${CMAKE_BINARY_DIR}/${APK_NAME}-deployment.json"
            "-DTARGET=$<TARGET_FILE:${TARGET}>"
            "-DOUTPUT_DIR=$<TARGET_FILE_DIR:${TARGET}>"
            "-DEXPORT_DIR=${ECM_APK_STAGING_ROOT_PATH}"
            "-DECM_ADDITIONAL_FIND_ROOT_PATH=\"${ECM_ADDITIONAL_FIND_ROOT_PATH}\""
            -P ${_ECM_TOOLCHAIN_DIR}/specifydependencies.cmake
        COMMAND Qt6::androiddeployqt
            ${ANDROIDDEPLOYQT_EXTRA_ARGS}
            --gradle
            --input "${CMAKE_BINARY_DIR}/${APK_NAME}-deployment.json"
            --apk "${ANDROID_APK_OUTPUT_DIR}/${APK_NAME_FULL}"
            --output "${APK_OUTPUT_DIR}"
            --android-platform android-${ANDROID_SDK_COMPILE_API}
            --deployment bundled
            --qml-importscanner-binary $<TARGET_FILE:Qt6::qmlimportscanner>
            ${arguments}
    )

    add_dependencies(create-apk ${CREATEAPK_TARGET_NAME})
    add_dependencies(${CREATEAPK_TARGET_NAME} create-fastlane)
endfunction()
# SPDX-FileCopyrightText: 2014 Alex Merry <alex.merry@kde.org>
# SPDX-FileCopyrightText: 2014 Ralf Habacker <ralf.habacker@freenet.de>
# SPDX-FileCopyrightText: 2006-2009 Alexander Neundorf <neundorf@kde.org>
# SPDX-FileCopyrightText: 2006, 2007 Laurent Montel <montel@kde.org>
# SPDX-FileCopyrightText: 2007 Matthias Kretz <kretz@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
ECMAddAppIcon
-------------

Add icons to executable files and packages.

::

 ecm_add_app_icon(<sources_var_name(|target (since 5.83))>
                  ICONS <icon> [<icon> [...]]
                  [SIDEBAR_ICONS <icon> [<icon> [...]] # Since 5.49
                  [OUTFILE_BASENAME <name>]) # Since 5.49
                  )

The given icons, whose names must match the pattern::

  <size>-<other_text>.png

will be added as platform-specific application icons
to the variable named ``<sources_var_name>`` or, if the first argument
is a target (since 5.83), to the ``SOURCES`` property of ``<target>``.
Any target must be created with add_executable() and not be an alias.

Other icon files are ignored but on macOS SVG files can be supported and
it is thus possible to mix those with png files in a single macro call.

The platforms currently supported are Windows and macOS, on all others
the call has no effect and is ignored.

``<size>`` is a numeric pixel size (typically 16, 32, 48, 64, 128 or 256).
``<other_text>`` can be any other text. See the platform notes below for any
recommendations about icon sizes.

``SIDEBAR_ICONS`` can be used to add macOS sidebar
icons to the generated iconset. They are used when a folder monitored by the
application is dragged into Finder's sidebar. Since 5.49.

``OUTFILE_BASENAME`` will be used as the basename for the icon file. If
you specify it, the icon file will be called ``<OUTFILE_BASENAME>.icns`` on macOS
and ``<OUTFILE_BASENAME>.ico`` on Windows. If you don't specify it, it defaults
to ``<sources_var_name>.<ext>``. Since 5.49.


Windows notes
   * Icons are compiled into the executable using a resource file.
   * Icons may not show up in Windows Explorer if the executable
     target does not have the ``WIN32_EXECUTABLE`` property set.
   * Icotool (see :find-module:`FindIcoTool`) is required.
   * Supported sizes: 16, 24, 32, 48, 64, 128, 256, 512 and 1024.

macOS notes
   * The executable target must have the ``MACOSX_BUNDLE`` property set.
   * Icons are added to the bundle.
   * If the ksvg2icns tool from KIconThemes is available, .svg and .svgz
     files are accepted; the first that is converted successfully to .icns
     will provide the application icon. SVG files are ignored otherwise.
   * The tool iconutil (provided by Apple) is required for bitmap icons.
   * Supported sizes: 16, 32, 64, 128, 256 (and 512, 1024 after OS X 10.9).
   * At least a 128x128px (or an SVG) icon is required.
   * Larger sizes are automatically used to substitute for smaller sizes on
     "Retina" (high-resolution) displays. For example, a 32px icon, if
     provided, will be used as a 32px icon on standard-resolution displays,
     and as a 16px-equivalent icon (with an "@2x" tag) on high-resolution
     displays. That is why you should provide 64px and 1024px icons although
     they are not supported anymore directly. Instead they will be used as
     32px@2x and 512px@2x. If an SVG icon is provided, ksvg2icns will be
     used internally to automatically generate all appropriate sizes,
     including the high-resolution ones.
   * This function sets the ``MACOSX_BUNDLE_ICON_FILE`` variable to the name
     of the generated icns file, so that it will be used as the
     ``MACOSX_BUNDLE_ICON_FILE`` target property when you call
     ``add_executable``.
   * Sidebar icons should typically provided in 16, 32, 64, 128 and 256px.

Since 1.7.0.
#]=======================================================================]

function(ecm_add_app_icon appsources_or_target)
    set(options)
    set(oneValueArgs OUTFILE_BASENAME)
    set(multiValueArgs ICONS SIDEBAR_ICONS)
    cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

    if(NOT ARG_ICONS)
        message(FATAL_ERROR "No ICONS argument given to ecm_add_app_icon")
    endif()
    if (TARGET ${appsources_or_target})
        get_target_property(target_type ${appsources_or_target} TYPE)
        if (NOT target_type STREQUAL "EXECUTABLE")
            message(FATAL_ERROR "Target argument passed to ecm_add_app_icon is not an executable: ${appsources_or_target}")
        endif()
        get_target_property(aliased_target ${appsources_or_target} ALIASED_TARGET)
        if(aliased_target)
            message(FATAL_ERROR "Target argument passed to ecm_add_app_icon must not be an alias: ${appsources_or_target}")
        endif()
    endif()
    if(ARG_UNPARSED_ARGUMENTS)
        message(FATAL_ERROR "Unexpected arguments to ecm_add_app_icon: ${ARG_UNPARSED_ARGUMENTS}")
    endif()

    if(APPLE)
        find_program(KSVG2ICNS NAMES ksvg2icns)
        foreach(icon ${ARG_ICONS})
            get_filename_component(icon_full ${icon} ABSOLUTE)
            get_filename_component(icon_type ${icon_full} EXT)
            # do we have ksvg2icns in the path and did we receive an svg (or compressed svg) icon?
            if(KSVG2ICNS AND (${icon_type} STREQUAL ".svg" OR ${icon_type} STREQUAL ".svgz"))
                # convert the svg icon to an icon resource
                execute_process(COMMAND ${KSVG2ICNS} "${icon_full}"
                    WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} RESULT_VARIABLE KSVG2ICNS_ERROR)
                if(${KSVG2ICNS_ERROR})
                    message(AUTHOR_WARNING "ksvg2icns could not generate an OS X application icon from ${icon}")
                else()
                    # install the icns file we just created
                    get_filename_component(icon_name ${icon_full} NAME_WE)
                    set(MACOSX_BUNDLE_ICON_FILE ${icon_name}.icns PARENT_SCOPE)
                    if (TARGET ${appsources_or_target})
                        target_sources(${appsources_or_target} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/${icon_name}.icns")
                    else()
                        set(${appsources_or_target} "${${appsources_or_target}};${CMAKE_CURRENT_BINARY_DIR}/${icon_name}.icns" PARENT_SCOPE)
                    endif()
                    set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/${icon_name}.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
                    # we're done now
                    return()
                endif()
            endif()
        endforeach()
    endif()


    _ecm_add_app_icon_categorize_icons("${ARG_ICONS}" "icons" "16;24;32;48;64;128;256;512;1024")
    if(ARG_SIDEBAR_ICONS)
        _ecm_add_app_icon_categorize_icons("${ARG_SIDEBAR_ICONS}" "sidebar_icons" "16;32;64;128;256")
    endif()

    set(mac_icons
                  # Icons: https://developer.apple.com/library/content/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Optimizing/Optimizing.html#//apple_ref/doc/uid/TP40012302-CH7-SW4
                  ${icons_at_16px}
                  ${icons_at_32px}
                  ${icons_at_64px}
                  ${icons_at_128px}
                  ${icons_at_256px}
                  ${icons_at_512px}
                  ${icons_at_1024px})

    set(mac_sidebar_icons
                  # Sidebar Icons: https://developer.apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/Finder.html#//apple_ref/doc/uid/TP40014214-CH15-SW15
                  ${sidebar_icons_at_16px}
                  ${sidebar_icons_at_32px}
                  ${sidebar_icons_at_64px}
                  ${sidebar_icons_at_128px}
                  ${sidebar_icons_at_256px})

    if (NOT (mac_icons OR mac_sidebar_icons))
        message(AUTHOR_WARNING "No icons suitable for use on macOS provided")
    endif()


    set(windows_icons_classic ${icons_at_16px}
                              ${icons_at_24px}
                              ${icons_at_32px}
                              ${icons_at_48px}
                              ${icons_at_64px}
                              ${icons_at_128px})
    set(windows_icons_modern  ${windows_icons_classic}
                              ${icons_at_256px}
                              ${icons_at_512px}
                              ${icons_at_1024px})

    if (NOT (windows_icons_modern OR windows_icons_classic))
        message(AUTHOR_WARNING "No icons suitable for use on Windows provided")
    endif()

    if (ARG_OUTFILE_BASENAME)
        set (_outfilebasename "${ARG_OUTFILE_BASENAME}")
    else()
        set (_outfilebasename "${appsources_or_target}")
    endif()
    set (_outfilename "${CMAKE_CURRENT_BINARY_DIR}/${_outfilebasename}")

    if (WIN32 AND (windows_icons_modern OR windows_icons_classic))
        set(saved_CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}")
        set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_FIND_MODULE_DIR})
        find_package(IcoTool)
        set(CMAKE_MODULE_PATH "${saved_CMAKE_MODULE_PATH}")

        function(create_windows_icon_and_rc command args deps)
                add_custom_command(
                    OUTPUT "${_outfilename}.ico"
                    COMMAND ${command}
                    ARGS ${args}
                    DEPENDS ${deps}
                    WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
                )
                # this bit's a little hacky to make the dependency stuff work
                file(WRITE "${_outfilename}.rc.in" "IDI_ICON1        ICON        DISCARDABLE    \"${_outfilename}.ico\"\n")
                add_custom_command(
                    OUTPUT "${_outfilename}.rc"
                    COMMAND ${CMAKE_COMMAND}
                    ARGS -E copy "${_outfilename}.rc.in" "${_outfilename}.rc"
                    DEPENDS "${_outfilename}.ico"
                    WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
                )
        endfunction()

        if (IcoTool_FOUND)
            list(APPEND icotool_args "-c" "-o" "${_outfilename}.ico")

            # According to https://stackoverflow.com/a/40851713/2886832
            # Windows always chooses the first icon above 255px, all other ones will be ignored
            set(maxSize 0)
            foreach(size 256 512 1024)
                if(icons_at_${size}px)
                    set(maxSize "${size}")
                endif()
            endforeach()

            foreach(size 16 24 32 48 64 128 ${maxSize})
                if(NOT icons_at_${size}px)
                    continue()
                endif()

                set(icotool_icon_arg "")
                if(size STREQUAL "${maxSize}")
                    # maxSize icon needs to be included as raw png
                    list(APPEND icotool_args "-r")
                endif()

                foreach(icon ${icons_at_${size}px})
                    list(APPEND icotool_args "${icons_at_${size}px}")
                endforeach()
            endforeach()

            create_windows_icon_and_rc(IcoTool::IcoTool "${icotool_args}" "${windows_icons_modern}")
            if (TARGET ${appsources_or_target})
                target_sources(${appsources_or_target} PRIVATE "${_outfilename}.rc")
            else()
                set(${appsources_or_target} "${${appsources_or_target}};${_outfilename}.rc" PARENT_SCOPE)
            endif()
        else()
            message(WARNING "Unable to find the icotool utilities or icons in matching sizes - application will not have an application icon!")
        endif()
    elseif (APPLE AND (mac_icons OR mac_sidebar_icons))
        # first generate .iconset directory structure, then convert to .icns format using the macOS "iconutil" utility,
        # to create retina compatible icon, you need png source files in pixel resolution 16x16, 32x32, 64x64, 128x128,
        # 256x256, 512x512, 1024x1024
        find_program(ICONUTIL_EXECUTABLE NAMES iconutil)
        if (ICONUTIL_EXECUTABLE)
            add_custom_command(
                OUTPUT "${_outfilename}.iconset"
                COMMAND ${CMAKE_COMMAND}
                ARGS -E make_directory "${_outfilename}.iconset"
            )
            set(iconset_icons)
            macro(copy_icon filename sizename type)
                add_custom_command(
                    OUTPUT "${_outfilename}.iconset/${type}_${sizename}.png"
                    COMMAND ${CMAKE_COMMAND}
                    ARGS -E copy
                         "${filename}"
                         "${_outfilename}.iconset/${type}_${sizename}.png"
                    DEPENDS
                        "${_outfilename}.iconset"
                        "${filename}"
                    WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
                )
                list(APPEND iconset_icons
                        "${_outfilename}.iconset/${type}_${sizename}.png")
            endmacro()

            # List of supported sizes and filenames taken from:
            # https://developer.apple.com/library/content/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Optimizing/Optimizing.html#//apple_ref/doc/uid/TP40012302-CH7-SW4
            foreach(size 16 32 128 256 512)
                math(EXPR double_size "2 * ${size}")
                foreach(file ${icons_at_${size}px})
                    copy_icon("${file}" "${size}x${size}" "icon")
                endforeach()
                foreach(file ${icons_at_${double_size}px})
                    copy_icon("${file}" "${size}x${size}@2x" "icon")
                endforeach()
            endforeach()

            # List of supported sizes and filenames taken from:
            # https://developer.apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/Finder.html#//apple_ref/doc/uid/TP40014214-CH15-SW15
            foreach(file ${sidebar_icons_at_16px})
                copy_icon("${file}" "16x16" "sidebar")
            endforeach()
            foreach(file ${sidebar_icons_at_32px})
                copy_icon("${file}" "16x16@2x" "sidebar")
            endforeach()
            foreach(file ${sidebar_icons_at_32px})
                copy_icon("${file}" "18x18" "sidebar")
            endforeach()
            foreach(file ${sidebar_icons_at_64px})
                copy_icon("${file}" "18x18@2x" "sidebar")
            endforeach()
            foreach(file ${sidebar_icons_at_128px})
                copy_icon("${file}" "32x32" "sidebar")
            endforeach()
            foreach(file ${sidebar_icons_at_256px})
                copy_icon("${file}" "32x32@2x" "sidebar")
            endforeach()

            # generate .icns icon file
            add_custom_command(
                OUTPUT "${_outfilename}.icns"
                COMMAND ${ICONUTIL_EXECUTABLE}
                ARGS
                    --convert icns
                    --output "${_outfilename}.icns"
                    "${_outfilename}.iconset"
                DEPENDS "${iconset_icons}"
                WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
            )
            # This will register the icon into the bundle
            set(MACOSX_BUNDLE_ICON_FILE "${_outfilebasename}.icns" PARENT_SCOPE)

            # Append the icns file to the sources list so it will be a dependency to the
            # main target
            if (TARGET ${appsources_or_target})
                target_sources(${appsources_or_target} PRIVATE "${_outfilename}.icns")
            else()
                set(${appsources_or_target} "${${appsources_or_target}};${_outfilename}.icns" PARENT_SCOPE)
            endif()

            # Install the icon into the Resources dir in the bundle
            set_source_files_properties("${_outfilename}.icns" PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
        else()
            message(STATUS "Unable to find the iconutil utility - application will not have an application icon!")
        endif()
    endif()
endfunction()

macro(_ecm_add_app_icon_categorize_icons icons type known_sizes)
    set(_${type}_known_sizes)
    foreach(size ${known_sizes})
        set(${type}_at_${size}px)
        list(APPEND _${type}_known_sizes ${size})
    endforeach()


    foreach(icon ${icons})
        get_filename_component(icon_full ${icon} ABSOLUTE)
        if (NOT EXISTS "${icon_full}")
            message(AUTHOR_WARNING "${icon_full} does not exist, ignoring")
        else()
            get_filename_component(icon_name ${icon} NAME)
            string(REGEX MATCH "([0-9]+|sc)\\-[^/]+\\.([a-z]+)$"
                               _dummy "${icon_name}")
            set(size  "${CMAKE_MATCH_1}")
            set(ext   "${CMAKE_MATCH_2}")

            if (NOT (ext STREQUAL "svg" OR ext STREQUAL "svgz"))
                if (NOT size)
                    message(AUTHOR_WARNING "${icon_full} is not named correctly for ecm_add_app_icon - ignoring")
                elseif (NOT ext STREQUAL "png")
                    message(AUTHOR_WARNING "${icon_full} is not a png file - ignoring")
                else()
                    list(FIND _${type}_known_sizes ${size} offset)

                    if (offset GREATER -1)
                        list(APPEND ${type}_at_${size}px "${icon_full}")
                    elseif()
                        message(STATUS "not found ${type}_at_${size}px ${icon_full}")
                    endif()
                endif()
            endif()
        endif()
    endforeach()
endmacro()
# SPDX-FileCopyrightText: 2016-2017 Friedrich W. H. Kossebau <kossebau@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
ECMAddQch
------------------

This module provides the ``ecm_add_qch`` function for generating API
documentation files in the QCH format, and the ``ecm_install_qch_export``
function for generating and installing exported CMake targets for such
generated QCH files to enable builds of other software with generation of
QCH files to create links into the given QCH files.

::

  ecm_add_qch(<target_name>
      NAME <name>
      VERSION <version>
      QCH_INSTALL_DESTINATION <qchfile_install_path>
      TAGFILE_INSTALL_DESTINATION <tagsfile_install_path>
      [COMPONENT <component>]
      [BASE_NAME <basename>]
      [SOURCE_DIRS <dir> [<dir2> [...]]]
      [SOURCES <file> [<file2> [...]]]
      |MD_MAINPAGE <md_file>]
      [INCLUDE_DIRS <incdir> [<incdir2> [...]]]
      [IMAGE_DIRS <idir> [<idir2> [...]]]
      [EXAMPLE_DIRS <edir> [<edir2> [...]]]
      [ORG_DOMAIN <domain>]
      [NAMESPACE <namespace>]
      [LINK_QCHS <qch> [<qch2> [...]]]
      [PREDEFINED_MACROS <macro[=content]> [<macro2[=content]> [...]]]
      [BLANK_MACROS <macro> [<macro2> [...]]]
      [CONFIG_TEMPLATE <configtemplate_file>]
      [VERBOSE]
  )

This macro adds a target called <target_name> for the creation of an API
documentation manual in the QCH format from the given sources.
It currently uses doxygen, future versions might optionally also allow other
tools.
Next to the QCH file the target will generate a corresponding doxygen tag
file, which enables creating links from other documentation into the
generated QCH file.

It is recommended to make the use of this macro optional, by depending
the call to ``ecm_add_qch`` on a CMake option being set, with a name like
``BUILD_QCH`` and being ``TRUE`` by default. This will allow the developers to
saves resources on normal source development build cycles by setting this
option to FALSE.

The macro will set the target properties ``DOXYGEN_TAGFILE``, ``QHP_NAMESPACE``,
``QHP_NAMESPACE_VERSIONED``, ``QHP_VIRTUALFOLDER`` and ``LINK_QCHS`` to the respective
values, to allow other code access to them, e.g. the macro
``ecm_install_qch_export``.
To enable the use of the target <target_name> as item for ``LINK_QCHS``
in further ``ecm_add_qch`` calls in the current build,
additionally a target property ``DOXYGEN_TAGFILE_BUILD`` is set, with the path
of the created doxygen tag file in the build dir.
If existing, ``ecm_add_qch`` will use this property instead of
``DOXYGEN_TAGFILE`` for access to the tags file.

``NAME`` specifies the name for the generated documentation.

``VERSION`` specifies the version of the library for which the documentation is
created.

``BASE_NAME`` specifies the base name for the generated files.
The default basename is ``<name>``.

``SOURCE_DIRS`` specifies the dirs (incl. subdirs) with the source files for
which the API documentation should be generated.  Dirs can be relative to
the current source dir. Dependencies to the files in the dirs are not
tracked currently, other than with the ``SOURCES`` argument. So do not use for
sources generated during the build.
Needs to be used when ``SOURCES`` or ``CONFIG_TEMPLATE`` are not used.

``SOURCES`` specifies the source files for which the API documentation should be
generated.
Needs to be used when ``SOURCE_DIRS`` or ``CONFIG_TEMPLATE`` are not used.

``MD_MAINPAGE`` specifies a file in Markdown format that should be used as main
page. This page will overrule any ``\mainpage`` command in the included
sources.

``INCLUDE_DIRS`` specifies the dirs which should be searched for included
headers. Dirs can be relative to the current source dir. Since 5.63.

``IMAGE_DIRS`` specifies the dirs which contain images that are included in the
documentation. Dirs can be relative to the current source dir.

``EXAMPLE_DIRS`` specifies the dirs which contain examples that are included in
the documentation. Dirs can be relative to the current source dir.

``QCH_INSTALL_DESTINATION`` specifies where the generated QCH file will be
installed.

``TAGFILE_INSTALL_DESTINATION`` specifies where the generated tag file will be
installed.

``COMPONENT`` specifies the installation component name with which the install
rules for the generated QCH file and tag file are associated.

``NAMESPACE`` can be used to set a custom namespace <namespace> of the generated
QCH file. The namepspace is used as the unique id by QHelpEngine (cmp.
https://doc.qt.io/qt-5/qthelpproject.html#namespace).
The default namespace is ``<domain>.<name>``.
Needs to be used when ``ORG_DOMAIN`` is not used.

``ORG_DOMAIN`` can be used to define the organization domain prefix for the
default namespace of the generated QCH file.
Needs to be used when ``NAMESPACE`` is not used.

``LINK_QCHS`` specifies a list of other QCH targets which should be used for
creating references to API documentation of code in external libraries.
For each target <qch> in the list these target properties are expected to be
defined: ``DOXYGEN_TAGFILE``, ``QHP_NAMESPACE`` and ``QHP_VIRTUALFOLDER``.
If any of these is not existing, <qch> will be ignored.
Use the macro ``ecm_install_qch_export`` for exporting a target with these
properties with the CMake config of a library.
Any target <qch> can also be one created before in the same buildsystem by
another call of ``ecm_add_qch``.

``PREDEFINED_MACROS`` specifies a list of C/C++ macros which should be handled as
given by the API dox generation tool.
Examples are macros only defined in generated files, so whose
definition might be not available to the tool.

``BLANK_MACROS`` specifies a list of C/C++ macro names which should be ignored by
the API dox generation tool and handled as if they resolve to empty strings.
Examples are export macros only defined in generated files, so whose
definition might be not available to the tool.

``CONFIG_TEMPLATE`` specifies a custom cmake template file for the config file
that is created to control the execution of the API dox generation tool.
The following CMake variables need to be used:
- ``ECM_QCH_DOXYGEN_QHELPGENERATOR_EXECUTABLE``
- ``ECM_QCH_DOXYGEN_FILEPATH, ECM_QCH_DOXYGEN_TAGFILE``
The following CMake variables can be used:
- ``ECM_QCH_DOXYGEN_PROJECTNAME``
- ``ECM_QCH_DOXYGEN_PROJECTVERSION``
- ``ECM_QCH_DOXYGEN_VIRTUALFOLDER``
- ``ECM_QCH_DOXYGEN_FULLNAMESPACE``
- ``ECM_QCH_DOXYGEN_TAGFILES``
- ``ECM_QCH_DOXYGEN_WARN_LOGFILE``
- ``ECM_QCH_DOXYGEN_QUIET``
There is no guarantue that the other CMake variables currently used in the
default config file template will also be present with the same semantics
in future versions of this macro.

``VERBOSE`` tells the API dox generation tool to be more verbose about its
activity.

The default config file for the API dox generation tool, so the one when not
using ``CONFIG_TEMPLATE``, allows code to handle the case of being processed by
the tool by defining the C/C++ preprocessor macro ``K_DOXYGEN`` when run
(since v5.67.0). For backward-compatibility also the definition
``DOXYGEN_SHOULD_SKIP_THIS`` is set, but its usage is deprecated.

Example usage:

.. code-block:: cmake

  ecm_add_qch(
      MyLib_QCH
      NAME MyLib
      VERSION "0.42.0"
      ORG_DOMAIN org.myorg
      SOURCE_DIRS
          src
      LINK_QCHS
          Qt5Core_QCH
          Qt5Xml_QCH
          Qt5Gui_QCH
          Qt5Widgets_QCH
      BLANK_MACROS
          MyLib_EXPORT
          MyLib_DEPRECATED
      TAGFILE_INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}/share/docs/tags
      QCH_INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}/share/docs/qch
      COMPONENT Devel
  )

Example usage (with two QCH files, second linking first):

.. code-block:: cmake

  ecm_add_qch(
      MyLib_QCH
      NAME MyLib
      VERSION ${MyLib_VERSION}
      ORG_DOMAIN org.myorg
      SOURCES ${MyLib_PUBLIC_HEADERS}
      MD_MAINPAGE src/mylib/README.md
      LINK_QCHS Qt5Core_QCH
      TAGFILE_INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}/share/docs/tags
      QCH_INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}/share/docs/qch
      COMPONENT Devel
  )
  ecm_add_qch(
      MyOtherLib_QCH
      NAME MyOtherLib
      VERSION ${MyOtherLib_VERSION}
      ORG_DOMAIN org.myorg
      SOURCES ${MyOtherLib_PUBLIC_HEADERS}
      MD_MAINPAGE src/myotherlib/README.md
      LINK_QCHS Qt5Core_QCH MyLib_QCH
      TAGFILE_INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}/share/docs/tags
      QCH_INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}/share/docs/qch
      COMPONENT Devel
  )

::

  ecm_install_qch_export(
      TARGETS [<name> [<name2> [...]]]
      FILE <file>
      DESTINATION <dest>
      [COMPONENT <component>]
  )

This macro creates and installs a CMake file <file> which exports the given
QCH targets <name> etc., so they can be picked up by CMake-based builds of
other software that also generate QCH files (using ``ecm_add_qch``) and
which should include links to the QCH files created by the given targets.
The installed CMake file <file> is expected to be included by the CMake
config file created for the software the related QCH files are documenting.

``TARGETS`` specifies the QCH targets which should be exported. If a target does
not exist or does not have all needed properties, a warning will be
generated and the target skipped.
This behaviour might change in future versions to result in a fail instead.

``FILE`` specifies the name of the created CMake file, typically with a .cmake
extension.

``DESTINATION`` specifies the directory on disk to which the file will be
installed. It usually is the same as the one where the CMake config files
for this software are installed.

``COMPONENT`` specifies the installation component name with which the
install rule is associated.

Example usage:

.. code-block:: cmake

  ecm_install_qch_export(
      TARGETS MyLib_QCH
      FILE MyLibQCHTargets.cmake
      DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/cmake/MyLib"
      COMPONENT Devel
  )

Since 5.36.0.
#]=======================================================================]

include(${CMAKE_CURRENT_LIST_DIR}/../modules/QtVersionOption.cmake)
include(ECMQueryQt)


# Helper method: adding the LINK_QCHS property to a Qt QCH targets, from module base names ("Core" etc.)
# if target does not exist (e.g. because no tagsfile was found), this is a no-op
macro(_ecm_setup_qt_qch_links _module)
    set(_target "Qt${QT_MAJOR_VERSION}${_module}_QCH")
    if(TARGET ${_target})
        set(_linkqchs)
        foreach(_linkqch ${ARGN})
            list(APPEND _linkqchs "Qt${QT_MAJOR_VERSION}${_linkqch}_QCH")
        endforeach()
        set_property(TARGET ${_target} PROPERTY LINK_QCHS ${_linkqchs})
    endif()
endmacro()

# Helper method: ensure Qt QCH targets are created
function(_ecm_ensure_qt_qch_targets)
    # create QCH targets for Qt
    # Ideally one day Qt CMake Config files provide these
    if(NOT TARGET Qt${QT_MAJOR_VERSION}Core_QCH)
        # get Qt version, if any
        find_package(Qt${QT_MAJOR_VERSION}Core CONFIG QUIET)
        # lookup tag files
        ecm_query_qt(qt_docs_dir QT_INSTALL_DOCS TRY)
        find_path(_qtcoreTagsPath qtcore/qtcore.tags
            PATHS
                ${qt_docs_dir}
        )

        if(Qt${QT_MAJOR_VERSION}Core_FOUND AND _qtcoreTagsPath)
            string(REPLACE "." "" _version ${Qt${QT_MAJOR_VERSION}Core_VERSION})
            # TODO: properly find each tag file
            # TODO: complete list of Qt modules
            if (QT_MAJOR_VERSION EQUAL "6")
                set(_module_list
                    3D Bluetooth Concurrent Core DBus Gui Location
                    Network Nfc Pdf Positioning PrintSupport Qml Quick
                    Sensors SerialBus SerialPort Sql StateMachine Svg
                    Test TextToSpeech WebChannel WebEngine WebSockets Widgets Xml)
            else()
                set(_module_list
                    3D Bluetooth Concurrent Core DBus Gui Location
                    Network Positioning PrintSupport Qml Quick
                    Sensors SerialPort Sql Svg
                    WebChannel WebEngine WebSockets Widgets Xml XmlPatterns)
            endif()
            foreach(_module ${_module_list})
                string(TOLOWER ${_module} _lowermodule)

                set(_tagfile "${_qtcoreTagsPath}/qt${_lowermodule}/qt${_lowermodule}.tags")
                if(EXISTS "${_tagfile}")
                    add_custom_target(Qt${QT_MAJOR_VERSION}${_module}_QCH)
                    set_target_properties(Qt${QT_MAJOR_VERSION}${_module}_QCH PROPERTIES
                        DOXYGEN_TAGFILE         "${_tagfile}"
                        QHP_NAMESPACE           "org.qt-project.qt${_lowermodule}"
                        QHP_NAMESPACE_VERSIONED "org.qt-project.qt${_lowermodule}.${_version}"
                        QHP_VIRTUALFOLDER       "qt${_lowermodule}"
                    )
                endif()
            endforeach()
            _ecm_setup_qt_qch_links(3D           Gui Core)
            _ecm_setup_qt_qch_links(Bluetooth    DBus Core)
            _ecm_setup_qt_qch_links(Concurrent   Gui Core)
            _ecm_setup_qt_qch_links(DBus         Core)
            _ecm_setup_qt_qch_links(Gui          Core)
            _ecm_setup_qt_qch_links(Location     Positioning Gui Core)
            _ecm_setup_qt_qch_links(Network      Core)
            if (QT_MAJOR_VERSION EQUAL "6")
                _ecm_setup_qt_qch_links(Nfc      Core)
                _ecm_setup_qt_qch_links(Pdf      Gui Core)
            endif()
            _ecm_setup_qt_qch_links(Positioning  Core)
            _ecm_setup_qt_qch_links(PrintSupport Widgets Gui Core)
            _ecm_setup_qt_qch_links(Qml          Network Core)
            _ecm_setup_qt_qch_links(Quick        Qml Network Gui Core)
            _ecm_setup_qt_qch_links(Sensors      Core)
            if (QT_MAJOR_VERSION EQUAL "6")
                _ecm_setup_qt_qch_links(SerialBus   Core)
            endif()
            _ecm_setup_qt_qch_links(SerialPort   Core)
            _ecm_setup_qt_qch_links(Sql          Core)
            if (QT_MAJOR_VERSION EQUAL "6")
                _ecm_setup_qt_qch_links(StateMachine   Core)
            endif()
            _ecm_setup_qt_qch_links(Svg          Widgets Gui Core)
            _ecm_setup_qt_qch_links(Test         Core)
            if (QT_MAJOR_VERSION EQUAL "6")
                _ecm_setup_qt_qch_links(TextToSpeech   Core)
            endif()
            _ecm_setup_qt_qch_links(WebChannel   Qml Core)
            _ecm_setup_qt_qch_links(WebEngine    Quick Qml Gui Core)
            _ecm_setup_qt_qch_links(WebSockets   Network Core)
            _ecm_setup_qt_qch_links(Widgets      Gui Core)
            _ecm_setup_qt_qch_links(Xml          Core)
            if (QT_MAJOR_VERSION EQUAL "5")
                _ecm_setup_qt_qch_links(XmlPatterns  Network Core)
            endif()
        endif()
    endif()
endfunction()

# Helper method: collect all qch targets from the LINK_QCHS dependency tree and set result to <var>
function(_ecm_collect_linkable_qch_targets name)
    set(_candidate_qchs ${ARGN})
    set(_handled_qchs)
    set(_good_qchs)
    # while unhandled qch targets
    while(_candidate_qchs)
        # get another unhandled qch target
        list(GET _candidate_qchs 0 _qch)
        list(REMOVE_AT _candidate_qchs 0)
        list(FIND _handled_qchs ${_qch} _index)
        # if not already handled
        if(_index EQUAL -1)
            list(APPEND _handled_qchs ${_qch})
            if(TARGET ${_qch})
                # always look at other linked qch targets, also for incomplete targets
                get_property(_link_qchs TARGET ${_qch} PROPERTY LINK_QCHS)
                if(_link_qchs)
                    list(APPEND _candidate_qchs ${_link_qchs})
                endif()
                # check if this target has all needed properties
                set(_target_usable TRUE)
                foreach(_propertyname
                    DOXYGEN_TAGFILE
                    QHP_NAMESPACE
                    QHP_VIRTUALFOLDER
                )
                    get_target_property(_property ${_qch} ${_propertyname})
                    if(NOT _property)
                        message(STATUS "No property ${_propertyname} set on ${_qch} when calling ecm_add_qch(). <<${_property}>>")
                        set(_target_usable FALSE)
                    endif()
                endforeach()
                get_target_property(_tagfile_build ${_qch} DOXYGEN_TAGFILE_BUILD)
                if (NOT _tagfile_build)
                    get_target_property(_tagfile ${_qch} DOXYGEN_TAGFILE)
                    if(NOT EXISTS ${_tagfile})
                        message(STATUS "No such tag file \"${_tagfile}\" found for ${_qch} when calling ecm_add_qch().")
                        set(_target_usable FALSE)
                    endif()
                endif()
                if(_target_usable)
                    list(APPEND _good_qchs ${_qch})
                else()
                    message(WARNING "No linking to API dox of ${_qch}.")
                endif()
            else()
                message(STATUS "No such target ${_qch} defined when calling ecm_add_qch(), ignored.")
            endif()
        endif()
    endwhile()
    set(${name} ${_good_qchs} PARENT_SCOPE)
endfunction()


function(ecm_add_qch target_name)
    # Parse arguments
    set(options VERBOSE)
    set(oneValueArgs NAME BASE_NAME QCH_INSTALL_DESTINATION TAGFILE_INSTALL_DESTINATION COMPONENT VERSION NAMESPACE MD_MAINPAGE ORG_DOMAIN CONFIG_TEMPLATE)
    set(multiValueArgs SOURCE_DIRS SOURCES INCLUDE_DIRS IMAGE_DIRS EXAMPLE_DIRS PREDEFINED_MACROS BLANK_MACROS LINK_QCHS)
    cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

    # check required args
    foreach(_arg_name NAME QCH_INSTALL_DESTINATION TAGFILE_INSTALL_DESTINATION VERSION)
        if(NOT DEFINED ARGS_${_arg_name})
            message(FATAL_ERROR "${_arg_name} needs to be defined when calling ecm_add_qch")
        endif()
    endforeach()
    if(NOT DEFINED ARGS_SOURCE_DIRS AND NOT DEFINED ARGS_SOURCES AND NOT DEFINED ARGS_CONFIG_TEMPLATE)
        message(FATAL_ERROR "SOURCE_DIRS or SOURCES needs to be defined when calling ecm_add_qch")
    endif()
    if(DEFINED ARGS_SOURCE_DIRS AND DEFINED ARGS_SOURCES)
        message(FATAL_ERROR "Either SOURCE_DIRS or SOURCES, not both, needs to be defined when calling ecm_add_qch")
    endif()
    if(NOT DEFINED ARGS_ORG_DOMAIN AND NOT DEFINED ARGS_NAMESPACE)
        message(FATAL_ERROR "ORG_DOMAIN or NAMESPACE needs to be defined when calling ecm_add_qch")
    endif()

    # find required tools
    if (NOT DOXYGEN_PATCHED_JSFILESADDED)
        set(REQUIRED_DOXYGEN_VERSION 1.8.13)
    endif()
    find_package(Doxygen ${REQUIRED_DOXYGEN_VERSION} REQUIRED)
    if (NOT DOXYGEN_FOUND AND NOT DOXYGEN_PATCHED_JSFILESADDED)
        set(doxygen_description_addition " (Or older version patched with https://github.com/doxygen/doxygen/commit/bf9415698e53d79b, pass -DDOXYGEN_PATCHED_JSFILESADDED=ON to cmake if patched)")
    endif()
    set_package_properties(Doxygen PROPERTIES
        TYPE REQUIRED
        PURPOSE "Needed for API dox QCH file generation${doxygen_description_addition}"
    )

    if (QT_MAJOR_VERSION EQUAL "5")
        find_package(QHelpGenerator REQUIRED)
        set_package_properties(QHelpGenerator PROPERTIES
            TYPE REQUIRED
            PURPOSE "Needed for API dox QCH file generation"
            DESCRIPTION "Part of Qt5 tools"
        )
    else()
        find_package(Qt6 COMPONENTS ToolsTools CONFIG REQUIRED)
        set_package_properties(Qt6ToolsTools PROPERTIES
            TYPE REQUIRED
            PURPOSE "Needed for API dox QCH file generation"
            DESCRIPTION "qhelpgenerator from Qt6 tools"
        )
        if(TARGET Qt6::qhelpgenerator)
            get_target_property(QHelpGenerator_EXECUTABLE Qt6::qhelpgenerator LOCATION)
        endif()
    endif()

    set(_missing_tools)
    if (NOT DOXYGEN_FOUND)
        list(APPEND _missing_tools "Doxygen")
    endif()
    if (NOT QHelpGenerator_FOUND AND NOT TARGET Qt6::qhelpgenerator)
        list(APPEND _missing_tools "qhelpgenerator")
    endif()

    if (_missing_tools)
        message(WARNING "API dox QCH file will not be generated, tools missing: ${_missing_tools}!")
    else()
        _ecm_ensure_qt_qch_targets()

        # prepare base dirs, working file names and other vars
        if (DEFINED ARGS_BASE_NAME)
            set(_basename ${ARGS_BASE_NAME})
        else()
            set(_basename ${ARGS_NAME})
        endif()
        set(_qch_file_basename "${_basename}.qch")
        set(_tags_file_basename "${_basename}.tags")
        set(_qch_buildpath "${CMAKE_CURRENT_BINARY_DIR}/${_qch_file_basename}")
        set(_tags_buildpath "${CMAKE_CURRENT_BINARY_DIR}/${_tags_file_basename}")
        set(_apidox_builddir "${CMAKE_CURRENT_BINARY_DIR}/${_basename}_ECMQchDoxygen")
        if (DEFINED ARGS_NAMESPACE)
            set(_namespace "${ARGS_NAMESPACE}")
        else()
            set(_namespace "${ARGS_ORG_DOMAIN}.${ARGS_NAME}")
        endif()
        string(REPLACE "." "_" _dotLessVersion ${ARGS_VERSION})
        set(_versioned_namespace "${_namespace}.${_dotLessVersion}")
        set(_sources)
        set(_dep_tagfiles)
        set(_dep_qch_targets)

        ### Create doxygen config file
        set(_doxygenconfig_file "${CMAKE_CURRENT_BINARY_DIR}/${_basename}_ECMQchDoxygen.config")
        if (DEFINED ARGS_CONFIG_TEMPLATE)
            set(_doxygenconfig_template_file "${ARGS_CONFIG_TEMPLATE}")
        else()
            set(_doxygenconfig_template_file "${ECM_MODULE_DIR}/ECMQchDoxygen.config.in")
        endif()
        set(_doxygen_layout_file "${ECM_MODULE_DIR}/ECMQchDoxygenLayout.xml")
        # Setup variables used in config file template, ECM_QCH_DOXYGEN_*
        set(ECM_QCH_DOXYGEN_OUTPUTDIR "\"${_apidox_builddir}\"")
        set(ECM_QCH_DOXYGEN_TAGFILE "\"${_tags_buildpath}\"")
        set(ECM_QCH_DOXYGEN_LAYOUTFILE "\"${_doxygen_layout_file}\"")
        set(ECM_QCH_DOXYGEN_INCLUDE_PATH)
        foreach(_include_DIR IN LISTS ARGS_INCLUDE_DIRS)
            if (NOT IS_ABSOLUTE ${_include_DIR})
                set(_include_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${_include_DIR}")
            endif()
            # concat dirs separated by a break, it is no issue that first has also a leading break
            set(ECM_QCH_DOXYGEN_INCLUDE_PATH "${ECM_QCH_DOXYGEN_INCLUDE_PATH} \\\n\"${_include_DIR}\"")
        endforeach()
        set(ECM_QCH_DOXYGEN_IMAGEDIRS)
        foreach(_image_DIR IN LISTS ARGS_IMAGE_DIRS)
            if (NOT IS_ABSOLUTE ${_image_DIR})
                set(_image_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${_image_DIR}")
            endif()
            # concat dirs separated by a break, it is no issue that first has also a leading break
            set(ECM_QCH_DOXYGEN_IMAGEDIRS "${ECM_QCH_DOXYGEN_IMAGEDIRS} \\\n\"${_image_DIR}\"")
        endforeach()
        set(ECM_QCH_DOXYGEN_EXAMPLEDIRS)
        foreach(_example_DIR IN LISTS ARGS_EXAMPLE_DIRS)
            if (NOT IS_ABSOLUTE ${_example_DIR})
                set(_example_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${_example_DIR}")
            endif()
            # concat dirs separated by a break, it is no issue that first has also a leading break
            set(ECM_QCH_DOXYGEN_EXAMPLEDIRS "${ECM_QCH_DOXYGEN_EXAMPLEDIRS} \\\n\"${_example_DIR}\"")
        endforeach()
        if (ARGS_MD_MAINPAGE)
            if (NOT IS_ABSOLUTE ${ARGS_MD_MAINPAGE})
                set(ARGS_MD_MAINPAGE "${CMAKE_CURRENT_SOURCE_DIR}/${ARGS_MD_MAINPAGE}")
            endif()
            set(ECM_QCH_DOXYGEN_MAINPAGE_MDFILE "\"${ARGS_MD_MAINPAGE}\"")
        else()
            set(ECM_QCH_DOXYGEN_MAINPAGE_MDFILE)
        endif()
        set(ECM_QCH_DOXYGEN_INPUT)
        if (ARGS_SOURCE_DIRS)
            foreach(_source_DIR IN LISTS ARGS_SOURCE_DIRS)
                if (NOT IS_ABSOLUTE ${_source_DIR})
                    set(_source_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${_source_DIR}")
                endif()
                # concat dirs separated by a break, it is no issue that first has also a leading break
                set(ECM_QCH_DOXYGEN_INPUT "${ECM_QCH_DOXYGEN_INPUT} \\\n\"${_source_DIR}\"")
            endforeach()
            if (ARGS_MD_MAINPAGE)
                set(ECM_QCH_DOXYGEN_INPUT "${ECM_QCH_DOXYGEN_INPUT} \\\n\"${ARGS_MD_MAINPAGE}\"")
            endif()
            set(ECM_QCH_DOXYGEN_FILE_PATTERNS "*.h *.cpp *.hpp *.hh *.cc *.h++ *.c++ *.hxx *.cxx *.dox *.md")
        else()
            foreach(_source IN LISTS ARGS_SOURCES)
                if (NOT IS_ABSOLUTE ${_source})
                    set(_source "${CMAKE_CURRENT_SOURCE_DIR}/${_source}")
                endif()
                list(APPEND _sources "${_source}")
            endforeach()
            if (ARGS_MD_MAINPAGE)
                list(FIND _sources ${ARGS_MD_MAINPAGE} _mainpage_index)
                if (_mainpage_index STREQUAL -1)
                    list(APPEND _sources "${ARGS_MD_MAINPAGE}")
                endif()
            endif()
            foreach(_source IN LISTS _sources)
                # concat sources separated by a break, it is no issue that first has also a leading break
                set(ECM_QCH_DOXYGEN_INPUT "${ECM_QCH_DOXYGEN_INPUT} \\\n\"${_source}\"")
            endforeach()
            set(ECM_QCH_DOXYGEN_FILE_PATTERNS "")
        endif()

        set(ECM_QCH_DOXYGEN_PROJECTNAME ${ARGS_NAME})
        file(RELATIVE_PATH _builddirrelative_filepath "${_apidox_builddir}/html"  ${_qch_buildpath})
        set(ECM_QCH_DOXYGEN_FILEPATH "\"${_builddirrelative_filepath}\"")
        set(ECM_QCH_DOXYGEN_PROJECTVERSION ${ARGS_VERSION})
        string(TOLOWER ${ARGS_NAME} ECM_QCH_DOXYGEN_VIRTUALFOLDER)
        set(ECM_QCH_DOXYGEN_FULLNAMESPACE ${_versioned_namespace})
        set(ECM_QCH_DOXYGEN_PREDEFINED_MACROS)
        foreach(_macro IN LISTS ARGS_PREDEFINED_MACROS)
            # concat dirs separated by a break, it is no issue that first has also a leading break
            # wrap each macro in quotes, to handle potential blanks and commas
            string(REPLACE "\"" "\\\"" _macro "${_macro}")
            set(ECM_QCH_DOXYGEN_PREDEFINED_MACROS "${ECM_QCH_DOXYGEN_PREDEFINED_MACROS} \\\n\"${_macro}\"")
        endforeach()
        set(ECM_QCH_DOXYGEN_BLANK_MACROS)
        foreach(_macro IN LISTS ARGS_BLANK_MACROS)
            # concat dirs separated by a break, it is no issue that first has also a leading break
            # wrap each macro in quotes, to handle potential blanks and commas
            string(REPLACE "\"" "\\\"" _macro "${_macro}")
            set(ECM_QCH_DOXYGEN_BLANK_MACROS "${ECM_QCH_DOXYGEN_BLANK_MACROS} \\\n\"${_macro}=\"")
        endforeach()

        # create list of tag files for linking other QCH files
        set(ECM_QCH_DOXYGEN_TAGFILES)
        _ecm_collect_linkable_qch_targets(_link_qchs ${ARGS_LINK_QCHS})
        foreach(_link_qch IN LISTS _link_qchs)
            list(APPEND _dep_qch_targets ${_link_qch})
            get_target_property(_link_qch_tagfile ${_link_qch} DOXYGEN_TAGFILE)
            get_target_property(_link_qch_tagfile_build ${_link_qch} DOXYGEN_TAGFILE_BUILD)
            get_target_property(_link_qch_namespace ${_link_qch} QHP_NAMESPACE)
            get_target_property(_link_qch_virtualfolder ${_link_qch} QHP_VIRTUALFOLDER)
            # if same build, then prefer build version over any installed one
            if (_link_qch_tagfile_build)
                set(_link_qch_tagfile ${_link_qch_tagfile_build})
                list(APPEND _dep_tagfiles "${_link_qch_tagfile}")
            endif()
            get_property(_linkqchs TARGET ${_link_qch} PROPERTY LINK_QCHS)
            set(_tagfile_entry "\"${_link_qch_tagfile}=qthelp://${_link_qch_namespace}/${_link_qch_virtualfolder}/\"")
            # concat dirs separated by a break, it is no issue that first has also a leading break
            set(ECM_QCH_DOXYGEN_TAGFILES "${ECM_QCH_DOXYGEN_TAGFILES} \\\n${_tagfile_entry}")
        endforeach()

        set(ECM_QCH_DOXYGEN_WARN_LOGFILE "\"${_doxygenconfig_file}.log\"")
        if(ARGS_VERBOSE)
            set(ECM_QCH_DOXYGEN_QUIET "NO")
        else()
            set(ECM_QCH_DOXYGEN_QUIET "YES")
        endif()
        set(ECM_QCH_DOXYGEN_QHELPGENERATOR_EXECUTABLE ${QHelpGenerator_EXECUTABLE})

        # finally create doxygen config file
        configure_file(
            "${_doxygenconfig_template_file}"
            "${_doxygenconfig_file}"
            @ONLY
        )
        # Doxygen warns verbosely about outdated config entries.
        # To spare custom code here to generate configuration with no out-dated entries,
        # instead make use of the doxygen feature to update configuration files.
        execute_process(
            COMMAND ${DOXYGEN_EXECUTABLE} -u "${_doxygenconfig_file}"
            ERROR_VARIABLE _doxygen_update_error
            RESULT_VARIABLE _doxygen_update_result
        )
        if(NOT ${_doxygen_update_result} STREQUAL "0")
            message(WARNING "Updating the doxygen config file failed: ${_doxygen_update_error}")
        endif()

        # setup make target
        set(_qch_INSTALLPATH ${ARGS_QCH_INSTALL_DESTINATION})
        set(_tags_INSTALLPATH ${ARGS_TAGFILE_INSTALL_DESTINATION})
        file(RELATIVE_PATH _relative_qch_file ${CMAKE_BINARY_DIR}  ${_qch_buildpath})
        file(RELATIVE_PATH _relative_tags_file ${CMAKE_BINARY_DIR}  ${_tags_buildpath})
        add_custom_command(
            OUTPUT ${_qch_buildpath} ${_tags_buildpath}
            COMMENT "Generating ${_relative_qch_file}, ${_relative_tags_file}"
            COMMAND cmake -E remove_directory "${ECM_QCH_DOXYGEN_OUTPUTDIR}"
            COMMAND cmake -E make_directory "${ECM_QCH_DOXYGEN_OUTPUTDIR}"
            COMMAND ${DOXYGEN_EXECUTABLE} "${_doxygenconfig_file}"
            DEPENDS
                ${_doxygenconfig_file}
                ${_doxygen_layout_file}
                ${_sources}
                ${_dep_tagfiles}
                ${_dep_qch_targets}
        )
        add_custom_target(${target_name} ALL DEPENDS ${_qch_buildpath} ${_tags_buildpath})
        set_target_properties(${target_name} PROPERTIES
            DOXYGEN_TAGFILE "${_qch_INSTALLPATH}/${_tags_file_basename}"
            DOXYGEN_TAGFILE_NAME "${_tags_file_basename}"
            DOXYGEN_TAGFILE_INSTALLDIR "${_qch_INSTALLPATH}"
            DOXYGEN_TAGFILE_BUILD "${_tags_buildpath}"
            QHP_NAMESPACE "${_namespace}"
            QHP_NAMESPACE_VERSIONED  "${_versioned_namespace}"
            QHP_VIRTUALFOLDER "${ECM_QCH_DOXYGEN_VIRTUALFOLDER}"
        )
        # list as value does not work with set_target_properties
        set_property(TARGET ${target_name} PROPERTY LINK_QCHS "${ARGS_LINK_QCHS}")

        if (DEFINED ARGS_COMPONENT)
            set(_component COMPONENT ${ARGS_COMPONENT})
        else()
            set(_component)
        endif()

        # setup installation
        install(FILES
            ${_qch_buildpath}
            DESTINATION ${_qch_INSTALLPATH}
            ${_component}
        )

        install(FILES
            ${_tags_buildpath}
            DESTINATION ${_tags_INSTALLPATH}
            ${_component}
        )
    endif()

endfunction()


function(ecm_install_qch_export)
    set(options )
    set(oneValueArgs FILE DESTINATION COMPONENT)
    set(multiValueArgs TARGETS)

    cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

    if(NOT DEFINED ARGS_FILE)
        message(FATAL_ERROR "FILE needs to be defined when calling ecm_install_qch_export().")
    endif()

    if(NOT DEFINED ARGS_DESTINATION)
        message(FATAL_ERROR "DESTINATION needs to be defined when calling ecm_install_qch_export().")
    endif()

    # TARGETS may be empty (and ARGS_TARGETS will not be defined then by cmake_parse_arguments)

    set(_content
"# This file was generated by ecm_install_qch_export(). DO NOT EDIT!
"
    )

    foreach(_target IN LISTS ARGS_TARGETS)
        set(_target_usable TRUE)

        if (NOT TARGET ${_target})
            message(STATUS "No such target ${_target} when calling ecm_install_qch_export().")
            set(_target_usable FALSE)
        else()
            foreach(_propertyname
                DOXYGEN_TAGFILE_NAME
                DOXYGEN_TAGFILE_INSTALLDIR
                QHP_NAMESPACE
                QHP_NAMESPACE_VERSIONED
                QHP_VIRTUALFOLDER
            )
                get_target_property(_property ${_target} ${_propertyname})
                if(NOT _property)
                    message(STATUS "No property ${_propertyname} set on ${_target} when calling ecm_install_qch_export(). <${_property}>")
                    set(_target_usable FALSE)
                endif()
            endforeach()
        endif()
        if(_target_usable)
            get_target_property(_tagfile_name ${_target} DOXYGEN_TAGFILE_NAME)
            get_target_property(_tagfile_installdir ${_target} DOXYGEN_TAGFILE_INSTALLDIR)
            if (NOT IS_ABSOLUTE ${_tagfile_installdir})
                set(_tagfile_installdir "${CMAKE_INSTALL_PREFIX}/${_tagfile_installdir}")
            endif()
            get_target_property(_namespace ${_target} QHP_NAMESPACE)
            get_target_property(_namespace_versioned ${_target} QHP_NAMESPACE_VERSIONED)
            get_target_property(_virtualfolder ${_target} QHP_VIRTUALFOLDER)
            get_property(_linkqchs TARGET ${_target} PROPERTY LINK_QCHS)
            set(_content "${_content}
if (NOT TARGET ${_target})

add_custom_target(${_target})
set_target_properties(${_target} PROPERTIES
    DOXYGEN_TAGFILE \"${_tagfile_installdir}/${_tagfile_name}\"
    QHP_NAMESPACE \"${_namespace}\"
    QHP_NAMESPACE_VERSIONED \"${_namespace_versioned}\"
    QHP_VIRTUALFOLDER \"${_virtualfolder}\"
)
set_property(TARGET ${_target} PROPERTY LINK_QCHS ${_linkqchs})

endif()
"
            )
        else()
            message(STATUS "No target exported for ${_target}.")
        endif()
    endforeach()

    if (NOT IS_ABSOLUTE ${ARGS_FILE})
        set(ARGS_FILE "${CMAKE_CURRENT_BINARY_DIR}/${ARGS_FILE}")
    endif()

    file(GENERATE
        OUTPUT "${ARGS_FILE}"
        CONTENT "${_content}"
    )

    if (DEFINED ARGS_COMPONENT)
        set(_component COMPONENT ${ARGS_COMPONENT})
    else()
        set(_component)
    endif()
    install(
        FILES "${ARGS_FILE}"
        DESTINATION "${ARGS_DESTINATION}"
        ${_component}
    )

endfunction()
# SPDX-FileCopyrightText: 2019 Friedrich W. H. Kossebau <kossebau@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
ECMAddQtDesignerPlugin
----------------------

This module provides the ``ecm_add_qtdesignerplugin`` function for generating
Qt Designer plugins for custom widgets. Each of those widgets is described
using a second function ``ecm_qtdesignerplugin_widget``.

::

  ecm_add_qtdesignerplugin(<target_name>
      NAME <name>
      WIDGETS <widgetid> [<widgetid2> [...]]
      LINK_LIBRARIES <lib> [<lib2> [...]]
      INSTALL_DESTINATION <install_path>
      [OUTPUT_NAME <output_name>]
      [DEFAULT_GROUP <group>]
      [DEFAULT_HEADER_CASE <SAME_CASE|LOWER_CASE|UPPER_CASE>]
      [DEFAULT_HEADER_EXTENSION <header_extension>]
      [DEFAULT_ICON_DIR <icon_dir>]
      [INCLUDE_FILES <include_file> [<include_file2> [...]]]
      [SOURCES <src> [<src2> [...]]]
      [COMPONENT <component>]
  )

``NAME`` specifies the base name to use in the generated sources.
The default is <target_name>.

``WIDGETS`` specifies the widgets the plugin should support. Each widget has
to be defined before by a call of ``ecm_qtdesignerplugin_widget`` with the
respective <widgetid>, in a scope including the current call.

``LINK_LIBRARIES`` specifies the libraries to link against. This will be at
least the library providing the widget class(es).

``INSTALL_DESTINATION`` specifies where the generated plugin binary will be
installed.

``OUTPUT_NAME`` specifies the name of the plugin binary. The default is
"<target_name>".

``DEFAULT_GROUP`` specifies the default group in Qt Designer where the
widgets will be placed. The default is "Custom".

``DEFAULT_HEADER_CASE`` specifies how the name of the header is derived from
the widget class name.  The default is "LOWER_CASE".

``DEFAULT_HEADER_EXTENSION`` specifies what file name extension is used for
the header file derived from the class name.  The default is "h".

``DEFAULT_ICON_DIR`` specifies what file name extension is used for
the header file derived from the class name.  The default is "pics".

``INCLUDE_FILES`` specifies additional include files to include with the
generated source file. This can be needed for custom code used in
initializing or creating widgets.

``SOURCES`` specifies additional source files to build the plugin from.
This can be needed to support custom code used in initializing or
creating widgets.

``COMPONENT`` specifies the installation component name with which the install
rules for the generated plugin are associated.

::

  ecm_qtdesignerplugin_widget(<widgetid>
      [CLASS_NAME <class_name>]
      [INCLUDE_FILE <include_file>]
      [CONTAINER]
      [ICON <iconfile>]
      [TOOLTIP <tooltip>]
      [WHATSTHIS <whatsthis>]
      [GROUP <group>]
      [CREATE_WIDGET_CODE_FROM_VARIABLE <create_widget_code_variable>]
      [INITIALIZE_CODE_FROM_VARIABLE <initialize_code_variable]
      [DOM_XML_FROM_VARIABLE <dom_xml_variable>]
      [IMPL_CLASS_NAME <impl_class_name>]
      [CONSTRUCTOR_ARGS_CODE <constructor_args_code>]
      [CONSTRUCTOR_ARGS_CODE_FROM_VARIABLE <constructor_args_code_variable>]
  )

``CLASS_NAME`` specifies the name of the widget class, including namespaces.
The default is "<widgetid>".

``INCLUDE_FILE`` specifies the include file to use for the class of this
widget. The default is derived from <class_name> as configured by the
``DEFAULT_HEADER_*`` options of ``ecm_add_qtdesignerplugin``, also replacing
any namespace separators with "/".

``CONTAINER`` specifies, if set, that this widget is a container
for other widgets.

``ICON`` specifies the icon file to use as symbol for this widget.
The default is "{lowercased <class_name>}.png" in the default icons dir as
configured by the ``DEFAULT_ICON_DIR`` option of
``ecm_add_qtdesignerplugin``, if such a file exists.

``TOOLTIP`` specifies the tooltip text to use for this widget. Default is
"<class_name> Widget".

``WHATSTHIS`` specifies the What's-This text to use for this widget.
Defaults to the tooltip.

``GROUP`` specifies the group in Qt Designer where the widget will be placed.
The default is set as configured by the ``DEFAULT_GROUP`` option of
``ecm_add_qtdesignerplugin``.

``CREATE_WIDGET_CODE_FROM_VARIABLE`` specifies the variable to get from the
C++ code to use as factory code to create an instance of the widget,
for the override of
``QDesignerCustomWidgetInterface::createWidget(QWidget* parent)``.
The default is "return new <impl_class_name><constructor_args_code>;".

``INITIALIZE_CODE_FROM_VARIABLE`` specifies the variable to get from the C++
code to use with the override of
``QDesignerCustomWidgetInterface::initialize(QDesignerFormEditorInterface* core)``.
The code has to use the present class member ``m_initialized`` to track and
update the state. The default code simply sets ``m_initialized`` to
``true``, if it was not before.

``DOM_XML_FROM_VARIABLE`` specifies the variable to get from the string to
use with the optional override of
``QDesignerCustomWidgetInterface::domXml()``.
Default does not override.

``IMPL_CLASS_NAME`` specifies the name of the widget class to use for the
widget instance with Qt Designer. The default is "<class_name>".

``CONSTRUCTOR_ARGS_CODE`` specifies the C++ code to use for the constructor
arguments with the default of ``CREATE_WIDGET_CODE_FROM_VARIABLE``. Note
that the parentheses are required. The default is "(parent)".

``CONSTRUCTOR_ARGS_CODE_FROM_VARIABLE`` specifies the variable to get from
the C++ code instead of passing it directly via ``CONSTRUCTOR_ARGS_CODE``.
This can be needed if the code is more complex and e.g. includes ";" chars.



Example usage:

.. code-block:: cmake

  ecm_qtdesignerplugin_widget(FooWidget
      TOOLTIP "Enables to browse foo."
      GROUP "Views (Foo)"
  )

  set(BarWidget_CREATE_WIDGET_CODE
  "
      auto* widget = new BarWidget(parent);
      widget->setBar("Example bar");
      return widget;
  ")

  ecm_qtdesignerplugin_widget(BarWidget
      TOOLTIP "Displays bars."
      GROUP "Display (Foo)"
      CREATE_WIDGET_CODE_FROM_VARIABLE BarWidget_CREATE_WIDGET_CODE
  )

  ecm_add_qtdesignerplugin(foowidgets
      NAME FooWidgets
      OUTPUT_NAME foo2widgets
      WIDGETS
          FooWidget
          BarWidget
      LINK_LIBRARIES
          Foo::Widgets
      INSTALL_DESTINATION "${KDE_INSTALL_QTPLUGINDIR}/designer"
      COMPONENT Devel
  )

Since 5.62.0.
#]=======================================================================]

include(FeatureSummary)
include(${CMAKE_CURRENT_LIST_DIR}/QtVersionOption.cmake)

# helper method
# escapes string for C++ code
function(_ecm_qtdesignerplugin_escape_cpp_string _varName input)
    string(REPLACE "\"" "\\\"" _string ${input})
    set(${_varName} "${_string}" PARENT_SCOPE)
endfunction()

# To make the data about the widgets available to the function ecm_add_qtdesignerplugin,
# variables are created in the scope of the caller of this method, protected by
# a namespace for this macro file, and otherwise from the widget id and the property id:
# ECM_QTDESIGNERPLUGIN_${widget}_${property}
function(ecm_qtdesignerplugin_widget widget)
    set(options
        CONTAINER
    )
    set(oneValueArgs
        CLASS_NAME
        INCLUDE_FILE
        ICON
        TOOLTIP
        WHATSTHIS
        GROUP
        CREATE_WIDGET_CODE_FROM_VARIABLE
        INITIALIZE_CODE_FROM_VARIABLE
        DOM_XML_FROM_VARIABLE
        IMPL_CLASS_NAME
        CONSTRUCTOR_ARGS_CODE
        CONSTRUCTOR_ARGS_CODE_FROM_VARIABLE
    )
    set(multiValueArgs
    )
    cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

    if(NOT ARGS_CLASS_NAME)
        set(ARGS_CLASS_NAME "${widget}")
    endif()
    if(NOT ARGS_TOOLTIP)
        set(ARGS_TOOLTIP "${ARGS_CLASS_NAME} Widget")
    endif()
    if(NOT ARGS_WHATSTHIS)
        set(ARGS_WHATSTHIS "${ARGS_TOOLTIP}")
    endif()
    if(ARGS_CONTAINER)
        set(_is_container TRUE)
    else()
        set(_is_container FALSE)
    endif()
    if(ARGS_CONSTRUCTOR_ARGS_CODE AND ARGS_CONSTRUCTOR_ARGS_CODE_FROM_VARIABLE)
        message(FATAL_ERROR "Either CONSTRUCTOR_ARGS_CODE or CONSTRUCTOR_ARGS_CODE_FROM_VARIABLE can be passed when calling ecm_qtdesignerplugin_widget().")
    endif()
    if(NOT ARGS_CREATE_WIDGET_CODE_FROM_VARIABLE)
        if(NOT ARGS_IMPL_CLASS_NAME)
            set(ARGS_IMPL_CLASS_NAME "${ARGS_CLASS_NAME}")
        endif()
        if(ARGS_CONSTRUCTOR_ARGS_CODE_FROM_VARIABLE)
            set(_constructor_args "${${ARGS_CONSTRUCTOR_ARGS_CODE_FROM_VARIABLE}}")
        elseif(ARGS_CONSTRUCTOR_ARGS_CODE)
            set(_constructor_args "${ARGS_CONSTRUCTOR_ARGS_CODE}")
        else()
            set(_constructor_args "(parent)")
        endif()
        set(_create_widget_code "        return new ${ARGS_IMPL_CLASS_NAME}${_constructor_args};")
    else()
        set(_create_widget_code "${${ARGS_CREATE_WIDGET_CODE_FROM_VARIABLE}}")
    endif()
    if(ARGS_ICON)
        if (NOT IS_ABSOLUTE ${ARGS_ICON})
            set(ARGS_ICON "${CMAKE_CURRENT_SOURCE_DIR}/${ARGS_ICON}")
        endif()
        if(NOT EXISTS "${ARGS_ICON}")
            message(FATAL_ERROR "No such file as passed with ICON when calling ecm_qtdesignerplugin_widget(): ${ARGS_ICON}")
        endif()
    endif()

    # store data about widget, so ecm_add_qtdesignerplugin can access it
    set(ECM_QTDESIGNERPLUGIN_${widget}_CLASS_NAME "${ARGS_CLASS_NAME}" PARENT_SCOPE)
    set(ECM_QTDESIGNERPLUGIN_${widget}_INCLUDE_FILE "${ARGS_INCLUDE_FILE}" PARENT_SCOPE)
    set(ECM_QTDESIGNERPLUGIN_${widget}_TOOLTIP "${ARGS_TOOLTIP}" PARENT_SCOPE)
    set(ECM_QTDESIGNERPLUGIN_${widget}_WHATSTHIS "${ARGS_WHATSTHIS}" PARENT_SCOPE)
    set(ECM_QTDESIGNERPLUGIN_${widget}_GROUP "${ARGS_GROUP}" PARENT_SCOPE)
    set(ECM_QTDESIGNERPLUGIN_${widget}_ICON "${ARGS_ICON}" PARENT_SCOPE)
    set(ECM_QTDESIGNERPLUGIN_${widget}_IS_CONTAINER "${_is_container}" PARENT_SCOPE)
    set(ECM_QTDESIGNERPLUGIN_${widget}_CREATE_WIDGET_CODE "${_create_widget_code}" PARENT_SCOPE)
    set(ECM_QTDESIGNERPLUGIN_${widget}_INITIALIZE_CODE "${${INITIALIZE_CODE_FROM_VARIABLE}}" PARENT_SCOPE)
    set(ECM_QTDESIGNERPLUGIN_${widget}_DOM_XML "${${ARGS_DOM_XML_FROM_VARIABLE}}" PARENT_SCOPE)
endfunction()

# helper method
function(_ecm_qtdesignerplugin_write_widget designer_src_file widget default_group rc_icon_dir)
    # prepare data
    set(_classname "${ECM_QTDESIGNERPLUGIN_${widget}_CLASS_NAME}")
    set(_factory_classname "${_classname}QtDesignerWidgetFactory")
    string(REPLACE "::" "__" _factory_classname "${_factory_classname}")
    set(ECM_QTDESIGNERPLUGIN_${widget}_FACTORY_CLASS_NAME "${_factory_classname}" PARENT_SCOPE)
    if(ECM_QTDESIGNERPLUGIN_${widget}_IS_CONTAINER)
        set(_is_container "true")
    else()
        set(_is_container "false")
    endif()
    _ecm_qtdesignerplugin_escape_cpp_string(_tooltip "${ECM_QTDESIGNERPLUGIN_${widget}_TOOLTIP}")
    _ecm_qtdesignerplugin_escape_cpp_string(_whatsthis "${ECM_QTDESIGNERPLUGIN_${widget}_WHATSTHIS}")
    set(_group ${ECM_QTDESIGNERPLUGIN_${widget}_GROUP})
    if(NOT _group)
        set(_group "${default_group}")
    endif()
    _ecm_qtdesignerplugin_escape_cpp_string(_group "${_group}")
    set(_dom_xml "${ECM_QTDESIGNERPLUGIN_${widget}_DOM_XML}")
    if(_dom_xml)
        string(REPLACE "\"" "\\\"" _dom_xml "${_dom_xml}")
        set(_dom_xml_method "    QString domXml() const override { return QStringLiteral(\"${_dom_xml}\"); }")
    else()
        set(_dom_xml_method)
    endif()
    set(_icon "${ECM_QTDESIGNERPLUGIN_${widget}_ICON}")
    if(_icon)
        get_filename_component(_icon_filename ${_icon} NAME)
        set(_icon_construct "QIcon(QStringLiteral(\":${rc_icon_dir}/${_icon_filename}\"))")
    else()
        set(_icon_construct "QIcon()")
    endif()
    set(_initialize_code "${ECM_QTDESIGNERPLUGIN_${widget}_INITIALIZE_CODE}")
    if(NOT _initialize_code)
        set(_initialize_code
"        Q_UNUSED(core);

        if (m_initialized) return;

        m_initialized = true;"
        )
    endif()

    # write code
    file(APPEND ${designer_src_file} "
class ${_factory_classname}
    : public QObject
    , public QDesignerCustomWidgetInterface
{
    Q_OBJECT
    Q_INTERFACES(QDesignerCustomWidgetInterface)

public:
    explicit ${_factory_classname}(QObject *parent = nullptr)
        : QObject(parent)
        , m_initialized(false)
    {}

    ~${_factory_classname}() override {}
    
public: // QDesignerCustomWidgetInterface API
    bool isInitialized() const override { return m_initialized; }
${_dom_xml_method}
    bool isContainer() const override { return ${_is_container}; }
    QIcon icon() const override { return ${_icon_construct}; }
    QString group() const override { return QStringLiteral(\"${_group}\"); }
    QString includeFile() const override { return QStringLiteral(\"${ECM_QTDESIGNERPLUGIN_${widget}_INCLUDE_FILE}\"); }
    QString name() const override { return QStringLiteral(\"${_classname}\"); }
    QString toolTip() const override { return QStringLiteral(\"${_tooltip}\"); }
    QString whatsThis() const override { return QStringLiteral(\"${_whatsthis}\"); }

    QWidget* createWidget(QWidget* parent) override
    {
${ECM_QTDESIGNERPLUGIN_${widget}_CREATE_WIDGET_CODE}
    }

    void initialize(QDesignerFormEditorInterface* core) override 
    {
${_initialize_code}
    }

private:
    bool m_initialized;
};
"
    )
endfunction()

# helper method
function(_ecm_qtdesignerplugin_write_icon_qrc_file rc_file rc_icon_dir)
    set(_icons ${ARGN})
    file(WRITE ${rc_file}
"<!DOCTYPE RCC><RCC version=\"1.0\">
<!-- DO NOT EDIT! Generated from ecm_add_qtdesignerplugin() -->
<qresource prefix=\"${rc_icon_dir}\">
"
    )
    foreach(_icon ${_icons})
        get_filename_component(_icon_filename ${_icon} NAME)
        file(APPEND ${rc_file} "<file alias=\"${_icon_filename}\">${_icon}</file>\n")
    endforeach()
    file(APPEND ${rc_file}
"</qresource>
</RCC>
"
    )
endfunction()

# This needs to be a macro not a function because of the nested
# find_package() call, which will set some variables.
macro(ecm_add_qtdesignerplugin target)
    set(options
    )
    set(oneValueArgs
        NAME
        OUTPUT_NAME
        INSTALL_DESTINATION
        DEFAULT_GROUP
        COMPONENT
        DEFAULT_HEADER_CASE
        DEFAULT_HEADER_EXTENSION
        DEFAULT_ICON_DIR
    )
    set(multiValueArgs
        WIDGETS
        LINK_LIBRARIES
        INCLUDE_FILES
        SOURCES
    )
    cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

    # args sanity check
    if (NOT ARGS_WIDGETS)
        message(FATAL_ERROR "No WIDGETS passed when calling ecm_add_qtdesignerplugin().")
    endif()
    foreach(_widget ${ARGS_WIDGETS})
        # using _CLASS_NAME as sample property to find if defined
        if (NOT ECM_QTDESIGNERPLUGIN_${_widget}_CLASS_NAME)
            message(FATAL_ERROR "Undefined widget passed when calling ecm_add_qtdesignerplugin(): ${_widget}")
        endif()
    endforeach()

    if(NOT ARGS_NAME)
        set(ARGS_NAME "${target}")
    endif()
    if(NOT ARGS_DEFAULT_GROUP)
        set(ARGS_DEFAULT_GROUP "Custom")
    endif()
    if(NOT ARGS_DEFAULT_HEADER_EXTENSION)
        set(ARGS_DEFAULT_HEADER_EXTENSION "h")
    endif()
    if(NOT ARGS_DEFAULT_HEADER_CASE)
        set(ARGS_DEFAULT_HEADER_CASE "LOWER_CASE")
    else()
        set(_allowed_values "LOWER_CASE" "UPPER_CASE" "SAME_CASE")
        list(FIND _allowed_values "${ARGS_DEFAULT_HEADER_CASE}" _index)
        if(_index EQUAL "-1")
            message(FATAL_ERROR "Unexpected value for DEFAULT_HEADER_CASE argument to ecm_add_qtdesignerplugin(): ${ARGS_DEFAULT_HEADER_CASE}")
        endif()
    endif()
    if(NOT ARGS_DEFAULT_ICON_DIR)
        set(ARGS_DEFAULT_ICON_DIR "${CMAKE_CURRENT_SOURCE_DIR}/pics")
    else()
        if (NOT IS_ABSOLUTE ${ARGS_DEFAULT_ICON_DIR})
            set(ARGS_DEFAULT_ICON_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${ARGS_DEFAULT_ICON_DIR}")
        endif()
        if(NOT EXISTS "${ARGS_DEFAULT_ICON_DIR}")
            message(FATAL_ERROR "No such directory as passed with DEFAULT_ICON_DIR when calling ecm_add_qtdesignerplugin(): ${ARGS_DEFAULT_ICON_DIR}")
        endif()
    endif()

    # Check deps
    if(NOT Qt${QT_MAJOR_VERSION}UiPlugin_FOUND)
        find_package(Qt${QT_MAJOR_VERSION}UiPlugin QUIET CONFIG)
        set_package_properties(Qt${QT_MAJOR_VERSION}UiPlugin PROPERTIES
            PURPOSE "Required to build Qt Designer plugins"
            TYPE REQUIRED
        )
    endif()

    # setup plugin only if uiplugin lib was found, as we do not abort hard the cmake run otherwise
    if (Qt${QT_MAJOR_VERSION}UiPlugin_FOUND)
        set(_generation_dir "${CMAKE_CURRENT_BINARY_DIR}/${target}_ECMQtDesignerPlugin")
        file(MAKE_DIRECTORY "${_generation_dir}")
        set(_rc_icon_dir "/${ARGS_NAME}/designer")

        # process defaults for widgets
        foreach(_widget ${ARGS_WIDGETS})
            set(_class_name "${ECM_QTDESIGNERPLUGIN_${_widget}_CLASS_NAME}")
            # include file
            set(_include_file "${ECM_QTDESIGNERPLUGIN_${_widget}_INCLUDE_FILE}")
            if(NOT _include_file)
                set(_include_file "${_class_name}")
                if (ARGS_DEFAULT_HEADER_CASE STREQUAL "LOWER_CASE")
                    string(TOLOWER "${_include_file}" _include_file)
                elseif(ARGS_DEFAULT_HEADER_CASE STREQUAL "UPPER_CASE")
                    string(TOUPPER "${_include_file}" _include_file)
                endif()
                # turn any namespaces into dir levels
                string(REPLACE "::" "/" _include_file ${_include_file})
                set(ECM_QTDESIGNERPLUGIN_${_widget}_INCLUDE_FILE "${_include_file}.${ARGS_DEFAULT_HEADER_EXTENSION}")
            endif()
            # icon
            set(_icon "${ECM_QTDESIGNERPLUGIN_${_widget}_ICON}")
            if(NOT _icon)
                string(TOLOWER "${_class_name}" _icon)
                # handle any namespaces
                string(REPLACE "::" "_" _icon "${_icon}")
                set(_icon "${ARGS_DEFAULT_ICON_DIR}/${_icon}.png")
                if(EXISTS "${_icon}")
                    set(ECM_QTDESIGNERPLUGIN_${_widget}_ICON "${_icon}")
                endif()
            endif()
        endforeach()

        set(_plugin_src_file "${_generation_dir}/designerplugin.cpp")
        set(_srcs
            ${ARGS_SOURCES}
            ${_plugin_src_file}
        )

        set(_icons)
        foreach(_widget ${ARGS_WIDGETS})
            list(APPEND _icons "${ECM_QTDESIGNERPLUGIN_${_widget}_ICON}")
        endforeach()

        # generate qrc file with icons
        if (_icons)
            set(_rc_file "${_generation_dir}/designerplugin.rc")
            set(_rc_work_file "${_rc_file}.work")

            _ecm_qtdesignerplugin_write_icon_qrc_file("${_rc_work_file}" "${_rc_icon_dir}" ${_icons})
            # avoid rebuilding if there was no change
            execute_process(
                COMMAND ${CMAKE_COMMAND} -E copy_if_different "${_rc_work_file}" "${_rc_file}"
            )
            file(REMOVE "${_rc_work_file}")

            if (QT_MAJOR_VERSION EQUAL "5")
                qt5_add_resources(_srcs ${_rc_file})
            else()
                qt6_add_resources(_srcs ${_rc_file})
            endif()
        endif()

        # generate source file
        set(_collection_classname "${ARGS_NAME}QtDesignerWidgetCollection")

        set(_include_files
            # classes inherited
            QDesignerCustomWidgetCollectionInterface
            QDesignerCustomWidgetInterface
            QObject
            # classes used
            QIcon
            QString
            ${ARGS_INCLUDE_FILES}
        )
        foreach(_widget ${ARGS_WIDGETS})
            list(APPEND _include_files ${ECM_QTDESIGNERPLUGIN_${_widget}_INCLUDE_FILE})
        endforeach()
        list(REMOVE_DUPLICATES _include_files)

        set(_plugin_src_work_file "${_plugin_src_file}.work")
        file(WRITE ${_plugin_src_work_file} "// DO NOT EDIT! Generated from ecm_add_qtdesignerplugin()\n\n")
        foreach(_include_file ${_include_files})
            if (NOT ${_include_file} MATCHES "^[\"<]")
                set(_include_file "<${_include_file}>")
            endif()
            file(APPEND ${_plugin_src_work_file} "#include ${_include_file}\n")
        endforeach()
        foreach(_widget ${ARGS_WIDGETS})
            _ecm_qtdesignerplugin_write_widget(${_plugin_src_work_file} ${_widget} ${ARGS_DEFAULT_GROUP} ${_rc_icon_dir})
        endforeach()
        file(APPEND ${_plugin_src_work_file} "
class ${_collection_classname}
    : public QObject
    , public QDesignerCustomWidgetCollectionInterface
{
    Q_OBJECT
    Q_INTERFACES(
        QDesignerCustomWidgetCollectionInterface
    )

    Q_PLUGIN_METADATA(IID \"org.qt-project.Qt.QDesignerCustomWidgetCollectionInterface\")

public:
    explicit ${_collection_classname}(QObject* parent = nullptr);

public: // QDesignerCustomWidgetCollectionInterface API
    QList<QDesignerCustomWidgetInterface*> customWidgets() const override;

private:
    QList<QDesignerCustomWidgetInterface*> m_widgetFactories;
};

${_collection_classname}::${_collection_classname}(QObject* parent)
    : QObject(parent)
{
    m_widgetFactories = QList<QDesignerCustomWidgetInterface*>{
"
        )
        foreach(_widget ${ARGS_WIDGETS})
            file(APPEND ${_plugin_src_work_file} "        new ${ECM_QTDESIGNERPLUGIN_${_widget}_FACTORY_CLASS_NAME}(this),\n")
        endforeach()
        file(APPEND ${_plugin_src_work_file}
"    };
}

QList<QDesignerCustomWidgetInterface*> ${_collection_classname}::customWidgets() const
{
    return m_widgetFactories;
}

#include \"designerplugin.moc\"
"
        )

        # avoid rebuilding if there was no change
        execute_process(
            COMMAND ${CMAKE_COMMAND} -E copy_if_different "${_plugin_src_work_file}" "${_plugin_src_file}"
        )
        file(REMOVE "${_plugin_src_work_file}")

        # setup plugin binary
        add_library(${target} MODULE ${_srcs})
        if(NOT WIN32)
            # Since there are no libraries provided by this module,
            # there is no point including the build tree in RPath,
            # and then having to edit it at install time.
            set_target_properties(${target} PROPERTIES
                SKIP_BUILD_RPATH TRUE
                BUILD_WITH_INSTALL_RPATH TRUE
            )
        endif()
        if (ARGS_OUTPUT_NAME)
            set_target_properties(${target} PROPERTIES
                OUTPUT_NAME ${ARGS_OUTPUT_NAME}
            )
        endif()
        target_link_libraries(${target} ${ARGS_LINK_LIBRARIES} Qt${QT_MAJOR_VERSION}::UiPlugin)

        if (DEFINED ARGS_COMPONENT)
            set(_component COMPONENT ${ARGS_COMPONENT})
        else()
            set(_component)
        endif()

        install(TARGETS ${target} DESTINATION ${ARGS_INSTALL_DESTINATION} ${_component})
    endif()
endmacro()
# SPDX-FileCopyrightText: 2013 Alexander Richardson <arichardson.kde@gmail.com>
# SPDX-FileCopyrightText: 2015 Alex Merry <alex.merry@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
ECMAddTests
-----------

Convenience functions for adding tests.

::

  ecm_add_tests(<sources>
      LINK_LIBRARIES <library> [<library> [...]]
      [NAME_PREFIX <prefix>]
      [GUI]
      [TARGET_NAMES_VAR <target_names_var>]
      [TEST_NAMES_VAR <test_names_var>]
      [WORKING_DIRECTORY <dir>] #  Since 5.111
  )

A convenience function for adding multiple tests, each consisting of a
single source file. For each file in <sources>, an executable target will be
created (the name of which will be the basename of the source file). This
will be linked against the libraries given with ``LINK_LIBRARIES``. Each
executable will be added as a test with the same name.

If ``NAME_PREFIX`` is given, this prefix will be prepended to the test names, but
not the target names. As a result, it will not prevent clashes between tests
with the same name in different parts of the project, but it can be used to
give an indication of where to look for a failing test.

If the flag ``GUI`` is passed the test binaries will be GUI executables, otherwise
the resulting binaries will be console applications (regardless of the value
of ``CMAKE_WIN32_EXECUTABLE`` or ``CMAKE_MACOSX_BUNDLE``). Be aware that this changes
the executable entry point on Windows (although some frameworks, such as Qt,
abstract this difference away).

The tests will be build with ``-DQT_FORCE_ASSERTS`` to enable assertions in the
test executable even for release builds.

The ``TARGET_NAMES_VAR`` and ``TEST_NAMES_VAR`` arguments, if given, should specify a
variable name to receive the list of generated target and test names,
respectively. This makes it convenient to apply properties to them as a
whole, for example, using ``set_target_properties()`` or  ``set_tests_properties()``.

The generated target executables will have the effects of ``ecm_mark_as_test()``
(from the :module:`ECMMarkAsTest` module) applied to it.

``WORKING_DIRECTORY`` sets the test property `WORKING_DIRECTORY
<https://cmake.org/cmake/help/latest/prop_test/WORKING_DIRECTORY.html>`_
in which to execute the test. By default the test will be run in
``${CMAKE_CURRENT_BINARY_DIR}``. The working directory can be specified using
generator expressions. Since 5.111.

::

  ecm_add_test(
      <sources>
      LINK_LIBRARIES <library> [<library> [...]]
      [TEST_NAME <name>]
      [NAME_PREFIX <prefix>]
      [GUI]
      [WORKING_DIRECTORY <dir>] #  Since 5.111
  )

This is a single-test form of ``ecm_add_tests`` that allows multiple source files
to be used for a single test. If using multiple source files, ``TEST_NAME`` must
be given; this will be used for both the target and test names (and, as with
``ecm_add_tests()``, the ``NAME_PREFIX`` argument will be prepended to the test name).

``WORKING_DIRECTORY`` sets the test property `WORKING_DIRECTORY
<https://cmake.org/cmake/help/latest/prop_test/WORKING_DIRECTORY.html>`_
in which to execute the test. By default the test will be run in
``${CMAKE_CURRENT_BINARY_DIR}``. The working directory can be specified using
generator expressions. Since 5.111.

Since pre-1.0.0.
#]=======================================================================]

include(ECMMarkAsTest)
include(ECMMarkNonGuiExecutable)

function(ecm_add_test)
  set(options GUI)
  # TARGET_NAME_VAR and TEST_NAME_VAR are undocumented args used by
  # ecm_add_tests
  set(oneValueArgs TEST_NAME NAME_PREFIX TARGET_NAME_VAR TEST_NAME_VAR WORKING_DIRECTORY)
  set(multiValueArgs LINK_LIBRARIES)
  cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  set(_sources ${ARG_UNPARSED_ARGUMENTS})
  list(LENGTH _sources _sourceCount)
  if(ARG_TEST_NAME)
    set(_targetname ${ARG_TEST_NAME})
  elseif(${_sourceCount} EQUAL "1")
    #use the source file name without extension as the testname
    get_filename_component(_targetname ${_sources} NAME_WE)
  else()
    #more than one source file passed, but no test name given -> error
    message(FATAL_ERROR "ecm_add_test() called with multiple source files but without setting \"TEST_NAME\"")
  endif()

  set(_testname ${ARG_NAME_PREFIX}${_targetname})
  set(gui_args)
  if(ARG_GUI)
      set(gui_args WIN32 MACOSX_BUNDLE)
  endif()
  add_executable(${_targetname} ${gui_args} ${_sources})
  if(NOT ARG_GUI)
    ecm_mark_nongui_executable(${_targetname})
  endif()
  set(test_args)
  if(DEFINED ARG_WORKING_DIRECTORY)
      list(APPEND test_args WORKING_DIRECTORY ${ARG_WORKING_DIRECTORY})
  endif()
  add_test(NAME ${_testname} COMMAND ${_targetname} ${test_args})
  target_link_libraries(${_targetname} ${ARG_LINK_LIBRARIES})
  target_compile_definitions(${_targetname} PRIVATE -DQT_FORCE_ASSERTS)
  ecm_mark_as_test(${_targetname})
  if (CMAKE_LIBRARY_OUTPUT_DIRECTORY)
    set(_plugin_path ${CMAKE_LIBRARY_OUTPUT_DIRECTORY})
    if (DEFINED ENV{QT_PLUGIN_PATH})
      if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
        # https://stackoverflow.com/questions/59862894/how-do-i-make-a-list-in-cmake-with-the-semicolon-value
        set(PATHSEP "\\\;") # Don't want cmake to treat it like a list
      else() # e.g. Linux
        set(PATHSEP ":")
      endif()
      set(_plugin_path "${_plugin_path}${PATHSEP}$ENV{QT_PLUGIN_PATH}")
    endif()
    set_property(TEST ${_testname} PROPERTY ENVIRONMENT "QT_PLUGIN_PATH=${_plugin_path}")
  endif()
  if (ARG_TARGET_NAME_VAR)
    set(${ARG_TARGET_NAME_VAR} "${_targetname}" PARENT_SCOPE)
  endif()
  if (ARG_TEST_NAME_VAR)
    set(${ARG_TEST_NAME_VAR} "${_testname}" PARENT_SCOPE)
  endif()
endfunction()

function(ecm_add_tests)
  set(options GUI)
  set(oneValueArgs NAME_PREFIX TARGET_NAMES_VAR TEST_NAMES_VAR WORKING_DIRECTORY)
  set(multiValueArgs LINK_LIBRARIES)
  cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  if(ARG_GUI)
    set(_exe_type GUI)
  else()
    set(_exe_type "")
  endif()
  set(test_args)
  if(DEFINED ARG_WORKING_DIRECTORY)
      list(APPEND test_args WORKING_DIRECTORY ${ARG_WORKING_DIRECTORY})
  endif()
  set(test_names)
  set(target_names)
  foreach(_test_source ${ARG_UNPARSED_ARGUMENTS})
    ecm_add_test(${_test_source}
      NAME_PREFIX ${ARG_NAME_PREFIX}
      LINK_LIBRARIES ${ARG_LINK_LIBRARIES}
      TARGET_NAME_VAR target_name
      TEST_NAME_VAR test_name
      ${_exe_type}
      ${test_args}
    )
    list(APPEND _test_names "${test_name}")
    list(APPEND _target_names "${target_name}")
  endforeach()
  if (ARG_TARGET_NAMES_VAR)
    set(${ARG_TARGET_NAMES_VAR} "${_target_names}" PARENT_SCOPE)
  endif()
  if (ARG_TEST_NAMES_VAR)
    set(${ARG_TEST_NAMES_VAR} "${_test_names}" PARENT_SCOPE)
  endif()
endfunction()
# SPDX-FileCopyrightText: 2020 Andreas Cord-Landwehr <cordlandwehr@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
ECMCheckOutboundLicense
-----------------------

Assert that source file licenses are compatible with a desired outbound license
of a compiled binary artifact (e.g., library, plugin or application).

This module provides the ``ecm_check_outbound_license`` function that
generates unit tests for checking the compatibility of license statements.
The license statements in all tested files are required to be added by using
the SPDX marker ``SPDX-License-Identifier``.

During the CMake configuration of the project, a temporary license bill of
materials (BOM) in SPDX format is generated by calling the REUSE tool
(see <https://reuse.software>). That BOM is parsed and license computations
based on an internal compatibility matrix are performed.

Preconditions for using this module:
    * All tested input source files must contain the SPDX-License-Identifier tag.
    * Python3 must be available.
    * The REUSE tool must be available, which generates the bill-of-materials
      by running ``reuse spdx`` on the tested directory.

When this module is included, a ``SKIP_LICENSE_TESTS`` option is added (default
``OFF``). Turning this option on skips the generation of license tests, which might
be convenient if licenses shall not be tested in all build configurations.

::

  ecm_check_outbound_license(LICENSES <outbound-licenses>
                             FILES <source-files>
                             [TEST_NAME <name>]
                             [WILL_FAIL])

This method adds a custom unit test to ensure the specified outbound license to be
compatible with the specified license headers. Note that a convenient way is to use
the CMake ``GLOB`` argument of the ``FILE`` function.

``LICENSES``  : List of one or multiple outbound license regarding which the compatibility of the source code files shall be tested.
                Currently, the following values are supported (values are SPDX registry identifiers):
                   * MIT
                   * BSD-2-Clause
                   * BSD-3-Clause
                   * LGPL-2.0-only
                   * LGPL-2.1-only
                   * LGPL-3.0-only
                   * GPL-2.0-only
                   * GPL-3.0-only

``FILES:``    : List of source files that contain valid SPDX-License-Identifier markers.
                The paths can be relative to the CMake file that generates the test case
                or be absolute paths.

``TEST_NAME`` : Optional parameter that defines the name of the generated test case.
                If no name is defined, the relative path to the test directory with appended
                license name is used. Every test has ``licensecheck_`` as prefix.

``WILL_FAIL`` : Optional parameter that inverts the test result. This parameter is usually only
                used for tests of the module.

Since 5.75.0
#]=======================================================================]

include(FeatureSummary)

option(SKIP_LICENSE_TESTS "Skip outbound license tests" OFF)

find_package(Python3)
set_package_properties(Python3 PROPERTIES
    PURPOSE "Required to run tests of module ECMCheckOutboundLicense"
    TYPE OPTIONAL
)

find_package(ReuseTool)
set_package_properties(ReuseTool PROPERTIES
    PURPOSE "Required to run tests of module ECMCheckOutboundLicense"
    TYPE OPTIONAL
)

if (NOT SKIP_LICENSE_TESTS AND NOT REUSETOOL_FOUND)
    add_feature_info(SPDX_LICENSE_TESTING FALSE "Automatic license testing based on SPDX definitions (requires reuse tool)")
    message(WARNING "Reuse tool not found, skipping test generation")
else()
    add_feature_info(SPDX_LICENSE_TESTING TRUE "Automatic license testing based on SPDX definitions (requires reuse tool)")
endif()

set(SPDX_BOM_OUTPUT "${CMAKE_BINARY_DIR}/spdx.txt")

# test fixture for generating SPDX bill of materials
if(SKIP_LICENSE_TESTS OR NOT REUSETOOL_FOUND)
    message(STATUS "Skipping execution of outbound license tests.")
else()
    add_test(
        NAME generate_spdx_bom
        COMMAND reuse spdx -o ${SPDX_BOM_OUTPUT}
        WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
    )
    set_tests_properties(generate_spdx_bom PROPERTIES FIXTURES_SETUP SPDX_BOM)
endif()

function(ecm_check_outbound_license)
    if(SKIP_LICENSE_TESTS OR NOT REUSETOOL_FOUND)
        return()
    endif()

    set(_options WILL_FAIL)
    set(_oneValueArgs TEST_NAME)
    set(_multiValueArgs LICENSES FILES)
    cmake_parse_arguments(ARG "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN} )

    if(NOT ARG_LICENSES)
        message(FATAL_ERROR "No LICENSES argument given to ecm_check_outbound_license")
    endif()

    if(NOT ARG_FILES)
        message(WARNING "No FILES argument given to ecm_check_outbound_license")
        return()
    endif()

    if(NOT ARG_TEST_NAME)
        # compute test name based on licensecheck_<relative-path>_<licence> if not name given
        string(REPLACE "${CMAKE_SOURCE_DIR}/" "" TEMP_TEST_NAME "${CMAKE_CURRENT_SOURCE_DIR}_${ARG_LICENSE}")
        string(MAKE_C_IDENTIFIER ${TEMP_TEST_NAME} ARG_TEST_NAME)
    endif()

    # generate file with list of relative file paths
    string(REPLACE "${CMAKE_BINARY_DIR}/" "" RELATIVE_PREFIX_PATH ${CMAKE_CURRENT_BINARY_DIR})
    set(OUTPUT_FILE ${CMAKE_BINARY_DIR}/licensecheck_${ARG_TEST_NAME}.txt)
    file(REMOVE ${OUTPUT_FILE})
    foreach(_file ${ARG_FILES})
        # check script expects files to start with "./", which must be relative to CMAKE_SOURCE_DIR
        if (IS_ABSOLUTE ${_file})
            string(REPLACE ${CMAKE_SOURCE_DIR} "." TEMPORARY_PATH ${_file})
            file(APPEND ${OUTPUT_FILE} "${TEMPORARY_PATH}\n")
        else()
            file(APPEND ${OUTPUT_FILE} "./${RELATIVE_PREFIX_PATH}/${_file}\n")
        endif()
    endforeach()

    file(COPY ${ECM_MODULE_DIR}/check-outbound-license.py DESTINATION ${CMAKE_BINARY_DIR})

    foreach(_license ${ARG_LICENSES})
        string(MAKE_C_IDENTIFIER ${_license} LICENSE_ID)
        add_test(
            NAME licensecheck_${ARG_TEST_NAME}_${LICENSE_ID}
            COMMAND python3 ${CMAKE_BINARY_DIR}/check-outbound-license.py -l ${_license} -s ${SPDX_BOM_OUTPUT} -i ${OUTPUT_FILE}
        )
        set_tests_properties(licensecheck_${ARG_TEST_NAME}_${LICENSE_ID} PROPERTIES FIXTURES_REQUIRED SPDX_BOM)
        set_tests_properties(licensecheck_${ARG_TEST_NAME}_${LICENSE_ID} PROPERTIES WILL_FAIL ${ARG_WILL_FAIL})
    endforeach()
endfunction()
# SPDX-FileCopyrightText: 2020 David Edmundson <davidedmundson@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
ECMConfiguredInstall
--------------------

Takes a list of files, runs ``configure_file`` on each and installs the resultant configured files in the given location.

Any suffix of ".in" in the passed file names will be stripped from the file name at the installed location.

::

  ecm_install_configured_files(
      INPUT <file> [<file2> [...]]
      DESTINATION <INSTALL_DIRECTORY>
      [COPYONLY]
      [ESCAPE_QUOTES]
      [@ONLY]
      [COMPONENT <component>])

Example usage:

.. code-block:: cmake

  ecm_install_configured_files(INPUT foo.txt.in DESTINATION ${KDE_INSTALL_DATADIR} @ONLY)

This will install the file as foo.txt with any cmake variable replacements made into the data directory.

Since 5.73.0.
#]=======================================================================]

function(ecm_install_configured_files)
    set(options COPYONLY ESCAPE_QUOTES @ONLY)
    set(oneValueArgs DESTINATION COMPONENT)
    set(multiValueArgs INPUT)

    cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}"
                          "${multiValueArgs}" ${ARGN})


    if(ARGS_UNPARSED_ARGUMENTS)
        message(FATAL_ERROR "Unknown arguments given to ecm_install_configured_file(): \"${ARGS_UNPARSED_ARGUMENTS}\"")
    endif()

    if (NOT ARGS_DESTINATION)
        message(FATAL_ERROR "missing DESTINATION argument to ECMConfiguredInstall")
    endif()

    foreach(_input ${ARGS_INPUT})
        # convert absolute paths
        get_filename_component(_name ${_input} NAME)

        string(REGEX REPLACE "\\.in$"  "" _name ${_name})

        set(_out_file ${CMAKE_CURRENT_BINARY_DIR}/${_name})

        set(_configure_args)
        if (ARGS_COPY_ONLY)
                list(APPEND _configure_args COPY_ONLY)
        endif()
        if (ARGS_ESCAPE_QUOTES)
                list(APPEND _configure_args  ESCAPE_QUOTES)
        endif()
        if (ARGS_@ONLY)
                list(APPEND _configure_args @ONLY)
        endif()

        configure_file(${_input} ${_out_file} ${_configure_args})

        if (DEFINED ARGS_COMPONENT)
            set(_component COMPONENT ${ARGS_COMPONENT})
        else()
            set(_component)
        endif()

        install(FILES ${_out_file} DESTINATION ${ARGS_DESTINATION} ${_component})
    endforeach()
endfunction()
# SPDX-FileCopyrightText: 2014 Aleix Pol Gonzalez <aleixpol@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
ECMCoverageOption
--------------------

Allow users to easily enable GCov code coverage support.

Code coverage allows you to check how much of your codebase is covered by
your tests. This module makes it easy to build with support for
`GCov <https://gcc.gnu.org/onlinedocs/gcc/Gcov.html>`_.

When this module is included, a ``BUILD_COVERAGE`` option is added (default
``OFF``). Turning this option on enables GCC's coverage instrumentation, and
links against ``libgcov``.

.. note::
  This will probably break the build if you are not using GCC.

Since 1.3.0.
#]=======================================================================]

option(BUILD_COVERAGE "Build the project with gcov support" OFF)

if(BUILD_COVERAGE)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage")
    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lgcov")
endif()
# SPDX-FileCopyrightText: 2014 Aurélien Gâteau <agateau@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
ECMCreateQmFromPoFiles
----------------------

.. warning:: This module is deprecated and will be removed by ECM 1.0. Use
             :module:`ECMPoQmTools` instead.

Generate QTranslator (.qm) catalogs from Gettext (.po) catalogs.

::

  ecm_create_qm_from_po_files(PO_FILES <file1>... <fileN>
                              [CATALOG_NAME <catalog_name>]
                              [INSTALL_DESTINATION <install_destination>])

Creates the necessary rules to compile .po files into .qm files, and install
them.

The .qm files are installed in ``<install_destination>/<lang>/LC_MESSAGES``,
where <install_destination> is the INSTALL_DESTINATION argument and <lang> is
extracted from the "Language" field inside the .po file.

INSTALL_DESTINATION defaults to ``${LOCALE_INSTALL_DIR}`` if defined,
otherwise it uses ``${CMAKE_INSTALL_LOCALEDIR}`` if that is defined, otherwise
it uses ``share/locale``.

CATALOG_NAME defines the name of the installed .qm files. If set, .qm files
will be installed as ``<catalog_name>.qm``. If not set .qm files will be named
after the name of their source .po file.

Setting the catalog name is useful when all .po files for a target are kept
in a single source directory. For example, the "mylib" probject might keep all
its translations in a "po" directory, like this::

  po/
      es.po
      fr.po

Without setting CATALOG_NAME, those .po will be turned into .qm and installed
as::

  share/locale/fr/LC_MESSAGES/fr.qm
  share/locale/es/LC_MESSAGES/es.qm

If CATALOG_NAME is set to "mylib", they will be installed as::

  share/locale/fr/LC_MESSAGES/mylib.qm
  share/locale/es/LC_MESSAGES/mylib.qm

Which is what the loader created by ecm_create_qm_loader() expects.

ecm_create_qm_from_po_files() creates a "translation" target. This target
builds all .po files into .qm files.

::

  ecm_create_qm_loader(<source_files_var> <catalog_name>)

ecm_create_qm_loader() generates a C++ file which ensures translations are
automatically loaded at startup. The path of the .cpp file is appended to
<source_files_var>.  Typical usage is like:

.. code-block:: cmake

  set(mylib_SRCS foo.cpp bar.cpp)
  ecm_create_qm_loader(mylib_SRCS mylib)
  add_library(mylib ${mylib_SRCS})

This generates a C++ file which loads "mylib.qm" at startup, assuming it has
been installed by ecm_create_qm_from_po_files(), and compiles it into ``mylib``.

Since pre-1.0.0.
#]=======================================================================]

message(AUTHOR_WARNING "ECMCreateQmFromPoFiles is deprecated and will be removed before the release of Extra CMake Modules 1.0. Use ECMPoQmTools instead.")

# Stolen from FindGettext.cmake
function(_ECM_QM_GET_UNIQUE_TARGET_NAME _name _unique_name)
   set(propertyName "_ECM_QM_UNIQUE_COUNTER_${_name}")
   get_property(currentCounter GLOBAL PROPERTY "${propertyName}")
   if(NOT currentCounter)
      set(currentCounter 1)
   endif()
   set(${_unique_name} "${_name}_${currentCounter}" PARENT_SCOPE)
   math(EXPR currentCounter "${currentCounter} + 1")
   set_property(GLOBAL PROPERTY ${propertyName} ${currentCounter} )
endfunction()

function(_ECM_QM_EXTRACT_LANGUAGE out_language po_file)
    file(READ ${po_file} content)
    # msginit uses "Language: <lang>" but lconvert uses "X-Language: <lang>"
    string(REGEX MATCH "\"(X-)?Language: ([a-z_A-Z]+)" match "${content}")
    if (NOT match)
        message(FATAL_ERROR "_ECM_QM_EXTRACT_LANGUAGE: Could not extract language from ${po_file}")
    endif()
    set(${out_language} ${CMAKE_MATCH_2} PARENT_SCOPE)
endfunction()

function(_ECM_QM_CREATE_TARGET install_destination catalog_name)
    # Find lconvert
    if(TARGET Qt5::lconvert)
        set(lconvert_executable Qt5::lconvert)
    else()
        # Qt < 5.3.1 does not define Qt5::lconvert
        get_target_property(lrelease_location Qt5::lrelease LOCATION)
        get_filename_component(lrelease_path ${lrelease_location} PATH)
        find_program(lconvert_executable
            NAMES lconvert-qt5 lconvert
            PATHS ${lrelease_path}
            NO_DEFAULT_PATH
            )
    endif()

    if (catalog_name)
        set(install_args RENAME ${catalog_name}.qm)
    else()
        set(install_args)
    endif()

    foreach (it ${ARGN})
        get_filename_component(filename_base ${it} ABSOLUTE)
        get_filename_component(filename_base ${it} NAME_WE)

        file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
        set(tsfile ${CMAKE_CURRENT_BINARY_DIR}/${filename_base}.ts)
        set(qmfile ${CMAKE_CURRENT_BINARY_DIR}/${filename_base}.qm)

        _ECM_QM_EXTRACT_LANGUAGE(language ${it})

        # lconvert from .po to .ts and then run lupdate to generate the correct
        # strings. Finally run lrelease to create the .qm files.
        add_custom_command(OUTPUT ${qmfile}
            COMMAND ${lconvert_executable}
                ARGS -i ${it} -o ${tsfile} -target-language ${language}
            COMMAND Qt5::lrelease
                ARGS -removeidentical -silent ${tsfile} -qm ${qmfile}
            DEPENDS ${it}
            )
        install(
            FILES ${qmfile}
            DESTINATION ${install_destination}/${language}/LC_MESSAGES
            ${install_args}
        )
        set(qmfiles ${qmfiles} ${qmfile})
    endforeach()

    if(NOT TARGET translations)
        add_custom_target(translations ALL)
    endif()
    _ecm_qm_get_unique_target_name(translations target_name)
    add_custom_target(${target_name} DEPENDS ${qmfiles})
    add_dependencies(translations ${target_name})
endfunction()

function(ECM_CREATE_QM_LOADER out_var catalog_name)
    # catalog_name is used in ECMQmLoader.cpp.in
    configure_file(${ECM_MODULE_DIR}/ECMQmLoader.cpp.in ECMQmLoader.cpp @ONLY)
    set(${out_var} ${${out_var}} ${CMAKE_CURRENT_BINARY_DIR}/ECMQmLoader.cpp PARENT_SCOPE)
endfunction()

function(ECM_CREATE_QM_FROM_PO_FILES)
    # This gives us Qt5::lrelease and Qt5::lupdate but unfortunately no Qt5::lconvert
    # See https://bugreports.qt-project.org/browse/QTBUG-37937
    find_package(Qt5LinguistTools CONFIG REQUIRED)

    foreach (arg ${ARGN})
        if (arg STREQUAL "PO_DIR")
            _ecm_create_qm_from_po_files_legacy(${ARGN})
            return()
        endif()
    endforeach()

    set(options)
    set(oneValueArgs CATALOG_NAME INSTALL_DESTINATION)
    set(multiValueArgs PO_FILES)
    cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

    if(ARGS_UNPARSED_ARGUMENTS)
        message(FATAL_ERROR "Unknown keywords given to ECM_CREATE_QM_FROM_PO_FILES(): \"${ARGS_UNPARSED_ARGUMENTS}\"")
    endif()

    if(NOT ARGS_PO_FILES)
        message(FATAL_ERROR "ECM_CREATE_QM_FROM_PO_FILES(): Must be called with PO_FILES argument")
    endif()

    if(NOT ARGS_INSTALL_DESTINATION)
        if (LOCALE_INSTALL_DIR)
            set(ARGS_INSTALL_DESTINATION "${LOCALE_INSTALL_DIR}")
        elseif (CMAKE_INSTALL_LOCALEDIR)
            set(ARGS_INSTALL_DESTINATION "${CMAKE_INSTALL_LOCALEDIR}")
        else()
            set(ARGS_INSTALL_DESTINATION share/locale)
        endif()
    endif()

    _ecm_qm_create_target(${ARGS_INSTALL_DESTINATION} "${ARGS_CATALOG_NAME}" ${ARGS_PO_FILES})
endfunction()

# Handles the syntax exposed in ECM 0.0.12, shipped with KDE Frameworks 5.0beta1
#
# This is a macro so that the value written in ${ARGS_CREATE_LOADER} is
# correctly propagated to ECM_CREATE_QM_FROM_PO_FILES parent scope. If it were
# not a macro, ECM_CREATE_QM_FROM_PO_FILES would have to ckeck if
# CREATE_LOADER is in the arguments and propagate the value itself.
macro(_ECM_CREATE_QM_FROM_PO_FILES_LEGACY)
    set(options)
    set(oneValueArgs PO_DIR POT_NAME DATA_INSTALL_DIR DATA_INSTALL_SUB_DIR CREATE_LOADER)
    set(multiValueArgs)
    cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

    if(ARGS_UNPARSED_ARGUMENTS)
        message(FATAL_ERROR "Unknown keywords given to _ECM_CREATE_QM_FROM_PO_FILES_LEGACY(): \"${ARGS_UNPARSED_ARGUMENTS}\"")
    endif()

    if(NOT ARGS_POT_NAME)
        message(FATAL_ERROR "Required argument POT_NAME missing in _ECM_CREATE_QM_FROM_PO_FILES_LEGACY() call")
    endif()
    get_filename_component(catalog_name ${ARGS_POT_NAME} NAME_WE)

    if (LOCALE_INSTALL_DIR)
        set(install_destination "${LOCALE_INSTALL_DIR}")
    elseif (CMAKE_INSTALL_LOCALEDIR)
        set(install_destination "${CMAKE_INSTALL_LOCALEDIR}")
    else()
        set(install_destination share/locale)
    endif()

    file(GLOB po_files "${ARGS_PO_DIR}/*.po")
    _ecm_qm_create_target(${install_destination} "${catalog_name}" ${po_files})

    if (ARGS_CREATE_LOADER)
        ecm_create_qm_loader(loader ${catalog_name})
        set(${ARGS_CREATE_LOADER} ${loader} PARENT_SCOPE)
    endif()
endmacro()
# SPDX-FileCopyrightText: 2021 Alexander Lohnau <alexander.lohnau@gmx.de>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
ECMDeprecationSettings
-----------------------

This module provides the ``ecm_set_disabled_deprecation_versions`` function setting the excluding
deprecated API for Qt and KF projects.

This method expects pairs of the identifier and deprecation version.
For the identifier ``QT`` this functions adds the definition ``QT_DISABLE_DEPRECATED_BEFORE`` with the given version in a hexadecimal format.
Otherwise the name for the definition is generated using ``${IDENTIFIER}_DISABLE_DEPRECATED_BEFORE_AND_AT``,
following the naming of the generated code in :module:`ECMGenerateExportHeader`.
The version for the definition can be overwritten, by passing definition name and the deprecation version
as a CMake definition. This allows one to exclude deprecations without having to edit the CMakeLists.txt file.

This module provides the following function:

::

  ecm_set_disabled_deprecation_versions(
      [DISABLE_NEWER_WARNINGS] # since 5.96
      [<identifier> <deprecation_version>]
      [<identifier2> <deprecation_version2>]
  )

``DISABLE_NEWER_WARNINGS`` disables additionally the compiler warnings for API deprecated in newer versions
of the same major version.


Example usage:

.. code-block:: cmake

  set(QT_MIN_VERSION "5.15.2")
  set(KF5_MIN_VERSION "5.90")

  ecm_set_disabled_deprecation_versions(
    QT ${QT_MIN_VERSION}
    KF ${KF5_MIN_VERSION}
    KCOREADDONS 5.89.0 # In case we depend on deprecated KCoreAddons API
  )



Since 5.91
#]=======================================================================]

function (ecm_set_disabled_deprecation_versions)
    cmake_parse_arguments(ARGS "SHOW_DEPRECATIONS;DISABLE_NEWER_WARNINGS" "" "" ${ARGN})

    # support legacy initial flag to opt-in to warnings
    if (ARGS_SHOW_DEPRECATIONS)
        message(DEPRECATION "SHOW_DEPRECATIONS is deprecated, since 5.96 warnings are enabled by default.")
    endif()
    if (ARGS_SHOW_DEPRECATIONS AND ARGS_DISABLE_NEWER_WARNINGS)
        message(FATAL_ERROR "SHOW_DEPRECATIONS && DISABLE_NEWER_WARNINGS cannot be set both.")
    endif()
    set(show_newer_warnings TRUE)
    if (ARGS_DISABLE_NEWER_WARNINGS)
        set(show_newer_warnings FALSE)
    endif()

    list(LENGTH ARGS_UNPARSED_ARGUMENTS PAIR_COUNT)
    math(EXPR is_even_number "${PAIR_COUNT} % 2")
    if (NOT is_even_number EQUAL 0)
        message(FATAL_ERROR "Expected number of arguments is an even number of identifiers and version")
    endif()
    math(EXPR number_pairs "(${PAIR_COUNT} / 2) - 1")
    foreach (it RANGE ${number_pairs})
        # get values
        math(EXPR current_index "${it} * 2")
        list(GET ARGS_UNPARSED_ARGUMENTS ${current_index} DEPRECATION_NAME)
        math(EXPR next_index "(${it} *2) + 1")
        list(GET ARGS_UNPARSED_ARGUMENTS ${next_index} DEPRECATION_VERSION)

        # get the string identifier for the target definition
        string(COMPARE EQUAL ${DEPRECATION_NAME} "QT" IS_QT_DEPRECATION)
        if (IS_QT_DEPRECATION)
            set(DEPRECATION_DEFINITION_NAME QT_DISABLE_DEPRECATED_BEFORE)
        else()
            set(DEPRECATION_DEFINITION_NAME ${DEPRECATION_NAME}_DISABLE_DEPRECATED_BEFORE_AND_AT)
        endif()
        # we want to be able to set this version without being forced to edit the CMakeLists.txt file
        if (${${DEPRECATION_DEFINITION_NAME}})
            set(DEPRECATION_VERSION "${${DEPRECATION_DEFINITION_NAME}}")
        endif()

        # make a sanity check to make sure we do not get malformed versions
        _ecm_version_triple_sanity_check("${DEPRECATION_VERSION}")

        # add the actual compile definition with the given hex value
        _ecm_geh_generate_hex_number_from_version(DEPRECATION_HEX_VERSION ${DEPRECATION_VERSION})
        add_definitions(-D${DEPRECATION_DEFINITION_NAME}=${DEPRECATION_HEX_VERSION})

        # Set the version for the deprecation warnings
        if (show_newer_warnings)
            string(REGEX MATCH "([0-9]+)\\." _ ${DEPRECATION_VERSION})
            if (NOT CMAKE_MATCH_1)
                message(FATAL_ERROR "Failed to get major version from ${DEPRECATION_VERSION}")
            endif()
            # Add 1 to the major version and store it as a hex value
            math(EXPR next_major_version "(${CMAKE_MATCH_1} + 1) * 65536 " OUTPUT_FORMAT HEXADECIMAL)
            add_definitions(-D${DEPRECATION_NAME}_DEPRECATED_WARNINGS_SINCE=${next_major_version})
        endif()

    endforeach()
endfunction()

# helper method
function(_ecm_geh_generate_hex_number_from_version _var_name _version)
    set(_hexnumber 0)

    string(REGEX MATCH "^([0-9]+)\\.([0-9]+)(\\.([0-9]+))?$" _ ${_version})

    # Set the patch version to 0, if none is specified by the regex.
    # This is the case for min. versions that don't specify the patch level, like in the snipped of the method docs.
    if (NOT CMAKE_MATCH_4)
        set(CMAKE_MATCH_4 "0")
    endif()

    math(EXPR _hexnumber "${CMAKE_MATCH_1}*65536 + ${CMAKE_MATCH_2}*256 + ${CMAKE_MATCH_4}" OUTPUT_FORMAT HEXADECIMAL)
    set(${_var_name} ${_hexnumber} PARENT_SCOPE)
endfunction()

function (_ecm_version_triple_sanity_check unchecked_version)
    # helper string
    set(_version_triple_regexp "^([0-9]+)\\.([0-9]+)(\\.([0-9]+))?$")
    # args sanity check
    if (NOT unchecked_version)
        message(FATAL_ERROR "No VERSION passed when calling ecm_set_deprecation_versions().")
    elseif(NOT unchecked_version MATCHES ${_version_triple_regexp})
        message(FATAL_ERROR "VERSION ${unchecked_version} expected to be in x.y.z format when calling ecm_set_deprecation_versions().")
    endif()
endfunction()
# SPDX-FileCopyrightText: 2014 Mathieu Tarral <mathieu.tarral@gmail.com>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
ECMEnableSanitizers
-------------------

Enable compiler sanitizer flags.

The following sanitizers are supported:

- Address Sanitizer
- Memory Sanitizer
- Thread Sanitizer
- Leak Sanitizer
- Undefined Behaviour Sanitizer

All of them are implemented in Clang, depending on your version, and
there is an work in progress in GCC, where some of them are currently
implemented.

This module will check your current compiler version to see if it
supports the sanitizers that you want to enable

Usage
=====

Simply add::

   include(ECMEnableSanitizers)

to your ``CMakeLists.txt``. Note that this module is included in
:kde-module:`KDECompilerSettings`, so projects using that module do not need to also
include this one.

The sanitizers are not enabled by default. Instead, you must set
``ECM_ENABLE_SANITIZERS`` (either in your ``CMakeLists.txt`` or on the
command line) to a semicolon-separated list of sanitizers you wish to enable.
The options are:

- address
- memory
- thread
- leak
- undefined
- fuzzer

The sanitizers "address", "memory" and "thread" are mutually exclusive.  You
cannot enable two of them in the same build.

"leak" requires the  "address" sanitizer.

.. note::

  To reduce the overhead induced by the instrumentation of the sanitizers, it
  is advised to enable compiler optimizations (``-O1`` or higher).

Example
=======

This is an example of usage::

  mkdir build
  cd build
  cmake -DECM_ENABLE_SANITIZERS='address;leak;undefined' ..

.. note::

  Most of the sanitizers will require Clang. To enable it, use::

    -DCMAKE_CXX_COMPILER=clang++

Since 1.3.0.
#]=======================================================================]

# MACRO check_compiler_version
#-----------------------------
macro (check_compiler_version gcc_required_version clang_required_version msvc_required_version)
    if (
        (
            CMAKE_CXX_COMPILER_ID MATCHES "GNU"
            AND
            CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${gcc_required_version}
        )
        OR
        (
            CMAKE_CXX_COMPILER_ID MATCHES "Clang"
            AND
            CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${clang_required_version}
        )
        OR
        (
            CMAKE_CXX_COMPILER_ID MATCHES "MSVC"
            AND
            CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${msvc_required_version}
        )
    )
        # error !
        message(FATAL_ERROR "You ask to enable the sanitizer ${CUR_SANITIZER},
        but your compiler ${CMAKE_CXX_COMPILER_ID} version ${CMAKE_CXX_COMPILER_VERSION}
        does not support it !
        You should use at least GCC ${gcc_required_version}, Clang ${clang_required_version}
        or MSVC ${msvc_required_version}
        (99.99 means not implemented yet)")
    endif ()
endmacro ()

# MACRO check_compiler_support
#------------------------------
macro (enable_sanitizer_flags sanitize_option)
    if (${sanitize_option} MATCHES "address")
        check_compiler_version("4.8" "3.1" "19.28")
        if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
            set(XSAN_COMPILE_FLAGS "-fsanitize=address")
        else()
            set(XSAN_COMPILE_FLAGS "-fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls")
            set(XSAN_LINKER_FLAGS "asan")
        endif()
    elseif (${sanitize_option} MATCHES "thread")
        check_compiler_version("4.8" "3.1" "99.99")
        set(XSAN_COMPILE_FLAGS "-fsanitize=thread")
        set(XSAN_LINKER_FLAGS "tsan")
    elseif (${sanitize_option} MATCHES "memory")
        check_compiler_version("99.99" "3.1" "99.99")
        set(XSAN_COMPILE_FLAGS "-fsanitize=memory")
    elseif (${sanitize_option} MATCHES "leak")
        check_compiler_version("4.9" "3.4" "99.99")
        set(XSAN_COMPILE_FLAGS "-fsanitize=leak")
        set(XSAN_LINKER_FLAGS "lsan")
    elseif (${sanitize_option} MATCHES "undefined")
        check_compiler_version("4.9" "3.1" "99.99")
        set(XSAN_COMPILE_FLAGS "-fsanitize=undefined -fno-omit-frame-pointer -fno-optimize-sibling-calls")
    elseif (${sanitize_option} MATCHES "fuzzer")
        check_compiler_version("99.99" "6.0" "99.99")
        set(XSAN_COMPILE_FLAGS "-fsanitize=fuzzer")
    else ()
        message(FATAL_ERROR "Compiler sanitizer option \"${sanitize_option}\" not supported.")
    endif ()
endmacro ()

if (ECM_ENABLE_SANITIZERS)
    if (CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
        # for each element of the ECM_ENABLE_SANITIZERS list
        foreach ( CUR_SANITIZER ${ECM_ENABLE_SANITIZERS} )
            # lowercase filter
            string(TOLOWER ${CUR_SANITIZER} CUR_SANITIZER)
            # check option and enable appropriate flags
            enable_sanitizer_flags ( ${CUR_SANITIZER} )
            # TODO: GCC will not link pthread library if enabled ASan
            if(CMAKE_C_COMPILER_ID MATCHES "Clang")
              set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${XSAN_COMPILE_FLAGS}" )
            endif()
            set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${XSAN_COMPILE_FLAGS}" )
            if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
              link_libraries(${XSAN_LINKER_FLAGS})
            endif()
            if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
                string(REPLACE "-Wl,--no-undefined " "" CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ")
                string(REPLACE "-Wl,--no-undefined " "" CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ")
            endif ()
        endforeach()
    else()
        message(STATUS "Tried to enable sanitizers (-DECM_ENABLE_SANITIZERS=${ECM_ENABLE_SANITIZERS}), \
but compiler (${CMAKE_CXX_COMPILER_ID}) does not have sanitizer support")
    endif()
endif()
# SPDX-FileCopyrightText: 2023 David Faure <faure@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
ECMFeatureSummary
-----------------

Call feature_summary(), except when being called from a subdirectory.
This ensures that frameworks being used as submodules by third-party applications
do not call feature_summary(), so that it doesn't end up being called multiple
times in the same cmake run.


::

  include(ECMFeatureSummary)
  ecm_feature_summary([... see feature_summary documentation ...])

Example:

.. code-block:: cmake

  find_package(ECM REQUIRED)
  include(ECMFeatureSummary)
  ecm_feature_summary(WHAT ALL   FATAL_ON_MISSING_REQUIRED_PACKAGES)

Since 5.247
#]=======================================================================]

include(FeatureSummary)
function(ecm_feature_summary)

    if (CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
       feature_summary(${ARGV})
    endif()

endfunction()
# SPDX-FileCopyrightText: 2014 Alex Merry <alex.merry@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
ECMFindModuleHelpers
--------------------

Helper macros for find modules: ``ecm_find_package_version_check()``,
``ecm_find_package_parse_components()`` and
``ecm_find_package_handle_library_components()``.

::

  ecm_find_package_version_check(<name>)

Prints warnings if the CMake version or the project's required CMake version
is older than that required by extra-cmake-modules.

::

  ecm_find_package_parse_components(<name>
      RESULT_VAR <variable>
      KNOWN_COMPONENTS <component1> [<component2> [...]]
      [SKIP_DEPENDENCY_HANDLING])

This macro will populate <variable> with a list of components found in
<name>_FIND_COMPONENTS, after checking that all those components are in the
list of ``KNOWN_COMPONENTS``; if there are any unknown components, it will print
an error or warning (depending on the value of <name>_FIND_REQUIRED) and call
``return()``.

The order of components in <variable> is guaranteed to match the order they
are listed in the ``KNOWN_COMPONENTS`` argument.

If ``SKIP_DEPENDENCY_HANDLING`` is not set, for each component the variable
<name>_<component>_component_deps will be checked for dependent components.
If <component> is listed in <name>_FIND_COMPONENTS, then all its (transitive)
dependencies will also be added to <variable>.

::

  ecm_find_package_handle_library_components(<name>
      COMPONENTS <component> [<component> [...]]
      [SKIP_DEPENDENCY_HANDLING])
      [SKIP_PKG_CONFIG])

Creates an imported library target for each component.  The operation of this
macro depends on the presence of a number of CMake variables.

The <name>_<component>_lib variable should contain the name of this library,
and <name>_<component>_header variable should contain the name of a header
file associated with it (whatever relative path is normally passed to
'#include'). <name>_<component>_header_subdir variable can be used to specify
which subdirectory of the include path the headers will be found in.
``ecm_find_package_components()`` will then search for the library
and include directory (creating appropriate cache variables) and create an
imported library target named <name>::<component>.

Additional variables can be used to provide additional information:

If ``SKIP_PKG_CONFIG``, the <name>_<component>_pkg_config variable is set, and
pkg-config is found, the pkg-config module given by
<name>_<component>_pkg_config will be searched for and used to help locate the
library and header file.  It will also be used to set
<name>_<component>_VERSION.

Note that if version information is found via pkg-config,
<name>_<component>_FIND_VERSION can be set to require a particular version
for each component.

If ``SKIP_DEPENDENCY_HANDLING`` is not set, the ``INTERFACE_LINK_LIBRARIES`` property
of the imported target for <component> will be set to contain the imported
targets for the components listed in <name>_<component>_component_deps.
<component>_FOUND will also be set to ``FALSE`` if any of the components in
<name>_<component>_component_deps are not found.  This requires the components
in <name>_<component>_component_deps to be listed before <component> in the
``COMPONENTS`` argument.

The following variables will be set:

``<name>_TARGETS``
  the imported targets
``<name>_LIBRARIES``
  the found libraries
``<name>_INCLUDE_DIRS``
  the combined required include directories for the components
``<name>_DEFINITIONS``
  the "other" CFLAGS provided by pkg-config, if any
``<name>_VERSION``
  the value of ``<name>_<component>_VERSION`` for the first component that
  has this variable set (note that components are searched for in the order
  they are passed to the macro), although if it is already set, it will not
  be altered

.. note::
  These variables are never cleared, so if
  ``ecm_find_package_handle_library_components()`` is called multiple times with
  different components (typically because of multiple ``find_package()`` calls) then
  ``<name>_TARGETS``, for example, will contain all the targets found in any
  call (although no duplicates).

Since pre-1.0.0.
#]=======================================================================]

macro(ecm_find_package_version_check module_name)
    if(CMAKE_VERSION VERSION_LESS 3.16.0)
        message(FATAL_ERROR "CMake 3.16.0 is required by Find${module_name}.cmake")
    endif()
    if(CMAKE_MINIMUM_REQUIRED_VERSION VERSION_LESS 3.16.0)
        message(AUTHOR_WARNING "Your project should require at least CMake 3.16.0 to use Find${module_name}.cmake")
    endif()
endmacro()

macro(ecm_find_package_parse_components module_name)
    set(ecm_fppc_options SKIP_DEPENDENCY_HANDLING)
    set(ecm_fppc_oneValueArgs RESULT_VAR)
    set(ecm_fppc_multiValueArgs KNOWN_COMPONENTS DEFAULT_COMPONENTS)
    cmake_parse_arguments(ECM_FPPC "${ecm_fppc_options}" "${ecm_fppc_oneValueArgs}" "${ecm_fppc_multiValueArgs}" ${ARGN})

    if(ECM_FPPC_UNPARSED_ARGUMENTS)
        message(FATAL_ERROR "Unexpected arguments to ecm_find_package_parse_components: ${ECM_FPPC_UNPARSED_ARGUMENTS}")
    endif()
    if(NOT ECM_FPPC_RESULT_VAR)
        message(FATAL_ERROR "Missing RESULT_VAR argument to ecm_find_package_parse_components")
    endif()
    if(NOT ECM_FPPC_KNOWN_COMPONENTS)
        message(FATAL_ERROR "Missing KNOWN_COMPONENTS argument to ecm_find_package_parse_components")
    endif()
    if(NOT ECM_FPPC_DEFAULT_COMPONENTS)
        set(ECM_FPPC_DEFAULT_COMPONENTS ${ECM_FPPC_KNOWN_COMPONENTS})
    endif()

    if(${module_name}_FIND_COMPONENTS)
        set(ecm_fppc_requestedComps ${${module_name}_FIND_COMPONENTS})

        if(NOT ECM_FPPC_SKIP_DEPENDENCY_HANDLING)
            # Make sure deps are included
            foreach(ecm_fppc_comp ${ecm_fppc_requestedComps})
                foreach(ecm_fppc_dep_comp ${${module_name}_${ecm_fppc_comp}_component_deps})
                    list(FIND ecm_fppc_requestedComps "${ecm_fppc_dep_comp}" ecm_fppc_index)
                    if("${ecm_fppc_index}" STREQUAL "-1")
                        if(NOT ${module_name}_FIND_QUIETLY)
                            message(STATUS "${module_name}: ${ecm_fppc_comp} requires ${${module_name}_${ecm_fppc_comp}_component_deps}")
                        endif()
                        list(APPEND ecm_fppc_requestedComps "${ecm_fppc_dep_comp}")
                    endif()
                endforeach()
            endforeach()
        else()
            message(STATUS "Skipping dependency handling for ${module_name}")
        endif()
        list(REMOVE_DUPLICATES ecm_fppc_requestedComps)

        # This makes sure components are listed in the same order as
        # KNOWN_COMPONENTS (potentially important for inter-dependencies)
        set(${ECM_FPPC_RESULT_VAR})
        foreach(ecm_fppc_comp ${ECM_FPPC_KNOWN_COMPONENTS})
            list(FIND ecm_fppc_requestedComps "${ecm_fppc_comp}" ecm_fppc_index)
            if(NOT "${ecm_fppc_index}" STREQUAL "-1")
                list(APPEND ${ECM_FPPC_RESULT_VAR} "${ecm_fppc_comp}")
                list(REMOVE_AT ecm_fppc_requestedComps ${ecm_fppc_index})
            endif()
        endforeach()
        # if there are any left, they are unknown components
        if(ecm_fppc_requestedComps)
            set(ecm_fppc_msgType STATUS)
            if(${module_name}_FIND_REQUIRED)
                set(ecm_fppc_msgType FATAL_ERROR)
            endif()
            if(NOT ${module_name}_FIND_QUIETLY)
                message(${ecm_fppc_msgType} "${module_name}: requested unknown components ${ecm_fppc_requestedComps}")
            endif()
            return()
        endif()
    else()
        set(${ECM_FPPC_RESULT_VAR} ${ECM_FPPC_DEFAULT_COMPONENTS})
    endif()
endmacro()

macro(ecm_find_package_handle_library_components module_name)
    set(ecm_fpwc_options SKIP_PKG_CONFIG SKIP_DEPENDENCY_HANDLING)
    set(ecm_fpwc_oneValueArgs)
    set(ecm_fpwc_multiValueArgs COMPONENTS)
    cmake_parse_arguments(ECM_FPWC "${ecm_fpwc_options}" "${ecm_fpwc_oneValueArgs}" "${ecm_fpwc_multiValueArgs}" ${ARGN})

    if(ECM_FPWC_UNPARSED_ARGUMENTS)
        message(FATAL_ERROR "Unexpected arguments to ecm_find_package_handle_components: ${ECM_FPWC_UNPARSED_ARGUMENTS}")
    endif()
    if(NOT ECM_FPWC_COMPONENTS)
        message(FATAL_ERROR "Missing COMPONENTS argument to ecm_find_package_handle_components")
    endif()

    include(FindPackageHandleStandardArgs)
    find_package(PkgConfig QUIET)
    foreach(ecm_fpwc_comp ${ECM_FPWC_COMPONENTS})
        set(ecm_fpwc_dep_vars)
        set(ecm_fpwc_dep_targets)
        if(NOT SKIP_DEPENDENCY_HANDLING)
            foreach(ecm_fpwc_dep ${${module_name}_${ecm_fpwc_comp}_component_deps})
                list(APPEND ecm_fpwc_dep_vars "${module_name}_${ecm_fpwc_dep}_FOUND")
                list(APPEND ecm_fpwc_dep_targets "${module_name}::${ecm_fpwc_dep}")
            endforeach()
        endif()

        if(NOT ECM_FPWC_SKIP_PKG_CONFIG AND ${module_name}_${ecm_fpwc_comp}_pkg_config)
            pkg_check_modules(PKG_${module_name}_${ecm_fpwc_comp} QUIET
                              ${${module_name}_${ecm_fpwc_comp}_pkg_config})
        endif()

        find_path(${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR
            NAMES ${${module_name}_${ecm_fpwc_comp}_header}
            HINTS ${PKG_${module_name}_${ecm_fpwc_comp}_INCLUDE_DIRS}
            PATH_SUFFIXES ${${module_name}_${ecm_fpwc_comp}_header_subdir}
        )
        find_library(${module_name}_${ecm_fpwc_comp}_LIBRARY
            NAMES ${${module_name}_${ecm_fpwc_comp}_lib}
            HINTS ${PKG_${module_name}_${ecm_fpwc_comp}_LIBRARY_DIRS}
        )

        set(${module_name}_${ecm_fpwc_comp}_VERSION "${PKG_${module_name}_${ecm_fpwc_comp}_VERSION}")
        if(NOT ${module_name}_VERSION)
            set(${module_name}_VERSION ${${module_name}_${ecm_fpwc_comp}_VERSION})
        endif()

        set(FPHSA_NAME_MISMATCHED 1)
        find_package_handle_standard_args(${module_name}_${ecm_fpwc_comp}
            FOUND_VAR
                ${module_name}_${ecm_fpwc_comp}_FOUND
            REQUIRED_VARS
                ${module_name}_${ecm_fpwc_comp}_LIBRARY
                ${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR
                ${ecm_fpwc_dep_vars}
            VERSION_VAR
                ${module_name}_${ecm_fpwc_comp}_VERSION
            )
        unset(FPHSA_NAME_MISMATCHED)

        mark_as_advanced(
            ${module_name}_${ecm_fpwc_comp}_LIBRARY
            ${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR
        )

        if(${module_name}_${ecm_fpwc_comp}_FOUND)
            list(APPEND ${module_name}_LIBRARIES
                        "${${module_name}_${ecm_fpwc_comp}_LIBRARY}")
            list(APPEND ${module_name}_INCLUDE_DIRS
                        "${${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR}")
            set(${module_name}_DEFINITIONS
                    ${${module_name}_DEFINITIONS}
                    ${PKG_${module_name}_${ecm_fpwc_comp}_DEFINITIONS})
            if(NOT TARGET ${module_name}::${ecm_fpwc_comp})
                add_library(${module_name}::${ecm_fpwc_comp} UNKNOWN IMPORTED)
                set_target_properties(${module_name}::${ecm_fpwc_comp} PROPERTIES
                    IMPORTED_LOCATION "${${module_name}_${ecm_fpwc_comp}_LIBRARY}"
                    INTERFACE_COMPILE_OPTIONS "${PKG_${module_name}_${ecm_fpwc_comp}_DEFINITIONS}"
                    INTERFACE_INCLUDE_DIRECTORIES "${${module_name}_${ecm_fpwc_comp}_INCLUDE_DIR}"
                    INTERFACE_LINK_LIBRARIES "${ecm_fpwc_dep_targets}"
                )
            endif()
            list(APPEND ${module_name}_TARGETS
                        "${module_name}::${ecm_fpwc_comp}")
        endif()
    endforeach()
    if(${module_name}_LIBRARIES)
        list(REMOVE_DUPLICATES ${module_name}_LIBRARIES)
    endif()
    if(${module_name}_INCLUDE_DIRS)
        list(REMOVE_DUPLICATES ${module_name}_INCLUDE_DIRS)
    endif()
    if(${module_name}_DEFINITIONS)
        list(REMOVE_DUPLICATES ${module_name}_DEFINITIONS)
    endif()
    if(${module_name}_TARGETS)
        list(REMOVE_DUPLICATES ${module_name}_TARGETS)
    endif()
endmacro()
# SPDX-FileCopyrightText: 2015 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
# SPDX-FileCopyrightText: 2023 Alexander Lohnau <alexander.lohnau@gmx.de>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
ECMFindQmlModule
----------------

Find QML import modules through a ``find_qmlmodule()`` call.
It looks for the qmldir and uses the qmlplugindump if needed application to find the plugins and sets them up as
runtime dependencies.
This is useful so that when we configure a project we are notified when some
QML imports are not present in the system.

::

  ecm_find_qmlmodule(<module_name>
    <version> # Optional for Qt6 builds
    [REQUIRED] # Since 6.0
  )

Usage example:

.. code-block:: cmake

  ecm_find_qmlmodule(org.kde.kirigami 2.1)
  ecm_find_qmlmodule(org.kde.kirigami 2.1 REQUIRED) # CMake will fail if the required version is not found
  ecm_find_qmlmodule(org.kde.kirigami) # Find it without a given version
  ecm_find_qmlmodule(org.kde.kirigami REQUIRED) # CMake will fail if it is not found

Since 5.38.0.
#]=======================================================================]

set(MODULES_DIR ${CMAKE_CURRENT_LIST_DIR})

function(ecm_find_qmlmodule MODULE_NAME)
    if (QT_MAJOR_VERSION STREQUAL 6)
      cmake_parse_arguments(ARG REQUIRED "" "" ${ARGN})
        if (ARG_UNPARSED_ARGUMENTS)
          list(GET ARG_UNPARSED_ARGUMENTS 0 VERSION) # If we have any unparsed args, that should be the version
        endif()
        set(ARGN "") # The find_package call below should not recieve arguments in KF6
    else()
        list(GET ARGN 0 VERSION)
        list(REMOVE_AT ARGN 0)
    endif()

    set(GENMODULE "${MODULE_NAME}-QMLModule")
    configure_file("${MODULES_DIR}/ECMFindQmlModule.cmake.in" "Find${GENMODULE}.cmake" @ONLY)
    set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_BINARY_DIR}" ${CMAKE_MODULE_PATH})
    find_package(${GENMODULE} ${ARGN})

    if(COMMAND set_package_properties)
      if (ARG_REQUIRED)
        set(TYPE_STRING TYPE REQUIRED)
      else()
        set(TYPE_STRING TYPE RUNTIME)
      endif()
        set_package_properties(${GENMODULE} PROPERTIES
            DESCRIPTION "QML module '${MODULE_NAME}' is a runtime dependency."
            ${TYPE_STRING})
    endif()
endfunction()
#=============================================================================
# SPDX-FileCopyrightText: 2015 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
# SPDX-FileCopyrightText: 2023 Alexander Lohnau <alexander.lohnau@gmx.de>
#
# SPDX-License-Identifier: BSD-3-Clause
#=============================================================================

include(FindPackageHandleStandardArgs)
include("${ECM_MODULE_DIR}/QtVersionOption.cmake")
include("${ECM_MODULE_DIR}/ECMQueryQt.cmake")

if (QT_MAJOR_VERSION EQUAL "6")
    include(${ECM_MODULE_DIR}/ECMQmlModule.cmake)
    # Get the qmldir file
    _ecm_qmlmodule_uri_to_path(MODULEDIR "@MODULE_NAME@" "@VERSION@")
    set(KDE_QMLDIR "${KDE_INSTALL_FULL_QMLDIR}/${MODULEDIR}")
    find_file(QMLDIR_FILE qmldir ${KDE_QMLDIR} NO_CACHE)
    if (NOT QMLDIR_FILE) # Check the install destination, the QT_PLUGIN_PATH might not be set up correctly at this point
        # Check the Qt installation
        ecm_query_qt(qt_qml_dir QT_INSTALL_QML)
        set(QMLDIR_FILE "${qt_qml_dir}/${MODULEDIR}/qmldir")
        if (NOT EXISTS "${QMLDIR_FILE}")
            message(WARNING "qmldir not found in ${KDE_QMLDIR} or ${QMLDIR_FILE}")
            set(MODULE_NOTFOUND TRUE)
        endif()
    endif()

    if (NOT MODULE_NOTFOUND AND NOT "@VERSION@" STREQUAL "") # Check if we even need to check the version
        find_file(VERSION_FILE kde-qmlmodule.version ${KDE_QMLDIR} NO_CACHE)
        if (VERSION_FILE)
            file(READ "${VERSION_FILE}" FILE_CONTENTS)
            if ("${FILE_CONTENTS}" MATCHES "([0-9]+(\\.[0-9]+)*)")
                if ("${CMAKE_MATCH_1}" VERSION_GREATER_EQUAL "@VERSION@")
                    set(@GENMODULE@_FOUND TRUE)
                endif()
                set(@GENMODULE@_VERSION "${CMAKE_MATCH_1}")
            endif()
        else()
            file(READ "${QMLDIR_FILE}" FILE_CONTENTS)
            if ("${FILE_CONTENTS}" MATCHES "# KDE-qmldir-Version: ([0-9]+(\\.[0-9]+)*)")
                if ("${CMAKE_MATCH_1}" VERSION_GREATER_EQUAL "@VERSION@")
                    set(@GENMODULE@_FOUND TRUE)
                endif()
                set(@GENMODULE@_VERSION "${CMAKE_MATCH_1}")
            endif()
        endif()
    elseif(NOT MODULE_NOTFOUND) # if we don't have a specific version and the qmldir file was found, we are all set
        set(@GENMODULE@_FOUND TRUE)
    endif()
endif()

# If we haven't checked the version above, use qmlplugindump
if (NOT CMAKE_CROSSCOMPILING AND NOT MODULE_NOTFOUND AND NOT @GENMODULE@_FOUND AND (NOT DEFINED QT6_IS_SHARED_LIBS_BUILD OR QT6_IS_SHARED_LIBS_BUILD))
    if (QT_MAJOR_VERSION EQUAL "6")
        find_package(Qt6 COMPONENTS QmlTools REQUIRED)
        get_target_property(QMLPLUGINDUMP_PROGRAM Qt6::qmlplugindump LOCATION)
    else()
        ecm_query_qt(qt_binaries_dir QT_HOST_BINS)
        find_program(QMLPLUGINDUMP_PROGRAM NAMES qmlplugindump HINTS ${qt_binaries_dir})
    endif()

    set(ENV{QML2_IMPORT_PATH} ${KDE_INSTALL_FULL_QMLDIR})
    execute_process(COMMAND "${QMLPLUGINDUMP_PROGRAM}" "@MODULE_NAME@" "@VERSION@" ERROR_VARIABLE ERRORS_OUTPUT OUTPUT_VARIABLE DISREGARD_VARIABLE RESULT_VARIABLE ExitCode TIMEOUT 30)
    if(ExitCode EQUAL 0)
        set(@GENMODULE@_FOUND TRUE)
    else()
        message(STATUS "qmlplugindump failed for @MODULE_NAME@.")
        set(@GENMODULE@_FOUND FALSE)
    endif()
endif()

set(@GENMODULE@_FOUND ${@GENMODULE@_FOUND} PARENT_SCOPE)
set(@GENMODULE@_VERSION ${@GENMODULE@_VERSION} PARENT_SCOPE)
find_package_handle_standard_args(@GENMODULE@
    VERSION_VAR @GENMODULE@_VERSION
    REQUIRED_VARS @GENMODULE@_FOUND
    HANDLE_COMPONENTS
)
# SPDX-FileCopyrightText: 2020 Kai Uwe Broulik <kde@broulik.de>
# SPDX-FileCopyrightText: 2020 Henri Chain <henri.chain@enioka.com>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
ECMGenerateDBusServiceFile
---------------------------

This module provides the ``ecm_generate_dbus_service_file`` function for
generating and installing a D-Bus service file.

::

  ecm_generate_dbus_service_file(
      NAME <service name>
      EXECUTABLE <executable>
      [SYSTEMD_SERVICE <systemd service>]
      DESTINATION <install_path>
      [RENAME <dbus service filename>] # Since 5.75
  )

A D-Bus service file ``<service name>.service`` will be generated and installed
in the relevant D-Bus config location. This filename can be customized with RENAME.

``<executable>`` must be an absolute path to the installed service executable. When using it with
:kde-module:`KDEInstallDirs` it needs to be the ``_FULL_`` variant of the path variable.

.. note::
  On Windows, the macro will only use the file name part of ``<executable>`` since D-Bus
  service executables are to be installed in the same directory as the D-Bus daemon.

Optionally, a ``<systemd service>`` can be specified to launch the corresponding
systemd service instead of the ``<executable>`` if the D-Bus daemon is started by systemd.

Example usage:

.. code-block:: cmake

  ecm_generate_dbus_service_file(
      NAME org.kde.kded5
      EXECUTABLE ${KDE_INSTALL_FULL_BINDIR}/kded5
      DESTINATION ${KDE_INSTALL_DBUSSERVICEDIR}
  )

.. code-block:: cmake

  ecm_generate_dbus_service_file(
      NAME org.kde.kded5
      EXECUTABLE ${KDE_INSTALL_FULL_BINDIR}/kded5
      SYSTEMD_SERVICE plasma-kded.service
      DESTINATION ${KDE_INSTALL_DBUSSERVICEDIR}
      RENAME org.kde.daemon.service
  )

Since 5.73.0.
#]=======================================================================]

function(ecm_generate_dbus_service_file)
    set(options)
    set(oneValueArgs EXECUTABLE NAME SYSTEMD_SERVICE DESTINATION RENAME)
    set(multiValueArgs)
    cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

    if(ARG_UNPARSED_ARGUMENTS)
        message(FATAL_ERROR "Unexpected arguments to ecm_generate_dbus_service_file: ${ARG_UNPARSED_ARGUMENTS}")
    endif()
    if(NOT ARG_NAME)
        message(FATAL_ERROR "Missing NAME argument for ecm_generate_dbus_service_file")
    endif()
    if(NOT ARG_EXECUTABLE)
        message(FATAL_ERROR "Missing EXECUTABLE argument for ecm_generate_dbus_service_file")
    endif()
    if(NOT ARG_DESTINATION)
        message(FATAL_ERROR "Missing DESTINATION argument for ecm_generate_dbus_service_file")
    endif()

    if(WIN32)
        get_filename_component(_exec "${ARG_EXECUTABLE}" NAME)
    else()
        if (NOT IS_ABSOLUTE ${ARG_EXECUTABLE})
            message(FATAL_ERROR "EXECUTABLE must be an absolute path in ecm_generate_dbus_service_file")
        else()
            set(_exec ${ARG_EXECUTABLE})
        endif()
    endif()

    set(_service_file ${CMAKE_CURRENT_BINARY_DIR}/${ARG_NAME}.service)

    file(WRITE ${_service_file}
    "[D-BUS Service]
Name=${ARG_NAME}
Exec=${_exec}
")

    if (ARG_SYSTEMD_SERVICE)
        file(APPEND ${_service_file} "SystemdService=${ARG_SYSTEMD_SERVICE}\n")
    endif()

    if (ARG_RENAME)
        install(FILES ${_service_file} DESTINATION ${ARG_DESTINATION} RENAME ${ARG_RENAME})
    else()
        install(FILES ${_service_file} DESTINATION ${ARG_DESTINATION})
    endif()
endfunction()
# SPDX-FileCopyrightText: 2019 Friedrich W. H. Kossebau <kossebau@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
ECMGenerateExportHeader
-----------------------

This module provides the ``ecm_generate_export_header`` function for
generating export macros for libraries with version-based control over
visibility of and compiler warnings for deprecated API for the library user,
as well as over excluding deprecated API and their implementation when
building the library itself.

For preparing some values useful in the context it also provides a function
``ecm_export_header_format_version``.

::

  ecm_generate_export_header(<library_target_name>
      VERSION <version>
      [BASE_NAME <base_name>]
      [GROUP_BASE_NAME <group_base_name>]
      [EXPORT_MACRO_NAME <export_macro_name>]
      [EXPORT_FILE_NAME <export_file_name>]
      [DEPRECATED_MACRO_NAME <deprecated_macro_name>]
      [NO_EXPORT_MACRO_NAME <no_export_macro_name>]
      [INCLUDE_GUARD_NAME <include_guard_name>]
      [STATIC_DEFINE <static_define>]
      [PREFIX_NAME <prefix_name>]
      [DEPRECATED_BASE_VERSION <deprecated_base_version>]
      [DEPRECATION_VERSIONS <deprecation_version> [<deprecation_version2> [...]]]
      [EXCLUDE_DEPRECATED_BEFORE_AND_AT <exclude_deprecated_before_and_at_version>]
      [NO_BUILD_SET_DEPRECATED_WARNINGS_SINCE]
      [NO_DEFINITION_EXPORT_TO_BUILD_INTERFACE]
      [USE_VERSION_HEADER [<version_file_name>]] #  Since 5.106
      [VERSION_BASE_NAME <version_base_name>] #  Since 5.106
      [VERSION_MACRO_NAME <version_macro_name>] #  Since 5.106
      [CUSTOM_CONTENT_FROM_VARIABLE <variable>]
  )

``VERSION`` specifies the version of the library, given in the format
"<major>.<minor>.<patchlevel>".

``GROUP_BASE_NAME`` specifies the name to use for the macros defining
library group default values. If set, this will generate code supporting
``<group_base_name>_NO_DEPRECATED_WARNINGS``,
``<group_base_name>_DISABLE_DEPRECATED_BEFORE_AND_AT``,
``<group_base_name>_DEPRECATED_WARNINGS_SINCE``  and
``<group_base_name>_NO_DEPRECATED`` (see below).
If not set, the generated code will ignore any such macros.

``DEPRECATED_BASE_VERSION`` specifies the default version before and at which
deprecated API is disabled. Possible values are "0", "CURRENT" (which
resolves to <version>) and a version string in the format
"<major>.<minor>.<patchlevel>". The default is the value of
"<exclude_deprecated_before_and_at_version>" if set, or "<major>.0.0", with
<major> taken from <version>.

``DEPRECATION_VERSIONS`` specifies versions in "<major>.<minor>" format in
which API was declared deprecated. Any version used with the generated
macro ``<prefix_name><base_name>_DEPRECATED_VERSION(major, minor, text)``
or ``<prefix_name><base_name>_DEPRECATED_VERSION_BELATED(major, minor, textmajor, textminor, text)``
needs to be listed here, otherwise the macro will fail to work.

``EXCLUDE_DEPRECATED_BEFORE_AND_AT`` specifies the version for which all API
deprecated before and at should be excluded from the build completely.
Possible values are "0" (default), "CURRENT" (which resolves to <version>)
and a version string in the format "<major>.<minor>.<patchlevel>".

``NO_BUILD_SET_DEPRECATED_WARNINGS_SINCE`` specifies that the definition
``<prefix_name><uppercase_base_name>_DEPRECATED_WARNINGS_SINCE`` will
not be set for the library inside its own build, and thus will be defined
by either explicit definition in the build system configuration or by the
default value mechanism (see below).
The default is that it is set for the build, to the version specified by
``EXCLUDE_DEPRECATED_BEFORE_AND_AT``, so no deprecation warnings are
done for any own deprecated API used in the library implementation itself.

``NO_DEFINITION_EXPORT_TO_BUILD_INTERFACE`` specifies that the definition
``<prefix_name><uppercase_base_name>_DISABLE_DEPRECATED_BEFORE_AND_AT`` will
not be set in the public interface of the library inside its own build, and
the same for the definition
``<prefix_name><uppercase_base_name>_DEPRECATED_WARNINGS_SINCE`` (if not
disabled by ``NO_BUILD_SET_DEPRECATED_WARNINGS_SINCE`` already).
The default is that they are set, to the version specified by
``EXCLUDE_DEPRECATED_BEFORE_AND_AT``, so e.g. test and examples part of the
project automatically build against the full API included in the build and
without any deprecation warnings for it.

``USE_VERSION_HEADER`` defines whether a given header file
``<version_file_name>`` providing macros specifying the library version should
be included in the generated header file. By default angle-brackets are used
for the include statement. To generate includes with double quotes, add
double quotes to the argument string (needs escaping), e.g. ``\"version.h\"``.
The macro from the included version header holding the library version is
given as ``<version_macro_name>`` by the argument ``VERSION_MACRO_NAME`` and
used in the generated code for calculating defaults. If not specified, the
defaults for the version file name and the version macro are derived from
``<version_base_name>`` as passed with ``VERSION_BASE_NAME``, which again
defaults to ``<base_name>`` or otherwise ``<library_target_name>``.
The macro name defaults to ``<uppercase_version_base_name>_VERSION``,
the version file name to ``<lowercase_version_base_name>_version.h``.
Since 5.106.

``CUSTOM_CONTENT_FROM_VARIABLE`` specifies the name of a variable whose
content will be appended at the end of the generated file, before any
final inclusion guard closing. Note that before 5.98 this was broken and
would only append the string passed as argument value.

The function ``ecm_generate_export_header`` defines C++ preprocessor macros
in the generated export header, some for use in the sources of the library
the header is generated for, other for use by projects linking agsinst the
library.

The macros for use in the library C++ sources are these, next to those also
defined by `GenerateExportHeader
<https://cmake.org/cmake/help/latest/module/GenerateExportHeader.html>`_:

``<prefix_name><uppercase_base_name>_DEPRECATED_VERSION(major, minor, text)``
  to use to conditionally set a
  ``<prefix_name><uppercase_base_name>_DEPRECATED`` macro for a class, struct
  or function (other elements to be supported in future versions), depending
  on the visibility macro flags set (see below)

``<prefix_name><uppercase_base_name>_DEPRECATED_VERSION_BELATED(major, minor, textmajor, textminor, text)``
  to use to conditionally set a
  ``<prefix_name><uppercase_base_name>_DEPRECATED`` macro for a class, struct
  or function (other elements to be supported in future versions), depending
  on the visibility macro flags set (see below), with ``major`` & ``minor``
  applied for the logic and ``textmajor`` & ``textminor`` for the warnings message.
  Useful for retroactive tagging of API for the compiler without injecting the
  API into the compiler warning conditions of already released versions.
  Since 5.71.

``<prefix_name><uppercase_base_name>_ENUMERATOR_DEPRECATED_VERSION(major, minor, text)``
  to use to conditionally set a
  ``<prefix_name><uppercase_base_name>_DEPRECATED`` macro for an enumerator, depending
  on the warnings macro flags set (see below). In builds using C++14 standard or earlier,
  where enumerator attributes are not yet supported, the macro will always yield an empty string.
  With MSVC it is also always an empty string for now.
  Since 5.82.

``<prefix_name><uppercase_base_name>_ENUMERATOR_DEPRECATED_VERSION_BELATED(major, minor, textmajor, textminor, text)``
  to use to conditionally set a
  ``<prefix_name><uppercase_base_name>_DEPRECATED`` macro for an enumerator, depending
  on the warnings macro flags set (see below), with ``major`` & ``minor``
  applied for the logic and ``textmajor`` & ``textminor`` for the warnings message.
  In builds using C++14 standard or earlier, where enumerator attributes are not yet supported,
  the macro will always yield an empty string.
  Useful for retroactive tagging of API for the compiler without injecting the
  API into the compiler warning conditions of already released versions.
  With MSVC it is also always an empty string for now.
  Since 5.82.

``<prefix_name><uppercase_base_name>_ENABLE_DEPRECATED_SINCE(major, minor)``
  evaluates to ``TRUE`` or ``FALSE`` depending on the visibility macro flags
  set (see below). To be used mainly with ``#if``/``#endif`` to mark sections
  of code which should be included depending on the visibility requested.

``<prefix_name><uppercase_base_name>_BUILD_DEPRECATED_SINCE(major, minor)``
  evaluates to ``TRUE`` or ``FALSE`` depending on the value of
  ``EXCLUDE_DEPRECATED_BEFORE_AND_AT``. To be used mainly with
  ``#if``/``#endif`` to mark sections of two types of code: implementation
  code for deprecated API and declaration code of deprecated API which only
  may be disabled at build time of the library for BC reasons (e.g. virtual
  methods, see notes below).

``<prefix_name><uppercase_base_name>_EXCLUDE_DEPRECATED_BEFORE_AND_AT``
  holds the version used to exclude deprecated API at build time of the
  library.

The macros used to control visibility when building against the library are:

``<prefix_name><uppercase_base_name>_DISABLE_DEPRECATED_BEFORE_AND_AT``
  definition to set to a value in single hex number version notation
  (``0x<major><minor><patchlevel>``).

``<prefix_name><uppercase_base_name>_NO_DEPRECATED``
  flag to define to disable all deprecated API, being a shortcut for
  settings ``<prefix_name><uppercase_base_name>_DISABLE_DEPRECATED_BEFORE_AND_AT``
  to the current version. If both are set, this flag overrules.

``<prefix_name><uppercase_base_name>_DEPRECATED_WARNINGS_SINCE``
  definition to set to a value in single hex number version notation
  (``0x<major><minor><patchlevel>``). Warnings will be only activated for
  API deprecated up to and including the version. If
  ``<prefix_name><uppercase_base_name>_DISABLE_DEPRECATED_BEFORE_AND_AT``
  is set (directly or via the group default), it will default to that
  version, resulting in no warnings. Otherwise the default is the current
  version, resulting in warnings for all deprecated API.

``<prefix_name><uppercase_base_name>_NO_DEPRECATED_WARNINGS``
  flag to define to disable all deprecation warnings, being a shortcut for
  setting ``<prefix_name><uppercase_base_name>_DEPRECATED_WARNINGS_SINCE``
  to "0". If both are set, this flag overrules.

When the ``GROUP_BASE_NAME`` has been used, the same macros but with the
given ``<group_base_name>`` prefix are available to define the defaults of
these macros, if not explicitly set.

.. warning::
  The tricks applied here for hiding deprecated API to the compiler
  when building against a library do not work for all deprecated API:

  * virtual methods need to stay visible to the compiler to build proper
    virtual method tables for subclasses
  * enumerators from enums cannot be simply removed, as this changes
    auto values of following enumerators, also can poke holes in enumerator
    series used as index into tables

  In such cases the API can be only "hidden" at build time of the library,
  itself, by generated hard coded macro settings, using
  ``<prefix_name><uppercase_base_name>_BUILD_DEPRECATED_SINCE(major, minor)``.

Examples:

Preparing a library "Foo" created by target "foo", which is part of a group
of libraries "Bar", where some API of "Foo" got deprecated at versions
5.0 & 5.12:

.. code-block:: cmake

  ecm_generate_export_header(foo
      GROUP_BASE_NAME BAR
      VERSION ${FOO_VERSION}
      DEPRECATION_VERSIONS 5.0 5.12
  )

In the library "Foo" sources in the headers the API would be prepared like
this, using the generated macros ``FOO_ENABLE_DEPRECATED_SINCE`` and
``FOO_DEPRECATED_VERSION``:

.. code-block:: cpp

  #include <foo_export.h>

  #if FOO_ENABLE_DEPRECATED_SINCE(5, 0)
  /**
    * @deprecated Since 5.0
    */
  FOO_EXPORT
  FOO_DEPRECATED_VERSION(5, 0, "Use doFoo2()")
  void doFoo();
  #endif

  #if FOO_ENABLE_DEPRECATED_SINCE(5, 12)
  /**
    * @deprecated Since 5.12
    */
  FOO_EXPORT
  FOO_DEPRECATED_VERSION(5, 12, "Use doBar2()")
  void doBar();
  #endif

Projects linking against the "Foo" library can control which part of its
deprecated API should be hidden to the compiler by adding a definition
using the ``FOO_DISABLE_DEPRECATED_BEFORE_AND_AT`` macro variable set to the
desired value (in version hex number notation):

.. code-block:: cmake

  add_definitions(-DFOO_DISABLE_DEPRECATED_BEFORE_AND_AT=0x050000)

Or using the macro variable of the group:

.. code-block:: cmake

  add_definitions(-DBAR_DISABLE_DEPRECATED_BEFORE_AND_AT=0x050000)

If both are specified, ``FOO_DISABLE_DEPRECATED_BEFORE_AND_AT`` will take
precedence.

To build a variant of a library with some deprecated API completely left
out from the build, not only optionally invisible to consumers, one uses the
``EXCLUDE_DEPRECATED_BEFORE_AND_AT`` parameter. This is best combined with a
cached CMake variable.

.. code-block:: cmake

  set(EXCLUDE_DEPRECATED_BEFORE_AND_AT 0 CACHE STRING "Control the range of deprecated API excluded from the build [default=0].")

  ecm_generate_export_header(foo
      VERSION ${FOO_VERSION}
      EXCLUDE_DEPRECATED_BEFORE_AND_AT ${EXCLUDE_DEPRECATED_BEFORE_AND_AT}
      DEPRECATION_VERSIONS 5.0 5.12
  )

The macros used in the headers for library consumers are reused for
disabling the API excluded in the build of the library. For disabling the
implementation of that API as well as for disabling deprecated API which
only can be disabled at build time of the library for BC reasons, one
uses the generated macro ``FOO_BUILD_DEPRECATED_SINCE``, like this:

.. code-block:: cpp

  #include <foo_export.h>

  enum Bars {
      One,
  #if FOO_BUILD_DEPRECATED_SINCE(5, 0)
      Two FOO_ENUMERATOR_DEPRECATED_VERSION(5, 0, "Use Three"), // macro available since 5.82
  #endif
      Three,
  };

  #if FOO_ENABLE_DEPRECATED_SINCE(5, 0)
  /**
    * @deprecated Since 5.0
    */
  FOO_EXPORT
  FOO_DEPRECATED_VERSION(5, 0, "Use doFoo2()")
  void doFoo();
  #endif

  #if FOO_ENABLE_DEPRECATED_SINCE(5, 12)
  /**
    * @deprecated Since 5.12
    */
  FOO_EXPORT
  FOO_DEPRECATED_VERSION(5, 12, "Use doBar2()")
  void doBar();
  #endif

  class FOO_EXPORT Foo {
  public:
  #if FOO_BUILD_DEPRECATED_SINCE(5, 0)
      /**
        * @deprecated Since 5.0
        */
      FOO_DEPRECATED_VERSION(5, 0, "Feature removed")
      virtual void doWhat();
  #endif
  };

.. code-block:: cpp

  #if FOO_BUILD_DEPRECATED_SINCE(5, 0)
  void doFoo()
  {
      // [...]
  }
  #endif

  #if FOO_BUILD_DEPRECATED_SINCE(5, 12)
  void doBar()
  {
      // [...]
  }
  #endif

  #if FOO_BUILD_DEPRECATED_SINCE(5, 0)
  void Foo::doWhat()
  {
      // [...]
  }
  #endif

So e.g. if ``EXCLUDE_DEPRECATED_BEFORE_AND_AT`` is set to "5.0.0", the
enumerator ``Two`` as well as the methods ``::doFoo()`` and ``Foo::doWhat()``
will be not available to library consumers. The methods will not have been
compiled into the library binary, and the declarations will be hidden to the
compiler, ``FOO_DISABLE_DEPRECATED_BEFORE_AND_AT`` also cannot be used to
reactivate them.

When using the ``NO_DEFINITION_EXPORT_TO_BUILD_INTERFACE`` and the project
for the "Foo" library includes also tests and examples linking against the
library and using deprecated API (like tests covering it), one better
explicitly sets ``FOO_DISABLE_DEPRECATED_BEFORE_AND_AT`` for those targets
to the version before and at which all deprecated API has been excluded from
the build.
Even more when building against other libraries from the same group "Bar" and
disabling some deprecated API of those libraries using the group macro
``BAR_DISABLE_DEPRECATED_BEFORE_AND_AT``, which also works as default for
``FOO_DISABLE_DEPRECATED_BEFORE_AND_AT``.

To get the hex number style value the helper macro
``ecm_export_header_format_version()`` will be used:

.. code-block:: cmake

  set(EXCLUDE_DEPRECATED_BEFORE_AND_AT 0 CACHE STRING "Control what part of deprecated API is excluded from build [default=0].")

  ecm_generate_export_header(foo
      VERSION ${FOO_VERSION}
      GROUP_BASE_NAME BAR
      EXCLUDE_DEPRECATED_BEFORE_AND_AT ${EXCLUDE_DEPRECATED_BEFORE_AND_AT}
      NO_DEFINITION_EXPORT_TO_BUILD_INTERFACE
      DEPRECATION_VERSIONS 5.0 5.12
  )

  ecm_export_header_format_version(${EXCLUDE_DEPRECATED_BEFORE_AND_AT}
      CURRENT_VERSION ${FOO_VERSION}
      HEXNUMBER_VAR foo_no_deprecated_before_and_at
  )

  # disable all deprecated API up to 5.9.0 from all other libs of group "BAR" that we use ourselves
  add_definitions(-DBAR_DISABLE_DEPRECATED_BEFORE_AND_AT=0x050900)

  add_executable(app app.cpp)
  target_link_libraries(app foo)
  target_compile_definitions(app
       PRIVATE "FOO_DISABLE_DEPRECATED_BEFORE_AND_AT=${foo_no_deprecated_before_and_at}")

Since 5.64.0.
#]=======================================================================]

include(GenerateExportHeader)

cmake_policy(PUSH)
cmake_policy(SET CMP0057 NEW) # if IN_LIST

# helper method
function(_ecm_geh_generate_hex_number _var_name _version)
    set(_hexnumber 0)

    set(version_regex "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$")
    string(REGEX REPLACE ${version_regex} "\\1" _version_major "${_version}")
    string(REGEX REPLACE ${version_regex} "\\2" _version_minor "${_version}")
    string(REGEX REPLACE ${version_regex} "\\3" _version_patch "${_version}")
    set(_outputformat)
    set(_outputformat OUTPUT_FORMAT HEXADECIMAL)
    math(EXPR _hexnumber "${_version_major}*65536 + ${_version_minor}*256 + ${_version_patch}" ${_outputformat})
    set(${_var_name} ${_hexnumber} PARENT_SCOPE)
endfunction()

function(ecm_export_header_format_version _version)
    set(options
    )
    set(oneValueArgs
        CURRENT_VERSION
        STRING_VAR
        HEXNUMBER_VAR
    )
    set(multiValueArgs
    )
    cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

    if (NOT ARGS_STRING_VAR AND NOT ARGS_HEXNUMBER_VAR)
        message(FATAL_ERROR "No STRING_VAR or HEXNUMBER_VAR passed when calling ecm_export_header_format_version().")
    endif()

    if(_version STREQUAL "CURRENT")
        if (NOT ARGS_CURRENT_VERSION )
            message(FATAL_ERROR "\"CURRENT\" as version value not supported when CURRENT_VERSION not passed on calling ecm_export_header_format_version().")
        endif()
        set(_version ${ARGS_CURRENT_VERSION})
    endif()

    if (ARGS_STRING_VAR)
        set(${ARGS_STRING_VAR} ${_version} PARENT_SCOPE)
    endif()

    if (ARGS_HEXNUMBER_VAR)
        set(_hexnumber 0) # by default build all deprecated API
        if(_version)
            _ecm_geh_generate_hex_number(_hexnumber ${_version})
        endif()
        set(${ARGS_HEXNUMBER_VAR} ${_hexnumber} PARENT_SCOPE)
    endif()
endfunction()


function(ecm_generate_export_header target)
    set(options
        NO_DEFINITION_EXPORT_TO_BUILD_INTERFACE
        NO_BUILD_SET_DEPRECATED_WARNINGS_SINCE
    )
    set(oneValueArgs
        BASE_NAME
        GROUP_BASE_NAME
        EXPORT_FILE_NAME
        DEPRECATED_BASE_VERSION
        VERSION
        VERSION_BASE_NAME
        VERSION_MACRO_NAME
        EXCLUDE_DEPRECATED_BEFORE_AND_AT
        EXPORT_MACRO_NAME
        DEPRECATED_MACRO_NAME
        NO_EXPORT_MACRO_NAME
        INCLUDE_GUARD_NAME
        STATIC_DEFINE
        PREFIX_NAME
        CUSTOM_CONTENT_FROM_VARIABLE
    )
    set(multiValueArgs
        DEPRECATION_VERSIONS
        USE_VERSION_HEADER
    )
    cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

    # helper string
    set(_version_triple_regexp "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$")
    # args sanity check
    if (NOT ARGS_VERSION)
        message(FATAL_ERROR "No VERSION passed when calling ecm_generate_export_header().")
    elseif(NOT ARGS_VERSION MATCHES ${_version_triple_regexp})
        message(FATAL_ERROR "VERSION expected to be in x.y.z format when calling ecm_generate_export_header().")
    endif()
    if (NOT ARGS_EXCLUDE_DEPRECATED_BEFORE_AND_AT)
        set(ARGS_EXCLUDE_DEPRECATED_BEFORE_AND_AT 0)
    elseif(ARGS_EXCLUDE_DEPRECATED_BEFORE_AND_AT STREQUAL "CURRENT")
        set(ARGS_EXCLUDE_DEPRECATED_BEFORE_AND_AT ${ARGS_VERSION})
    elseif(NOT ARGS_EXCLUDE_DEPRECATED_BEFORE_AND_AT MATCHES ${_version_triple_regexp} AND
           NOT ARGS_EXCLUDE_DEPRECATED_BEFORE_AND_AT STREQUAL "0")
        message(FATAL_ERROR "EXCLUDE_DEPRECATED_BEFORE_AND_AT expected to be in \"x.y.z\" format, \"0\" or \"CURRENT\" when calling ecm_generate_export_header().")
    endif()
    if (NOT DEFINED ARGS_DEPRECATED_BASE_VERSION)
        if (ARGS_EXCLUDE_DEPRECATED_BEFORE_AND_AT)
            set(ARGS_DEPRECATED_BASE_VERSION "${ARGS_EXCLUDE_DEPRECATED_BEFORE_AND_AT}")
        else()
            string(REGEX REPLACE ${_version_triple_regexp} "\\1" _version_major "${ARGS_VERSION}")
            set(ARGS_DEPRECATED_BASE_VERSION "${_version_major}.0.0")
        endif()
    else()
        if(ARGS_DEPRECATED_BASE_VERSION STREQUAL "CURRENT")
            set(ARGS_DEPRECATED_BASE_VERSION ${ARGS_VERSION})
        elseif(NOT ARGS_DEPRECATED_BASE_VERSION MATCHES ${_version_triple_regexp} AND
               NOT ARGS_DEPRECATED_BASE_VERSION STREQUAL "0")
            message(FATAL_ERROR "DEPRECATED_BASE_VERSION expected to be in \"x.y.z\" format, \"0\" or \"CURRENT\" when calling ecm_generate_export_header().")
        endif()
        if (ARGS_DEPRECATED_BASE_VERSION VERSION_LESS ARGS_EXCLUDE_DEPRECATED_BEFORE_AND_AT)
            message(STATUS "DEPRECATED_BASE_VERSION (${ARGS_DEPRECATED_BASE_VERSION}) was lower than EXCLUDE_DEPRECATED_BEFORE_AND_AT (${ARGS_EXCLUDE_DEPRECATED_BEFORE_AND_AT}) when calling ecm_generate_export_header(), raising to that.")
            set(ARGS_DEPRECATED_BASE_VERSION "${ARGS_EXCLUDE_DEPRECATED_BEFORE_AND_AT}")
        endif()
    endif()
    if(NOT ARGS_BASE_NAME)
        set(ARGS_BASE_NAME "${target}")
    endif()
    if(NOT ARGS_VERSION_BASE_NAME)
        set(ARGS_VERSION_BASE_NAME "${ARGS_BASE_NAME}")
    endif()
    string(TOUPPER "${ARGS_BASE_NAME}" _upper_base_name)
    string(TOLOWER "${ARGS_BASE_NAME}" _lower_base_name)
    set(_version_header)
    if (USE_VERSION_HEADER IN_LIST ARGS_KEYWORDS_MISSING_VALUES)
        string(TOLOWER "${ARGS_VERSION_BASE_NAME}" _lower_version_base_name)
        set(_version_header "${_lower_version_base_name}_version.h")
    elseif (DEFINED ARGS_USE_VERSION_HEADER)
        list(LENGTH ARGS_USE_VERSION_HEADER _arg_count)
        if (_arg_count GREATER 1)
            message(FATAL_ERROR "USE_VERSION_HEADER only takes 1 or no arg when calling ecm_generate_export_header().")
        endif()
        set(_version_header ${ARGS_USE_VERSION_HEADER})
    endif()
    if(_version_header)
        if(ARGS_VERSION_MACRO_NAME)
            set(_version_hexnumber "${ARGS_VERSION_MACRO_NAME}")
        else()
            string(TOUPPER "${ARGS_VERSION_BASE_NAME}" _upper_version_base_name)
            set(_version_hexnumber "${_upper_version_base_name}_VERSION")
        endif()
    else()
        _ecm_geh_generate_hex_number(_version_hexnumber "${ARGS_VERSION}")
    endif()

    if(NOT ARGS_EXPORT_FILE_NAME)
        set(ARGS_EXPORT_FILE_NAME "${_lower_base_name}_export.h")
    endif()
    if (ARGS_DEPRECATED_BASE_VERSION STREQUAL "0")
        set(_default_disabled_deprecated_version_hexnumber "0")
    else()
        _ecm_geh_generate_hex_number(_default_disabled_deprecated_version_hexnumber "${ARGS_DEPRECATED_BASE_VERSION}")
    endif()

    set(_macro_base_name "${ARGS_PREFIX_NAME}${_upper_base_name}")
    if (ARGS_EXPORT_MACRO_NAME)
        set(_export_macro_name "${ARGS_EXPORT_MACRO_NAME}")
    else()
        set(_export_macro_name "${_macro_base_name}_EXPORT")
    endif()
    if (ARGS_NO_EXPORT_MACRO_NAME)
        set(_no_export_macro_name "${ARGS_NO_EXPORT_MACRO_NAME}")
    else()
        set(_no_export_macro_name "${_macro_base_name}_NO_EXPORT")
    endif()
    if (ARGS_DEPRECATED_MACRO_NAME)
        set(_deprecated_macro_name "${ARGS_DEPRECATED_MACRO_NAME}")
    else()
        set(_deprecated_macro_name "${_macro_base_name}_DEPRECATED")
    endif()

    if(NOT IS_ABSOLUTE ${ARGS_EXPORT_FILE_NAME})
        set(ARGS_EXPORT_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/${ARGS_EXPORT_FILE_NAME}")
    endif()

    set_property(TARGET ${target} APPEND PROPERTY AUTOGEN_TARGET_DEPENDS "${ARGS_EXPORT_FILE_NAME}")
    # build with all the API not excluded, ensure all deprecated API is visible in the build itself
    _ecm_geh_generate_hex_number(_hexnumber ${ARGS_EXCLUDE_DEPRECATED_BEFORE_AND_AT})
    set(_disabling_visibility_definition "${_macro_base_name}_DISABLE_DEPRECATED_BEFORE_AND_AT=${_hexnumber}")
    target_compile_definitions(${target} PRIVATE "${_disabling_visibility_definition}")
    if (NOT ARGS_NO_DEFINITION_EXPORT_TO_BUILD_INTERFACE)
        target_compile_definitions(${target} INTERFACE "$<BUILD_INTERFACE:${_disabling_visibility_definition}>")
    endif()
    if(NOT ARGS_NO_BUILD_SET_DEPRECATED_WARNINGS_SINCE)
        set(_enabling_warnings_definition "${_macro_base_name}_DEPRECATED_WARNINGS_SINCE=${_hexnumber}")
        target_compile_definitions(${target} PRIVATE "${_enabling_warnings_definition}")
        if (NOT ARGS_NO_DEFINITION_EXPORT_TO_BUILD_INTERFACE)
            target_compile_definitions(${target} INTERFACE "$<BUILD_INTERFACE:${_enabling_warnings_definition}>")
        endif()
    endif()

    # for the set of compiler versions supported by ECM/KF we can assume those attributes supported
    # KF6: with C++17 as minimum standard planned, switch to always use [[deprecated(text)]]
    if (CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID MATCHES "Clang")
        set(_decl_deprecated_text_definition "__attribute__ ((__deprecated__(text)))")
    elseif(MSVC)
        set(_decl_deprecated_text_definition "__declspec(deprecated(text))")
    else()
        set(_decl_deprecated_text_definition "${_macro_base_name}_DECL_DEPRECATED")
    endif()
    # generate header file
    set(_output)
    if(_version_header)
        if (_version_header MATCHES "^\".+\"$")
            string(APPEND _output "#include ${_version_header}\n")
        else()
            string(APPEND _output "#include <${_version_header}>\n")
        endif()
    endif()
    string(APPEND _output "
#define ${_macro_base_name}_DECL_DEPRECATED_TEXT(text) ${_decl_deprecated_text_definition}
"
    )
    if (ARGS_GROUP_BASE_NAME)
        string(TOUPPER "${ARGS_GROUP_BASE_NAME}" _upper_group_name)
        string(APPEND _output "
/* Take any defaults from group settings */
#if !defined(${_macro_base_name}_NO_DEPRECATED) && !defined(${_macro_base_name}_DISABLE_DEPRECATED_BEFORE_AND_AT)
#  ifdef ${_upper_group_name}_NO_DEPRECATED
#    define ${_macro_base_name}_NO_DEPRECATED
#  elif defined(${_upper_group_name}_DISABLE_DEPRECATED_BEFORE_AND_AT)
#    define ${_macro_base_name}_DISABLE_DEPRECATED_BEFORE_AND_AT ${_upper_group_name}_DISABLE_DEPRECATED_BEFORE_AND_AT
#  endif
#endif
#if !defined(${_macro_base_name}_DISABLE_DEPRECATED_BEFORE_AND_AT) && defined(${_upper_group_name}_DISABLE_DEPRECATED_BEFORE_AND_AT)
#  define ${_macro_base_name}_DISABLE_DEPRECATED_BEFORE_AND_AT ${_upper_group_name}_DISABLE_DEPRECATED_BEFORE_AND_AT
#endif

#if !defined(${_macro_base_name}_NO_DEPRECATED_WARNINGS) && !defined(${_macro_base_name}_DEPRECATED_WARNINGS_SINCE)
#  ifdef ${_upper_group_name}_NO_DEPRECATED_WARNINGS
#    define ${_macro_base_name}_NO_DEPRECATED_WARNINGS
#  elif defined(${_upper_group_name}_DEPRECATED_WARNINGS_SINCE)
#    define ${_macro_base_name}_DEPRECATED_WARNINGS_SINCE ${_upper_group_name}_DEPRECATED_WARNINGS_SINCE
#  endif
#endif
#if !defined(${_macro_base_name}_DEPRECATED_WARNINGS_SINCE) && defined(${_upper_group_name}_DEPRECATED_WARNINGS_SINCE)
#  define ${_macro_base_name}_DEPRECATED_WARNINGS_SINCE ${_upper_group_name}_DEPRECATED_WARNINGS_SINCE
#endif
"
        )
    endif()
    string(APPEND _output "
#if defined(${_macro_base_name}_NO_DEPRECATED)
#  undef ${_deprecated_macro_name}
#  define ${_deprecated_macro_name}_EXPORT ${_export_macro_name}
#  define ${_deprecated_macro_name}_NO_EXPORT ${_no_export_macro_name}
#elif defined(${_macro_base_name}_NO_DEPRECATED_WARNINGS)
#  define ${_deprecated_macro_name}
#  define ${_deprecated_macro_name}_EXPORT ${_export_macro_name}
#  define ${_deprecated_macro_name}_NO_EXPORT ${_no_export_macro_name}
#else
#  define ${_deprecated_macro_name} ${_macro_base_name}_DECL_DEPRECATED
#  define ${_deprecated_macro_name}_EXPORT ${_macro_base_name}_DECL_DEPRECATED_EXPORT
#  define ${_deprecated_macro_name}_NO_EXPORT ${_macro_base_name}_DECL_DEPRECATED_NO_EXPORT
#endif
"
    )
    if (ARGS_EXCLUDE_DEPRECATED_BEFORE_AND_AT)
        message(STATUS "Excluding from build all API deprecated before and at: ${ARGS_EXCLUDE_DEPRECATED_BEFORE_AND_AT}")
        # TODO: the generated code ideally would emit a warning if some consumer used a value
        # smaller then what the the build was done with
        _ecm_geh_generate_hex_number(_excluded_before_and_at_version_hexnumber "${ARGS_EXCLUDE_DEPRECATED_BEFORE_AND_AT}")
        string(APPEND _output "
/* Build was done with the API removed deprecated before: ${ARGS_EXCLUDE_DEPRECATED_BEFORE_AND_AT} */
#define ${_macro_base_name}_EXCLUDE_DEPRECATED_BEFORE_AND_AT ${_excluded_before_and_at_version_hexnumber}

#ifdef ${_macro_base_name}_DISABLE_DEPRECATED_BEFORE_AND_AT
#  if ${_macro_base_name}_DISABLE_DEPRECATED_BEFORE_AND_AT < ${_macro_base_name}_EXCLUDE_DEPRECATED_BEFORE_AND_AT
#    undef ${_macro_base_name}_DISABLE_DEPRECATED_BEFORE_AND_AT
#    define ${_macro_base_name}_DISABLE_DEPRECATED_BEFORE_AND_AT ${_macro_base_name}_EXCLUDE_DEPRECATED_BEFORE_AND_AT
#  endif
#endif

#define ${_macro_base_name}_BUILD_DEPRECATED_SINCE(major, minor) (((major<<16)|(minor<<8)) > ${_macro_base_name}_EXCLUDE_DEPRECATED_BEFORE_AND_AT)
"
        )
    else()
        string(APPEND _output "
/* No deprecated API had been removed from build */
#define ${_macro_base_name}_EXCLUDE_DEPRECATED_BEFORE_AND_AT 0

#define ${_macro_base_name}_BUILD_DEPRECATED_SINCE(major, minor) 1
"
        )
    endif()
    string(APPEND _output "
#ifdef ${_macro_base_name}_NO_DEPRECATED
#  define ${_macro_base_name}_DISABLE_DEPRECATED_BEFORE_AND_AT ${_version_hexnumber}
#endif
#ifdef ${_macro_base_name}_NO_DEPRECATED_WARNINGS
#  define ${_macro_base_name}_DEPRECATED_WARNINGS_SINCE 0
#endif

#ifndef ${_macro_base_name}_DEPRECATED_WARNINGS_SINCE
#  ifdef ${_macro_base_name}_DISABLE_DEPRECATED_BEFORE_AND_AT
#    define ${_macro_base_name}_DEPRECATED_WARNINGS_SINCE ${_macro_base_name}_DISABLE_DEPRECATED_BEFORE_AND_AT
#  else
#    define ${_macro_base_name}_DEPRECATED_WARNINGS_SINCE ${_version_hexnumber}
#  endif
#endif

#ifndef ${_macro_base_name}_DISABLE_DEPRECATED_BEFORE_AND_AT
#  define ${_macro_base_name}_DISABLE_DEPRECATED_BEFORE_AND_AT ${_default_disabled_deprecated_version_hexnumber}
#endif

#ifdef ${_deprecated_macro_name}
#  define ${_macro_base_name}_ENABLE_DEPRECATED_SINCE(major, minor) (((major<<16)|(minor<<8)) > ${_macro_base_name}_DISABLE_DEPRECATED_BEFORE_AND_AT)
#else
#  define ${_macro_base_name}_ENABLE_DEPRECATED_SINCE(major, minor) 0
#endif
"
    )
    if (DEFINED ARGS_DEPRECATION_VERSIONS)
        set(_major_versions)
        foreach(_version ${ARGS_DEPRECATION_VERSIONS})
            _ecm_geh_generate_hex_number(_version_hexnumber "${_version}.0")
            string(REPLACE "." "_" _underscored_version "${_version}")
            string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)$" "\\1"
 _version_major "${_version}")
            # IN_LIST only since cmake 3.3
            set(_in_list FALSE)
            foreach(_v ${_major_versions})
                if (_v STREQUAL _version_major)
                    set(_in_list TRUE)
                    break()
                endif()
            endforeach()
            if(NOT _in_list)
                list(APPEND _major_versions ${_version_major})
            endif()

            string(APPEND _output "
#if ${_macro_base_name}_DEPRECATED_WARNINGS_SINCE >= ${_version_hexnumber}
#  define ${_macro_base_name}_DEPRECATED_VERSION_${_underscored_version}(text) ${_macro_base_name}_DECL_DEPRECATED_TEXT(text)
#else
#  define ${_macro_base_name}_DEPRECATED_VERSION_${_underscored_version}(text)
#endif
"
            )
        endforeach()
        foreach(_major_version ${_major_versions})
            string(APPEND _output
"#define ${_macro_base_name}_DEPRECATED_VERSION_${_major_version}(minor, text)      ${_macro_base_name}_DEPRECATED_VERSION_${_major_version}_##minor(text)
"
            )
        endforeach()

        string(APPEND _output
"#define ${_macro_base_name}_DEPRECATED_VERSION(major, minor, text) ${_macro_base_name}_DEPRECATED_VERSION_##major(minor, \"Since \"#major\".\"#minor\". \" text)
"
        )
        string(APPEND _output
"#define ${_macro_base_name}_DEPRECATED_VERSION_BELATED(major, minor, textmajor, textminor, text) ${_macro_base_name}_DEPRECATED_VERSION_##major(minor, \"Since \"#textmajor\".\"#textminor\". \" text)
"
        )
        # reusing the existing version-controlled deprecation macros for enumerator deprecation macros
        # to avoid having to repeat all the explicit version variants
        # TODO: MSVC seems to have issues with __declspec(deprecated) being used as enumerator attribute
        # and deals only with standard [[deprecated(text)]].
        # But for now we have to keep the deprecation macros using the compiler-specific attributes,
        # because CMake's GenerateExportHeader uses the latter for the export macros and
        # at least GCC does not support both being used mixed e.g. on the same class or method.
        # Possibly needs to be solved by forking GenerateExportHeader to get complete control.
        if(NOT MSVC)
            string(APPEND _output
"#if defined(__cpp_enumerator_attributes) && __cpp_enumerator_attributes >= 201411
#  define ${_macro_base_name}_ENUMERATOR_DEPRECATED_VERSION(major, minor, text) ${_macro_base_name}_DEPRECATED_VERSION(major, minor, text)
#  define ${_macro_base_name}_ENUMERATOR_DEPRECATED_VERSION_BELATED(major, minor, textmajor, textminor, text) ${_macro_base_name}_DEPRECATED_VERSION_BELATED(major, minor, textmajor, textminor, text)
#else
#  define ${_macro_base_name}_ENUMERATOR_DEPRECATED_VERSION(major, minor, text)
#  define ${_macro_base_name}_ENUMERATOR_DEPRECATED_VERSION_BELATED(major, minor, textmajor, textminor, text)
#endif
"
            )
        else()
            string(APPEND _output
"// Not yet implemented for MSVC
#define ${_macro_base_name}_ENUMERATOR_DEPRECATED_VERSION(major, minor, text)
#define ${_macro_base_name}_ENUMERATOR_DEPRECATED_VERSION_BELATED(major, minor, textmajor, textminor, text)
"
            )
        endif()
    endif()
    if (ARGS_CUSTOM_CONTENT_FROM_VARIABLE)
        if(DEFINED "${ARGS_CUSTOM_CONTENT_FROM_VARIABLE}")
            string(APPEND _output "${${ARGS_CUSTOM_CONTENT_FROM_VARIABLE}}\n")
        else()
            message(DEPRECATION "Passing a value instead of a variable name with CUSTOM_CONTENT_FROM_VARIABLE. Since 5.98, use the name of a variable.")
            string(APPEND _output "${ARGS_CUSTOM_CONTENT_FROM_VARIABLE}\n")
        endif()
    endif()

    # prepare optional arguments to pass through to generate_export_header
    set(_include_guard_name_args)
    if (ARGS_INCLUDE_GUARD_NAME)
        set(_include_guard_name_args INCLUDE_GUARD_NAME "${ARGS_INCLUDE_GUARD_NAME}")
    endif()
    set(_export_macro_name_args)
    if (ARGS_EXPORT_MACRO_NAME)
        set(_export_macro_name_args EXPORT_MACRO_NAME "${ARGS_EXPORT_MACRO_NAME}")
    endif()
    set(_no_export_macro_name_args)
    if (ARGS_NO_EXPORT_MACRO_NAME)
        set(_no_export_macro_name_args ARGS_NO_EXPORT_MACRO_NAME "${ARGS_NO_EXPORT_MACRO_NAME}")
    endif()
    set(_prefix_name_args)
    if (ARGS_PREFIX_NAME)
        set(_prefix_name_args PREFIX_NAME "${ARGS_PREFIX_NAME}")
    endif()
    set(_static_define_args)
    if (ARGS_STATIC_DEFINE)
        set(_static_define_args STATIC_DEFINE "${ARGS_STATIC_DEFINE}")
    endif()
    generate_export_header(${target}
        BASE_NAME ${ARGS_BASE_NAME}
        DEPRECATED_MACRO_NAME "${_macro_base_name}_DECL_DEPRECATED"
        ${_prefix_name_args}
        ${_export_macro_name_args}
        ${_no_export_macro_name_args}
        ${_static_define_args}
        EXPORT_FILE_NAME "${ARGS_EXPORT_FILE_NAME}"
        ${_include_guard_name_args}
        CUSTOM_CONTENT_FROM_VARIABLE _output
    )
endfunction()

cmake_policy(POP)
# SPDX-FileCopyrightText: 2013 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
# SPDX-FileCopyrightText: 2014 Alex Merry <alex.merry@kdemail.net>
# SPDX-FileCopyrightText: 2015 Patrick Spendrin <patrick.spendrin@kdab.com>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
ECMGenerateHeaders
------------------

Generate C/C++ CamelCase forwarding headers.

::

  ecm_generate_headers(<camelcase_forwarding_headers_var>
      HEADER_NAMES <CamelCaseName> [<CamelCaseName> [...]]
      [ORIGINAL <CAMELCASE|LOWERCASE>]
      [HEADER_EXTENSION <header_extension>]
      [OUTPUT_DIR <output_dir>]
      [PREFIX <prefix>]
      [REQUIRED_HEADERS <variable>]
      [COMMON_HEADER <HeaderName>]
      [RELATIVE <relative_path>])

For each CamelCase header name passed to ``HEADER_NAMES``, a file of that name
will be generated that will include a version with ``.h`` or, if set,
``.<header_extension>`` appended.
For example, the generated header ``ClassA`` will include ``classa.h`` (or
``ClassA.h``, see ``ORIGINAL``).
If a CamelCaseName consists of multiple comma-separated files, e.g.
``ClassA,ClassB,ClassC``, then multiple camelcase header files will be
generated which are redirects to the first header file.
The file locations of these generated headers will be stored in
<camelcase_forwarding_headers_var>.

``ORIGINAL`` specifies how the name of the original header is written: lowercased
or also camelcased.  The default is "LOWERCASE". Since 1.8.0.

``HEADER_EXTENSION`` specifies what file name extension is used for the header
files.  The default is "h". Since 5.48.0.

``PREFIX`` places the generated headers in subdirectories.  This should be a
CamelCase name like ``KParts``, which will cause the CamelCase forwarding
headers to be placed in the ``KParts`` directory (e.g. ``KParts/Part``).  It
will also, for the convenience of code in the source distribution, generate
forwarding headers based on the original names (e.g. ``kparts/part.h``).  This
allows includes like ``"#include <kparts/part.h>"`` to be used before
installation, as long as the include_directories are set appropriately.

``OUTPUT_DIR`` specifies where the files will be generated; this should be within
the build directory. By default, ``${CMAKE_CURRENT_BINARY_DIR}`` will be used.
This option can be used to avoid file conflicts.

``REQUIRED_HEADERS`` specifies an output variable name where all the required
headers will be appended so that they can be installed together with the
generated ones.  This is mostly intended as a convenience so that adding a new
header to a project only requires specifying the CamelCase variant in the
CMakeLists.txt file; the original variant will then be added to this
variable.

``COMMON_HEADER`` generates an additional convenience header which includes all
other header files.

The ``RELATIVE`` argument indicates where the original headers can be found
relative to ``CMAKE_CURRENT_SOURCE_DIR``.  It does not affect the generated
CamelCase forwarding files, but ``ecm_generate_headers()`` uses it when checking
that the original header exists, and to generate originally named forwarding
headers when ``PREFIX`` is set.

To allow other parts of the source distribution (eg: tests) to use the
generated headers before installation, it may be desirable to set the
``INCLUDE_DIRECTORIES`` property for the library target to output_dir.  For
example, if ``OUTPUT_DIR`` is ``CMAKE_CURRENT_BINARY_DIR`` (the default), you could do

.. code-block:: cmake

  target_include_directories(MyLib PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>")

Example usage (without ``PREFIX``):

.. code-block:: cmake

  ecm_generate_headers(
      MyLib_FORWARDING_HEADERS
      HEADERS
          MLFoo
          MLBar
          # etc
      REQUIRED_HEADERS MyLib_HEADERS
      COMMON_HEADER MLGeneral
  )
  install(FILES ${MyLib_FORWARDING_HEADERS} ${MyLib_HEADERS}
          DESTINATION ${CMAKE_INSTALL_PREFIX}/include
          COMPONENT Devel)

Example usage (with ``PREFIX``):

.. code-block:: cmake

  ecm_generate_headers(
      MyLib_FORWARDING_HEADERS
      HEADERS
          Foo
          # several classes are contained in bar.h, so generate
          # additional files
          Bar,BarList
          # etc
      PREFIX MyLib
      REQUIRED_HEADERS MyLib_HEADERS
  )
  install(FILES ${MyLib_FORWARDING_HEADERS}
          DESTINATION ${CMAKE_INSTALL_PREFIX}/include/MyLib
          COMPONENT Devel)
  install(FILES ${MyLib_HEADERS}
          DESTINATION ${CMAKE_INSTALL_PREFIX}/include/mylib
          COMPONENT Devel)

Since pre-1.0.0.
#]=======================================================================]

function(ECM_GENERATE_HEADERS camelcase_forwarding_headers_var)
    set(options)
    set(oneValueArgs ORIGINAL HEADER_EXTENSION OUTPUT_DIR PREFIX REQUIRED_HEADERS COMMON_HEADER RELATIVE)
    set(multiValueArgs HEADER_NAMES)
    cmake_parse_arguments(EGH "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

    if (EGH_UNPARSED_ARGUMENTS)
        message(FATAL_ERROR "Unexpected arguments to ECM_GENERATE_HEADERS: ${EGH_UNPARSED_ARGUMENTS}")
    endif()

    if(NOT EGH_HEADER_NAMES)
       message(FATAL_ERROR "Missing header_names argument to ECM_GENERATE_HEADERS")
    endif()

    if(NOT EGH_ORIGINAL)
        # default
        set(EGH_ORIGINAL "LOWERCASE")
    endif()
    if(NOT EGH_ORIGINAL STREQUAL "LOWERCASE" AND NOT EGH_ORIGINAL STREQUAL "CAMELCASE")
        message(FATAL_ERROR "Unexpected value for original argument to ECM_GENERATE_HEADERS: ${EGH_ORIGINAL}")
    endif()

    if(NOT EGH_HEADER_EXTENSION)
        set(EGH_HEADER_EXTENSION "h")
    endif()

    if(NOT EGH_OUTPUT_DIR)
        set(EGH_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}")
    endif()

    # Make sure EGH_RELATIVE is /-terminated when it's not empty
    if (EGH_RELATIVE AND NOT "${EGH_RELATIVE}" MATCHES "^.*/$")
        set(EGH_RELATIVE "${EGH_RELATIVE}/")
    endif()

    set(originalprefix)
    if (EGH_PREFIX)
        if (NOT "${EGH_PREFIX}" MATCHES "^.*/$")
            set(EGH_PREFIX "${EGH_PREFIX}/")
        endif()
        if (EGH_ORIGINAL STREQUAL "CAMELCASE")
            set(originalprefix "${EGH_PREFIX}")
        else()
            string(TOLOWER "${EGH_PREFIX}" originalprefix)
        endif()
    endif()

    foreach(_classnameentry ${EGH_HEADER_NAMES})
        string(REPLACE "," ";" _classnames ${_classnameentry})
        list(GET _classnames 0 _baseclass)

        if (EGH_ORIGINAL STREQUAL "CAMELCASE")
            set(originalbasename "${_baseclass}")
        else()
            string(TOLOWER "${_baseclass}" originalbasename)
        endif()

        set(_actualheader "${CMAKE_CURRENT_SOURCE_DIR}/${EGH_RELATIVE}${originalbasename}.${EGH_HEADER_EXTENSION}")
        get_source_file_property(_generated "${_actualheader}" GENERATED)
        if (NOT _generated AND NOT EXISTS ${_actualheader})
            message(FATAL_ERROR "Could not find \"${_actualheader}\"")
        endif()

        foreach(_CLASSNAME ${_classnames})
            set(FANCY_HEADER_FILE "${EGH_OUTPUT_DIR}/${EGH_PREFIX}${_CLASSNAME}")
            if (NOT EXISTS ${FANCY_HEADER_FILE})
                file(WRITE ${FANCY_HEADER_FILE} "#include \"${originalprefix}${originalbasename}.${EGH_HEADER_EXTENSION}\" // IWYU pragma: export\n")
            endif()
            list(APPEND ${camelcase_forwarding_headers_var} "${FANCY_HEADER_FILE}")
            if (EGH_PREFIX)
                # Local forwarding header, for namespaced headers, e.g. kparts/part.h
                if(EGH_ORIGINAL STREQUAL "CAMELCASE")
                    set(originalclassname "${_CLASSNAME}")
                else()
                    string(TOLOWER "${_CLASSNAME}" originalclassname)
                endif()
                set(REGULAR_HEADER_NAME ${EGH_OUTPUT_DIR}/${originalprefix}${originalclassname}.${EGH_HEADER_EXTENSION})
                if (NOT EXISTS ${REGULAR_HEADER_NAME})
                    file(RELATIVE_PATH _actualheader_relative "${EGH_OUTPUT_DIR}/${originalprefix}" "${_actualheader}")
                    file(WRITE ${REGULAR_HEADER_NAME} "#include \"${_actualheader_relative}\" // IWYU pragma: export\n")
                endif()
            endif()
        endforeach()

        list(APPEND _REQUIRED_HEADERS "${_actualheader}")
    endforeach()

    if(EGH_COMMON_HEADER)
        #combine required headers into 1 big convenience header
        set(COMMON_HEADER ${EGH_OUTPUT_DIR}/${EGH_PREFIX}${EGH_COMMON_HEADER})
        file(WRITE ${COMMON_HEADER} "// convenience header\n")
        foreach(_header ${_REQUIRED_HEADERS})
            get_filename_component(_base ${_header} NAME)
            file(APPEND ${COMMON_HEADER} "#include \"${_base}\"\n")
        endforeach()
        list(APPEND ${camelcase_forwarding_headers_var} "${COMMON_HEADER}")
    endif()

    set(${camelcase_forwarding_headers_var} ${${camelcase_forwarding_headers_var}} PARENT_SCOPE)
    if (EGH_REQUIRED_HEADERS)
        set(${EGH_REQUIRED_HEADERS} ${${EGH_REQUIRED_HEADERS}} ${_REQUIRED_HEADERS} PARENT_SCOPE)
    endif ()
endfunction()
# SPDX-FileCopyrightText: 2014 Aleix Pol Gonzalez <aleixpol@kde.org>
# SPDX-FileCopyrightText: 2014 David Faure <faure@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
ECMGeneratePkgConfigFile
------------------------

Generate a `pkg-config <https://www.freedesktop.org/wiki/Software/pkg-config/>`_
file for the benefit of
`autotools <https://www.gnu.org/software/automake/manual/html_node/Autotools-Introduction.html>`_-based
projects.

::

  ecm_generate_pkgconfig_file(BASE_NAME <baseName>
                        [LIB_NAME <libName>]
                        [DEPS [PRIVATE|PUBLIC] <dep> [[PRIVATE|PUBLIC] <dep> [...]]]
                        [FILENAME_VAR <filename_variable>]
                        [INCLUDE_INSTALL_DIR <dir>]
                        [LIB_INSTALL_DIR <dir>]
                        [DEFINES -D<variable=value>...]
                        [DESCRIPTION <library description>] # since 5.41.0
                        [URL <url>] # since 5.89.0
                        [INSTALL])

``BASE_NAME`` is the name of the module. It's the name projects will use to
find the module.

``LIB_NAME`` is the name of the library that is being exported. If undefined,
it will default to the ``BASE_NAME``. That means the ``LIB_NAME`` will be set
as the name field as well as the library to link to.

``DEPS`` is the list of libraries required by this library. Libraries that are
not exposed to applications should be marked with ``PRIVATE``. The default
is ``PUBLIC``, but note that according to the
`Guide to pkg-config <https://people.freedesktop.org/~dbn/pkg-config-guide.html>`_
marking dependencies as private is usually preferred. The ``PUBLIC`` and
``PRIVATE`` keywords are supported since 5.89.0.

``FILENAME_VAR`` is specified with a variable name. This variable will
receive the location of the generated file will be set, within the build
directory. This way it can be used in case some processing is required. See
also ``INSTALL``.

``INCLUDE_INSTALL_DIR`` specifies where the includes will be installed. If
it's not specified, it will default to ``INSTALL_INCLUDEDIR``,
``CMAKE_INSTALL_INCLUDEDIR`` or just "include/" in case they are specified,
with the ``BASE_NAME`` postfixed.

``LIB_INSTALL_DIR`` specifies where the library is being installed. If it's
not specified, it will default to ``LIB_INSTALL_DIR``,
``CMAKE_INSTALL_LIBDIR`` or just "lib/" in case they are specified.

``DEFINES`` is a list of preprocessor defines that it is recommended users of
the library pass to the compiler when using it.

``DESCRIPTION`` describes what this library is. If it's not specified, CMake
will first try to get the description from the metainfo.yaml file or will
create one based on ``LIB_NAME``. Since 5.41.0.

``URL`` An URL where people can get more information about and download the
package. Defaults to "https://www.kde.org/". Since 5.89.0.

``INSTALL`` will cause the module to be installed to the ``pkgconfig``
subdirectory of ``LIB_INSTALL_DIR``, unless the ``ECM_PKGCONFIG_INSTALL_DIR``
cache variable is set to something different.

.. note::
  The first call to ``ecm_generate_pkgconfig_file()`` with the ``INSTALL``
  argument will cause ``ECM_PKGCONFIG_INSTALL_DIR`` to be set to the cache,
  and will be used in any subsequent calls.

To properly use this macro a version needs to be set. To retrieve it,
``ECM_PKGCONFIG_INSTALL_DIR`` uses ``PROJECT_VERSION``. To set it, use the
``project()`` command or the ``ecm_setup_version()`` macro

Example usage:

.. code-block:: cmake

  ecm_generate_pkgconfig_file(
      BASE_NAME KF5Archive
      DEPS Qt5Core
      FILENAME_VAR pkgconfig_filename
      INSTALL
  )

Since 1.3.0.
#]=======================================================================]

function(ECM_GENERATE_PKGCONFIG_FILE)
  set(options INSTALL)
  set(oneValueArgs BASE_NAME LIB_NAME FILENAME_VAR INCLUDE_INSTALL_DIR LIB_INSTALL_DIR DESCRIPTION URL)
  set(multiValueArgs DEPS DEFINES)

  cmake_parse_arguments(EGPF "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

  if(EGPF_UNPARSED_ARGUMENTS)
    message(FATAL_ERROR "Unknown keywords given to ECM_GENERATE_PKGCONFIG_FILE(): \"${EGPF_UNPARSED_ARGUMENTS}\"")
  endif()

  if(NOT EGPF_BASE_NAME)
    message(FATAL_ERROR "Required argument BASE_NAME missing in ECM_GENERATE_PKGCONFIG_FILE() call")
  endif()
  if(NOT PROJECT_VERSION)
    message(FATAL_ERROR "Required variable PROJECT_VERSION not set before ECM_GENERATE_PKGCONFIG_FILE() call. Did you call ecm_setup_version or project with the VERSION argument?")
  endif()
  if(NOT EGPF_LIB_NAME)
    set(EGPF_LIB_NAME ${EGPF_BASE_NAME})
  endif()
  if(NOT EGPF_INCLUDE_INSTALL_DIR)
      if(INCLUDE_INSTALL_DIR)
          set(EGPF_INCLUDE_INSTALL_DIR "${INCLUDE_INSTALL_DIR}/${EGPF_BASE_NAME}")
      elseif(CMAKE_INSTALL_INCLUDEDIR)
          set(EGPF_INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_INCLUDEDIR}/${EGPF_BASE_NAME}")
      else()
          set(EGPF_INCLUDE_INSTALL_DIR "include/${EGPF_BASE_NAME}")
      endif()
  endif()
  if(NOT EGPF_LIB_INSTALL_DIR)
      if(LIB_INSTALL_DIR)
          set(EGPF_LIB_INSTALL_DIR "${LIB_INSTALL_DIR}")
      elseif(CMAKE_INSTALL_LIBDIR)
          set(EGPF_LIB_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}")
      else()
          set(EGPF_LIB_INSTALL_DIR "lib")
      endif()
  endif()
  if(NOT EGPF_DESCRIPTION)
      if(EXISTS ${CMAKE_SOURCE_DIR}/metainfo.yaml)
          file(STRINGS "${CMAKE_SOURCE_DIR}/metainfo.yaml" _EGPF_METAINFO_DESCRIPTION_STRING REGEX "^description:.*$")
          if(_EGPF_METAINFO_DESCRIPTION_STRING)
              string(REGEX REPLACE "^description:[ ]*(.*)" "\\1" EGPF_DESCRIPTION ${_EGPF_METAINFO_DESCRIPTION_STRING})
          endif()
      endif()
      if("${EGPF_DESCRIPTION}" STREQUAL "")
          set(EGPF_DESCRIPTION "${EGPF_LIB_NAME} library.")
      endif()
  endif()
  if(NOT EGPF_URL)
      set(EGPF_URL "https://www.kde.org/")
  endif()

  set(PKGCONFIG_TARGET_BASENAME ${EGPF_BASE_NAME})
  set(PKGCONFIG_TARGET_LIBNAME ${EGPF_LIB_NAME})
  if (DEFINED EGPF_DEPS)
    # convert the dependencies to a list
    string(REPLACE " " ";" EGPF_DEPS "${EGPF_DEPS}")
    foreach(EGPF_DEP ${EGPF_DEPS})
        if("${EGPF_DEP}" STREQUAL "")
        elseif("${EGPF_DEP}" STREQUAL "PRIVATE")
            set(private_deps ON)
        elseif("${EGPF_DEP}" STREQUAL "PUBLIC")
            unset(private_deps)
        else()
            if(private_deps)
                list(APPEND PKGCONFIG_TARGET_DEPS_PRIVATE "${EGPF_DEP}")
            else()
                list(APPEND PKGCONFIG_TARGET_DEPS "${EGPF_DEP}")
            endif()
        endif()
    endforeach()
    list(JOIN PKGCONFIG_TARGET_DEPS " " PKGCONFIG_TARGET_DEPS)
    list(JOIN PKGCONFIG_TARGET_DEPS_PRIVATE " " PKGCONFIG_TARGET_DEPS_PRIVATE)
  endif ()
  if(TARGET ${EGPF_LIB_NAME})
    # Generator expression cannot be evaluated when creating the pkgconfig file, we need to convert the public include directories
    # into something pkgconfig can understand
    get_target_property(__EGPF_TARGET_INCLUDE_DIRS ${EGPF_LIB_NAME} INTERFACE_INCLUDE_DIRECTORIES)

    if(__EGPF_TARGET_INCLUDE_DIRS)
      set(_EGPF_TARGET_INCLUDE_DIRS "${__EGPF_TARGET_INCLUDE_DIRS}")
      # INTERFACE_INCLUDE_DIRS can contain semicolon separated locations. Since CMake still doesn't accept different separators,
      # We need to convert _EGPF_TARGET_INCLUDE_DIRS to a string, extract the locations and convert it back to a list
      string(REPLACE ";" "|" _EGPF_TARGET_INCLUDE_DIRS "${_EGPF_TARGET_INCLUDE_DIRS}")
      list(TRANSFORM _EGPF_TARGET_INCLUDE_DIRS REPLACE "\\$<INSTALL_INTERFACE:([^,>]+)>" "\\1")
      string(REPLACE "|" ";" _EGPF_TARGET_INCLUDE_DIRS "${_EGPF_TARGET_INCLUDE_DIRS}")

      # Remove any other generator expression.
      string(GENEX_STRIP "${_EGPF_TARGET_INCLUDE_DIRS}" _EGPF_TARGET_INCLUDE_DIRS)

      # Remove possible duplicate entries a first time
      list(REMOVE_DUPLICATES _EGPF_TARGET_INCLUDE_DIRS)

      foreach(EGPF_INCLUDE_DIR IN LISTS _EGPF_TARGET_INCLUDE_DIRS)
        # if the path is not absolute (that would be the case for KDEInstallDirs variables), append \${prefix} before each entry
        if(NOT IS_ABSOLUTE "${EGPF_INCLUDE_DIR}")
          list(TRANSFORM _EGPF_TARGET_INCLUDE_DIRS REPLACE "${EGPF_INCLUDE_DIR}" "\${prefix}/${EGPF_INCLUDE_DIR}")
        endif()
      endforeach()
    endif()
  endif()

  if(IS_ABSOLUTE "${EGPF_INCLUDE_INSTALL_DIR}")
      list(APPEND PKGCONFIG_TARGET_INCLUDES "${EGPF_INCLUDE_INSTALL_DIR}")
  else()
      list(APPEND PKGCONFIG_TARGET_INCLUDES "\${prefix}/${EGPF_INCLUDE_INSTALL_DIR}")
  endif()
  list(APPEND _EGPF_TARGET_INCLUDE_DIRS "${PKGCONFIG_TARGET_INCLUDES}")

  # Strip trailing '/' if present anywhere
  list(TRANSFORM _EGPF_TARGET_INCLUDE_DIRS REPLACE "(.*)/$" "\\1")

  # Deduplicate the list a second time, append -I before each entry and convert it to a string
  list(REMOVE_DUPLICATES _EGPF_TARGET_INCLUDE_DIRS)
  list(TRANSFORM _EGPF_TARGET_INCLUDE_DIRS PREPEND "-I")
  string(REPLACE ";" " " PKGCONFIG_CFLAGS_INCLUDES "${_EGPF_TARGET_INCLUDE_DIRS}")

  if(IS_ABSOLUTE "${EGPF_LIB_INSTALL_DIR}")
      set(PKGCONFIG_TARGET_LIBS "${EGPF_LIB_INSTALL_DIR}")
  else()
      set(PKGCONFIG_TARGET_LIBS "\${prefix}/${EGPF_LIB_INSTALL_DIR}")
  endif()
  set(PKGCONFIG_TARGET_DESCRIPTION "${EGPF_DESCRIPTION}")
  set(PKGCONFIG_TARGET_URL "${EGPF_URL}")
  set(PKGCONFIG_TARGET_DEFINES "")
  if(EGPF_DEFINES)
    # Transform the list to a string without semicolon
    string(REPLACE ";" " " EGPF_DEFINES "${EGPF_DEFINES}")
    set(PKGCONFIG_TARGET_DEFINES "${EGPF_DEFINES}")
  endif()

  set(PKGCONFIG_FILENAME ${CMAKE_CURRENT_BINARY_DIR}/${PKGCONFIG_TARGET_BASENAME}.pc)
  if (EGPF_FILENAME_VAR)
     set(${EGPF_FILENAME_VAR} ${PKGCONFIG_FILENAME} PARENT_SCOPE)
  endif()

  set(PKGCONFIG_CONTENT
"
prefix=${CMAKE_INSTALL_PREFIX}
exec_prefix=\${prefix}
libdir=${PKGCONFIG_TARGET_LIBS}
includedir=${PKGCONFIG_TARGET_INCLUDES}

Name: ${PKGCONFIG_TARGET_LIBNAME}
Description: ${PKGCONFIG_TARGET_DESCRIPTION}
URL: ${PKGCONFIG_TARGET_URL}
Version: ${PROJECT_VERSION}
Libs: -L${PKGCONFIG_TARGET_LIBS} -l${PKGCONFIG_TARGET_LIBNAME}
Cflags: ${PKGCONFIG_CFLAGS_INCLUDES} ${PKGCONFIG_TARGET_DEFINES}
Requires: ${PKGCONFIG_TARGET_DEPS}
"
  )
  if(PKGCONFIG_TARGET_DEPS_PRIVATE)
    set(PKGCONFIG_CONTENT
"${PKGCONFIG_CONTENT}Requires.private: ${PKGCONFIG_TARGET_DEPS_PRIVATE}
"
    )
  endif()
  file(WRITE ${PKGCONFIG_FILENAME} "${PKGCONFIG_CONTENT}")

  if(EGPF_INSTALL)
    if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
      set(ECM_PKGCONFIG_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/libdata/pkgconfig" CACHE PATH "The directory where pkgconfig will be installed to.")
    else()
      set(ECM_PKGCONFIG_INSTALL_DIR "${EGPF_LIB_INSTALL_DIR}/pkgconfig" CACHE PATH "The directory where pkgconfig will be installed to.")
    endif()
    install(FILES ${PKGCONFIG_FILENAME} DESTINATION ${ECM_PKGCONFIG_INSTALL_DIR})
  endif()
endfunction()
# SPDX-FileCopyrightText: 2014 David Faure <faure@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
ECMGeneratePriFile
------------------

Generate a ``.pri`` file for the benefit of qmake-based projects.

As well as the function below, this module creates the cache variable
``ECM_MKSPECS_INSTALL_DIR`` and sets the default value to ``mkspecs/modules``.
This assumes Qt and the current project are both installed to the same
non-system prefix.  Packagers who use ``-DCMAKE_INSTALL_PREFIX=/usr`` will
certainly want to set ``ECM_MKSPECS_INSTALL_DIR`` to something like
``share/qt5/mkspecs/modules``.

The main thing is that this should be the ``modules`` subdirectory of either
the default qmake ``mkspecs`` directory or of a directory that will be in the
``$QMAKEPATH`` environment variable when qmake is run.

::

  ecm_generate_pri_file(BASE_NAME <baseName>
                        LIB_NAME <libName>
                        [VERSION <version>] # since 5.83
                        [DEPS "<dep> [<dep> [...]]"]
                        [FILENAME_VAR <filename_variable>]
                        [INCLUDE_INSTALL_DIRS <dir> [<dir> [...]]]  # since 5.92
                        [INCLUDE_INSTALL_DIR <dir>] # deprecated since 5.92
                        [LIB_INSTALL_DIR <dir>])

If your CMake project produces a Qt-based library, you may expect there to be
applications that wish to use it that use a qmake-based build system, rather
than a CMake-based one.  Creating a ``.pri`` file will make use of your
library convenient for them, in much the same way that CMake config files make
things convenient for CMake-based applications. ``ecm_generate_pri_file()``
generates just such a file.

``VERSION`` specifies the version of the library the ``.pri`` file describes. If
not set, the value is taken from the context variable ``PROJECT_VERSION``.
This variable is usually set by the ``project(... VERSION ...)`` command or,
if CMake policy CMP0048 is not ``NEW``, by :module:`ECMSetupVersion`.
For backward-compatibility with older ECM versions the
``PROJECT_VERSION_STRING`` variable as set by :module:`ECMSetupVersion`
will be preferred over ``PROJECT_VERSION`` if set, unless the minimum
required version of ECM is 5.83 and newer. Since 5.83.

``BASE_NAME`` specifies the name qmake project (.pro) files should use to refer to
the library (eg: KArchive).  ``LIB_NAME`` is the name of the actual library to
link to (ie: the first argument to add_library()).  ``DEPS`` is a space-separated
list of the base names of other libraries (for Qt libraries, use the same
names you use with the ``QT`` variable in a qmake project file, such as "core"
for QtCore).  ``FILENAME_VAR`` specifies the name of a variable to store the path
to the generated file in.

``INCLUDE_INSTALL_DIRS`` are the paths (relative to ``CMAKE_INSTALL_PREFIX``) that
include files will be installed to. It defaults to
``${INCLUDE_INSTALL_DIR}/<baseName>`` if the ``INCLUDE_INSTALL_DIR`` variable
is set. If that variable is not set, the ``CMAKE_INSTALL_INCLUDEDIR`` variable
is used instead, and if neither are set ``include`` is used.  ``LIB_INSTALL_DIR``
operates similarly for the installation location for libraries; it defaults to
``${LIB_INSTALL_DIR}``, ``${CMAKE_INSTALL_LIBDIR}`` or ``lib``, in that order.

``INCLUDE_INSTALL_DIR`` is the old variant of ``INCLUDE_INSTALL_DIRS``, taking only one
directory.

Example usage:

.. code-block:: cmake

  ecm_generate_pri_file(
      BASE_NAME KArchive
      LIB_NAME KF5KArchive
      DEPS "core"
      FILENAME_VAR pri_filename
      VERSION 4.2.0
  )
  install(FILES ${pri_filename} DESTINATION ${ECM_MKSPECS_INSTALL_DIR})

A qmake-based project that wished to use this would then do::

  QT += KArchive

in their ``.pro`` file.

Since pre-1.0.0.
#]=======================================================================]

# Replicate the logic from KDEInstallDirs.cmake as we can't depend on it
# Ask qmake if we're using the same prefix as Qt
set(_should_query_qt OFF)
if(NOT DEFINED KDE_INSTALL_USE_QT_SYS_PATHS)
    include(ECMQueryQt)
    ecm_query_qt(qt_install_prefix_dir QT_INSTALL_PREFIX TRY)
    if(qt_install_prefix_dir STREQUAL "${CMAKE_INSTALL_PREFIX}")
        set(_should_query_qt ON)
    endif()
endif()

if(KDE_INSTALL_USE_QT_SYS_PATHS OR _should_query_qt)
  include(ECMQueryQt)
  ecm_query_qt(qt_install_prefix_dir QT_INSTALL_PREFIX)
  ecm_query_qt(qt_host_data_dir QT_HOST_DATA)
  if(qt_install_prefix_dir STREQUAL "${CMAKE_INSTALL_PREFIX}")
    file(RELATIVE_PATH qt_host_data_dir ${qt_install_prefix_dir} ${qt_host_data_dir})
  endif()
  if(qt_host_data_dir STREQUAL "")
    set(mkspecs_install_dir mkspecs/modules)
  else()
    set(mkspecs_install_dir ${qt_host_data_dir}/mkspecs/modules)
  endif()
  set(ECM_MKSPECS_INSTALL_DIR ${mkspecs_install_dir} CACHE PATH "The directory where mkspecs will be installed to.")
else()
  set(ECM_MKSPECS_INSTALL_DIR mkspecs/modules CACHE PATH "The directory where mkspecs will be installed to.")
endif()

function(ECM_GENERATE_PRI_FILE)
  set(options )
  set(oneValueArgs BASE_NAME LIB_NAME DEPS FILENAME_VAR INCLUDE_INSTALL_DIR LIB_INSTALL_DIR VERSION)
  set(multiValueArgs INCLUDE_INSTALL_DIRS)

  cmake_parse_arguments(EGPF "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

  if(EGPF_UNPARSED_ARGUMENTS)
    message(FATAL_ERROR "Unknown keywords given to ECM_GENERATE_PRI_FILE(): \"${EGPF_UNPARSED_ARGUMENTS}\"")
  endif()

  if(ECM_GLOBAL_FIND_VERSION VERSION_LESS 5.83.0)
    set(_support_backward_compat_version_string_var TRUE)
  else()
    set(_support_backward_compat_version_string_var FALSE)
  endif()

  if(NOT EGPF_BASE_NAME)
    message(FATAL_ERROR "Required argument BASE_NAME missing in ECM_GENERATE_PRI_FILE() call")
  endif()
  if(NOT EGPF_LIB_NAME)
    message(FATAL_ERROR "Required argument LIB_NAME missing in ECM_GENERATE_PRI_FILE() call")
  endif()
  if(NOT EGPF_VERSION)
    if(_support_backward_compat_version_string_var)
      if(NOT PROJECT_VERSION_STRING AND NOT PROJECT_VERSION)
        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)?")
      endif()
    else()
      if(NOT PROJECT_VERSION)
        message(FATAL_ERROR "Required variable PROJECT_VERSION not set before ECM_GENERATE_PRI_FILE() call. Missing call of ecm_setup_version() or project(VERSION)?")
      endif()
    endif()
  endif()
  if(EGPF_INCLUDE_INSTALL_DIR)
    if(EGPF_INCLUDE_INSTALL_DIRS)
      message(FATAL_ERROR "Only one argument of INCLUDE_INSTALL_DIR & INCLUDE_INSTALL_DIRS can be used in ECM_GENERATE_PRI_FILE() call")
    endif()
    set(EGPF_INCLUDE_INSTALL_DIRS ${EGPF_INCLUDE_INSTALL_DIR})
  endif()
  if(NOT EGPF_INCLUDE_INSTALL_DIRS)
      if(INCLUDE_INSTALL_DIR)
          set(EGPF_INCLUDE_INSTALL_DIRS "${INCLUDE_INSTALL_DIR}/${EGPF_BASE_NAME}")
      elseif(CMAKE_INSTALL_INCLUDEDIR)
          set(EGPF_INCLUDE_INSTALL_DIRS "${CMAKE_INSTALL_INCLUDEDIR}/${EGPF_BASE_NAME}")
      else()
          set(EGPF_INCLUDE_INSTALL_DIRS "include/${EGPF_BASE_NAME}")
      endif()
  endif()
  if(NOT EGPF_LIB_INSTALL_DIR)
      if(LIB_INSTALL_DIR)
          set(EGPF_LIB_INSTALL_DIR "${LIB_INSTALL_DIR}")
      elseif(CMAKE_INSTALL_LIBDIR)
          set(EGPF_LIB_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}")
      else()
          set(EGPF_LIB_INSTALL_DIR "lib")
      endif()
  endif()

  if(EGPF_VERSION)
    set(PRI_VERSION "${EGPF_VERSION}")
  else()
    if(_support_backward_compat_version_string_var AND PROJECT_VERSION_STRING)
      set(PRI_VERSION "${PROJECT_VERSION_STRING}")
      if(NOT PROJECT_VERSION_STRING STREQUAL PROJECT_VERSION)
        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.")
      endif()
    else()
      set(PRI_VERSION "${PROJECT_VERSION}")
    endif()
  endif()

  string(REGEX REPLACE "^([0-9]+)\\.[0-9]+\\.[0-9]+.*" "\\1" PRI_VERSION_MAJOR "${PRI_VERSION}")
  string(REGEX REPLACE "^[0-9]+\\.([0-9]+)\\.[0-9]+.*" "\\1" PRI_VERSION_MINOR "${PRI_VERSION}")
  string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" PRI_VERSION_PATCH "${PRI_VERSION}")

  # Prepare the right number of "../.." to go from ECM_MKSPECS_INSTALL_DIR to the install prefix
  # This allows to make the generated pri files relocatable (no absolute paths)
  if (IS_ABSOLUTE ${ECM_MKSPECS_INSTALL_DIR})
     set(BASEPATH ${CMAKE_INSTALL_PREFIX})
  else()
    string(REGEX REPLACE "[^/]+" ".." PRI_ROOT_RELATIVE_TO_MKSPECS ${ECM_MKSPECS_INSTALL_DIR})
    set(BASEPATH "$$PWD/${PRI_ROOT_RELATIVE_TO_MKSPECS}")
 endif()

  set(PRI_TARGET_BASENAME ${EGPF_BASE_NAME})
  set(PRI_TARGET_LIBNAME ${EGPF_LIB_NAME})
  set(PRI_TARGET_QTDEPS ${EGPF_DEPS})
  set(PRI_TARGET_INCLUDES)
  foreach(_dir ${EGPF_INCLUDE_INSTALL_DIRS})
    # separate list entries with space
    if(IS_ABSOLUTE "${_dir}")
        string(APPEND PRI_TARGET_INCLUDES " ${_dir}")
    else()
        string(APPEND PRI_TARGET_INCLUDES " ${BASEPATH}/${_dir}")
    endif()
  endforeach()
  if(IS_ABSOLUTE "${EGPF_LIB_INSTALL_DIR}")
      set(PRI_TARGET_LIBS "${EGPF_LIB_INSTALL_DIR}")
  else()
      set(PRI_TARGET_LIBS "${BASEPATH}/${EGPF_LIB_INSTALL_DIR}")
  endif()
  set(PRI_TARGET_DEFINES "")

  set(PRI_FILENAME ${CMAKE_CURRENT_BINARY_DIR}/qt_${PRI_TARGET_BASENAME}.pri)
  if (EGPF_FILENAME_VAR)
     set(${EGPF_FILENAME_VAR} ${PRI_FILENAME} PARENT_SCOPE)
  endif()

  set(PRI_TARGET_MODULE_CONFIG "")
  # backward compat: it was not obvious LIB_NAME needs to be a target name,
  # and some projects where the target name was not the actual library output name
  # passed the output name for LIB_NAME, so .name & .module prperties are correctly set.
  # TODO: improve API dox, allow control over module name if target name != output name
  if(TARGET ${EGPF_LIB_NAME})
    get_target_property(target_type ${EGPF_LIB_NAME} TYPE)
    if (target_type STREQUAL "STATIC_LIBRARY")
        set(PRI_TARGET_MODULE_CONFIG "staticlib")
    endif()
  endif()

  file(GENERATE
     OUTPUT ${PRI_FILENAME}
     CONTENT
     "QT.${PRI_TARGET_BASENAME}.VERSION = ${PRI_VERSION}
QT.${PRI_TARGET_BASENAME}.MAJOR_VERSION = ${PRI_VERSION_MAJOR}
QT.${PRI_TARGET_BASENAME}.MINOR_VERSION = ${PRI_VERSION_MINOR}
QT.${PRI_TARGET_BASENAME}.PATCH_VERSION = ${PRI_VERSION_PATCH}
QT.${PRI_TARGET_BASENAME}.name = ${PRI_TARGET_LIBNAME}
QT.${PRI_TARGET_BASENAME}.module = ${PRI_TARGET_LIBNAME}
QT.${PRI_TARGET_BASENAME}.defines = ${PRI_TARGET_DEFINES}
QT.${PRI_TARGET_BASENAME}.includes = ${PRI_TARGET_INCLUDES}
QT.${PRI_TARGET_BASENAME}.private_includes =
QT.${PRI_TARGET_BASENAME}.libs = ${PRI_TARGET_LIBS}
QT.${PRI_TARGET_BASENAME}.depends = ${PRI_TARGET_QTDEPS}
QT.${PRI_TARGET_BASENAME}.module_config = ${PRI_TARGET_MODULE_CONFIG}
"
  )
endfunction()
# SPDX-FileCopyrightText: 2023 The Qt Company Ltd.
# SPDX-FileCopyrightText: 2024 Manuel Alcaraz Zambrano <manuelalcarazzam@gmail.com>
# SPDX-License-Identifier: BSD-3-Clause

# Based on https://code.qt.io/cgit/pyside/pyside-setup.git/tree/examples/widgetbinding/CMakeLists.txt

#[=======================================================================[.rst:
ECMGeneratePythonBindings
-------------------------

This module is experimental and internal.  The interface will likely
change in the coming releases.

Generate Python bindings using Shiboken.

::

  ecm_generate_python_bindings(PACKAGE_NAME <pythonlibrary>
                               VERSION <version>
                               WRAPPED_HEADER <filename>
                               TYPESYSTEM <filename>
                               GENERATED_SOURCES <filename> [<filename> [...]]
                               DEPENDENCIES <target> [<target> [...]]
                               QT_VERSION <version>
                               HOMEPAGE_URL <url>
                               ISSUES_URL <url>
                               AUTHOR <string>
                               README <filename> )

``<pythonlibrary>`` is the name of the Python library that will be created.

``VERSION`` is the version of the library.

``WRAPPED_HEADER`` is a C++ header that contains all the required includes
for the library.

``TYPESYSTEM`` is the XML file where the bindings are defined.

``GENERATED_SOURCES`` is the list of generated C++ source files by Shiboken
that will be used to build the shared library.

``QT_VERSION`` is the minimum required Qt version of the library.

``DEPENDENCIES`` is the list of dependencies that the bindings uses.

``HOMEPAGE_URL`` is a URL to the proyect homepage.

``ISSUES_URL` is a URL where users can report bugs and feature requests.

``AUTHOR`` is a string with the author of the library.

``README`` is a Markdown file that will be used as the project's
description on the Python Package Index.

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

set(MODULES_DIR ${CMAKE_CURRENT_LIST_DIR})

function(ecm_generate_python_bindings)
    set(options )
    set(oneValueArgs PACKAGE_NAME WRAPPED_HEADER TYPESYSTEM VERSION QT_VERSION HOMEPAGE_URL ISSUES_URL AUTHOR README)
    set(multiValueArgs GENERATED_SOURCES DEPENDENCIES)

    cmake_parse_arguments(PB "${options}" "${oneValueArgs}" "${multiValueArgs}"  ${ARGN})

    # Ugly hacks because PySide6::pyside6 only includes /usr/includes/PySide6 and none of the sub directory
    # Qt bugreport: PYSIDE-2882
    get_property(PYSIDE_INCLUDE_DIRS TARGET "PySide6::pyside6" PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
    foreach(PYSIDE_INCLUDE_DIR ${PYSIDE_INCLUDE_DIRS})
        file(GLOB PYSIDE_SUBDIRS LIST_DIRECTORIES true "${PYSIDE_INCLUDE_DIR}/*")
        foreach (PYSIDE_SUBDIR ${PYSIDE_SUBDIRS})
            if (IS_DIRECTORY ${PYSIDE_SUBDIR})
                set_property(TARGET PySide6::pyside6
                    APPEND
                    PROPERTY INTERFACE_INCLUDE_DIRECTORIES
                    ${PYSIDE_SUBDIR}
                )
            endif()
        endforeach()
    endforeach()

    list(APPEND PB_DEPENDENCIES PySide6::pyside6)
    list(APPEND PB_DEPENDENCIES Shiboken6::libshiboken)

    # Get the relevant include dirs, to pass them on to shiboken.
    set(INCLUDES "")

    if(WIN32)
        set(PATH_SEP "\;")
    else()
        set(PATH_SEP ":")
    endif()

    macro(make_path varname)
        # accepts any number of path variables
        string(REPLACE ";" "${PATH_SEP}" ${varname} "${ARGN}")
    endmacro()

    foreach(_dependency ${PB_DEPENDENCIES})
        get_property(DEPENDENCY_INCLUDE_DIRS TARGET "${_dependency}" PROPERTY INTERFACE_INCLUDE_DIRECTORIES)

        make_path(_include_dirs $<JOIN:$<TARGET_PROPERTY:${_dependency},INTERFACE_INCLUDE_DIRECTORIES>,${PATH_SEP}>)
        list(APPEND INCLUDES "--include-paths=${_include_dirs}")
    endforeach()

    # Set up the options to pass to shiboken.
    set(shiboken_options --enable-pyside-extensions
        ${INCLUDES}
        --include-paths=${CMAKE_SOURCE_DIR}
        --typesystem-paths=${CMAKE_SOURCE_DIR}
        --typesystem-paths=${PYSIDE_TYPESYSTEMS}
        --output-directory=${CMAKE_CURRENT_BINARY_DIR})

    set(generated_sources_dependencies ${PB_WRAPPED_HEADER} ${PB_TYPESYSTEM})

    # Add custom target to run shiboken to generate the binding cpp files.
    add_custom_command(
        OUTPUT ${PB_GENERATED_SOURCES}
        COMMAND shiboken6 ${shiboken_options} ${PB_WRAPPED_HEADER} ${PB_TYPESYSTEM}
        DEPENDS ${generated_sources_dependencies}
        WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
        COMMENT "Running generator for ${PB_TYPESYSTEM}"
    )

    # Set the cpp files which will be used for the bindings library.
    set(${PB_PACKAGE_NAME}_sources ${PB_GENERATED_SOURCES})

    # PySide6 uses deprecated code.
    get_property(_defs DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY COMPILE_DEFINITIONS)
    list(FILTER _defs EXCLUDE REGEX [[^QT_DISABLE_DEPRECATED_BEFORE=]])
    set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY COMPILE_DEFINITIONS ${_defs})
    get_property(_defs DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY COMPILE_DEFINITIONS)
    list(FILTER _defs EXCLUDE REGEX [[^QT_DISABLE_DEPRECATED_BEFORE=]])
    set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY COMPILE_DEFINITIONS ${_defs})

    # Define and build the bindings library.
    add_library(${PB_PACKAGE_NAME} SHARED ${${PB_PACKAGE_NAME}_sources})

    target_link_libraries(${PB_PACKAGE_NAME} PRIVATE
        PySide6::pyside6
        Shiboken6::libshiboken
        ${Python3_LIBRARIES}
    )

    # Apply relevant include and link flags.
    target_include_directories(${PB_PACKAGE_NAME} PRIVATE
        ${PYSIDE_PYTHONPATH}/include
        ${SHIBOKEN_PYTHON_INCLUDE_DIRS}
        $<TARGET_PROPERTY:PySide6::pyside6,INTERFACE_INCLUDE_DIRECTORIES>
        $<TARGET_PROPERTY:Shiboken6::libshiboken,INTERFACE_INCLUDE_DIRECTORIES>
    )

    # Hide noisy warnings
    target_compile_options(${PB_PACKAGE_NAME} PRIVATE -Wno-cast-function-type -Wno-missing-include-dirs)

    # Adjust the name of generated module.
    set_property(TARGET ${PB_PACKAGE_NAME} PROPERTY PREFIX "")
    set_property(TARGET ${PB_PACKAGE_NAME} PROPERTY LIBRARY_OUTPUT_NAME "${PB_PACKAGE_NAME}.${Python3_SOABI}")
    set_property(TARGET ${PB_PACKAGE_NAME} PROPERTY LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${PB_PACKAGE_NAME}/build/lib)

    # Build Python Wheel
    file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${PB_PACKAGE_NAME}/${PB_PACKAGE_NAME}")
    configure_file("${MODULES_DIR}/ECMGeneratePythonBindings.toml.in" "${CMAKE_CURRENT_BINARY_DIR}/${PB_PACKAGE_NAME}/pyproject.toml")
    configure_file(${PB_README} "${CMAKE_CURRENT_BINARY_DIR}/${PB_PACKAGE_NAME}/README.md" COPYONLY)

    add_custom_command(
        TARGET ${PB_PACKAGE_NAME}
        POST_BUILD
        COMMAND Python3::Interpreter -m build --wheel --no-isolation
        WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${PB_PACKAGE_NAME}"
        COMMENT "Building Python Wheel"
    )

endfunction()
[project]
name = "${PB_PACKAGE_NAME}"
version = "${PB_VERSION}"
authors = [
    { name="${PB_AUTHOR}" },
]
description = "Python bindings for ${PB_PACKAGE_NAME}"
readme = "README.md"
requires-python = ">=3.10"
dependencies = [
    "PySide6>=${PB_QT_VERSION},<7",
]
classifiers = [
    "Development Status :: 5 - Production/Stable",
    "Environment :: X11 Applications :: KDE",
    "Environment :: X11 Applications :: Qt",
    "Operating System :: POSIX :: Linux",
    "Programming Language :: Python :: 3",
    "Programming Language :: Python :: 3.10",
    "Programming Language :: Python :: 3.11",
    "Programming Language :: Python :: 3.12",
]

[project.urls]
Homepage = "${PB_HOMEPAGE_URL}"
Issues = "${PB_ISSUES_URL}"
SPDX-FileCopyrightText: 2024 Manuel Alcaraz Zambrano <manuelalcarazzam@gmail.com>
SPDX-License-Identifier: CC0-1.0# SPDX-FileCopyrightText: 2017 Aleix Pol Gonzalez <aleixpol@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
ECMGenerateQmlTypes
-------------------

Generates plugins.qmltypes files for QML plugins.

::

  ecm_generate_qmltypes(<org.kde.pluginname> 1.3
                        DESTINATION <${KDE_INSTALL_QMLDIR}/org/kde/pluginname>)

Makes it possible to generate plugins.qmltypes files for the QML plugins that
our project offers. These files offer introspection upon our plugin and are
useful for integrating with IDE language support of our plugin. It offers
information about the objects its methods and their argument types.

The developer will be in charge of making sure that these files are up to date.
The plugin.qmltypes file will sit in the source directory. This function will
include the code that installs the file in the right place and a small unit
test named qmltypes-pluginname-version that makes sure that it doesn't need updating.


Since 5.33.0
#]=======================================================================]

function(ecm_generate_qmltypes)
    if (NOT TARGET qmltypes)
        add_custom_target(qmltypes)
    endif ()

    set(options)
    set(oneValueArgs DESTINATION TEST_ENABLED)
    cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "" ${ARGN})

    set(targetname "qmltypes-${ARG_UNPARSED_ARGUMENTS}")
    string(REPLACE ";" - targetname "${targetname}")

    set(generatedFile ${CMAKE_CURRENT_SOURCE_DIR}/plugins.qmltypes)
    add_custom_target(${targetname}
        BYPRODUCTS ${generatedFile}
        COMMAND qmlplugindump -nonrelocatable ${ARG_UNPARSED_ARGUMENTS} ${KDE_INSTALL_QMLDIR} > ${generatedFile}
    )
    add_dependencies(qmltypes ${targetname})
    if (EXISTS ${generatedFile})
        install(FILES ${generatedFile} DESTINATION "${ARG_DESTINATION}")
    endif()

    string(REPLACE ";" / processedArgs "${ARG_UNPARSED_ARGUMENTS}")

    # sometimes qmlplugindump output isn't reproducible, we better have it opt in for now
    if(ARG_TEST_ENABLED)
        add_test(NAME ${targetname} COMMAND
            cmake -DARG_UNPARSED_ARGUMENTS=${processedArgs} -DKDE_INSTALL_QMLDIR=${KDE_INSTALL_QMLDIR} -DINPUT=${generatedFile} -P ${ECM_MODULE_DIR}/../test-modules/test_execute_and_compare.cmake
        )
    endif()
endfunction()
# SPDX-FileCopyrightText: 2014 Alex Merry <alex.merry@kde.org>
# SPDX-FileCopyrightText: 2013 David Edmundson <kde@davidedmundson.co.uk>
# SPDX-FileCopyrightText: 2008 Chusslove Illich <caslav.ilic@gmx.net>
# SPDX-FileCopyrightText: 2006 Alex Neundorf <neundorf@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
ECMInstallIcons
---------------

Installs icons, sorting them into the correct directories according to the
FreeDesktop.org icon naming specification.

::

  ecm_install_icons(ICONS <icon> [<icon> [...]]
                    DESTINATION <icon_install_dir>
                    [LANG <l10n_code>]
                    [THEME <theme>])

The given icons, whose names must match the pattern::

  <size>-<group>-<name>.<ext>

will be installed to the appropriate subdirectory of ``DESTINATION`` according to
the FreeDesktop.org icon naming scheme. By default, they are installed to the
"hicolor" theme, but this can be changed using the ``THEME`` argument.  If the
icons are localized, the LANG argument can be used to install them in a
locale-specific directory.

``<size>`` is a numeric pixel size (typically 16, 22, 32, 48, 64, 128 or 256)
or ``sc`` for scalable (SVG) files, ``<group>`` is one of the standard
FreeDesktop.org icon groups (actions, animations, apps, categories, devices,
emblems, emotes, intl, mimetypes, places, status) and ``<ext>`` is one of
``.png``, ``.mng`` or ``.svgz``.

The typical installation directory is ``share/icons``.

.. code-block:: cmake

  ecm_install_icons(ICONS 22-actions-menu_new.png
                    DESTINATION share/icons)

The above code will install the file ``22-actions-menu_new.png`` as
``${CMAKE_INSTALL_PREFIX}/share/icons/<theme>/22x22/actions/menu_new.png``

Users of the :kde-module:`KDEInstallDirs` module would normally use
``${KDE_INSTALL_ICONDIR}`` as the DESTINATION, while users of the GNUInstallDirs
module should use ``${CMAKE_INSTALL_DATAROOTDIR}/icons``.

An old form of arguments will also be accepted::

  ecm_install_icons(<icon_install_dir> [<l10n_code>])

This matches files named like::

  <theme><size>-<group>-<name>.<ext>

where ``<theme>`` is one of

* ``hi`` for hicolor
* ``lo`` for locolor
* ``cr`` for the Crystal icon theme
* ``ox`` for the Oxygen icon theme
* ``br`` for the Breeze icon theme

With this syntax, the file ``hi22-actions-menu_new.png`` would be installed
into ``<icon_install_dir>/hicolor/22x22/actions/menu_new.png``

Since pre-1.0.0.
#]=======================================================================]

# A "map" of short type names to the directories.
# Unknown names produce a warning.
set(_ECM_ICON_GROUP_mimetypes  "mimetypes")
set(_ECM_ICON_GROUP_places     "places")
set(_ECM_ICON_GROUP_devices    "devices")
set(_ECM_ICON_GROUP_apps       "apps")
set(_ECM_ICON_GROUP_actions    "actions")
set(_ECM_ICON_GROUP_categories "categories")
set(_ECM_ICON_GROUP_status     "status")
set(_ECM_ICON_GROUP_emblems    "emblems")
set(_ECM_ICON_GROUP_emotes     "emotes")
set(_ECM_ICON_GROUP_animations "animations")
set(_ECM_ICON_GROUP_intl       "intl")

# For the "compatibility" syntax: a "map" of short theme names to the theme
# directory
set(_ECM_ICON_THEME_br "breeze")
set(_ECM_ICON_THEME_ox "oxygen")
set(_ECM_ICON_THEME_cr "crystalsvg")
set(_ECM_ICON_THEME_lo "locolor")
set(_ECM_ICON_THEME_hi "hicolor")

macro(_ecm_install_icons_v1 _defaultpath)
   # the l10n-subdir if language given as second argument (localized icon)
   set(_lang ${ARGV1})
   if(_lang)
      set(_l10n_SUBDIR l10n/${_lang})
   else()
      set(_l10n_SUBDIR ".")
   endif()

   set(_themes)

   # first the png icons
   file(GLOB _icons *.png)
   foreach (_current_ICON ${_icons} )
      # since CMake 2.6 regex matches are stored in special variables CMAKE_MATCH_x, if it didn't match, they are empty
      string(REGEX MATCH "^.*/([a-zA-Z]+)([0-9]+)\\-([a-z]+)\\-(.+\\.png)$" _dummy  "${_current_ICON}")
      set(_type  "${CMAKE_MATCH_1}")
      set(_size  "${CMAKE_MATCH_2}")
      set(_group "${CMAKE_MATCH_3}")
      set(_name  "${CMAKE_MATCH_4}")

      set(_theme_GROUP ${_ECM_ICON_THEME_${_type}})
      if( _theme_GROUP)
         list(APPEND _themes "${_theme_GROUP}")
         _ECM_ADD_ICON_INSTALL_RULE(${CMAKE_CURRENT_BINARY_DIR}/install_icons.cmake
                    ${_defaultpath}/${_theme_GROUP}/${_size}x${_size}
                    ${_group} ${_current_ICON} ${_name} ${_l10n_SUBDIR})
      endif()
   endforeach (_current_ICON)

   # mng icons
   file(GLOB _icons *.mng)
   foreach (_current_ICON ${_icons} )
      # since CMake 2.6 regex matches are stored in special variables CMAKE_MATCH_x, if it didn't match, they are empty
      string(REGEX MATCH "^.*/([a-zA-Z]+)([0-9]+)\\-([a-z]+)\\-(.+\\.mng)$" _dummy  "${_current_ICON}")
      set(_type  "${CMAKE_MATCH_1}")
      set(_size  "${CMAKE_MATCH_2}")
      set(_group "${CMAKE_MATCH_3}")
      set(_name  "${CMAKE_MATCH_4}")

      set(_theme_GROUP ${_ECM_ICON_THEME_${_type}})
      if( _theme_GROUP)
         list(APPEND _themes "${_theme_GROUP}")
         _ECM_ADD_ICON_INSTALL_RULE(${CMAKE_CURRENT_BINARY_DIR}/install_icons.cmake
                ${_defaultpath}/${_theme_GROUP}/${_size}x${_size}
                ${_group} ${_current_ICON} ${_name} ${_l10n_SUBDIR})
      endif()
   endforeach (_current_ICON)

   # and now the svg icons
   file(GLOB _icons *.svgz)
   foreach (_current_ICON ${_icons} )
      # since CMake 2.6 regex matches are stored in special variables CMAKE_MATCH_x, if it didn't match, they are empty
      string(REGEX MATCH "^.*/([a-zA-Z]+)sc\\-([a-z]+)\\-(.+\\.svgz)$" _dummy "${_current_ICON}")
      set(_type  "${CMAKE_MATCH_1}")
      set(_group "${CMAKE_MATCH_2}")
      set(_name  "${CMAKE_MATCH_3}")

      set(_theme_GROUP ${_ECM_ICON_THEME_${_type}})
      if( _theme_GROUP)
         list(APPEND _themes "${_theme_GROUP}")
          _ECM_ADD_ICON_INSTALL_RULE(${CMAKE_CURRENT_BINARY_DIR}/install_icons.cmake
                            ${_defaultpath}/${_theme_GROUP}/scalable
                            ${_group} ${_current_ICON} ${_name} ${_l10n_SUBDIR})
      endif()
   endforeach (_current_ICON)

   if (_themes)
       list(REMOVE_DUPLICATES _themes)
       foreach(_theme ${_themes})
           _ecm_update_iconcache("${_defaultpath}" "${_theme}")
       endforeach()
   else()
       message(AUTHOR_WARNING "No suitably-named icons found")
   endif()

endmacro()

# only used internally by _ecm_install_icons_v1
macro(_ecm_add_icon_install_rule _install_SCRIPT _install_PATH _group _orig_NAME _install_NAME _l10n_SUBDIR)

   # if the string doesn't match the pattern, the result is the full string, so all three have the same content
   if (NOT ${_group} STREQUAL ${_install_NAME} )
      set(_icon_GROUP  ${_ECM_ICON_GROUP_${_group}})
      if(NOT _icon_GROUP)
         message(WARNING "Icon ${_install_NAME} uses invalid category ${_group}, setting to 'actions'")
         set(_icon_GROUP "actions")
      endif()
#      message(STATUS "icon: ${_current_ICON} size: ${_size} group: ${_group} name: ${_name} l10n: ${_l10n_SUBDIR}")
      install(FILES ${_orig_NAME} DESTINATION ${_install_PATH}/${_icon_GROUP}/${_l10n_SUBDIR}/ RENAME ${_install_NAME} )
   endif (NOT ${_group} STREQUAL ${_install_NAME} )

endmacro()

# Updates the mtime of the icon theme directory, so caches that
# watch for changes to the directory will know to update.
# If present, this also runs gtk-update-icon-cache (which despite the name is also used by Qt).
function(_ecm_update_iconcache installdir theme)
    find_program(GTK_UPDATE_ICON_CACHE_EXECUTABLE NAMES gtk-update-icon-cache)
    # We don't always have touch command (e.g. on Windows), so instead
    # create and delete a temporary file in the theme dir.
    install(CODE "
    set(DESTDIR_VALUE \"\$ENV{DESTDIR}\")
    if (NOT DESTDIR_VALUE)
        execute_process(COMMAND \"${CMAKE_COMMAND}\" -E touch \"${CMAKE_INSTALL_PREFIX}/${installdir}/${theme}\")
        set(HAVE_GTK_UPDATE_ICON_CACHE_EXEC ${GTK_UPDATE_ICON_CACHE_EXECUTABLE})
        if (HAVE_GTK_UPDATE_ICON_CACHE_EXEC)
            execute_process(COMMAND ${GTK_UPDATE_ICON_CACHE_EXECUTABLE} -q -t -i . WORKING_DIRECTORY \"${CMAKE_INSTALL_PREFIX}/${installdir}/${theme}\")
        endif ()
    endif (NOT DESTDIR_VALUE)
    ")
endfunction()

function(ecm_install_icons)
    set(options)
    set(oneValueArgs DESTINATION LANG THEME)
    set(multiValueArgs ICONS)
    cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

    if(NOT ARG_ICONS AND NOT ARG_DESTINATION)
        message(AUTHOR_WARNING "ecm_install_icons() with no ICONS argument is deprecated")
        _ecm_install_icons_v1(${ARGN})
        return()
    endif()
    if(ARG_UNPARSED_ARGUMENTS)
        message(FATAL_ERROR "Unexpected arguments to ecm_install_icons: ${ARG_UNPARSED_ARGUMENTS}")
    endif()
    if(NOT ARG_DESTINATION)
        message(FATAL_ERROR "No DESTINATION argument given to ecm_install_icons")
    endif()
    if(NOT ARG_THEME)
        set(ARG_THEME "hicolor")
    endif()
    if(ARG_LANG)
        set(l10n_subdir "l10n/${ARG_LANG}/")
    endif()

    foreach(icon ${ARG_ICONS})
        get_filename_component(filename "${icon}" NAME)
        string(REGEX MATCH "([0-9sc]+)\\-([a-z]+)\\-([^/]+)\\.([a-z]+)$"
                           complete_match "${filename}")
        set(size  "${CMAKE_MATCH_1}")
        set(group "${CMAKE_MATCH_2}")
        set(name  "${CMAKE_MATCH_3}")
        set(ext   "${CMAKE_MATCH_4}")
        if(NOT size OR NOT group OR NOT name OR NOT ext)
            message(WARNING "${icon} is not named correctly for ecm_install_icons - ignoring")
        elseif(NOT size STREQUAL "sc" AND NOT size GREATER 0)
            message(WARNING "${icon} size (${size}) is invalid - ignoring")
        else()
            if (NOT complete_match STREQUAL filename)
                # We can't stop accepting filenames with leading characters,
                # because that would break existing projects, so just warn
                # about them instead.
                message(AUTHOR_WARNING "\"${icon}\" has characters before the size; it should be renamed to \"${size}-${group}-${name}.${ext}\"")
            endif()
            if(NOT _ECM_ICON_GROUP_${group})
                message(WARNING "${icon} group (${group}) is not recognized")
            endif()
            if(size STREQUAL "sc")
                if(NOT ext STREQUAL "svg" AND NOT ext STREQUAL "svgz")
                    message(WARNING "Scalable icon ${icon} is not SVG or SVGZ")
                endif()
                set(size_dir "scalable")
            else()
                if(NOT ext STREQUAL "png" AND NOT ext STREQUAL "mng" AND NOT ext STREQUAL "svg" AND NOT ext STREQUAL "svgz")
                    message(WARNING "Fixed-size icon ${icon} is not PNG/MNG/SVG/SVGZ")
                endif()
                set(size_dir "${size}x${size}")
            endif()
            install(
                FILES "${icon}"
                DESTINATION "${ARG_DESTINATION}/${ARG_THEME}/${size_dir}/${group}/${l10n_subdir}"
                RENAME "${name}.${ext}"
            )
        endif()
    endforeach()
    _ecm_update_iconcache("${ARG_DESTINATION}" "${ARG_THEME}")
endfunction()
# SPDX-FileCopyrightText: 2012 Stephen Kelly <steveire@gmail.com>
# SPDX-FileCopyrightText: 2012 Alex Neundorf <neundorf@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
ECMMarkAsTest
-------------

Marks a target as only being required for tests.

::

  ecm_mark_as_test(<target1> [<target2> [...]])

This will cause the specified targets to not be built unless either
``BUILD_TESTING`` is set to ``ON`` or the user invokes the ``buildtests`` target.

``BUILD_TESTING`` is created as a cache variable by the CTest module and by the
:kde-module:`KDECMakeSettings` module.

Since pre-1.0.0.
#]=======================================================================]

if (NOT BUILD_TESTING)
  if(NOT TARGET buildtests)
    add_custom_target(buildtests)
  endif()
endif()

function(ecm_mark_as_test)
  if (NOT BUILD_TESTING)
    foreach(_target ${ARGN})
      set_target_properties(${_target}
                              PROPERTIES
                              EXCLUDE_FROM_ALL TRUE
                           )
      add_dependencies(buildtests ${_target})
    endforeach()
  endif()
endfunction()
# SPDX-FileCopyrightText: 2012 Stephen Kelly <steveire@gmail.com>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
ECMMarkNonGuiExecutable
-----------------------

Marks an executable target as not being a GUI application.

::

  ecm_mark_nongui_executable(<target1> [<target2> [...]])

This will indicate to CMake that the specified targets should not be included
in a MACOSX_BUNDLE and should not be WIN32_EXECUTABLEs.  On platforms other
than MacOS X or Windows, this will have no effect.

Since pre-1.0.0.
#]=======================================================================]

function(ecm_mark_nongui_executable)
  foreach(_target ${ARGN})
    set_target_properties(${_target}
                            PROPERTIES
                            WIN32_EXECUTABLE FALSE
                            MACOSX_BUNDLE FALSE
                          )
  endforeach()
endfunction()
# SPDX-FileCopyrightText: 2007 Alexander Neundorf <neundorf@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
ECMOptionalAddSubdirectory
--------------------------

Make subdirectories optional.

::

  ecm_optional_add_subdirectory(<dir>)

This behaves like ``add_subdirectory()``, except that it does not complain if the
directory does not exist.  Additionally, if the directory does exist, it
creates an option to allow the user to skip it. The option will be named
BUILD_<dir>.

This is useful for "meta-projects" that combine several mostly-independent
sub-projects.

If the CMake variable ``DISABLE_ALL_OPTIONAL_SUBDIRECTORIES`` is set to ``TRUE`` for
the first CMake run on the project, all optional subdirectories will be
disabled by default (but can of course be enabled via the respective options).
For example, the following will disable all optional subdirectories except the
one named "foo":

.. code-block:: sh

  cmake -DDISABLE_ALL_OPTIONAL_SUBDIRECTORIES=TRUE -DBUILD_foo=TRUE myproject

Since pre-1.0.0.
#]=======================================================================]

function(ECM_OPTIONAL_ADD_SUBDIRECTORY _dir)
  get_filename_component(_fullPath ${_dir} ABSOLUTE)
  if(EXISTS ${_fullPath}/CMakeLists.txt)
    if(DISABLE_ALL_OPTIONAL_SUBDIRECTORIES)
      set(_DEFAULT_OPTION_VALUE FALSE)
    else()
      set(_DEFAULT_OPTION_VALUE TRUE)
    endif()
    if(DISABLE_ALL_OPTIONAL_SUBDIRS  AND NOT DEFINED  BUILD_${_dir})
      set(_DEFAULT_OPTION_VALUE FALSE)
    endif()
    option(BUILD_${_dir} "Build directory ${_dir}" ${_DEFAULT_OPTION_VALUE})
    if(BUILD_${_dir})
      add_subdirectory(${_dir})
    endif()
  endif()
endfunction()
# SPDX-FileCopyrightText: 2014 Alex Merry <alex.merry@kdemail.net>
# SPDX-FileCopyrightText: 2013 Stephen Kelly <steveire@gmail.com>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
ECMPackageConfigHelpers
-----------------------

Helper macros for generating CMake package config files.

``write_basic_package_version_file()`` is the same as the one provided by the
`CMakePackageConfigHelpers
<https://www.cmake.org/cmake/help/v2.8.12/cmake.html#module:CMakePackageConfigHelpers>`_
module in CMake; see that module's documentation for
more information.

::

  ecm_configure_package_config_file(<input> <output>
      INSTALL_DESTINATION <path>
      [PATH_VARS <var1> [<var2> [...]]
      [NO_SET_AND_CHECK_MACRO]
      [NO_CHECK_REQUIRED_COMPONENTS_MACRO])


This behaves in the same way as ``configure_package_config_file()`` from CMake
2.8.12, except that it adds an extra helper macro: ``find_dependency()``. It is
highly recommended that you read the `documentation for
CMakePackageConfigHelpers
<https://www.cmake.org/cmake/help/v2.8.12/cmake.html#module:CMakePackageConfigHelpers>`_
for more information, particularly with regard to the ``PATH_VARS`` argument.

Note that there is no argument that will disable the ``find_dependency()`` macro;
if you do not require this macro, you should use
``configure_package_config_file`` from the CMakePackageConfigHelpers module.

CMake 3.0 includes a CMakeFindDependencyMacro module that provides the
``find_dependency()`` macro (which you can ``include()`` in your package config
file), so this file is only useful for projects wishing to provide config
files that will work with CMake 2.8.12.

Additional Config File Macros
=============================

::

  find_dependency(<dep> [<version> [EXACT]])

``find_dependency()`` should be used instead of ``find_package()`` to find package
dependencies.  It forwards the correct parameters for ``EXACT``, ``QUIET`` and
``REQUIRED`` which were passed to the original ``find_package()`` call.  It also sets
an informative diagnostic message if the dependency could not be found.

Since pre-1.0.0.
#]=======================================================================]

include(${CMAKE_ROOT}/Modules/CMakePackageConfigHelpers.cmake)

set(_ecm_package_config_helpers_included TRUE)

message(AUTHOR_WARNING "Your project already requires a version of CMake that includes the find_dependency macro via the CMakeFindDependencyMacro module. You should use CMakePackageConfigHelpers instead of ECMPackageConfigHelpers.")

function(ECM_CONFIGURE_PACKAGE_CONFIG_FILE _inputFile _outputFile)
  set(options NO_SET_AND_CHECK_MACRO NO_CHECK_REQUIRED_COMPONENTS_MACRO)
  set(oneValueArgs INSTALL_DESTINATION )
  set(multiValueArgs PATH_VARS )

  cmake_parse_arguments(CCF "${options}" "${oneValueArgs}" "${multiValueArgs}"  ${ARGN})

  if(CCF_UNPARSED_ARGUMENTS)
    message(FATAL_ERROR "Unknown keywords given to CONFIGURE_PACKAGE_CONFIG_FILE(): \"${CCF_UNPARSED_ARGUMENTS}\"")
  endif()

  if(NOT CCF_INSTALL_DESTINATION)
    message(FATAL_ERROR "No INSTALL_DESTINATION given to CONFIGURE_PACKAGE_CONFIG_FILE()")
  endif()

  if(IS_ABSOLUTE "${CCF_INSTALL_DESTINATION}")
    set(absInstallDir "${CCF_INSTALL_DESTINATION}")
  else()
    set(absInstallDir "${CMAKE_INSTALL_PREFIX}/${CCF_INSTALL_DESTINATION}")
  endif()

  file(RELATIVE_PATH PACKAGE_RELATIVE_PATH "${absInstallDir}" "${CMAKE_INSTALL_PREFIX}" )

  foreach(var ${CCF_PATH_VARS})
    if(NOT DEFINED ${var})
      message(FATAL_ERROR "Variable ${var} does not exist")
    else()
      if(IS_ABSOLUTE "${${var}}")
        string(REPLACE "${CMAKE_INSTALL_PREFIX}" "\${PACKAGE_PREFIX_DIR}"
                        PACKAGE_${var} "${${var}}")
      else()
        set(PACKAGE_${var} "\${PACKAGE_PREFIX_DIR}/${${var}}")
      endif()
    endif()
  endforeach()

  get_filename_component(inputFileName "${_inputFile}" NAME)

  set(PACKAGE_INIT "
####### Expanded from @PACKAGE_INIT@ by configure_package_config_file() (ECM variant) #######
####### Any changes to this file will be overwritten by the next CMake run            #######
####### The input file was ${inputFileName}                                           #######

get_filename_component(PACKAGE_PREFIX_DIR \"\${CMAKE_CURRENT_LIST_DIR}/${PACKAGE_RELATIVE_PATH}\" ABSOLUTE)
")

  if("${absInstallDir}" MATCHES "^(/usr)?/lib(64)?/.+")
    # Handle "/usr move" symlinks created by some Linux distros.
    set(PACKAGE_INIT "${PACKAGE_INIT}
# Use original install prefix when loaded through a \"/usr move\"
# cross-prefix symbolic link such as /lib -> /usr/lib.
get_filename_component(_realCurr \"\${CMAKE_CURRENT_LIST_DIR}\" REALPATH)
get_filename_component(_realOrig \"${absInstallDir}\" REALPATH)
if(_realCurr STREQUAL _realOrig)
  set(PACKAGE_PREFIX_DIR \"${CMAKE_INSTALL_PREFIX}\")
endif()
unset(_realOrig)
unset(_realCurr)
")
  endif()

  if(NOT CCF_NO_SET_AND_CHECK_MACRO)
    set(PACKAGE_INIT "${PACKAGE_INIT}
macro(set_and_check _var _file)
  set(\${_var} \"\${_file}\")
  if(NOT EXISTS \"\${_file}\")
    message(FATAL_ERROR \"File or directory \${_file} referenced by variable \${_var} does not exist !\")
  endif()
endmacro()

include(CMakeFindDependencyMacro OPTIONAL RESULT_VARIABLE _CMakeFindDependencyMacro_FOUND)

if (NOT _CMakeFindDependencyMacro_FOUND)
  macro(find_dependency dep)
    if (NOT \${dep}_FOUND)

      set(ecm_fd_version)
      if (\${ARGC} GREATER 1)
        set(ecm_fd_version \${ARGV1})
      endif()
      set(ecm_fd_exact_arg)
      if(\${CMAKE_FIND_PACKAGE_NAME}_FIND_VERSION_EXACT)
        set(ecm_fd_exact_arg EXACT)
      endif()
      set(ecm_fd_quiet_arg)
      if(\${CMAKE_FIND_PACKAGE_NAME}_FIND_QUIETLY)
        set(ecm_fd_quiet_arg QUIET)
      endif()
      set(ecm_fd_required_arg)
      if(\${CMAKE_FIND_PACKAGE_NAME}_FIND_REQUIRED)
        set(ecm_fd_required_arg REQUIRED)
      endif()

      find_package(\${dep} \${ecm_fd_version}
          \${ecm_fd_exact_arg}
          \${ecm_fd_quiet_arg}
          \${ecm_fd_required_arg}
      )

      if (NOT \${dep}_FOUND)
        set(\${CMAKE_FIND_PACKAGE_NAME}_NOT_FOUND_MESSAGE \"\${CMAKE_FIND_PACKAGE_NAME} could not be found because dependency \${dep} could not be found.\")
        set(\${CMAKE_FIND_PACKAGE_NAME}_FOUND False)
        return()
      endif()

      set(ecm_fd_version)
      set(ecm_fd_required_arg)
      set(ecm_fd_quiet_arg)
      set(ecm_fd_exact_arg)
    endif()
  endmacro()
endif()

")
  endif()


  if(NOT CCF_NO_CHECK_REQUIRED_COMPONENTS_MACRO)
    set(PACKAGE_INIT "${PACKAGE_INIT}
macro(check_required_components _NAME)
  foreach(comp \${\${_NAME}_FIND_COMPONENTS})
    if(NOT \${_NAME}_\${comp}_FOUND)
      if(\${_NAME}_FIND_REQUIRED_\${comp})
        set(\${_NAME}_FOUND FALSE)
      endif()
    endif()
  endforeach()
endmacro()
")
  endif()

  set(PACKAGE_INIT "${PACKAGE_INIT}
####################################################################################")

  configure_file("${_inputFile}" "${_outputFile}" @ONLY)

endfunction()
# SPDX-FileCopyrightText: 2007-2009 Kitware, Inc.
# SPDX-FileCopyrightText: 2007 Alexander Neundorf <neundorf@kde.org>
# SPDX-FileCopyrightText: 2014 Aurélien Gâteau <agateau@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
ECMPoQmTools
------------

This module provides the ``ecm_process_po_files_as_qm`` and
``ecm_install_po_files_as_qm`` functions for generating QTranslator (.qm)
catalogs from Gettext (.po) catalogs, and the ``ecm_create_qm_loader``
function for generating the necessary code to load them in a Qt application
or library.

::

  ecm_process_po_files_as_qm(<lang> [ALL]
                             [INSTALL_DESTINATION <install_destination>]
                             PO_FILES <pofile> [<pofile> [...]])

Compile .po files into .qm files for the given language.

If ``INSTALL_DESTINATION`` is given, the .qm files are installed in
``<install_destination>/<lang>/LC_MESSAGES``. Typically,
``<install_destination>`` is set to ``share/locale``.

``ecm_process_po_files_as_qm`` creates a "translations" target. This target
builds all .po files into .qm files.  If ``ALL`` is specified, these rules are
added to the "all" target (and so the .qm files will be built by default).

::

  ecm_create_qm_loader(<sources_var_name(|target (since 5.83))> <catalog_name>)

Generates C++ code which ensures translations are automatically loaded at
startup. The generated files are appended to the variable named
``<sources_var_name>`` or, if the first argument is a target (since 5.83), to
the ``SOURCES`` property of ``<target>``. Any target must be created with
``add_executable()`` or ``add_library()`` and not be an alias.

It assumes that the .qm file for the language code ``<lang>`` is installed as
``<sharedir>/locale/<lang>/LC_MESSAGES/<catalog_name>.qm``, where
``<sharedir>`` is one of the directories given by the ``GenericDataLocation``
of ``QStandardPaths``.

Typical usage is like:

.. code-block:: cmake

  set(mylib_SRCS foo.cpp bar.cpp)
  ecm_create_qm_loader(mylib_SRCS mycatalog)
  add_library(mylib ${mylib_SRCS})

  # Or, since 5.83:
  add_library(mylib foo.cpp bar.cpp)
  ecm_create_qm_loader(mylib mycatalog)

::

  ecm_install_po_files_as_qm(<podir>)

Searches for .po files and installs them to the standard location.

This is a convenience function which relies on all .po files being kept in
``<podir>/<lang>/``, where ``<lang>`` is the language the .po files are
written in.

For example, given the following directory structure::

 po/
   fr/
     mylib.po

``ecm_install_po_files_as_qm(po)`` compiles ``mylib.po`` into ``mylib.qm`` and
installs it in ``<install_destination>/fr/LC_MESSAGES``.
``<install_destination>`` defaults to ``${LOCALE_INSTALL_DIR}`` if defined,
otherwise it uses ``${CMAKE_INSTALL_LOCALEDIR}`` if that is defined, otherwise
it uses ``share/locale``.

Since pre-1.0.0.
#]=======================================================================]

include(${CMAKE_CURRENT_LIST_DIR}/QtVersionOption.cmake)
option(KF_SKIP_PO_PROCESSING "Skip processing of po files" OFF)

# Copied from FindGettext.cmake
function(_ecm_qm_get_unique_target_name _name _unique_name)
   set(propertyName "_ECM_QM_UNIQUE_COUNTER_${_name}")
   get_property(currentCounter GLOBAL PROPERTY "${propertyName}")
   if(NOT currentCounter)
      set(currentCounter 1)
   endif()
   set(${_unique_name} "${_name}_${currentCounter}" PARENT_SCOPE)
   math(EXPR currentCounter "${currentCounter} + 1")
   set_property(GLOBAL PROPERTY ${propertyName} ${currentCounter} )
endfunction()


function(ecm_create_qm_loader sourcesvar_or_target catalog_name)
    if (TARGET ${sourcesvar_or_target})
        get_target_property(target_type ${sourcesvar_or_target} TYPE)
        set(allowed_types "EXECUTABLE" "STATIC_LIBRARY" "MODULE_LIBRARY" "SHARED_LIBRARY" "OBJECT_LIBRARY" "INTERFACE_LIBRARY")
        if (NOT target_type IN_LIST allowed_types)
            message(FATAL_ERROR "Target argument passed to ecm_create_qm_loader is not an executable or a library: ${appsources_or_target}")
        endif()
        get_target_property(aliased_target ${sourcesvar_or_target} ALIASED_TARGET)
        if(aliased_target)
            message(FATAL_ERROR "Target argument passed to ecm_create_qm_loader must not be an alias: ${sourcesvar_or_target}")
        endif()
    endif()
    set(loader_base ${CMAKE_CURRENT_BINARY_DIR}/ECMQmLoader-${catalog_name})

    set(QM_LOADER_CATALOG_NAME "${catalog_name}")

    set(QM_LOADER_CPP_FILE "${loader_base}.cpp")
    configure_file(
        ${ECM_MODULE_DIR}/ECMQmLoader.cpp.in
        ${QM_LOADER_CPP_FILE}
        @ONLY
    )
    if (TARGET ${sourcesvar_or_target})
        target_sources(${sourcesvar_or_target} PRIVATE ${QM_LOADER_CPP_FILE})
    else()
        set(${sourcesvar_or_target} "${${sourcesvar_or_target}}" ${QM_LOADER_CPP_FILE} PARENT_SCOPE)
    endif()
endfunction()


function(ecm_process_po_files_as_qm lang)
    if (KF_SKIP_PO_PROCESSING)
      return()
    endif()
    # Parse arguments
    set(options ALL)
    set(oneValueArgs INSTALL_DESTINATION)
    set(multiValueArgs PO_FILES)
    cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

    if(ARGS_UNPARSED_ARGUMENTS)
        message(FATAL_ERROR "Unknown keywords given to ecm_process_po_files_as_qm(): \"${ARGS_UNPARSED_ARGUMENTS}\"")
    endif()

    if(NOT ARGS_PO_FILES)
        message(FATAL_ERROR "ecm_process_po_files_as_qm() must be called with PO_FILES argument")
    endif()

    # Find lrelease and lconvert
    if (QT_MAJOR_VERSION EQUAL "5")
        find_package(Qt5LinguistTools CONFIG REQUIRED)
    else()
        find_package(Qt6 COMPONENTS LinguistTools CONFIG REQUIRED)
    endif()

    if(TARGET Qt${QT_MAJOR_VERSION}::lconvert)
        set(lconvert_executable Qt${QT_MAJOR_VERSION}::lconvert)
    else()
        # Qt < 5.3.1 does not define Qt5::lconvert
        get_target_property(lrelease_location Qt5::lrelease LOCATION)
        get_filename_component(lrelease_path ${lrelease_location} PATH)
        find_program(lconvert_executable
            NAMES lconvert-qt5 lconvert
            PATHS ${lrelease_path}
            NO_DEFAULT_PATH
            )
    endif()

    # Create commands to turn po files into qm files
    set(qm_files)
    foreach (po_file ${ARGS_PO_FILES})
        get_filename_component(po_file ${po_file} ABSOLUTE)
        get_filename_component(filename_base ${po_file} NAME_WE)

        # Use own ECMPoQm/ subfolder for processing the files, to avoid cluttering
        # the default build dir as well as potential file/dir name clashes from
        # other build artifacts.
        # Include ${lang} in build dir because we might be called multiple times
        # with the same ${filename_base}
        set(build_dir ${CMAKE_CURRENT_BINARY_DIR}/ECMPoQm/${lang})
        set(ts_file ${build_dir}/${filename_base}.ts)
        set(qm_file ${build_dir}/${filename_base}.qm)

        file(MAKE_DIRECTORY ${build_dir})

        # lconvert from .po to .ts, then lrelease from .ts to .qm.
        add_custom_command(OUTPUT ${qm_file}
            COMMAND ${lconvert_executable}
                ARGS -i ${po_file} -o ${ts_file} -target-language ${lang}
            COMMAND Qt${QT_MAJOR_VERSION}::lrelease
                ARGS -removeidentical -nounfinished -silent ${ts_file} -qm ${qm_file}
            DEPENDS ${po_file}
            )
        if (ARGS_INSTALL_DESTINATION)
            install(
                FILES ${qm_file}
                DESTINATION ${ARGS_INSTALL_DESTINATION}/${lang}/LC_MESSAGES
            )
        endif()
        list(APPEND qm_files ${qm_file})
    endforeach()

    # Hook qm files to targets
    if(NOT TARGET translations)
        add_custom_target(translations)
    endif()

    _ecm_qm_get_unique_target_name(translations target_name)

    if (ARGS_ALL)
        add_custom_target(${target_name} ALL DEPENDS ${qm_files})
    else()
        add_custom_target(${target_name} DEPENDS ${qm_files})
    endif()

    add_dependencies(translations ${target_name})
endfunction()


function(ecm_install_po_files_as_qm podir)
    if (LOCALE_INSTALL_DIR)
        set(install_destination "${LOCALE_INSTALL_DIR}")
    elseif (CMAKE_INSTALL_LOCALEDIR)
        set(install_destination "${CMAKE_INSTALL_LOCALEDIR}")
    else()
        set(install_destination share/locale)
    endif()

    get_filename_component(absolute_podir ${podir} ABSOLUTE)

    # we try to find the po directory in the binary directory, in case it was downloaded
    # using ECM
    if (NOT (EXISTS "${absolute_podir}" AND IS_DIRECTORY "${absolute_podir}"))
        get_filename_component(absolute_podir ${CMAKE_BINARY_DIR}/${podir} ABSOLUTE)
    endif()

    if (NOT (EXISTS "${absolute_podir}" AND IS_DIRECTORY "${absolute_podir}"))
        # Nothing to do if there's no podir and it would create an empty
        # LOCALE_INSTALL_DIR in that case.
        return()
    endif()

    file(GLOB po_files "${absolute_podir}/*/*.po")
    foreach(po_file ${po_files})
        get_filename_component(po_dir ${po_file} DIRECTORY)
        get_filename_component(lang ${po_dir} NAME)
        ecm_process_po_files_as_qm(
            ${lang} ALL
            PO_FILES ${po_file}
            INSTALL_DESTINATION ${install_destination}
        )
    endforeach()
endfunction()
#
# SPDX-FileCopyrightText: 2021 Arjen Hiemstra <ahiemstra@heimr.nl>
#
# SPDX-License-Identifier: BSD-3-Clause

if (${ECM_GLOBAL_FIND_VERSION} VERSION_GREATER_EQUAL 5.88)
    message(DEPRECATION "ECMQMLModules.cmake is deprecated since 5.88.0, please use ECMFindQmlModule.cmake instead")
endif()

include(ECMFindQmlModule)
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
PROJECT_NAME           = @ECM_QCH_DOXYGEN_PROJECTNAME@
PROJECT_NUMBER         = @ECM_QCH_DOXYGEN_PROJECTVERSION@
OUTPUT_DIRECTORY       = @ECM_QCH_DOXYGEN_OUTPUTDIR@
GENERATE_TAGFILE       = @ECM_QCH_DOXYGEN_TAGFILE@
CREATE_SUBDIRS         = NO
OUTPUT_LANGUAGE        = English
BRIEF_MEMBER_DESC      = YES
REPEAT_BRIEF           = YES
ABBREVIATE_BRIEF       = "The \$name class" \
                         "The \$name widget" \
                         "The \$name file" \
                         is \
                         provides \
                         specifies \
                         contains \
                         represents \
                         a \
                         an \
                         the
ALWAYS_DETAILED_SEC    = YES
INLINE_INHERITED_MEMB  = NO
FULL_PATH_NAMES        = NO
STRIP_FROM_PATH        = 
STRIP_FROM_INC_PATH    = 
SHORT_NAMES            = NO
# Do not require explicitly @brief command for brief description
JAVADOC_AUTOBRIEF      = YES
MULTILINE_CPP_IS_BRIEF = NO
INHERIT_DOCS           = YES
SEPARATE_MEMBER_PAGES  = NO
TAB_SIZE               = 8
OPTIMIZE_OUTPUT_FOR_C  = NO
OPTIMIZE_OUTPUT_JAVA   = NO
BUILTIN_STL_SUPPORT    = NO
DISTRIBUTE_GROUP_DOC   = NO
SUBGROUPING            = YES
LAYOUT_FILE            = @ECM_QCH_DOXYGEN_LAYOUTFILE@
# Dark colors won't look nice in Qt Assistant
HTML_COLORSTYLE        = LIGHT
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
EXTRACT_ALL            = NO
EXTRACT_PRIVATE        = NO
EXTRACT_STATIC         = YES
EXTRACT_LOCAL_CLASSES  = NO
EXTRACT_LOCAL_METHODS  = NO
EXTRACT_ANON_NSPACES   = NO
# Require classes to be documented to appear in apidox, but always document all
# public and protected members (even if static)
HIDE_UNDOC_MEMBERS     = NO
HIDE_UNDOC_CLASSES     = YES
HIDE_FRIEND_COMPOUNDS  = YES
HIDE_IN_BODY_DOCS      = NO
INTERNAL_DOCS          = NO
CASE_SENSE_NAMES       = YES
HIDE_SCOPE_NAMES       = NO
SHOW_INCLUDE_FILES     = YES
HIDE_COMPOUND_REFERENCE = YES
INLINE_INFO            = YES
SORT_MEMBER_DOCS       = YES
SORT_MEMBERS_CTORS_1ST = YES
SORT_BRIEF_DOCS        = YES
SORT_BY_SCOPE_NAME     = NO
GENERATE_TODOLIST      = NO
GENERATE_TESTLIST      = NO
GENERATE_BUGLIST       = NO
GENERATE_DEPRECATEDLIST = YES
ENABLED_SECTIONS       = 
MAX_INITIALIZER_LINES  = 30
SHOW_USED_FILES        = NO
SHOW_FILES             = YES
FILE_VERSION_FILTER    = 
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
#---------------------------------------------------------------------------
QUIET                  = @ECM_QCH_DOXYGEN_QUIET@
WARNINGS               = YES
WARN_IF_UNDOCUMENTED   = YES
WARN_IF_DOC_ERROR      = YES
WARN_NO_PARAMDOC       = YES
WARN_FORMAT            = "\$file:\$line: \$text"
WARN_LOGFILE           = @ECM_QCH_DOXYGEN_WARN_LOGFILE@
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
INPUT                  = @ECM_QCH_DOXYGEN_INPUT@
FILE_PATTERNS          = @ECM_QCH_DOXYGEN_FILE_PATTERNS@
RECURSIVE              = YES
EXCLUDE                = 
EXCLUDE_SYMLINKS       = NO
EXCLUDE_PATTERNS       = */.svn/* \
                         */.git/* \
                         */cmake/* \
                         *.moc.* \
                         moc* \
                         *.all_cpp.* \
                         *unload.* \
                         */test/* \
                         */tests/* \
                         */autotests/* \
                         *_p.cpp \
                         *_p.h
# Symbols from Qt that show up occassionlly and we don't want to see
EXCLUDE_SYMBOLS        = iterator const_iterator
EXAMPLE_PATH           = @ECM_QCH_DOXYGEN_EXAMPLEDIRS@
EXAMPLE_PATTERNS       = *
EXAMPLE_RECURSIVE      = YES
IMAGE_PATH             = @ECM_QCH_DOXYGEN_IMAGEDIRS@
INPUT_FILTER           = 
FILTER_PATTERNS        = 
FILTER_SOURCE_FILES    = NO
USE_MDFILE_AS_MAINPAGE = @ECM_QCH_DOXYGEN_MAINPAGE_MDFILE@
#---------------------------------------------------------------------------
# configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
ALPHABETICAL_INDEX     = NO
#---------------------------------------------------------------------------
# do NOT generate any formats other than qhp
#---------------------------------------------------------------------------
SOURCE_BROWSER         = NO
GENERATE_HTML          = YES
GENERATE_LATEX         = NO
GENERATE_MAN           = NO
GENERATE_RTF           = NO
GENERATE_XML           = NO
GENERATE_AUTOGEN_DEF   = NO
GENERATE_PERLMOD       = NO
DISABLE_INDEX          = YES
HTML_DYNAMIC_SECTIONS  = NO
#---------------------------------------------------------------------------
# configuration options related to the qhp output
#---------------------------------------------------------------------------
GENERATE_QHP           = YES
QCH_FILE               = @ECM_QCH_DOXYGEN_FILEPATH@
QHP_NAMESPACE          = @ECM_QCH_DOXYGEN_FULLNAMESPACE@
QHP_VIRTUAL_FOLDER     = @ECM_QCH_DOXYGEN_VIRTUALFOLDER@
QHG_LOCATION           = @ECM_QCH_DOXYGEN_QHELPGENERATOR_EXECUTABLE@
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor   
#---------------------------------------------------------------------------
ENABLE_PREPROCESSING   = YES
MACRO_EXPANSION        = YES
EXPAND_ONLY_PREDEF     = NO
SEARCH_INCLUDES        = YES
INCLUDE_PATH           = @ECM_QCH_DOXYGEN_INCLUDE_PATH@
INCLUDE_FILE_PATTERNS  = 
EXPAND_AS_DEFINED      = 
SKIP_FUNCTION_MACROS   = YES
#---------------------------------------------------------------------------
# Configuration::additions related to external references   
#---------------------------------------------------------------------------
ALLEXTERNALS           = NO
EXTERNAL_GROUPS        = YES
TAGFILES               = @ECM_QCH_DOXYGEN_TAGFILES@
#---------------------------------------------------------------------------
# Configuration options related to the dot tool   
#---------------------------------------------------------------------------
CLASS_DIAGRAMS         = NO
HIDE_UNDOC_RELATIONS   = YES
HAVE_DOT               = NO
CLASS_GRAPH            = NO
COLLABORATION_GRAPH    = NO
GROUP_GRAPHS           = NO
UML_LOOK               = NO
TEMPLATE_RELATIONS     = NO
INCLUDE_GRAPH          = NO
INCLUDED_BY_GRAPH      = NO
CALL_GRAPH             = NO
CALLER_GRAPH           = NO
GRAPHICAL_HIERARCHY    = NO
DIRECTORY_GRAPH        = NO
GENERATE_LEGEND        = NO
#---------------------------------------------------------------------------
# Configuration::additions related to the search engine   
#---------------------------------------------------------------------------
SEARCHENGINE           = NO


### KDE Settings
ALIASES                = "intern=\par<b>Internal use only.</b>" \
                         "reimp=\par<b>Reimplemented from superclass.</b>" \
                         "obsolete=@deprecated" \
                         "feature=\xrefitem features \"Feature(s)\" \"Features\"" \
                         "unmaintained=\xrefitem unmaintained \"Unmaintained\" \"Unmaintained\"" \
                         "requirement=\xrefitem requirements \"Requirement(s)\" \"Requirements\"" \
                         "faq=\xrefitem FAQ \"F.A.Q.\" \"F.A.Q.\"" \
                         "authors=\xrefitem authors \"Author(s)\" \"Authors\"" \
                         "maintainers=\xrefitem maintainers \"Maintainer(s)\" \"Maintainers\"" \
                         "glossary=\xrefitem glossary \"Glossary\" \"Glossary\"" \
                         "acronym=\b " \
                         "licenses=\xrefitem licenses \"License(s)\" \"Licenses\"" \
                         "FIXME=\xrefitem fixme \"Fixme\" \"Fixme\"" \
                         "bc=\xrefitem bc \"Binary Compatible\" \"Binary Compatible\"" \
                         "threadsafe=\xrefitem threadsafe \"Threadsafe\" \"Threadsafe\"" \
                         "artistic=<a href=\"https://opensource.org/licenses/artistic-license.php\">Artistic</a>" \
                         "bsd=<a href=\"https://www.xfree86.org/3.3.6/COPYRIGHT2.html#5\">BSD</a>" \
                         "x11=<a href=\"https://www.xfree86.org/3.3.6/COPYRIGHT2.html#3\">X11</a>" \
                         "gpl=<a href=\"https://www.gnu.org/licenses/old-licenses/gpl-2.0.html#SEC1\">GPLv2</a>" \
                         "lgpl=<a href=\"https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html#SEC1\">LGPLv2</a>" \
                         "mit=<a href=\"https://www.opensource.org/licenses/mit-license.php\">MIT</a>" \
                         "qpl=<a href=\"https://opensource.org/licenses/QPL-1.0\">QPL</a>"

# K_DOXYGEN set to have preprocessor macros know that kapidox/doxygen processes them
# DOXYGEN_SHOULD_SKIP_THIS is the deprecated variant (remove for KF6)
PREDEFINED = DOXYGEN_SHOULD_SKIP_THIS \
        K_DOXYGEN \
\
        Q_WS_X11= \
        Q_WS_WIN= \
        Q_WS_MAC= \
        Q_WS_QWS= \
        Q_WS_MAEMO_5= \
        Q_OS_LINUX= \
        Q_OS_UNIX= \
        Q_OS_WIN= \
        Q_OS_MAC= \
        Q_OS_MACX= \
        Q_OS_DARWIN= \
        Q_OS_FREEBSD= \
        Q_OS_NETBSD= \
        Q_OS_OPENBSD= \
        Q_OS_BSD4= \
        Q_OS_SOLARIS= \
        Q_OS_IRIX= \
\
        Q_SLOTS=slots \
        Q_SIGNALS=signals \
        "Q_DECLARE_FLAGS(Flags, Enum)=typedef QFlags<Enum> Flags;" \
        Q_DECL_CONSTEXPR=constexpr \
        Q_DECL_RELAXED_CONSTEXPR= \
        Q_DECL_OVERRIDE=override \
        Q_DECL_FINAL=final \
        "Q_DECL_EQ_DEFAULT= = default" \
        "Q_DECL_EQ_DELETE= = delete" \
        Q_DECL_NOEXCEPT= \
        Q_DECL_DEPRECATED= \
        Q_DECL_UNUSED_MEMBER= \
        Q_DECL_VARIABLE_DEPRECATED= \
        Q_DECL_EXPORT= \
        Q_DECL_IMPORT= \
        Q_DECL_HIDDEN= \
        Q_DECL_NULLPTR=nullptr \
        Q_REQUIRED_RESULT= \
        Q_SCRIPTABLE= \
        Q_INVOKABLE= \
        @ECM_QCH_DOXYGEN_PREDEFINED_MACROS@ \
        @ECM_QCH_DOXYGEN_BLANK_MACROS@
<doxygenlayout version="1.0">
  <!-- Generated by doxygen 1.8.7 -->
  <!-- Navigation index tabs for HTML output -->
  <navindex>
    <tab type="mainpage" visible="yes" title=""/>
    <tab type="pages" visible="yes" title="" intro=""/>
    <tab type="modules" visible="yes" title="" intro=""/>
    <tab type="namespaces" visible="yes" title="">
      <tab type="namespacelist" visible="yes" title="" intro=""/>
      <tab type="namespacemembers" visible="yes" title="" intro=""/>
    </tab>
    <tab type="classes" visible="yes" title="">
      <tab type="classlist" visible="yes" title="" intro=""/>
      <tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/> 
      <tab type="hierarchy" visible="yes" title="" intro=""/>
      <tab type="classmembers" visible="yes" title="" intro=""/>
    </tab>
    <tab type="files" visible="yes" title="">
      <tab type="filelist" visible="yes" title="" intro=""/>
      <tab type="globals" visible="yes" title="" intro=""/>
    </tab>
    <tab type="examples" visible="yes" title="" intro=""/>  
  </navindex>

  <!-- Layout definition for a class page -->
  <class>
    <briefdescription visible="yes"/>
    <includes visible="$SHOW_INCLUDE_FILES"/>
    <inheritancegraph visible="$CLASS_GRAPH"/>
    <collaborationgraph visible="$COLLABORATION_GRAPH"/>
    <memberdecl>
      <nestedclasses visible="yes" title=""/>
      <publictypes title=""/>
      <services title=""/>
      <interfaces title=""/>
      <properties title=""/>
      <signals title=""/>
      <publicslots title=""/>
      <publicmethods title=""/>
      <publicstaticmethods title=""/>
      <publicattributes title=""/>
      <publicstaticattributes title=""/>
      <protectedtypes title=""/>
      <protectedslots title=""/>
      <protectedmethods title=""/>
      <protectedstaticmethods title=""/>
      <protectedattributes title=""/>
      <protectedstaticattributes title=""/>
      <packagetypes title=""/>
      <packagemethods title=""/>
      <packagestaticmethods title=""/>
      <packageattributes title=""/>
      <packagestaticattributes title=""/>
      <events title=""/>
      <privatetypes title=""/>
      <privateslots title=""/>
      <privatemethods title=""/>
      <privatestaticmethods title=""/>
      <privateattributes title=""/>
      <privatestaticattributes title=""/>
      <friends title=""/>
      <related title="" subtitle=""/>
      <membergroups visible="yes"/>
    </memberdecl>
    <detaileddescription title=""/>
    <memberdef>
      <inlineclasses title=""/>
      <typedefs title=""/>
      <enums title=""/>
      <properties title=""/>
      <services title=""/>
      <interfaces title=""/>
      <constructors title=""/>
      <functions title=""/>
      <related title=""/>
      <variables title=""/>
      <events title=""/>
    </memberdef>
    <allmemberslink visible="yes"/>
    <usedfiles visible="$SHOW_USED_FILES"/>
    <authorsection visible="yes"/>
  </class>

  <!-- Layout definition for a namespace page -->
  <namespace>
    <briefdescription visible="yes"/>
    <memberdecl>
      <nestednamespaces visible="yes" title=""/>
      <constantgroups visible="yes" title=""/>
      <classes visible="yes" title=""/>
      <typedefs title=""/>
      <enums title=""/>
      <functions title=""/>
      <variables title=""/>
      <membergroups visible="yes"/>
    </memberdecl>
    <detaileddescription title=""/>
    <memberdef>
      <inlineclasses title=""/>
      <typedefs title=""/>
      <enums title=""/>
      <functions title=""/>
      <variables title=""/>
    </memberdef>
    <authorsection visible="yes"/>
  </namespace>

  <!-- Layout definition for a file page -->
  <file>
    <briefdescription visible="yes"/>
    <includes visible="no"/>
    <includegraph visible="$INCLUDE_GRAPH"/>
    <includedbygraph visible="$INCLUDED_BY_GRAPH"/>
    <sourcelink visible="no"/>
    <memberdecl>
      <classes visible="yes" title=""/>
      <namespaces visible="yes" title=""/>
      <constantgroups visible="yes" title=""/>
      <defines title=""/>
      <typedefs title=""/>
      <enums title=""/>
      <functions title=""/>
      <variables title=""/>
      <membergroups visible="yes"/>
    </memberdecl>
    <detaileddescription title=""/>
    <memberdef>
      <inlineclasses title=""/>
      <defines title=""/>
      <typedefs title=""/>
      <enums title=""/>
      <functions title=""/>
      <variables title=""/>
    </memberdef>
    <authorsection/>
  </file>

  <!-- Layout definition for a group page -->
  <group>
    <briefdescription visible="yes"/>
    <groupgraph visible="$GROUP_GRAPHS"/>
    <memberdecl>
      <nestedgroups visible="yes" title=""/>
      <dirs visible="yes" title=""/>
      <files visible="yes" title=""/>
      <namespaces visible="yes" title=""/>
      <classes visible="yes" title=""/>
      <defines title=""/>
      <typedefs title=""/>
      <enums title=""/>
      <enumvalues title=""/>
      <functions title=""/>
      <variables title=""/>
      <signals title=""/>
      <publicslots title=""/>
      <protectedslots title=""/>
      <privateslots title=""/>
      <events title=""/>
      <properties title=""/>
      <friends title=""/>
      <membergroups visible="yes"/>
    </memberdecl>
    <detaileddescription title=""/>
    <memberdef>
      <pagedocs/>
      <inlineclasses title=""/>
      <defines title=""/>
      <typedefs title=""/>
      <enums title=""/>
      <enumvalues title=""/>
      <functions title=""/>
      <variables title=""/>
      <signals title=""/>
      <publicslots title=""/>
      <protectedslots title=""/>
      <privateslots title=""/>
      <events title=""/>
      <properties title=""/>
      <friends title=""/>
    </memberdef>
    <authorsection visible="yes"/>
  </group>

  <!-- Layout definition for a directory page -->
  <directory>
    <briefdescription visible="yes"/>
    <directorygraph visible="yes"/>
    <memberdecl>
      <dirs visible="yes"/>
      <files visible="yes"/>
    </memberdecl>
    <detaileddescription title=""/>
  </directory>
</doxygenlayout>
/* This file was generated by ecm_create_qm_loader(). DO NOT EDIT!
 *
 * Building this file in a library ensures translations are automatically loaded
 * when an application makes use of the library.
 *
 *
 * SPDX-FileCopyrightText: 2014 Aurélien Gâteau <agateau@kde.org>
 * SPDX-FileCopyrightText: 2015 Alex Merry <alex.merry@kde.org>
 * SPDX-FileCopyrightText: 2023 Ingo Klöcker <kloecker@kde.org>
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */
#include <QCoreApplication>
#include <QLocale>
#include <QStandardPaths>
#include <QThread>
#include <QTranslator>
#include <QDir>

namespace {

    static QLocale getSystemLocale()
    {
#if defined(Q_OS_WIN) || defined(Q_OS_MAC)
        // On Windows and Apple OSs, we cannot use QLocale::system() if an application-specific
        // language was set by kxmlgui because Qt ignores LANGUAGE on Windows and Apple OSs.
        // The following code is a simplified variant of QSystemLocale::fallbackUiLocale()
        // (in qlocale_unix.cpp) ignoring LC_ALL, LC_MESSAGES, and LANG.
        QString language = qEnvironmentVariable("LANGUAGE");
        if (!language.isEmpty()) {
            language = language.split(QLatin1Char{':'}).constFirst();
            if (!language.isEmpty()) {
                return QLocale{language};
            }
        }
#endif
        return QLocale::system();
    }

    enum class LoadOptions { CreateWatcher, DoNotCreateWatcher };

    void load(LoadOptions options);

    class LanguageChangeWatcher : public QObject
    {
    public:
        LanguageChangeWatcher(QObject *parent) : QObject(parent)
        {
            m_loadedLocale = getSystemLocale().name();
            QCoreApplication::instance()->installEventFilter(this);
        }

    private:
        bool eventFilter(QObject *obj, QEvent *event) override
        {
            if (event->type() == QEvent::LanguageChange) {
                const auto systemLocaleName = getSystemLocale().name();
                if (m_loadedLocale != systemLocaleName) {
                    m_loadedLocale = systemLocaleName;
                    load(LoadOptions::DoNotCreateWatcher);
                }
            }
            return QObject::eventFilter(obj, event);
        }


        QString m_loadedLocale;
    };

    bool loadTranslation(const QString &localeDirName)
    {
        QString subPath = QStringLiteral("locale/") + localeDirName + QStringLiteral("/LC_MESSAGES/@QM_LOADER_CATALOG_NAME@.qm");

#if defined(Q_OS_ANDROID)
        const QString fullPath = QStringLiteral("assets:/share/") + subPath;
        if (!QFile::exists(fullPath)) {
            return false;
        }
#else
        const QString fullPath = QStandardPaths::locate(QStandardPaths::GenericDataLocation, subPath);
        if (fullPath.isEmpty()) {
            return false;
        }
#endif
        QTranslator *translator = new QTranslator(QCoreApplication::instance());
        if (!translator->load(fullPath)) {
            delete translator;
            return false;
        }
        QCoreApplication::instance()->installTranslator(translator);
        return true;
    }

    void load(LoadOptions options)
    {
        // The way Qt translation system handles plural forms makes it necessary to
        // have a translation file which contains only plural forms for `en`. That's
        // why we load the `en` translation unconditionally, then load the
        // translation for the current locale to overload it.
        loadTranslation(QStringLiteral("en"));

        auto langs = getSystemLocale().uiLanguages();
        for (auto it = langs.begin(); it != langs.end(); ++it) {
            (*it).replace(QLatin1Char('-'), QLatin1Char('_'));
            const auto idx = (*it).indexOf(QLatin1Char('_'));
            if (idx > 0) {
                const QString genericLang = (*it).left(idx);
                it = langs.insert(++it, genericLang);
            }
        }
        langs.removeDuplicates();
        for (const auto &lang : langs) {
            if (lang == QLatin1String("en") || loadTranslation(lang)) {
                break;
            }
        }

        if (options == LoadOptions::CreateWatcher) {
            new LanguageChangeWatcher(QCoreApplication::instance());
        }
    }

    void loadOnMainThread()
    {
        // If this library is loaded after the QCoreApplication instance is
        // created (eg: because it is brought in by a plugin), there is no
        // guarantee this function will be called on the main thread.
        // QCoreApplication::installTranslator needs to be called on the main
        // thread, because it uses QCoreApplication::sendEvent.
        if (QThread::currentThread() == QCoreApplication::instance()->thread()) {
            load(LoadOptions::CreateWatcher);
        } else {
            QMetaObject::invokeMethod(QCoreApplication::instance(), [] { load(LoadOptions::CreateWatcher); }, Qt::QueuedConnection);
        }
    }
}

Q_COREAPP_STARTUP_FUNCTION(loadOnMainThread)
#
# SPDX-FileCopyrightText: 2021 Arjen Hiemstra <ahiemstra@heimr.nl>
#
# SPDX-License-Identifier: BSD-3-Clause

#[========================================================================[.rst:
ECMQmlModule
------------

This file contains helper functions to make it easier to create QML modules. It
takes care of a number of things that often need to be repeated. It also takes
care of special handling of QML modules between shared and static builds. When
building a static version of a QML module, the relevant QML source files are
bundled into the static library. When using a shared build, the QML plugin and
relevant QML files are copied to the target's ``RUNTIME_OUTPUT_DIRECTORY`` to make
it easier to run things directly from the build directory.

Since 6.0.0, when using Qt 6, most functionality of this module has been
implemented by upstream Qt. Most of the functions here will now forward to the
similar Qt functions.

Example usage:

.. code-block:: cmake

    ecm_add_qml_module(ExampleModule URI "org.example.Example")

    target_sources(ExampleModule PRIVATE ExamplePlugin.cpp)
    target_link_libraries(ExampleModule PRIVATE Qt::Quick)

    ecm_target_qml_sources(ExampleModule SOURCES ExampleItem.qml) # This will have 1.0 as the default version
    ecm_target_qml_sources(ExampleModule SOURCES AnotherExampleItem.qml VERSION 1.5)

    ecm_finalize_qml_module(ExampleModule DESTINATION ${KDE_INSTALL_QMLDIR})


::

    ecm_add_qml_module(<target name>
        URI <module uri>
        [VERSION <module version>]
        [NO_PLUGIN] # Deprecated since 6.0.0 when using Qt 6
        [CLASSNAME <class name>] # Deprecated since 6.0.0 when using Qt 6, use CLASS_NAME instead
        [QT_NO_PLUGIN] # Since 6.0.0, when using Qt 6
        [GENERATE_PLUGIN_SOURCE] # Since 6.0.0, when using Qt 6
    )

This will declare a new CMake target called ``<target name>``. The ``URI``
argument is required and should be a proper QML module URI. The ``URI`` is used,
among others, to generate a subdirectory where the module will be installed to.

If the ``VERSION`` argument is specified, it is used to initialize the default
version that is used by  ``ecm_target_qml_sources`` when adding QML files. If it
is not specified, a  default of 1.0 is used. Additionally, if a version greater
than or equal to 2.0 is specified, the major version is appended to the
Qt5 installation path of the module.
In case you don't specify and version, but specify a version for the individual sources, the latest
will be set as the resulting version for this plugin. This will be used in the ECMFindQmlModule module.

If the option ``NO_PLUGIN`` is set, a target is declared that is not expected to
contain any C++ QML plugin.

If the optional ``CLASSNAME`` argument is supplied, it will be used as class
name in the generated QMLDIR file. If it is not specified, the target name will
be used instead.

You can add C++ and QML source files to the target using ``target_sources`` and
``ecm_target_qml_sources``, respectively.

Since 5.91.0

Since 6.0.0, when used with Qt 6, this will forward to ``qt_add_qml_module``. Any extra arguments will
be forwarded as well. The ``NO_PLUGIN`` argument is deprecated and implies ``GENERATE_PLUGIN_SOURCE``,
since modules in Qt 6 always require a plugin or backing target. If you want to use Qt's behaviour for
``NO_PLUGIN``, use ``QT_NO_PLUGIN`` instead. Additionally, to maintain backward compatibility, by
default we pass ``NO_GENERATE_PLUGIN_SOURCE`` to ``qt_add_qml_module``. To have Qt generate the plugin
sources, pass ``GENERATE_PLUGIN_SOURCE``.

::

    ecm_add_qml_module_dependencies(<target> DEPENDS <module string> [<module string> ...])

Add the list of dependencies specified by the ``DEPENDS`` argument to be listed
as dependencies in the generated QMLDIR file of ``<target>``.

Since 5.91.0

Since 6.0.0, this is deprecated and ignored when using Qt 6, instead use the
``DEPENDENCIES`` and ``IMPORTS`` arguments to ``ecm_add_qml_module``.

::

    ecm_target_qml_sources(<target> SOURCES <source.qml> [<source.qml> ...] [VERSION <version>] [PATH <path>] [PRIVATE])

Add the list of QML files specified by the ``SOURCES`` argument as source files
to the QML module target ``<target>``.

If the optional ``VERSION`` argument is specified, all QML files will be added
with the specified version. If it is not specified, they will use the version of
the QML module target.

If the optional ``PRIVATE`` argument is specified, the QML files will be
included in the target but not in the generated qmldir file. Any version
argument will be ignored.

The optional ``PATH`` argument declares a subdirectory of the module where the
files should be copied to. By default, files will be copied to the module root.

This function will fail if ``<target>`` is not a QML module target or any of the
specified files do not exist.

Since 5.91.0

Since 6.0.0, when used with Qt 6, this will forward to ``qt_target_qml_sources()``.
The ``SOURCES`` argument will be translated to ``QML_SOURCES``. ``VERSION`` and
``PRIVATE`` will set Qt's ``QT_QML_SOURCE_VERSIONS`` and ``QT_QML_INTERNAL_TYPE``
properties on ``SOURCES`` before calling ``qt_target_qml_sources()``. Since Qt
includes the path relative to the current source dir, for each source file a
resource alias will be generated with the path stripped. If the ``PATH`` argument
is set, it will be prefixed to the alias. Any additional arguments will be passed
to ``qt_target_qml_sources()``.

::

    ecm_finalize_qml_module(<target>
        [DESTINATION <QML install destination>] # Optional since 6.0
        [VERSION <Project Version>] # Added for 6.0 when using Qt 6
        [EXPORT <export-set>] # Added for 6.8 when using Qt 6
    )

Finalize the specified QML module target. This must be called after all other
setup (like adding sources) on the target has been done. It will perform a
number of tasks:

- It will generate a qmldir file from the QML files added to the target. If the
  module has a C++ plugin, this will also be included in the qmldir file.
- If ``BUILD_SHARED_LIBS`` is off, a QRC file is generated from the QML files
  added to the target. This QRC file will be included when compiling the C++ QML
  module. The built static library will be installed in a subdirection of
  ``DESTINATION`` based on the QML module's uri. If this value is not set, KDE_INSTALL_QMLDIR will be used.
  Note that if ``NO_PLUGIN`` is set, a C++ QML plugin will be generated to include the QRC files.
- If ``BUILD_SHARED_LIBS`` in on, all generated files, QML sources and the C++
  plugin will be installed in a subdirectory of ``DESTINATION`` based upon the
  QML module's uri. In addition, these files will also be copied to the target's
  ``RUNTIME_OUTPUT_DIRECTORY`` in a similar subdirectory.
- If ``BUILD_SHARED_LIBS`` is off, ``EXPORT`` allows to specify a CMake export set
  all installed targets should be added to.

This function will fail if ``<target>`` is not a QML module target.

Since 5.91.0

Since 6.0.0, when using Qt 6, this will instead install the files generated
by ``qt_add_qml_module``. The optional ``VERSION`` argument was added that will
default to ``PROJECT_VERSION`` and which will write a file that is used by
``ECMFindQmlModule`` to detect the version of the QML module.

Since 6.1.0

Enabling the option ``VERBOSE_QML_COMPILER`` will activate verbose output for qmlcachegen.

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

include(${CMAKE_CURRENT_LIST_DIR}/QtVersionOption.cmake)

# This is also used by ECMFindQmlModule, so needs to be available for both
# Qt 5 and Qt 6.
macro(_ecm_qmlmodule_uri_to_path ARG_OUTPUT ARG_PATH ARG_VERSION)
    string(REPLACE "." "/" _output "${ARG_PATH}")

    # If the major version of the module is >2.0, Qt expects a ".MajorVersion" suffix on the directory
    # However, we only need to do this in Qt5
    if ("${QT_MAJOR_VERSION}" STREQUAL "5" AND "${ARG_VERSION}" VERSION_GREATER_EQUAL 2.0)
        string(REGEX MATCH "^([0-9]+)" _version_major ${ARG_VERSION})
        set("${ARG_OUTPUT}" "${_output}.${_version_major}")
    else()
        set("${ARG_OUTPUT}" "${_output}")
    endif()
endmacro()

# The implementation for this has diverged significantly between Qt 5 and Qt 6
# so it has been split to separate files.
if ("${QT_MAJOR_VERSION}" STREQUAL "6")
    include(${CMAKE_CURRENT_LIST_DIR}/ECMQmlModule6.cmake)
elseif("${QT_MAJOR_VERSION}" STREQUAL "5")
    include(${CMAKE_CURRENT_LIST_DIR}/ECMQmlModule5.cmake)
else()
    message(FATAL_ERROR "Could not determine Qt major version")
endif()
// This file is autogenerated by ECMQmlModule to support static QML-only plugins.

#include "QmlModule.h"

#include <QQmlEngine>

void QmlModule::registerTypes(const char* uri)
{
    Q_ASSERT(QLatin1String(uri) == QLatin1String("@_qml_uri@"));
}
SPDX-FileCopyrightText: 2021 Arjen Hiemstra <ahiemstra@heimr.nl>
SPDX-License-Identifier: CC0-1.0
// This file is autogenerated by ECMQmlModule to support static QML-only plugins.

#ifndef QMLMODULE_H
#define QMLMODULE_H

#include <QQmlExtensionPlugin>

class QmlModule : public QQmlExtensionPlugin
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")

public:
    void registerTypes(const char* uri) override;
};

#endif
SPDX-FileCopyrightText: 2021 Arjen Hiemstra <ahiemstra@heimr.nl>
SPDX-License-Identifier: CC0-1.0
#
# SPDX-FileCopyrightText: 2021 Arjen Hiemstra <ahiemstra@heimr.nl>
#
# SPDX-License-Identifier: BSD-3-Clause

# Qt 5 implementation of ECMQmlModule

set(_ECM_QMLMODULE_STATIC_QMLONLY_H   "${CMAKE_CURRENT_LIST_DIR}/ECMQmlModule.h.in")
set(_ECM_QMLMODULE_STATIC_QMLONLY_CPP "${CMAKE_CURRENT_LIST_DIR}/ECMQmlModule.cpp.in")

set(_ECM_QMLMODULE_PROPERTY_URI "_ecm_qml_uri")
set(_ECM_QMLMODULE_PROPERTY_QMLDIR "_ecm_qmldir_file")
set(_ECM_QMLMODULE_PROPERTY_FILES "_ecm_qml_files")
set(_ECM_QMLMODULE_PROPERTY_QMLONLY "_ecm_qml_only")
set(_ECM_QMLMODULE_PROPERTY_VERSION "_ecm_qml_version")
set(_ECM_QMLMODULE_PROPERTY_PRIVATE "_ecm_qml_private")
set(_ECM_QMLMODULE_PROPERTY_PATH "_ecm_qml_path")
set(_ECM_QMLMODULE_PROPERTY_CLASSNAME "_ecm_qml_classname")
set(_ECM_QMLMODULE_PROPERTY_DEPENDS "_ecm_qml_depends")

macro(_ecm_qmlmodule_verify_qml_target ARG_TARGET)
    if (NOT TARGET ${ARG_TARGET})
        message(FATAL_ERROR "Target ${ARG_TARGET} does not exist")
    endif()
    get_target_property(_qml_uri ${ARG_TARGET} ${_ECM_QMLMODULE_PROPERTY_URI})
    if ("${_qml_uri}" STREQUAL "" OR "${_qml_uri}" STREQUAL "${_ECM_QMLMODULE_PROPERTY_URI}-NOTFOUND")
        message(FATAL_ERROR "Target ${ARG_TARGET} is not a QML plugin target")
    endif()
endmacro()

function(_ecm_qmlmodule_generate_qmldir ARG_TARGET)
    get_target_property(_qml_uri ${ARG_TARGET} ${_ECM_QMLMODULE_PROPERTY_URI})
    get_target_property(_qml_files ${ARG_TARGET} ${_ECM_QMLMODULE_PROPERTY_FILES})
    get_target_property(_qml_only ${ARG_TARGET} ${_ECM_QMLMODULE_PROPERTY_QMLONLY})
    get_target_property(_qml_classname ${ARG_TARGET} ${_ECM_QMLMODULE_PROPERTY_CLASSNAME})

    set(_qmldir_template "# This file was automatically generated by ECMQmlModule and should not be modified")

    string(APPEND _qmldir_template "\nmodule ${_qml_uri}")

    if (NOT ${_qml_only})
        string(APPEND _qmldir_template "\nplugin ${ARG_TARGET}")

        if ("${_qml_classname}" STREQUAL "")
            string(APPEND _qmldir_template "\nclassname ${ARG_TARGET}")
        else()
            string(APPEND _qmldir_template "\nclassname ${_qml_classname}")
        endif()
    endif()

    get_target_property(_qml_depends ${ARG_TARGET} ${_ECM_QMLMODULE_PROPERTY_DEPENDS})
    if (NOT "${_qml_depends}" STREQUAL "")
        foreach(_depends ${_qml_depends})
            string(APPEND _qmldir_template "\ndepends ${_depends}")
        endforeach()
    endif()

    foreach(_file ${_qml_files})
        get_filename_component(_filename ${_file} NAME)
        get_filename_component(_classname ${_file} NAME_WE)
        get_property(_version SOURCE ${_file} PROPERTY ${_ECM_QMLMODULE_PROPERTY_VERSION})
        get_property(_private SOURCE ${_file} PROPERTY ${_ECM_QMLMODULE_PROPERTY_PRIVATE})
        get_property(_singleton SOURCE ${_file} PROPERTY "QT_QML_SINGLETON_TYPE")
        get_property(_path SOURCE ${_file} PROPERTY ${_ECM_QMLMODULE_PROPERTY_PATH})
        cmake_path(SET _actual_path "${_path}")
        cmake_path(APPEND _actual_path "${_filename}")
        if (_singleton)
            string(APPEND _qmldir_template "\nsingleton ${_classname} ${_version} ${_actual_path}")
        else()
            if (NOT _private)
                string(APPEND _qmldir_template "\n${_classname} ${_version} ${_actual_path}")
            else()
                string(APPEND _qmldir_template "\ninternal ${_classname} ${_actual_path}")
            endif()
        endif()
    endforeach()
    get_target_property(_qml_version ${ARG_TARGET} ${_ECM_QMLMODULE_PROPERTY_VERSION})
    string(APPEND _qmldir_template "\n# KDE-qmldir-Version: ${_qml_version}")

    string(APPEND _qmldir_template "\n")

    file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/${ARG_TARGET}_qmldir" "${_qmldir_template}")
    set_target_properties(${ARG_TARGET} PROPERTIES _ecm_qmldir_file "${CMAKE_CURRENT_BINARY_DIR}/${ARG_TARGET}_qmldir")
endfunction()

function(_ecm_qmlmodule_generate_qrc ARG_TARGET)
    get_target_property(_qml_uri ${ARG_TARGET} ${_ECM_QMLMODULE_PROPERTY_URI})
    get_target_property(_qml_files ${ARG_TARGET} ${_ECM_QMLMODULE_PROPERTY_FILES})
    get_target_property(_qmldir_file ${ARG_TARGET} ${_ECM_QMLMODULE_PROPERTY_QMLDIR})
    get_target_property(_qml_version ${ARG_TARGET} ${_ECM_QMLMODULE_PROPERTY_VERSION})

    _ecm_qmlmodule_uri_to_path(_qml_prefix "${_qml_uri}" "${_qml_version}")

    set(_qrc_template "<!-- This file was automatically generated by ECMQmlModule and should not be modified -->")

    string(APPEND _qrc_template "\n<RCC>\n<qresource prefix=\"/qt-project.org/imports/${_qml_prefix}\">")
    string(APPEND _qrc_template "\n<file alias=\"qmldir\">${_qmldir_file}</file>")

    foreach(_file ${_qml_files})
        get_filename_component(_filename ${_file} NAME)
        get_property(_path SOURCE ${_file} PROPERTY ${_ECM_QMLMODULE_PROPERTY_PATH})

        set(_file_path "${_filename}")
        if (NOT "${_path}" STREQUAL "")
            set(_file_path "${_path}/${_filename}")
        endif()

        string(APPEND _qrc_template "\n<file alias=\"${_file_path}\">${_file}</file>")
    endforeach()

    string(APPEND _qrc_template "\n</qresource>\n</RCC>\n")

    file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/${ARG_TARGET}.qrc" "${_qrc_template}")
    qt_add_resources(_qrc_output "${CMAKE_CURRENT_BINARY_DIR}/${ARG_TARGET}.qrc")

    target_sources(${ARG_TARGET} PRIVATE ${_qrc_output})
endfunction()

function(ecm_add_qml_module ARG_TARGET)
    cmake_parse_arguments(PARSE_ARGV 1 ARG "NO_PLUGIN" "URI;VERSION;CLASSNAME" "")

    if ("${ARG_TARGET}" STREQUAL "")
        message(FATAL_ERROR "ecm_add_qml_module called without a valid target name.")
    endif()

    if ("${ARG_URI}" STREQUAL "")
        message(FATAL_ERROR "ecm_add_qml_module called without a valid module URI.")
    endif()

    string(FIND "${ARG_URI}" " " "_space")
    if (${_space} GREATER_EQUAL 0)
        message(FATAL_ERROR "ecm_add_qml_module called without a valid module URI.")
    endif()

    if (${BUILD_SHARED_LIBS} AND ${ARG_NO_PLUGIN})
        # CMake doesn't like library targets without sources, so if we have no
        # C++ sources, use a plain target that we can add all the install stuff
        # to.
        add_custom_target(${ARG_TARGET} ALL)
    else()
        add_library(${ARG_TARGET})
    endif()

    if (NOT ARG_VERSION)
        set(ARG_VERSION "1.0")
    endif()

    set_target_properties(${ARG_TARGET} PROPERTIES
        ${_ECM_QMLMODULE_PROPERTY_URI} "${ARG_URI}"
        ${_ECM_QMLMODULE_PROPERTY_FILES} ""
        ${_ECM_QMLMODULE_PROPERTY_QMLONLY} "${ARG_NO_PLUGIN}"
        ${_ECM_QMLMODULE_PROPERTY_VERSION} "${ARG_VERSION}"
        ${_ECM_QMLMODULE_PROPERTY_CLASSNAME} "${ARG_CLASSNAME}"
        ${_ECM_QMLMODULE_PROPERTY_DEPENDS} ""
    )

    # QQmlImportDatabase::resolvePlugin doesn't accept lib prefixes under
    # Windows, causing to fail to import when using as a dynamic plugin.
    if (MINGW)
        set_target_properties(${ARG_TARGET} PROPERTIES PREFIX "")
    endif()

    # -Muri is required for static QML plugins to work properly, see
    # https://bugreports.qt.io/browse/QTBUG-82598
    set_target_properties(${ARG_TARGET} PROPERTIES AUTOMOC_MOC_OPTIONS -Muri=${ARG_URI})
endfunction()

function(ecm_add_qml_module_dependencies ARG_TARGET)
    cmake_parse_arguments(PARSE_ARGV 1 ARG "" "" "DEPENDS")

    _ecm_qmlmodule_verify_qml_target(${ARG_TARGET})

    if ("${ARG_DEPENDS}" STREQUAL "")
        message(FATAL_ERROR "ecm_add_qml_module_dependencies called without required argument DEPENDS")
    endif()

    set_target_properties(${ARG_TARGET} PROPERTIES ${_ECM_QMLMODULE_PROPERTY_DEPENDS} "${ARG_DEPENDS}")
endfunction()

function(ecm_target_qml_sources ARG_TARGET)
    cmake_parse_arguments(PARSE_ARGV 1 ARG "PRIVATE" "VERSION;PATH" "SOURCES")

    _ecm_qmlmodule_verify_qml_target(${ARG_TARGET})

    if ("${ARG_SOURCES}" STREQUAL "")
        message(FATAL_ERROR "ecm_target_qml_sources called without required argument SOURCES")
    endif()

    if ("${ARG_VERSION}" STREQUAL "")
        get_target_property(ARG_VERSION ${ARG_TARGET} "_ecm_qml_version")
    endif()
    # In case we have not specified a version in add_qml_module, we use 1.0 as a default for the individual QML files
    if (NOT ARG_VERSION)
        set(ARG_VERSION "1.0")
    endif()

    foreach(_file ${ARG_SOURCES})
        # Check if a given file exists, but only for files that are not
        # automatically generated.
        set(_path "${_file}")
        get_source_file_property(_generated ${_file} GENERATED)
        if (NOT _generated)
            if (IS_ABSOLUTE ${_path})
                # Assume absolute paths are generated, which may not always be
                # true but is fairly likely.
                set(_generated TRUE)
            else()
                string(FIND ${_file} ${CMAKE_BINARY_DIR} _in_binary_dir)
                if (${_in_binary_dir} GREATER_EQUAL 0)
                    # Assume anything in binary dir is generated.
                    set(_generated TRUE)
                else()
                    set(_path "${CMAKE_CURRENT_SOURCE_DIR}/${_file}")
                endif()
            endif()
        endif()

        if (NOT ${_generated} AND NOT EXISTS ${_path})
            message(FATAL_ERROR "ecm_target_qml_sources called with nonexistent file ${_file}")
        endif()

        set_property(SOURCE ${_file} PROPERTY ${_ECM_QMLMODULE_PROPERTY_VERSION} "${ARG_VERSION}")
        if (ARG_PRIVATE)
            set_property(SOURCE ${_file} PROPERTY ${_ECM_QMLMODULE_PROPERTY_PRIVATE} TRUE)
        endif()
        set_property(SOURCE ${_file} PROPERTY ${_ECM_QMLMODULE_PROPERTY_PATH} "${ARG_PATH}")
        set_property(TARGET ${ARG_TARGET}
            APPEND PROPERTY ${_ECM_QMLMODULE_PROPERTY_FILES} ${_path}
        )
    endforeach()
endfunction()

function(ecm_finalize_qml_module ARG_TARGET)
    cmake_parse_arguments(PARSE_ARGV 1 ARG "" "DESTINATION" "")

    _ecm_qmlmodule_verify_qml_target(${ARG_TARGET})

    if (NOT ARG_DESTINATION)
        set(ARG_DESTINATION "${KDE_INSTALL_QMLDIR}")
    endif()
    if ("${ARG_DESTINATION}" STREQUAL "")
        message(FATAL_ERROR "ecm_finalize_qml_module called without argument DESTINATION and KDE_INSTALL_QMLDIR is not set")
    endif()

    get_target_property(_qml_uri ${ARG_TARGET} ${_ECM_QMLMODULE_PROPERTY_URI})
    get_target_property(_version ${ARG_TARGET} ${_ECM_QMLMODULE_PROPERTY_VERSION})

    _ecm_qmlmodule_generate_qmldir(${ARG_TARGET})
    _ecm_qmlmodule_uri_to_path(_plugin_path "${_qml_uri}" "${_version}")

    get_target_property(_qml_only ${ARG_TARGET} ${_ECM_QMLMODULE_PROPERTY_QMLONLY})

    if (NOT BUILD_SHARED_LIBS)
        _ecm_qmlmodule_generate_qrc(${ARG_TARGET})
        set(CPP_RESOURCE_INIT "#include <qglobal.h> \n#include <QDebug> \n void initQmlResource${ARG_TARGET}() {Q_INIT_RESOURCE(${ARG_TARGET}); qWarning()<<Q_FUNC_INFO;};")
        file(WRITE ${ARG_TARGET}_init.cpp "${CPP_RESOURCE_INIT}")
        target_sources(${ARG_TARGET} PRIVATE ${ARG_TARGET}_init.cpp)
        target_compile_definitions(${ARG_TARGET} PRIVATE -DQT_PLUGIN_RESOURCE_INIT_FUNCTION=initQmlResource${ARG_TARGET} -DQT_STATICPLUGIN=1)

        if (${_qml_only})
            # If we do not have any C++ sources for the target, we need a way to
            # compile the generated QRC file. So generate a very plain C++ QML
            # plugin that we include in the target.
            configure_file(${_ECM_QMLMODULE_STATIC_QMLONLY_H} ${CMAKE_CURRENT_BINARY_DIR}/QmlModule.h @ONLY)
            configure_file(${_ECM_QMLMODULE_STATIC_QMLONLY_CPP} ${CMAKE_CURRENT_BINARY_DIR}/QmlModule.cpp @ONLY)

            target_sources(${ARG_TARGET} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/QmlModule.cpp)
            if (TARGET Qt::Qml)
                target_link_libraries(${ARG_TARGET} PRIVATE Qt::Qml)
            else()
                target_link_libraries(${ARG_TARGET} PRIVATE Qt5::Qml)
            endif()
        endif()

        install(TARGETS ${ARG_TARGET} DESTINATION ${ARG_DESTINATION}/${_plugin_path})

        return()
    endif()

    get_target_property(_runtime_output_dir ${ARG_TARGET} RUNTIME_OUTPUT_DIRECTORY)
    if (NOT ${_runtime_output_dir})
        if ("${CMAKE_RUNTIME_OUTPUT_DIRECTORY}" STREQUAL "")
            set(_runtime_output_dir ${CMAKE_CURRENT_BINARY_DIR})
        else()
            set(_runtime_output_dir ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
        endif()
    endif()

    add_custom_command(
        TARGET ${ARG_TARGET}
        POST_BUILD
        WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
        COMMAND ${CMAKE_COMMAND} -E make_directory ${_runtime_output_dir}/${_plugin_path}
        BYPRODUCTS ${_runtime_output_dir}/${_plugin_path}
    )

    get_target_property(_qmldir_file ${ARG_TARGET} ${_ECM_QMLMODULE_PROPERTY_QMLDIR})
    install(FILES ${_qmldir_file} DESTINATION ${ARG_DESTINATION}/${_plugin_path} RENAME "qmldir")

    add_custom_command(
        TARGET ${ARG_TARGET}
        POST_BUILD
        WORKING_DIRECTORY ${_runtime_output_dir}
        COMMAND ${CMAKE_COMMAND} -E copy ${_qmldir_file} ${_plugin_path}/qmldir
    )

    if (NOT ${_qml_only})
        install(TARGETS ${ARG_TARGET} DESTINATION ${ARG_DESTINATION}/${_plugin_path})

        add_custom_command(
            TARGET ${ARG_TARGET}
            POST_BUILD
            WORKING_DIRECTORY ${_runtime_output_dir}
            COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:${ARG_TARGET}> ${_plugin_path}
        )
    endif()

    get_target_property(_qml_files ${ARG_TARGET} ${_ECM_QMLMODULE_PROPERTY_FILES})
    foreach(_file ${_qml_files})
        get_filename_component(_filename ${_file} NAME)
        get_property(_path SOURCE ${_file} PROPERTY ${_ECM_QMLMODULE_PROPERTY_PATH})

        set(_file_path "${_plugin_path}/")
        if (NOT "${_path}" STREQUAL "")
            set(_file_path "${_plugin_path}/${_path}/")
        endif()

        install(FILES ${_file} DESTINATION ${ARG_DESTINATION}/${_file_path})

        add_custom_command(
            TARGET ${ARG_TARGET}
            POST_BUILD
            WORKING_DIRECTORY ${_runtime_output_dir}
            COMMAND ${CMAKE_COMMAND} -E make_directory ${_file_path}
            COMMAND ${CMAKE_COMMAND} -E copy ${_file} ${_file_path}
            BYPRODUCTS ${_file_path}/${_filename}
        )
    endforeach()
endfunction()
#
# SPDX-FileCopyrightText: 2023 Arjen Hiemstra <ahiemstra@heimr.nl>
#
# SPDX-License-Identifier: BSD-3-Clause

# Qt 6 implementation of ECMQmlModule

set(QT_NO_CREATE_VERSIONLESS_FUNCTIONS ON)
find_package(Qt6 COMPONENTS Core Qml CONFIG)
unset(QT_NO_CREATE_VERSIONLESS_FUNCTIONS)

if (NOT TARGET Qt6::Qml)
    message(WARNING "Target Qt6::Qml was not found. ECMQmlModule requires the QML module when building with Qt 6")
    return()
endif()

# Match KDECMakeSettings' RUNTIME_OUTPUT_DIRECTORY so that we can load plugins from
# the build directory when running tests. But only if we don't yet have an output directory.
if (NOT QT_QML_OUTPUT_DIRECTORY)
    set(QT_QML_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
endif()

# Stop warning about a changed import prefix.
qt6_policy(SET QTP0001 NEW)

function(ecm_add_qml_module ARG_TARGET)
    cmake_parse_arguments(PARSE_ARGV 1 ARG "NO_PLUGIN;QT_NO_PLUGIN;GENERATE_PLUGIN_SOURCE" "URI;VERSION;CLASSNAME;OUTPUT_TARGETS" "")

    if ("${ARG_TARGET}" STREQUAL "")
        message(FATAL_ERROR "ecm_add_qml_module called without a valid target name.")
    endif()

    if ("${ARG_URI}" STREQUAL "")
        message(FATAL_ERROR "ecm_add_qml_module called without a valid module URI.")
    endif()

    string(FIND "${ARG_URI}" " " "_space")
    if (${_space} GREATER_EQUAL 0)
        message(FATAL_ERROR "ecm_add_qml_module called without a valid module URI.")
    endif()

    set(_arguments ${ARG_TARGET} URI ${ARG_URI})

    if (ARG_VERSION)
        list(APPEND _arguments VERSION ${ARG_VERSION})
    endif()

    if (ARG_CLASSNAME)
        message(AUTHOR_WARNING "The CLASSNAME argument to ecm_add_qml_module is deprecated for Qt 6; Use CLASS_NAME instead.")
        list(APPEND _arguments CLASS_NAME ${ARG_CLASSNAME})
    endif()

    if (ARG_NO_PLUGIN)
        message(AUTHOR_WARNING "The NO_PLUGIN argument to ecm_add_qml_module is deprecated for Qt 6; For Qt 6 QML modules always require a plugin library. Use GENERATE_PLUGIN_SOURCE instead. If you wish to use the NO_PLUGIN feature from qt_add_qml_module, use QT_NO_PLUGIN.")
        set(ARG_GENERATE_PLUGIN_SOURCE TRUE)
    endif()

    if (ARG_QT_NO_PLUGIN)
        list(APPEND _arguments NO_PLUGIN)
    endif()

    if (NOT ARG_GENERATE_PLUGIN_SOURCE)
        list(APPEND _arguments NO_GENERATE_PLUGIN_SOURCE)
    endif()

    if (NOT TARGET ${ARG_TARGET})
        list(APPEND _arguments PLUGIN_TARGET ${ARG_TARGET})
        if (BUILD_SHARED_LIBS)
            list(APPEND _arguments SHARED)
        else()
            list(APPEND _arguments STATIC)
        endif()
    endif()

    # make qmlimportscanner also find QML modules installed
    # outside of the Qt prefix
    if(IS_DIRECTORY "${CMAKE_INSTALL_PREFIX}/${KDE_INSTALL_QMLDIR}")
        list(APPEND _import_paths "${CMAKE_INSTALL_PREFIX}/${KDE_INSTALL_QMLDIR}")
    endif()
    foreach(_prefix ${CMAKE_PREFIX_PATH})
        if(IS_DIRECTORY "${_prefix}/${KDE_INSTALL_QMLDIR}")
            list(APPEND _import_paths "${_prefix}/${KDE_INSTALL_QMLDIR}")
        endif()
    endforeach()
    list(APPEND _arguments IMPORT_PATH ${_import_paths})

    list(APPEND _arguments ${ARG_UNPARSED_ARGUMENTS})

    qt6_add_qml_module(${_arguments} OUTPUT_TARGETS _out_targets)
    if (ARG_OUTPUT_TARGETS)
        set(${ARG_OUTPUT_TARGETS} ${_out_targets} PARENT_SCOPE)
    endif()
    set_target_properties(${ARG_TARGET} PROPERTIES _ecm_output_targets "${_out_targets}")

    # KDECMakeSettings sets the prefix of MODULE targets to empty but Qt will
    # not load a QML plugin without prefix. So we need to force it here.
    qt6_query_qml_module(${ARG_TARGET} PLUGIN_TARGET _plugin_target)
    if (NOT WIN32 AND TARGET ${_plugin_target})
        set_target_properties(${_plugin_target} PROPERTIES PREFIX "lib")
    endif()

    option(VERBOSE_QML_COMPILER "Enable verbose output for qmlcachegen" OFF)

    if (VERBOSE_QML_COMPILER)
        set_target_properties(${ARG_TARGET} PROPERTIES
            QT_QMLCACHEGEN_ARGUMENTS "--verbose"
        )
    endif()

endfunction()

function(ecm_add_qml_module_dependencies ARG_TARGET)
    message(AUTHOR_WARNING "ecm_add_qml_module_dependencies is deprecated for Qt 6; use the DEPENDENCIES argument to ecm_add_qml_module() instead.")
endfunction()

function(ecm_target_qml_sources ARG_TARGET)
    cmake_parse_arguments(PARSE_ARGV 1 ARG "PRIVATE" "VERSION;PATH;OUTPUT_TARGETS" "SOURCES")

    if ("${ARG_SOURCES}" STREQUAL "")
        message(FATAL_ERROR "ecm_target_qml_sources called without required argument SOURCES")
    endif()

    if (ARG_VERSION)
        set_source_files_properties(${ARG_SOURCES} PROPERTIES QT_QML_SOURCE_VERSIONS "${ARG_VERSION}")
    endif()

    if (ARG_PRIVATE)
        set_source_files_properties(${ARG_SOURCES} PROPERTIES QT_QML_INTERNAL_TYPE TRUE)
    endif()

    set(_QML_FILES)
    set(_RESOURCES)
    foreach(_path ${ARG_SOURCES})
        get_filename_component(_file "${_path}" NAME)
        get_filename_component(_ext "${_path}" EXT)
        set(_resource_alias "${_file}")
        if (ARG_PATH)
            set(_resource_alias "${ARG_PATH}/${_file}")
        endif()
        set_source_files_properties("${_path}" PROPERTIES QT_RESOURCE_ALIAS "${_resource_alias}")
        if ("${_ext}" MATCHES "(.qml|.js|.mjs)")
            list(APPEND _QML_FILES "${_path}")
        else()
            list(APPEND _RESOURCES "${_path}")
        endif()
    endforeach()

    if(_QML_FILES)
        qt6_target_qml_sources(${ARG_TARGET} QML_FILES ${_QML_FILES} OUTPUT_TARGETS _out_targets_qml ${ARG_UNPARSED_ARGUMENTS})
    endif()
    if(_RESOURCES)
        qt6_target_qml_sources(${ARG_TARGET} RESOURCES ${_RESOURCES} OUTPUT_TARGETS _out_targets_qrc ${ARG_UNPARSED_ARGUMENTS})
    endif()
    list(APPEND _out_targets "${_out_targets_qml}" "${_out_targets_qrc}")
    if (ARG_OUTPUT_TARGETS)
        set(${ARG_OUTPUT_TARGETS} ${_out_targets} PARENT_SCOPE)
    endif()
    get_target_property(_ecm_output_targets ${ARG_TARGET} _ecm_output_targets)
    list(APPEND _ecm_output_targets ${_out_targets})
    set_target_properties(${ARG_TARGET} PROPERTIES _ecm_output_targets "${_ecm_output_targets}")

endfunction()

function(ecm_finalize_qml_module ARG_TARGET)
    cmake_parse_arguments(PARSE_ARGV 1 ARG "" "DESTINATION;VERSION;EXPORT" "")

    if (NOT ARG_DESTINATION)
        set(ARG_DESTINATION "${KDE_INSTALL_QMLDIR}")
    endif()

    if ("${ARG_DESTINATION}" STREQUAL "")
        message(FATAL_ERROR "ecm_finalize_qml_module called without required argument DESTINATION and KDE_INSTALL_QMLDIR is not set")
    endif()

    if (NOT ARG_VERSION)
        set(ARG_VERSION "${PROJECT_VERSION}")
    endif()

    # This is effectively a workaround for missing upstream API, see QTBUG-100102

    qt6_query_qml_module(${ARG_TARGET}
        URI module_uri
        VERSION module_version
        PLUGIN_TARGET module_plugin_target
        TARGET_PATH module_target_path
        QMLDIR module_qmldir
        TYPEINFO module_typeinfo
        QML_FILES module_qml_files
        RESOURCES module_resources
    )

    set(module_dir "${ARG_DESTINATION}/${module_target_path}")

    if (NOT TARGET "${module_plugin_target}")
        return()
    endif()

    if (ARG_EXPORT AND NOT BUILD_SHARED_LIBS)
        set(_install_targets_args EXPORT "${ARG_EXPORT}")
    endif()
    install(TARGETS "${module_plugin_target}"
        ${_install_targets_args}
        LIBRARY DESTINATION "${module_dir}"
        RUNTIME DESTINATION "${module_dir}"
    )

    # Install dependent targets created for static builds
    get_target_property(_ecm_output_targets ${ARG_TARGET} _ecm_output_targets)
    if (_ecm_output_targets AND ARG_EXPORT)
        install(TARGETS ${_ecm_output_targets}
            EXPORT ${ARG_EXPORT}
            LIBRARY DESTINATION "${module_dir}"
            RUNTIME DESTINATION "${module_dir}"
            OBJECTS DESTINATION "${module_dir}"
        )
    endif()

    # Install the QML module meta information.
    install(FILES "${module_qmldir}"   DESTINATION "${module_dir}")
    install(FILES "${module_typeinfo}" DESTINATION "${module_dir}")

    # Install QML files, possibly renamed.
    # see Kirigami::StyleSelector::resolveFileX, on Android we never use QML files from disk
    # but rather always the ones from qrc
    if (NOT ANDROID)
        list(LENGTH module_qml_files num_files)
        if (NOT "${module_qml_files}" MATCHES "NOTFOUND" AND ${num_files} GREATER 0)
            qt6_query_qml_module(${ARG_TARGET} QML_FILES_DEPLOY_PATHS qml_files_deploy_paths)

            math(EXPR last_index "${num_files} - 1")
            foreach(i RANGE 0 ${last_index})
                list(GET module_qml_files       ${i} src_file)
                list(GET qml_files_deploy_paths ${i} deploy_path)
                get_filename_component(dst_name "${deploy_path}" NAME)
                get_filename_component(dest_dir "${deploy_path}" DIRECTORY)
                install(FILES "${src_file}" DESTINATION "${module_dir}/${dest_dir}" RENAME "${dst_name}")
            endforeach()
        endif()
    endif()

    # Install resources, possibly renamed.
    list(LENGTH module_resources num_files)
    if (NOT "${module_resources}" MATCHES "NOTFOUND" AND ${num_files} GREATER 0)
        qt6_query_qml_module(${ARG_TARGET} RESOURCES_DEPLOY_PATHS resources_deploy_paths)

        math(EXPR last_index "${num_files} - 1")
        foreach(i RANGE 0 ${last_index})
            list(GET module_resources       ${i} src_file)
            list(GET resources_deploy_paths ${i} deploy_path)
            get_filename_component(dst_name "${deploy_path}" NAME)
            get_filename_component(dest_dir "${deploy_path}" DIRECTORY)
            install(FILES "${src_file}" DESTINATION "${module_dir}/${dest_dir}" RENAME "${dst_name}")
        endforeach()
    endif()

    file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${ARG_TARGET}-kde-qmlmodule.version" CONTENT "${ARG_VERSION}\n")
    install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${ARG_TARGET}-kde-qmlmodule.version" DESTINATION "${module_dir}" RENAME "kde-qmlmodule.version")
endfunction()
# SPDX-FileCopyrightText: 2015 Alex Merry <alex.merry@kde.org>
# SPDX-FileCopyrightText: 2020 Friedrich W. H. Kossebau <kossebau@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
ECMQtDeclareLoggingCategory
---------------------------

This module provides the ``ecm_qt_declare_logging_category`` function for
generating declarations for logging categories in Qt5, and the
``ecm_qt_install_logging_categories`` function for generating and installing
a file in KDebugSettings format with the info about all those categories,
as well as a file with info about any renamed categories if defined.
To include in that file any logging categories that are manually defined
also a function ``ecm_qt_export_logging_category`` is provided.

::

  ecm_qt_declare_logging_category(<sources_var_name(|target (since 5.80))>
      HEADER <filename>
      IDENTIFIER <identifier>
      CATEGORY_NAME <category_name>
      [OLD_CATEGORY_NAMES <oldest_cat_name> [<second_oldest_cat_name> [...]]]
      [DEFAULT_SEVERITY <Debug|Info|Warning|Critical|Fatal>]
      [EXPORT <exportid>]
      [DESCRIPTION <description>]
  )

A header file, ``<filename>``, will be generated along with a corresponding
source file. These will provide a QLoggingCategory category that can be referred
to from C++ code using ``<identifier>``, and from the logging configuration using
``<category_name>``.

The generated source file will be added to the variable with the name
``<sources_var_name>``. If the given argument is a target though, instead both the
generated header file and the generated source file will be added to the target as
private sources (since 5.80). The target must not be an alias.

If ``<filename>`` is not absolute, it will be taken relative to the current
binary directory.

``<identifier>`` may include namespaces (eg: ``foo::bar::IDENT``).

If ``EXPORT`` is passed, the category will be registered for the group id
``<exportid>``. Info about the categories of that group can then be
generated in a file and installed by that group id with the
``ecm_qt_install_logging_categories`` function. In that case also ``DESCRIPTION``
will need to be passed, with ``<description>`` being a short single line text.
And ``OLD_CATEGORY_NAMES`` can be used to inform about any renamings of the category,
so user settings can be migrated. Since 5.68.0.

Since 5.14.0.

::

  ecm_qt_export_logging_category(
      IDENTIFIER <identifier>
      CATEGORY_NAME <category_name>
      [OLD_CATEGORY_NAMES <oldest_category_name> [<second_oldest_category_name> [...]]]
      EXPORT <exportid>
      DESCRIPTION <description>
      [DEFAULT_SEVERITY <Debug|Info|Warning|Critical|Fatal>]
  )

Registers a logging category for being included in the generated and
installed KDebugSettings files. To be used for categories who are declared by
manual code or other ways instead of code generated with
``ecm_qt_declare_logging_category``.

``<identifier>`` may include namespaces (eg: ``foo::bar::IDENT``).

``EXPORT`` specifies the group id with which the category will be registered.
Info about the categories of that group can then be generated in a file and
installed by that group id with the ``ecm_qt_install_logging_categories`` function.

``DESCRIPTION`` specifies a short single line text describing the category.

``OLD_CATEGORY_NAMES`` can be used to inform about any renamings of the category,
so user settings can be migrated.

Since 5.68.0.

::

  ecm_qt_install_logging_categories(
      EXPORT <exportid>
      [FILE <filename>]
      DESTINATION <install_path>
      [SORT]
      [COMPONENT <component>]
  )

Generates and installs a file in KDebugSettings format with the info about all
the categories registered for the group ``<exportid>``, as well as a file with
info about any renamed categories, if there are.

The method call needs to be after the last ``ecm_qt_declare_logging_category``
call which uses the same ``<exportid>``. This can be in the same directory, or
any subdirectory or parent directory.

``EXPORT`` specifies the group id of categories whose information should be
stored in the file generated and installed.

``FILE`` specifies the name of the file generated and installed. It will default
to lower-cased ``<exportid>.categories``. The name of the file with info about
renamed categories will use the same final base name and the suffix
``.renamecategories``. Note: Before 5.113, the base name should not have any
further ``.`` in the name, as its end would be defined by that.

``DESTINATION`` specifies where the generated file will be
installed.

IF ``SORT`` is set, entries will be sorted by identifiers.

``COMPONENT`` specifies the installation component name with which the install
rules for the generated file are associated.

Since 5.85.0 this is a no-op when building for Android, as KDebugSettings is
not available on that platform and the logging category files therefore just
bloat the APK.

Example usage:

.. code-block:: cmake

  ecm_qt_declare_logging_category(
      MYPROJECT_SRCS
      HEADER "myproject_debug.h"
      IDENTIFIER "MYPROJECT_DEBUG"
      CATEGORY_NAME "myproject"
      OLD_CATEGORY_NAMES "myprojectlog"
      DESCRIPTION "My project"
      EXPORT MyProject
  )

  ecm_qt_export_logging_category(
      IDENTIFIER "MYPROJECT_SUBMODULE_DEBUG"
      CATEGORY_NAME "myproject.submodule"
      DESCRIPTION "My project - submodule"
      EXPORT MyProject
  )

  ecm_qt_install_logging_categories(
      EXPORT MyProject
      FILE myproject.categories
      DESTINATION "${KDE_INSTALL_LOGGINGCATEGORIESDIR}"
  )

Since 5.68.0.
#]=======================================================================]

set(_ECM_QT_DECLARE_LOGGING_CATEGORY_TEMPLATE_CPP "${CMAKE_CURRENT_LIST_DIR}/ECMQtDeclareLoggingCategory.cpp.in")
set(_ECM_QT_DECLARE_LOGGING_CATEGORY_TEMPLATE_H   "${CMAKE_CURRENT_LIST_DIR}/ECMQtDeclareLoggingCategory.h.in")

function(ecm_qt_export_logging_category)
    set(options)
    set(oneValueArgs IDENTIFIER CATEGORY_NAME DEFAULT_SEVERITY EXPORT DESCRIPTION)
    set(multiValueArgs OLD_CATEGORY_NAMES)
    cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

    if(ARG_UNPARSED_ARGUMENTS)
        message(FATAL_ERROR "Unexpected arguments to ecm_qt_export_logging_category: ${ARG_UNPARSED_ARGUMENTS}")
    endif()
    if(NOT ARG_IDENTIFIER)
        message(FATAL_ERROR "Missing IDENTIFIER argument for ecm_qt_export_logging_category")
    endif()
    if(NOT ARG_CATEGORY_NAME)
        message(FATAL_ERROR "Missing CATEGORY_NAME argument for ecm_qt_export_logging_category")
    endif()
    if(NOT ARG_DEFAULT_SEVERITY)
        set(ARG_DEFAULT_SEVERITY Info)
        set(is_explicite_default_severity FALSE)
    else()
        set(acceptible_severities Debug Info Warning Critical Fatal)
        list(FIND acceptible_severities "${ARG_DEFAULT_SEVERITY}" pos)
        if (pos EQUAL -1)
            message(FATAL_ERROR "Unknown DEFAULT_SEVERITY ${pos}")
        endif()
        set(is_explicite_default_severity TRUE)
    endif()
    if(NOT ARG_EXPORT)
        message(FATAL_ERROR "Missing EXPORT argument for ecm_qt_export_logging_category.")
    endif()
    if(NOT ARG_DESCRIPTION)
        message(FATAL_ERROR "Missing DESCRIPTION argument for ecm_qt_export_logging_category.")
    endif()

    # note data in global properties
    set(_propertyprefix "ECM_QT_LOGGING_CATEGORY_${ARG_EXPORT}")
    set_property(GLOBAL APPEND PROPERTY "${_propertyprefix}_CATEGORIES" ${ARG_CATEGORY_NAME})
    set_property(GLOBAL PROPERTY "${_propertyprefix}_IDENTIFIER_${ARG_CATEGORY_NAME}" "${ARG_IDENTIFIER}")
    set_property(GLOBAL PROPERTY "${_propertyprefix}_DESCRIPTION_${ARG_CATEGORY_NAME}" "${ARG_DESCRIPTION}")
    set_property(GLOBAL PROPERTY "${_propertyprefix}_OLD_NAMES_${ARG_CATEGORY_NAME}" "${ARG_OLD_CATEGORY_NAMES}")
    if (is_explicite_default_severity)
        set_property(GLOBAL PROPERTY "${_propertyprefix}_DEFAULT_SEVERITY_${ARG_CATEGORY_NAME}" "${ARG_DEFAULT_SEVERITY}")
    endif()
endfunction()


function(ecm_qt_declare_logging_category sources_var)
    set(options)
    set(oneValueArgs HEADER IDENTIFIER CATEGORY_NAME DEFAULT_SEVERITY EXPORT DESCRIPTION)
    set(multiValueArgs OLD_CATEGORY_NAMES)
    cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

    if(ARG_UNPARSED_ARGUMENTS)
        message(FATAL_ERROR "Unexpected arguments to ecm_qt_declare_logging_category: ${ARG_UNPARSED_ARGUMENTS}")
    endif()
    if(NOT ARG_HEADER)
        message(FATAL_ERROR "Missing HEADER argument for ecm_qt_declare_logging_category")
    endif()
    if(NOT ARG_IDENTIFIER)
        message(FATAL_ERROR "Missing IDENTIFIER argument for ecm_qt_declare_logging_category")
    endif()
    if(NOT ARG_CATEGORY_NAME)
        message(FATAL_ERROR "Missing CATEGORY_NAME argument for ecm_qt_declare_logging_category")
    endif()
    if(NOT ARG_DEFAULT_SEVERITY)
        set(ARG_DEFAULT_SEVERITY Info)
        set(is_explicite_default_severity FALSE)
    else()
        set(acceptible_severities Debug Info Warning Critical Fatal)
        list(FIND acceptible_severities "${ARG_DEFAULT_SEVERITY}" pos)
        if (pos EQUAL -1)
            message(FATAL_ERROR "Unknown DEFAULT_SEVERITY ${pos}")
        endif()
        set(is_explicite_default_severity TRUE)
    endif()
    if(ARG_EXPORT AND NOT ARG_DESCRIPTION)
        message(FATAL_ERROR "Missing DESCRIPTION argument for ecm_qt_declare_logging_category.")
    endif()
    if (TARGET ${sources_var})
        get_target_property(aliased_target ${sources_var} ALIASED_TARGET)
        if(aliased_target)
            message(FATAL_ERROR "Target argument passed to ecm_qt_declare_logging_category must not be an alias: ${sources_var}")
        endif()
    endif()

    if (NOT IS_ABSOLUTE "${ARG_HEADER}")
        set(ARG_HEADER "${CMAKE_CURRENT_BINARY_DIR}/${ARG_HEADER}")
    endif()

    string(REPLACE "::" ";" namespaces "${ARG_IDENTIFIER}")
    list(LENGTH namespaces len)
    math(EXPR last_pos "${len} - 1")
    list(GET namespaces ${last_pos} IDENTIFIER)
    list(REMOVE_AT namespaces ${last_pos})

    set(OPEN_NAMESPACES)
    set(CLOSE_NAMESPACES)
    foreach(ns ${namespaces})
        set(OPEN_NAMESPACES "${OPEN_NAMESPACES} namespace ${ns} {")
        set(CLOSE_NAMESPACES "} ${CLOSE_NAMESPACES}")
    endforeach()

    string(FIND "${ARG_HEADER}" "." pos REVERSE)
    if (pos EQUAL -1)
        set(cpp_filename "${ARG_HEADER}.cpp")
    else()
        string(SUBSTRING "${ARG_HEADER}" 0 ${pos} cpp_filename)
        set(cpp_filename "${cpp_filename}.cpp")
    endif()

    get_filename_component(HEADER_NAME "${ARG_HEADER}" NAME)

    string(REGEX REPLACE "[^a-zA-Z0-9]" "_" GUARD_NAME "${HEADER_NAME}")
    string(REPLACE "::" "_" GUARD_PREFIX "ECM_QLOGGINGCATEGORY_${ARG_IDENTIFIER}")
    string(TOUPPER "${GUARD_PREFIX}_${GUARD_NAME}" GUARD_NAME)

    if (NOT _ECM_QT_DECLARE_LOGGING_CATEGORY_TEMPLATE_CPP)
       message(FATAL_ERROR "You must include(ECMQtDeclareLoggingCategory) before using ecm_qt_declare_logging_category")
    endif()

    configure_file("${_ECM_QT_DECLARE_LOGGING_CATEGORY_TEMPLATE_CPP}" "${cpp_filename}")
    configure_file("${_ECM_QT_DECLARE_LOGGING_CATEGORY_TEMPLATE_H}" "${ARG_HEADER}")

    if(TARGET ${sources_var})
        target_sources(${sources_var} PRIVATE ${cpp_filename} "${ARG_HEADER}")
    else()
        set(sources "${${sources_var}}")
        list(APPEND sources "${cpp_filename}")
        set(${sources_var} "${sources}" PARENT_SCOPE)
    endif()

    # note data in global properties
    if (ARG_EXPORT)
        set(_default_severity)
        if (is_explicite_default_severity)
            set(_default_severity DEFAULT_SEVERITY ${ARG_DEFAULT_SEVERITY})
        endif()
        set(_old_category_name)
        if (ARG_OLD_CATEGORY_NAMES)
            set(_old_category_names OLD_CATEGORY_NAMES ${ARG_OLD_CATEGORY_NAMES})
        endif()
        ecm_qt_export_logging_category(
            IDENTIFIER ${ARG_IDENTIFIER}
            CATEGORY_NAME ${ARG_CATEGORY_NAME}
            ${_old_category_names}
            ${_default_severity}
            EXPORT ${ARG_EXPORT}
            DESCRIPTION "${ARG_DESCRIPTION}"
        )
    endif()
endfunction()


function(ecm_qt_install_logging_categories)
    # on Android there is no KDebugSettings, and thus the logging categories files make no sense in APKs
    if (ANDROID)
        return()
    endif()

    set(options SORT)
    set(oneValueArgs FILE EXPORT DESTINATION COMPONENT)
    set(multiValueArgs)

    cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

    if(NOT ARGS_EXPORT)
        message(FATAL_ERROR "Missing EXPORT argument for ecm_qt_install_logging_categories")
    endif()

    if(NOT ARGS_DESTINATION)
        message(FATAL_ERROR "Missing DESTINATION argument for ecm_qt_install_logging_categories")
    endif()

    if(NOT ARGS_FILE)
        string(TOLOWER "${ARGS_EXPORT}.categories" ARGS_FILE)
    endif()

    set(_propertyprefix "ECM_QT_LOGGING_CATEGORY_${ARGS_EXPORT}")
    get_property(has_category GLOBAL PROPERTY "${_propertyprefix}_CATEGORIES" SET)

    if (NOT has_category)
        message(AUTHOR_WARNING "No Qt logging categories exported for \"${ARGS_EXPORT}\", generating & installing an empty file.")
    endif()

    get_property(_categories GLOBAL PROPERTY "${_propertyprefix}_CATEGORIES")
    if (ARGS_SORT)
        list(SORT _categories)
    endif()

    set(_renamed_categories)

    # generate categories file
    if (NOT IS_ABSOLUTE "${ARGS_FILE}")
        set(ARGS_FILE "${CMAKE_CURRENT_BINARY_DIR}/${ARGS_FILE}")
    endif()

    set(_categories_content
"# KDebugSettings data file
# This file was generated by ecm_qt_install_logging_categories(). DO NOT EDIT!

")

    foreach(_category IN LISTS _categories)
        get_property(_description GLOBAL PROPERTY "${_propertyprefix}_DESCRIPTION_${_category}")
        get_property(_identifier GLOBAL PROPERTY "${_propertyprefix}_IDENTIFIER_${_category}")
        get_property(_default_severity GLOBAL PROPERTY "${_propertyprefix}_DEFAULT_SEVERITY_${_category}")
        if (_default_severity)
            string(TOUPPER "${_default_severity}" _default_severity)
            set(_default_severity "DEFAULT_SEVERITY [${_default_severity}] ") # final space wanted
        endif()
        get_property(_old_category_names GLOBAL PROPERTY "${_propertyprefix}_OLD_NAMES_${_category}")
        if (_old_category_names)
            list(APPEND _renamed_categories ${_category})
        endif()

        # Format:
        # logname<space>description(optional <space> DEFAULT_SEVERITY [DEFAULT_CATEGORY] as WARNING/DEBUG/INFO/CRITICAL) optional IDENTIFIER [...])
        string(APPEND _categories_content "${_category} ${_description} ${_default_severity}IDENTIFIER [${_identifier}]\n")
    endforeach()

    file(GENERATE
        OUTPUT ${ARGS_FILE}
        CONTENT ${_categories_content}
    )

    set(_renamed_cats_file)
    if (_renamed_categories)
        get_filename_component(_dir ${ARGS_FILE} DIRECTORY)
        get_filename_component(_base_name ${ARGS_FILE} NAME_WLE)
        set(_renamed_cats_file "${_dir}/${_base_name}.renamecategories")
        set(_renamed_cats_content
"# KDebugSettings data file
# This file was generated by ecm_qt_install_logging_categories(). DO NOT EDIT!

")

        foreach(_category IN LISTS _renamed_categories)
            get_property(_category_name_history GLOBAL PROPERTY "${_propertyprefix}_OLD_NAMES_${_category}")

            list(APPEND _category_name_history ${_category})
            list(GET _category_name_history 0 _old_category_name)
            list(REMOVE_AT _category_name_history 0)
            foreach(_category_name IN LISTS _category_name_history)
                # Format:
                # oldlogname<space>newlogname
                string(APPEND _renamed_cats_content "${_old_category_name} ${_category_name}\n")
                set(_old_category_name ${_category_name})
            endforeach()
        endforeach()

        file(GENERATE
            OUTPUT ${_renamed_cats_file}
            CONTENT ${_renamed_cats_content}
        )
    endif()

    # install files
    set(_component_install)
    if (ARGS_COMPONENT)
        set(_component_install COMPONENT ${ARGS_COMPONENT})
    endif()
    install(
        FILES ${ARGS_FILE} ${_renamed_cats_file}
        DESTINATION "${ARGS_DESTINATION}"
        ${_component_install}
    )
endfunction()
// This file was generated by ecm_qt_declare_logging_category(): DO NOT EDIT!

#include "@HEADER_NAME@"

@OPEN_NAMESPACES@
Q_LOGGING_CATEGORY(@IDENTIFIER@, "@ARG_CATEGORY_NAME@", Qt@ARG_DEFAULT_SEVERITY@Msg)
@CLOSE_NAMESPACES@
// This file was generated by ecm_qt_declare_logging_category(): DO NOT EDIT!

#ifndef @GUARD_NAME@
#define @GUARD_NAME@

#include <QLoggingCategory>
@OPEN_NAMESPACES@
Q_DECLARE_LOGGING_CATEGORY(@IDENTIFIER@)
@CLOSE_NAMESPACES@

#endif
if (${ECM_GLOBAL_FIND_VERSION} VERSION_GREATER_EQUAL 5.93)
    message(DEPRECATION "ECMQueryQmake.cmake is deprecated since 5.93, please use ECMQueryQt.cmake instead.")
endif()

include(${CMAKE_CURRENT_LIST_DIR}/QtVersionOption.cmake)
find_package(Qt${QT_MAJOR_VERSION}Core QUIET)

if (Qt5Core_FOUND)
    set(_qmake_executable_default "qmake-qt5")
endif ()
if (TARGET Qt5::qmake)
    get_target_property(_qmake_executable_default Qt5::qmake LOCATION)
endif()
set(QMAKE_EXECUTABLE ${_qmake_executable_default}
    CACHE FILEPATH "Location of the Qt5 qmake executable")

# Helper method
# This is not public API (yet)!
# Usage: query_qmake(<result_variable> <qt_variable> [TRY])
# Passing TRY will result in the method not failing fatal if no qmake executable
# has been found, but instead simply returning an empty string
function(query_qmake result_variable qt_variable)
    set(options TRY)
    set(oneValueArgs )
    set(multiValueArgs )

    cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

    if(NOT QMAKE_EXECUTABLE)
        if(ARGS_TRY)
            set(${result_variable} "" PARENT_SCOPE)
            message(STATUS "No qmake Qt5 binary found. Can't check ${qt_variable}")
            return()
        else()
            message(FATAL_ERROR "No qmake Qt5 binary found. Can't check ${qt_variable} as required")
        endif()
    endif()
    execute_process(
        COMMAND ${QMAKE_EXECUTABLE} -query "${qt_variable}"
        RESULT_VARIABLE return_code
        OUTPUT_VARIABLE output
    )
    if(return_code EQUAL 0)
        string(STRIP "${output}" output)
        file(TO_CMAKE_PATH "${output}" output_path)
        set(${result_variable} "${output_path}" PARENT_SCOPE)
    else()
        message(WARNING "Failed call: ${QMAKE_EXECUTABLE} -query \"${qt_variable}\"")
        message(FATAL_ERROR "QMake call failed: ${return_code}")
    endif()
endfunction()
# SPDX-FileCopyrightText: 2014 Rohan Garg <rohan16garg@gmail.com>
# SPDX-FileCopyrightText: 2014 Alex Merry <alex.merry@kde.org>
# SPDX-FileCopyrightText: 2014-2016 Aleix Pol <aleixpol@kde.org>
# SPDX-FileCopyrightText: 2017 Friedrich W. H. Kossebau <kossebau@kde.org>
# SPDX-FileCopyrightText: 2022 Ahmad Samir <a.samir78@gmail.com>
#
# SPDX-License-Identifier: BSD-3-Clause
#[=======================================================================[.rst:
ECMQueryQt
---------------
This module can be used to query the installation paths used by Qt.

For Qt5 this uses ``qmake``, and for Qt6 this used ``qtpaths`` (the latter has built-in
support to query the paths of a target platform when cross-compiling).

This module defines the following function:
::

    ecm_query_qt(<result_variable> <qt_variable> [TRY])

Passing ``TRY`` will result in the method not making the build fail if the executable
used for querying has not been found, but instead simply print a warning message and
return an empty string.

Example usage:

.. code-block:: cmake

    include(ECMQueryQt)
    ecm_query_qt(bin_dir QT_INSTALL_BINS)

If the call succeeds ``${bin_dir}`` will be set to ``<prefix>/path/to/bin/dir`` (e.g.
``/usr/lib64/qt/bin/``).

Since: 5.93
#]=======================================================================]

include(${CMAKE_CURRENT_LIST_DIR}/QtVersionOption.cmake)
include(CheckLanguage)
check_language(CXX)
if (CMAKE_CXX_COMPILER)
    # Enable the CXX language to let CMake look for config files in library dirs.
    # See: https://gitlab.kitware.com/cmake/cmake/-/issues/23266
    enable_language(CXX)
endif()

if (QT_MAJOR_VERSION STREQUAL "5")
    # QUIET to accommodate the TRY option
    find_package(Qt${QT_MAJOR_VERSION}Core QUIET)
    set(_exec_name_text "Qt5 qmake")
    if(TARGET Qt5::qmake)
        get_target_property(_qmake_executable_default Qt5::qmake LOCATION)

        set(QUERY_EXECUTABLE ${_qmake_executable_default})
        set(_cli_option "-query")
    endif()
elseif(QT_MAJOR_VERSION STREQUAL "6")
    # QUIET to accommodate the TRY option
    find_package(Qt6 COMPONENTS CoreTools QUIET CONFIG)
    set(_exec_name_text "Qt6 qtpaths")
    if (TARGET Qt6::qtpaths)
        get_target_property(_qtpaths_executable Qt6::qtpaths LOCATION)

        set(QUERY_EXECUTABLE ${_qtpaths_executable})
        set(_cli_option "--query")
    endif()
endif()

function(ecm_query_qt result_variable qt_variable)
    set(options TRY)
    set(oneValueArgs)
    set(multiValueArgs)

    cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

    if(NOT QUERY_EXECUTABLE)
        if(ARGS_TRY)
            set(${result_variable} "" PARENT_SCOPE)
            message(STATUS "No ${_exec_name_text} executable found. Can't check ${qt_variable}")
            return()
        else()
            message(FATAL_ERROR "No ${_exec_name_text} executable found. Can't check ${qt_variable} as required")
        endif()
    endif()
    execute_process(
        COMMAND ${QUERY_EXECUTABLE} ${_cli_option} "${qt_variable}"
        RESULT_VARIABLE return_code
        OUTPUT_VARIABLE output
    )
    if(return_code EQUAL 0)
        string(STRIP "${output}" output)
        file(TO_CMAKE_PATH "${output}" output_path)
        set(${result_variable} "${output_path}" PARENT_SCOPE)
    else()
        message(WARNING "Failed call: ${QUERY_EXECUTABLE} ${_cli_option} ${qt_variable}")
        message(FATAL_ERROR "${_exec_name_text} call failed: ${return_code}")
    endif()
endfunction()
# SPDX-FileCopyrightText: 2018 Friedrich W. H. Kossebau <kossebau@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
ECMSetupQtPluginMacroNames
--------------------------

Instruct CMake's automoc about C++ preprocessor macros used to define Qt-style plugins.

::

  ecm_setup_qtplugin_macro_names(
      [JSON_NONE <macro_name> [<macro_name> [...]]]
      [JSON_ARG1 <macro_name> [<macro_name> [...]]]
      [JSON_ARG2 <macro_name> [<macro_name> [...]]]
      [JSON_ARG3 <macro_name> [<macro_name> [...]]]
      [CONFIG_CODE_VARIABLE <variable_name>] )

CMake's automoc needs some support when parsing C++ source files to detect whether moc
should be run on those files and if there are also dependencies on other files, like those
with Qt plugin metadata in JSON format. Because automoc just greps overs the raw plain text
of the sources without any C++ preprocessor-like processing.
CMake in newer versions provides the variables ``CMAKE_AUTOMOC_DEPEND_FILTERS`` (CMake >= 3.9.0)
and ``CMAKE_AUTOMOC_MACRO_NAMES`` (CMake >= 3.10) to allow the developer to assist automoc.

This macro cares for the explicit setup needed for those variables for common cases of
C++ preprocessor macros used for Qt-style plugins.

``JSON_NONE`` lists the names of C++ preprocessor macros for Qt-style plugins which do not refer to
external files with the plugin metadata.

``JSON_ARG1`` lists the names of C++ preprocessor macros for Qt-style plugins where the first argument
to the macro is the name of the external file with the plugin metadata.

``JSON_ARG2`` is the same as ``JSON_ARG1`` but with the file name being the second argument.

``JSON_ARG3`` is the same as ``JSON_ARG1`` but with the file name being the third argument.

``CONFIG_CODE_VARIABLE`` specifies the name of the variable which will get set as
value some generated CMake code for instructing automoc for the given macro names,
as useful in an installed CMake config file. The variable can then be used as usual in
the template file for such a CMake config file, by ``@<variable_name>@``.


Example usage:

Given some plugin-oriented Qt-based software which defines a custom C++ preprocessor
macro ``EXPORT_MYPLUGIN`` for declaring the central plugin object:

.. code-block:: c++

  #define EXPORT_MYPLUGIN_WITH_JSON(classname, jsonFile) \
  class classname : public QObject \
  { \
      Q_OBJECT \
      Q_PLUGIN_METADATA(IID "myplugin" FILE jsonFile) \
      explicit classname() {} \
  };

In the CMake buildsystem of the library one calls

.. code-block:: cmake

  ecm_setup_qtplugin_macro_names(
      JSON_ARG2
         EXPORT_MYPLUGIN_WITH_JSON
  )

to instruct automoc about the usage of that macro in the sources of the
library itself.

Given the software installs a library including the header with the macro
definition and a CMake config file, so 3rd-party can create additional
plugins by linking against the library, one passes additionally the name of
a variable which shall be set as value the CMake code needed to instruct
automoc about the usage of that macro.

.. code-block:: cmake

  ecm_setup_qtplugin_macro_names(
      JSON_ARG2
         EXPORT_MYPLUGIN_WITH_JSON
      CONFIG_CODE_VARIABLE
         PACKAGE_SETUP_AUTOMOC_VARIABLES
  )

This variable then is used in the template file (e.g.
``MyProjectConfig.cmake.in``) for the libary's installed CMake config file
and that way will ensure that in the 3rd-party plugin's buildsystem
automoc is instructed as well as needed:

::

  @PACKAGE_SETUP_AUTOMOC_VARIABLES@

Since 5.45.0.
#]=======================================================================]

include(CMakePackageConfigHelpers)

macro(ecm_setup_qtplugin_macro_names)
    set(options )
    set(oneValueArgs CONFIG_CODE_VARIABLE)
    set(multiValueArgs JSON_NONE JSON_ARG1 JSON_ARG2 JSON_ARG3)

    cmake_parse_arguments(ESQMN "${options}" "${oneValueArgs}" "${multiValueArgs}"  ${ARGN})

    if(ESQMN_UNPARSED_ARGUMENTS)
        message(FATAL_ERROR "Unknown keywords given to ECM_SETUP_QTPLUGIN_MACRO_NAMES(): \"${ESQMN_UNPARSED_ARGUMENTS}\"")
    endif()

    # CMAKE_AUTOMOC_MACRO_NAMES
    list(APPEND CMAKE_AUTOMOC_MACRO_NAMES
        ${ESQMN_JSON_NONE}
        ${ESQMN_JSON_ARG1}
        ${ESQMN_JSON_ARG2}
        ${ESQMN_JSON_ARG3}
    )

    # CMAKE_AUTOMOC_DEPEND_FILTERS
    # CMake's automoc needs help to find names of plugin metadata files in case Q_PLUGIN_METADATA
    # is indirectly used via other C++ preprocessor macros
    foreach(macro_name  ${ESQMN_JSON_ARG1})
        list(APPEND CMAKE_AUTOMOC_DEPEND_FILTERS
            "${macro_name}"
            "[\n^][ \t]*${macro_name}[ \t\n]*\\([ \t\n]*\"([^\"]+)\""
        )
    endforeach()
    foreach(macro_name  ${ESQMN_JSON_ARG2})
        list(APPEND CMAKE_AUTOMOC_DEPEND_FILTERS
            "${macro_name}"
            "[\n^][ \t]*${macro_name}[ \t\n]*\\([^,]*,[ \t\n]*\"([^\"]+)\""
        )
    endforeach()
    foreach(macro_name  ${ESQMN_JSON_ARG3})
        list(APPEND CMAKE_AUTOMOC_DEPEND_FILTERS
            "${macro_name}"
            "[\n^][ \t]*${macro_name}[ \t\n]*\\([^,]*,[^,]*,[ \t\n]*\"([^\"]+)\""
        )
    endforeach()

    if (ESQMN_CONFIG_CODE_VARIABLE)
        # As CMake config files of one project can be included multiple times,
        # the code to add entries to CMAKE_AUTOMOC_MACRO_NAMES & CMAKE_AUTOMOC_DEPEND_FILTERS
        # would then be also executed multiple times.
        # While there currently is no simple way known to have a unique flag to track
        # if the code was already executed, at least by the data currently passed to this macro,
        # simply check for the presence of the new entries  before adding them for now.
        # Not using IN_LIST in generated code, as projects might have CMP0057 set to OLD
        set(_content
"####################################################################################
# CMAKE_AUTOMOC
")
        set(_all_macro_names
            ${ESQMN_JSON_NONE}
            ${ESQMN_JSON_ARG1}
            ${ESQMN_JSON_ARG2}
            ${ESQMN_JSON_ARG3}
        )
        string(APPEND _content "
# CMake 3.9+ warns about automoc on files without Q_OBJECT, and doesn't know about other macros.
# 3.10+ lets us provide more macro names that require automoc.
foreach(macro_name  ${_all_macro_names})
    # we can be run multiple times, so add only once
    list (FIND CMAKE_AUTOMOC_MACRO_NAMES \"\${macro_name}\" _index)
    if(_index LESS 0)
        list(APPEND CMAKE_AUTOMOC_MACRO_NAMES \${macro_name})
    endif()
endforeach()
")

        if(ESQMN_JSON_ARG1 OR ESQMN_JSON_ARG2 OR ESQMN_JSON_ARG3)
            string(APPEND _content "
# CMake's automoc needs help to find names of plugin metadata files in case Q_PLUGIN_METADATA
# is indirectly used via other C++ preprocessor macros
")
            if(ESQMN_JSON_ARG1)
                string(APPEND _content
"foreach(macro_name  ${ESQMN_JSON_ARG1})
    # we can be run multiple times, so add only once
    list (FIND CMAKE_AUTOMOC_DEPEND_FILTERS \"\${macro_name}\" _index)
    if(_index LESS 0)
        list(APPEND CMAKE_AUTOMOC_DEPEND_FILTERS
            \"\${macro_name}\"
            \"[\\n^][ \\t]*\${macro_name}[ \\t\\n]*\\\\([ \\t\\n]*\\\"([^\\\"]+)\\\"\"
        )
    endif()
endforeach()
")
            endif()
            if(ESQMN_JSON_ARG2)
                string(APPEND _content
"foreach(macro_name  ${ESQMN_JSON_ARG2})
    # we can be run multiple times, so add only once
    list (FIND CMAKE_AUTOMOC_DEPEND_FILTERS \"\${macro_name}\" _index)
    if(_index LESS 0)
        list(APPEND CMAKE_AUTOMOC_DEPEND_FILTERS
            \"\${macro_name}\"
            \"[\\n^][ \\t]*\${macro_name}[ \\t\\n]*\\\\([^,]*,[ \\t\\n]*\\\"([^\\\"]+)\\\"\"
        )
    endif()
endforeach()
")
            endif()
            if(ESQMN_JSON_ARG3)
                string(APPEND _content
"foreach(macro_name  ${ESQMN_JSON_ARG3})
    # we can be run multiple times, so add only once
    list (FIND CMAKE_AUTOMOC_DEPEND_FILTERS \"\${macro_name}\" _index)
    if(_index LESS 0)
        list(APPEND CMAKE_AUTOMOC_DEPEND_FILTERS
            \"\${macro_name}\"
            \"[\\n^][ \\t]*\${macro_name}[ \\t\\n]*\\\\([^,]*,[^,]*,[ \\t\\n]*\\\"([^\\\"]+)\\\"\"
        )
    endif()
endforeach()
")
            endif()
        endif()
        string(APPEND _content "
####################################################################################"
        )

        set(${ESQMN_CONFIG_CODE_VARIABLE} ${_content})
    endif()
endmacro()
# SPDX-FileCopyrightText: 2014 Alex Merry <alex.merry@kde.org>
# SPDX-FileCopyrightText: 2012 Alexander Neundorf <neundorf@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
ECMSetupVersion
---------------

Handle library version information.

::

  ecm_setup_version(<version>
                    VARIABLE_PREFIX <prefix>
                    [SOVERSION <soversion>]
                    [VERSION_HEADER <filename>]
                    [PACKAGE_VERSION_FILE <filename> [COMPATIBILITY <compat>]] )

This parses a version string and sets up a standard set of version variables.
It can optionally also create a C version header file and a CMake package
version file to install along with the library.

If the ``<version>`` argument is of the form ``<major>.<minor>.<patch>``
(or ``<major>.<minor>.<patch>.<tweak>``), The following CMake variables are
set::

  <prefix>_VERSION_MAJOR  - <major>
  <prefix>_VERSION_MINOR  - <minor>
  <prefix>_VERSION_PATCH  - <patch>
  <prefix>_VERSION        - <version>
  <prefix>_SOVERSION      - <soversion>, or <major> if SOVERSION was not given

For backward-compatibility also this variable is set (only if the minimum required
version of ECM is < 5.83)::

  <prefix>_VERSION_STRING - <version> (use <prefix>_VERSION instead)

If CMake policy CMP0048 is not ``NEW``, the following CMake variables will also
be set::

  PROJECT_VERSION_MAJOR   - <major>
  PROJECT_VERSION_MINOR   - <minor>
  PROJECT_VERSION_PATCH   - <patch>
  PROJECT_VERSION         - <version>

For backward-compatibility, if CMake policy CMP0048 is not ``NEW``, also this variable is set
(only if the minimum required version of ECM is < 5.83)::

  PROJECT_VERSION_STRING  - <version> (use PROJECT_VERSION instead)

If the ``VERSION_HEADER`` option is used, a simple C header is generated with the
given filename. If filename is a relative path, it is interpreted as relative
to ``CMAKE_CURRENT_BINARY_DIR``.  The generated header contains the following
macros::

   <prefix>_VERSION_MAJOR  - <major> as an integer
   <prefix>_VERSION_MINOR  - <minor> as an integer
   <prefix>_VERSION_PATCH  - <patch> as an integer
   <prefix>_VERSION_STRING - <version> as a C string
   <prefix>_VERSION        - the version as an integer

``<prefix>_VERSION`` has ``<patch>`` in the bottom 8 bits, ``<minor>`` in the
next 8 bits and ``<major>`` in the remaining bits.  Note that ``<patch>`` and
``<minor>`` must be less than 256.

If the ``PACKAGE_VERSION_FILE`` option is used, a simple CMake package version
file is created using the ``write_basic_package_version_file()`` macro provided by
CMake. It should be installed in the same location as the Config.cmake file of
the library so that it can be found by ``find_package()``.  If the filename is a
relative path, it is interpreted as relative to ``CMAKE_CURRENT_BINARY_DIR``. The
optional ``COMPATIBILITY`` option is forwarded to
``write_basic_package_version_file()``, and defaults to ``AnyNewerVersion``.

If CMake policy CMP0048 is ``NEW``, an alternative form of the command is
available::

  ecm_setup_version(PROJECT
                    [VARIABLE_PREFIX <prefix>]
                    [SOVERSION <soversion>]
                    [VERSION_HEADER <filename>]
                    [PACKAGE_VERSION_FILE <filename>] )

This will use the version information set by the ``project()`` command.
``VARIABLE_PREFIX`` defaults to the project name.  Note that ``PROJECT`` must be the
first argument.  In all other respects, it behaves like the other form of the
command.

Since pre-1.0.0.

``COMPATIBILITY`` option available since 1.6.0.
#]=======================================================================]

include(CMakePackageConfigHelpers)

# save the location of the header template while CMAKE_CURRENT_LIST_DIR
# has the value we want
set(_ECM_SETUP_VERSION_HEADER_TEMPLATE "${CMAKE_CURRENT_LIST_DIR}/ECMVersionHeader.h.in")

function(ecm_setup_version _version)
    set(options )
    set(oneValueArgs VARIABLE_PREFIX SOVERSION VERSION_HEADER PACKAGE_VERSION_FILE COMPATIBILITY)
    set(multiValueArgs )

    cmake_parse_arguments(ESV "${options}" "${oneValueArgs}" "${multiValueArgs}"  ${ARGN})

    if(ESV_UNPARSED_ARGUMENTS)
        message(FATAL_ERROR "Unknown keywords given to ECM_SETUP_VERSION(): \"${ESV_UNPARSED_ARGUMENTS}\"")
    endif()

    set(project_manages_version FALSE)
    set(use_project_version FALSE)
    cmake_policy(GET CMP0048 project_version_policy)
    if(project_version_policy STREQUAL "NEW")
        set(project_manages_version TRUE)
        if(_version STREQUAL "PROJECT")
            set(use_project_version TRUE)
        endif()
    elseif(_version STREQUAL "PROJECT")
        message(FATAL_ERROR "ecm_setup_version given PROJECT argument, but CMP0048 is not NEW")
    endif()

    set(should_set_prefixed_vars TRUE)
    if(NOT ESV_VARIABLE_PREFIX)
        if(use_project_version)
            set(ESV_VARIABLE_PREFIX "${PROJECT_NAME}")
            set(should_set_prefixed_vars FALSE)
        else()
            message(FATAL_ERROR "Required argument PREFIX missing in ECM_SETUP_VERSION() call")
        endif()
    endif()

    if(use_project_version)
        set(_version "${PROJECT_VERSION}")
        # drop leading 0 from values to avoid bogus octal values in c/C++ e.g. with 08 or 09
        string(REGEX REPLACE "0*([0-9]+)" "\\1" _major "${PROJECT_VERSION_MAJOR}")
        string(REGEX REPLACE "0*([0-9]+)" "\\1" _minor "${PROJECT_VERSION_MINOR}")
        string(REGEX REPLACE "0*([0-9]+)" "\\1" _patch "${PROJECT_VERSION_PATCH}")
    else()
        string(REGEX REPLACE "^0*([0-9]+)\\.[0-9]+\\.[0-9]+.*" "\\1" _major "${_version}")
        string(REGEX REPLACE "^[0-9]+\\.0*([0-9]+)\\.[0-9]+.*" "\\1" _minor "${_version}")
        string(REGEX REPLACE "^[0-9]+\\.[0-9]+\\.0*([0-9]+).*" "\\1" _patch "${_version}")
    endif()

    if(NOT DEFINED ESV_SOVERSION) # use DEFINED, so "0" as valid SO version is not evaluated to FALSE
        set(ESV_SOVERSION ${_major})
    endif()

    if(ECM_GLOBAL_FIND_VERSION VERSION_LESS 5.83.0)
        set(_set_backward_compat_version_string_vars TRUE)
    else()
        set(_set_backward_compat_version_string_vars FALSE)
    endif()

    if(should_set_prefixed_vars)
        set(${ESV_VARIABLE_PREFIX}_VERSION "${_version}")
        set(${ESV_VARIABLE_PREFIX}_VERSION_MAJOR ${_major})
        set(${ESV_VARIABLE_PREFIX}_VERSION_MINOR ${_minor})
        set(${ESV_VARIABLE_PREFIX}_VERSION_PATCH ${_patch})
    endif()

    set(${ESV_VARIABLE_PREFIX}_SOVERSION ${ESV_SOVERSION})

    if(NOT project_manages_version)
        set(PROJECT_VERSION "${_version}")
        set(PROJECT_VERSION_MAJOR "${_major}")
        set(PROJECT_VERSION_MINOR "${_minor}")
        set(PROJECT_VERSION_PATCH "${_patch}")
    endif()

    if(_set_backward_compat_version_string_vars)
        set(PROJECT_VERSION_STRING "${PROJECT_VERSION}")
        set(${ESV_VARIABLE_PREFIX}_VERSION_STRING "${${ESV_VARIABLE_PREFIX}_VERSION}")
    endif()

    if(ESV_VERSION_HEADER)
        set(HEADER_PREFIX "${ESV_VARIABLE_PREFIX}")
        set(HEADER_VERSION "${_version}")
        set(HEADER_VERSION_MAJOR "${_major}")
        set(HEADER_VERSION_MINOR "${_minor}")
        set(HEADER_VERSION_PATCH "${_patch}")
        configure_file("${_ECM_SETUP_VERSION_HEADER_TEMPLATE}" "${ESV_VERSION_HEADER}")
    endif()

    if(ESV_PACKAGE_VERSION_FILE)
        if(NOT ESV_COMPATIBILITY)
            set(ESV_COMPATIBILITY AnyNewerVersion)
        endif()
        write_basic_package_version_file("${ESV_PACKAGE_VERSION_FILE}" VERSION ${_version} COMPATIBILITY ${ESV_COMPATIBILITY})
    endif()

    if(should_set_prefixed_vars)
        set(${ESV_VARIABLE_PREFIX}_VERSION_MAJOR "${${ESV_VARIABLE_PREFIX}_VERSION_MAJOR}" PARENT_SCOPE)
        set(${ESV_VARIABLE_PREFIX}_VERSION_MINOR "${${ESV_VARIABLE_PREFIX}_VERSION_MINOR}" PARENT_SCOPE)
        set(${ESV_VARIABLE_PREFIX}_VERSION_PATCH "${${ESV_VARIABLE_PREFIX}_VERSION_PATCH}" PARENT_SCOPE)
        set(${ESV_VARIABLE_PREFIX}_VERSION       "${${ESV_VARIABLE_PREFIX}_VERSION}"       PARENT_SCOPE)
    endif()

    # always set the soversion
    set(${ESV_VARIABLE_PREFIX}_SOVERSION "${${ESV_VARIABLE_PREFIX}_SOVERSION}" PARENT_SCOPE)

    if(NOT project_manages_version)
        set(PROJECT_VERSION       "${PROJECT_VERSION}"       PARENT_SCOPE)
        set(PROJECT_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}" PARENT_SCOPE)
        set(PROJECT_VERSION_MINOR "${PROJECT_VERSION_MINOR}" PARENT_SCOPE)
        set(PROJECT_VERSION_PATCH "${PROJECT_VERSION_PATCH}" PARENT_SCOPE)
    endif()

    if(_set_backward_compat_version_string_vars)
        set(PROJECT_VERSION_STRING "${PROJECT_VERSION_STRING}" PARENT_SCOPE)
        set(${ESV_VARIABLE_PREFIX}_VERSION_STRING "${${ESV_VARIABLE_PREFIX}_VERSION}" PARENT_SCOPE)
    endif()
endfunction()
# SPDX-FileCopyrightText: 2019 Harald Sitter <sitter@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
ECMSourceVersionControl
--------------------------

Tries to determine whether the source is under version control (git clone,
svn checkout, etc).

``ECM_SOURCE_UNDER_VERSION_CONTROL`` is set when indication is found that
``CMAKE_SOURCE_DIR`` is under version control.

Since 5.63
#]=======================================================================]

if(EXISTS "${CMAKE_SOURCE_DIR}/.git" OR
   EXISTS "${CMAKE_SOURCE_DIR}/.svn" OR
   EXISTS "${CMAKE_SOURCE_DIR}/.hg" OR
   EXISTS "${CMAKE_SOURCE_DIR}/.bzr")
    set(ECM_SOURCE_UNDER_VERSION_CONTROL TRUE)
else()
    set(ECM_SOURCE_UNDER_VERSION_CONTROL FALSE)
endif()
# SPDX-FileCopyrightText: 2015 Alex Merry <alex.merry@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
ECMUninstallTarget
------------------

Add an ``uninstall`` target.

By including this module, an ``uninstall`` target will be added to your CMake
project. This will remove all files installed (or updated) by a previous
invocation of the ``install`` target. It will not remove files created or
modified by an ``install(SCRIPT)`` or ``install(CODE)`` command; you should
create a custom uninstallation target for these and use ``add_dependency`` to
make the ``uninstall`` target depend on it:

.. code-block:: cmake

  include(ECMUninstallTarget)
  install(SCRIPT install-foo.cmake)
  add_custom_target(uninstall_foo COMMAND ${CMAKE_COMMAND} -P uninstall-foo.cmake)
  add_dependency(uninstall uninstall_foo)

The target will fail if the ``install`` target has not yet been run (so it is
not possible to run CMake on the project and then immediately run the
``uninstall`` target).

.. warning::

  CMake deliberately does not provide an ``uninstall`` target by default on
  the basis that such a target has the potential to remove important files
  from a user's computer. Use with caution.

Since 1.7.0.
#]=======================================================================]

if (NOT TARGET uninstall)
    configure_file(
        "${CMAKE_CURRENT_LIST_DIR}/ecm_uninstall.cmake.in"
        "${CMAKE_BINARY_DIR}/ecm_uninstall.cmake"
        IMMEDIATE
        @ONLY
    )

    add_custom_target(uninstall
        COMMAND "${CMAKE_COMMAND}" -P "${CMAKE_BINARY_DIR}/ecm_uninstall.cmake"
        WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
    )
endif()
# SPDX-FileCopyrightText: 2011 Alexander Neundorf <neundorf@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
ECMUseFindModules
-----------------

Selectively use some of the find modules provided by extra-cmake-modules.

This module is automatically available once extra-cmake-modules has been
found, so it is not necessary to ``include(ECMUseFindModules)`` explicitly.

::

  ecm_use_find_modules(DIR <dir>
                       MODULES module1.cmake [module2.cmake [...]]
                       [NO_OVERRIDE])

This allows selective use of the find modules provided by ECM, including
deferring to CMake's versions of those modules if it has them.  Rather than
adding ``${ECM_FIND_MODULE_DIR}`` to ``CMAKE_MODULE_PATH``, you use
``ecm_use_find_modules()`` to copy the modules you want to a local (build)
directory, and add that to ``CMAKE_MODULE_PATH``.

The find modules given to ``MODULES`` will be copied to the directory given by ``DIR``
(which should be located in ``${CMAKE_BINARY_DIR}`` and added to
``CMAKE_MODULE_PATH``).  If ``NO_OVERRIDE`` is given, only modules not also
provided by CMake will be copied.

Example:

.. code-block:: cmake

  find_package(ECM REQUIRED)
  ecm_use_find_modules(
      DIR ${CMAKE_BINARY_DIR}/cmake
      MODULES FindEGL.cmake
      NO_OVERRIDE
  )
  set(CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR}/cmake)

This example will make ``FindEGL.cmake`` available in your project, but only
as long as it is not yet part of CMake. Calls to ``find_package(EGL)`` will
then make use of this copied module (or the CMake module if it exists).

Another possible use for this macro is to take copies of find modules that can
be installed along with config files if they are required as a dependency (for
example, if targets provided by the find module are in the link interface of a
library).

Since pre-1.0.0.
#]=======================================================================]

function(ecm_use_find_modules)
   set(_options NO_OVERRIDE )
   set(_oneValueArgs DIR )
   set(_multiValueArgs MODULES )
   cmake_parse_arguments(EUFM "${_options}" "${_oneValueArgs}" "${_multiValueArgs}" ${ARGN} )
   if(NOT EUFM_DIR)
      message(FATAL_ERROR "No DIR specified for ecm_use_find_modules() !")
   endif()

   if(NOT IS_ABSOLUTE "${EUFM_DIR}")
      set(EUFM_DIR "${CMAKE_CURRENT_BINARY_DIR}/${EUFM_DIR}")
   endif()
   file(MAKE_DIRECTORY "${EUFM_DIR}")

   foreach(file ${EUFM_MODULES})
      if(NOT EXISTS ${ECM_FIND_MODULE_DIR}/${file} )
         message(FATAL_ERROR "File ${file} not found in ${ECM_FIND_MODULE_DIR} !")
      endif()
      if(NOT EXISTS "${CMAKE_ROOT}/Modules/${file}" OR NOT EUFM_NO_OVERRIDE)
         configure_file("${ECM_FIND_MODULE_DIR}/${file}" "${EUFM_DIR}/${file}" COPYONLY)
      endif()
   endforeach()
   # This is required by some of the find modules
   file(WRITE "${EUFM_DIR}/ECMFindModuleHelpersStub.cmake"
        "include(\"${ECM_MODULE_DIR}/ECMFindModuleHelpers.cmake\")")

endfunction()
// This file was generated by ecm_setup_version(): DO NOT EDIT!

#ifndef @HEADER_PREFIX@_VERSION_H
#define @HEADER_PREFIX@_VERSION_H

#define @HEADER_PREFIX@_VERSION_STRING "@HEADER_VERSION@"
#define @HEADER_PREFIX@_VERSION_MAJOR @HEADER_VERSION_MAJOR@
#define @HEADER_PREFIX@_VERSION_MINOR @HEADER_VERSION_MINOR@
#define @HEADER_PREFIX@_VERSION_PATCH @HEADER_VERSION_PATCH@
#define @HEADER_PREFIX@_VERSION ((@HEADER_VERSION_MAJOR@<<16)|(@HEADER_VERSION_MINOR@<<8)|(@HEADER_VERSION_PATCH@))

#endif
# SPDX-FileCopyrightText: 2016 Gleb Popov <6yearold@gmail.com>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
ECMWinResolveSymlinks
--------------------------

Resolve pseudo-symlinks created by git when cloning on Windows.

::

  ecm_win_resolve_symlinks(<dir>)

When git checks out a repository with UNIX symlinks on Windows machine,
it creates a text file for each symlink, containing a relative path to the
real file.
This function would recursively walk over specified directory and replace
pseudo-symlinks with corresponding real file's contents. It would then run
``git update-index --assume-unchanged`` on them to trick git.

This is useful for projects like "breeze-icons" that contain many identical
icons implemented as symlinks.

Since 5.28
#]=======================================================================]

function(ECM_WIN_RESOLVE_SYMLINKS _dir)
  get_filename_component(dir ${_dir} ABSOLUTE)
  find_program(GIT_EXECUTABLE git)
  if(NOT GIT_EXECUTABLE)
    message(SEND_ERROR "Git executable not found!")
  endif()

  message(STATUS "Resolving symlinks in ${dir}...")
  _find_symlinks(${dir} symlinks)
  _portioned_list(symlinks ${symlinks})
  foreach(s IN LISTS symlinks)
    string(REPLACE ":" ";" s ${s})
    _assume_unchanged(NO ${dir} "${s}")
    _checkout_symlinks(${dir} "${s}")
    _resolve_symlinks(${dir} "${s}")
    _assume_unchanged(YES ${dir} "${s}")
  endforeach()
  message(STATUS "Resolving symlinks in ${dir}... Done.")

  # touch cache every build to force CMake to re-run these functions every time
  if(NOT TARGET wrs_touch_cache)
    add_custom_target(wrs_touch_cache ALL
      COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_BINARY_DIR}/CMakeCache.txt
    )
  endif()
endfunction()

function(_assume_unchanged mode dir symlinks)
  if(mode)
    set(flag --assume-unchanged)
  else()
    set(flag --no-assume-unchanged)
  endif()

  execute_process(COMMAND ${GIT_EXECUTABLE} update-index ${flag} ${symlinks}
    WORKING_DIRECTORY ${dir}
  )
endfunction()

function(_find_symlinks dir outvar)
  execute_process(COMMAND ${GIT_EXECUTABLE} ls-files -s
    WORKING_DIRECTORY ${dir}
    OUTPUT_VARIABLE out
    OUTPUT_STRIP_TRAILING_WHITESPACE
  )

  set(${outvar})
  if(out)
    string(REPLACE "\n" ";" out ${out})

    foreach(f IN LISTS out)
      # 120000 0db97052931e18484b6705f3bc644484ef9403b0 0 <tab> icons-dark/actions/16/CVnamespace.svg
      string(REPLACE "\t" ";" f "${f}")
      string(REPLACE " " ";" f "${f}")
      list(GET f 0 mode)
      if(mode STREQUAL "120000")
        list(GET f 3 symlink)
        list(APPEND ${outvar} ${symlink})
      endif()
    endforeach()
  endif()
  set(${outvar} ${${outvar}} PARENT_SCOPE)
endfunction()

# In functions like _checkout_symlinks() the command line can become too lengthy for Windows.
# So we partition it, but in a hacky way due to CMake doesn't have list of lists.
function(_portioned_list outvar)
  list(LENGTH ARGN arglen)

  if(arglen EQUAL 0)
    set(${outvar} "" PARENT_SCOPE)
    return()
  endif()

  set(init)
  set(tail)
  math(EXPR range "${arglen} - 1")
  foreach(i RANGE ${range})
    list(GET ARGN ${i} v)
    string(LENGTH "${init}" initlen)
    string(LENGTH ${v} vlen)
    math(EXPR sumlen "${initlen} + ${vlen}")
    if(sumlen LESS 8192)
      list(APPEND init ${v})
    else()
      list(APPEND tail ${v})
    endif()
  endforeach()

  _portioned_list(tail_portioned ${tail})
  string(REPLACE ";" ":" init "${init}") # Generally this is not safe, because filepath can contain ':' character. But not on Windows. Phew.
  set(${outvar} ${init} ${tail_portioned} PARENT_SCOPE)
endfunction()

function(_checkout_symlinks dir symlinks)
  execute_process(COMMAND ${GIT_EXECUTABLE} checkout ${symlinks}
    WORKING_DIRECTORY ${dir}
  )
endfunction()

function(_resolve_symlinks dir symlinks)
  foreach(s IN LISTS symlinks)
    file(READ ${dir}/${s} sdata)
    get_filename_component(sdir ${dir}/${s} DIRECTORY)
    set(f "${sdir}/${sdata}")
    file(READ ${f} fdata)
    file(WRITE ${dir}/${s} ${fdata})
  endforeach()
endfunction()
# SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
QtVersionOption
---------------

Adds a build option to select the major Qt version if necessary,
that is, if the major Qt version has not yet been determined otherwise
(e.g. by a corresponding ``find_package()`` call).
This module is typically included by other modules requiring knowledge
about the major Qt version.

If the ECM version passed to find_package was at least 5.240.0 Qt6 is picked by default.
Otherwise Qt5 is picked.

``QT_MAJOR_VERSION`` is defined to either be "5" or "6".

Since 5.82.0.
#]=======================================================================]

if (DEFINED QT_MAJOR_VERSION)
    return()
endif()

if (TARGET Qt5::Core)
    set(QT_MAJOR_VERSION 5)
elseif (TARGET Qt6::Core)
    set(QT_MAJOR_VERSION 6)
else()
    if (ECM_GLOBAL_FIND_VERSION VERSION_GREATER_EQUAL 5.240)
        option(BUILD_WITH_QT6 "Build against Qt 6" ON)
    else()
        option(BUILD_WITH_QT6 "Build against Qt 6" OFF)
    endif()

    if (BUILD_WITH_QT6)
        set(QT_MAJOR_VERSION 6)
    else()
        set(QT_MAJOR_VERSION 5)
    endif()
endif()
#!/usr/bin/env python3
# SPDX-FileCopyrightText: 2020 Andreas Cord-Landwehr <cordlandwehr@kde.org>
# SPDX-License-Identifier: BSD-3-Clause

# key    : outbound license identifier
# values : list of acceptable licenses that are compatible with outbound license
compatibilityMatrix = {
    "MIT": [
        "CC0-1.0",
        "MIT"],
    "BSD-2-Clause": [
        "CC0-1.0",
        "MIT",
        "BSD-2-Clause"],
    "BSD-3-Clause": [
        "CC0-1.0",
        "MIT",
        "BSD-2-Clause",
        "BSD-3-Clause"],
    "LGPL-2.0-only": [
        "CC0-1.0",
        "LGPL-2.0-only",
        "LGPL-2.0-or-later",
        "MIT",
        "BSD-2-Clause",
        "BSD-3-Clause",
        "bzip2-1.0.6"],
    "LGPL-2.1-only": [
        "CC0-1.0",
        "LGPL-2.0-or-later",
        "LGPL-2.1-only",
        "LGPL-2.1-or-later",
        "MIT",
        "BSD-2-Clause",
        "BSD-3-Clause",
        "bzip2-1.0.6"],
    "LGPL-3.0-only": [
        "CC0-1.0",
        "LGPL-2.0-or-later",
        "LGPL-2.1-or-later",
        "LGPL-3.0-only",
        "LGPL-3.0-or-later",
        "LicenseRef-KDE-Accepted-LGPL",
        "MIT",
        "BSD-2-Clause",
        "BSD-3-Clause",
        "bzip2-1.0.6"],
    "GPL-2.0-only": [
        "CC0-1.0",
        "LGPL-2.0-only",
        "LGPL-2.1-only",
        "LGPL-2.0-or-later",
        "LGPL-2.1-or-later",
        "GPL-2.0-only",
        "GPL-2.0-or-later",
        "MIT",
        "BSD-2-Clause",
        "BSD-3-Clause",
        "bzip2-1.0.6"],
    "GPL-3.0-only": [
        "CC0-1.0",
        "LGPL-2.0-or-later",
        "LGPL-2.1-or-later",
        "LGPL-3.0-only",
        "LGPL-3.0-or-later",
        "GPL-2.0-or-later",
        "GPL-3.0-only",
        "GPL-3.0-or-later",
        "LicenseRef-KDE-Accepted-GPL",
        "LicenseRef-KDE-Accepted-LGPL",
        "MIT",
        "BSD-2-Clause",
        "BSD-3-Clause",
        "bzip2-1.0.6"]
}

def check_outbound_license(license, files, spdxDictionary):
    """
    Asserts that the list of source files @p files, when combined into
    a library or executable, can be delivered under the combined license @p license .
    """
    print("Checking Target License: " + license)
    if not license in compatibilityMatrix:
        print("Error: unknown license selected")
        return False

    allLicensesAreCompatible = True

    for sourceFile in files:
        compatible = False
        sourceFileStripped = sourceFile.strip()
        for fileLicense in spdxDictionary[sourceFileStripped]:
            if fileLicense in compatibilityMatrix[license]:
                compatible = True
                print("OK " + sourceFileStripped + " : " + fileLicense)
        if not compatible:
            allLicensesAreCompatible = False
            print("-- " + sourceFileStripped + " : ( " + ", ".join([str(i) for i in spdxDictionary[sourceFileStripped]]) + " )")
    return allLicensesAreCompatible

if __name__ == '__main__':
    print("Parsing SPDX BOM file")
    import sys
    import argparse

    # parse commands
    parser = argparse.ArgumentParser()
    parser.add_argument("-l", "--license", help="set outbound license to test")
    parser.add_argument("-s", "--spdx", help="spdx bill-of-materials file")
    parser.add_argument("-i", "--input", help="input file with list of source files to test")
    args = parser.parse_args()

    # TODO check if required arguments are present and give meaningful feedback

    # collect name and licenses from SPDX blocks
    spdxDictionary = {}
    fileName = ""
    licenses = []
    f = open(args.spdx, "r")
    for line in f:
        if line.startswith("FileName:"):
            # strip "FileName: "
            # thus name expected to start with "./", which is relative to CMAKE_SOURCE_DIR
            fileName = line[10:].strip()
        if line.startswith("LicenseInfoInFile:"):
            licenses.append(line[19:].strip())
        if line == '' or line == "\n":
            spdxDictionary[fileName] = licenses
            fileName = ""
            licenses = []
    f.close()

    spdxDictionary[fileName] = licenses

    # read file with list of test files
    f = open(args.input, "r")
    testfiles = f.readlines()
    f.close()

    if check_outbound_license(args.license, testfiles, spdxDictionary) is True:
        sys.exit(0)

    # in any other case, return error code
    sys.exit(1)
if(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt")
    message(FATAL_ERROR "Cannot find install manifest: @CMAKE_BINARY_DIR@/install_manifest.txt")
endif()

file(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files)
string(REGEX REPLACE "\n" ";" files "${files}")
foreach(file ${files})
    message(STATUS "Uninstalling $ENV{DESTDIR}${file}")
    if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
        execute_process(
            COMMAND "@CMAKE_COMMAND@" -E remove "$ENV{DESTDIR}${file}"
            RESULT_VARIABLE rm_retval
            )
        if(NOT "${rm_retval}" STREQUAL 0)
            message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}")
        endif()
    else()
        message(STATUS "File $ENV{DESTDIR}${file} does not exist.")
    endif()
endforeach()
string(REPLACE / ";" processedArgs "${ARG_UNPARSED_ARGUMENTS}")

execute_process(COMMAND qmlplugindump -nonrelocatable ${processedArgs} ${KDE_INSTALL_QMLDIR} > ${CMAKE_CURRENT_SOURCE_DIR}/plugins.qmltypes RESULT_VARIABLE code)
if(code)
    message(FATAL_ERROR "Could not call qmlplugindump successfully. Exited with code ${code}")
endif()

execute_process(COMMAND diff -I "//*" ${INPUT} ${CMAKE_CURRENT_SOURCE_DIR}/plugins.qmltypes RESULT_VARIABLE code OUTPUT_VARIABLE out)
if(code)
    message(FATAL_ERROR "both plugin dumps differ:\n${out}")
endif()
# SPDX-FileCopyrightText: 2014 Aleix Pol i Gonzalez <aleixpol@kde.org>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
AndroidToolchain
----------------

Enable easy compilation of cmake projects on Android.

By using this android toolchain, the projects will be set up to compile the
specified project targeting an Android platform, depending on its input.
Furthermore, if desired, an APK can be directly generated by using the
`androiddeployqt <https://doc.qt.io/qt-5/deployment-android.html>`_ tool.

CMake upstream has Android support now. This module will still give us some
useful features offering androiddeployqt integration and adequate executables
format for our Android applications.

Since we are using CMake Android support, any information from CMake documentation
still applies:
https://cmake.org/cmake/help/v3.7/manual/cmake-toolchains.7.html#cross-compiling-for-android

.. note::

  This module requires CMake 3.18.

Since 1.7.0.

Usage
=====

To use this file, you need to set the ``CMAKE_TOOLCHAIN_FILE`` to point to
``Android.cmake`` on the command line::

  cmake -DCMAKE_TOOLCHAIN_FILE=/usr/share/ECM/toolchain/Android.cmake

You will also need to provide the locations of the Android NDK and SDK. This
can be done on the commandline or with environment variables; in either case
the variable names are:

``CMAKE_ANDROID_NDK``
    The NDK root path.
``ANDROID_SDK_ROOT``
    The SDK root path.

Additional options are specified as cache variables (eg: on the command line):

``ANDROID_ABI``
    The ABI to use. See the ``sources/cxx-stl/gnu-libstdc++/*/libs``
    directories in the NDK. Default: ``armeabi-v7a``.
``ANDROID_SDK_COMPILE_API``
    The platform API level to compile against. May be different from the NDK
    target. Default: newest installed version (e.g. android-30).
``ANDROID_SDK_BUILD_TOOLS_REVISION``
    The build tools version to use.
    Default: newest installed version (e.g. ``30.0.2``).
``ANDROID_EXTRA_LIBS``
    The ";"-separated list of full paths to libs to include in resulting APK (Qt 5 only).

For integrating other libraries which are not part of the Android toolchain,
like Qt5, and installed to a separate prefix on the host system, the install
prefixes of those libraries would be passed as alternative roots as list via
``ECM_ADDITIONAL_FIND_ROOT_PATH``. Since 5.30.0.

For example, for integrating a Qt5 for Android present at
``~/Qt/5.14.2/android/`` and some other libraries installed to
the prefix ``/opt/android/foo``, you would use::

  cmake \
    -DCMAKE_TOOLCHAIN_FILE=/usr/share/ECM/toolchain/Android.cmake \
    -DECM_ADDITIONAL_FIND_ROOT_PATH="~/Qt/5.14.2/android/;/opt/android/foo"

If your project uses ``find_package()`` to locate build tools on the host
system, make sure to pass ``CMAKE_FIND_ROOT_PATH_BOTH`` or
``NO_CMAKE_FIND_ROOT_PATH`` as argument in the call. See the
``find_package()`` documentation for more details.

Deploying Qt 5 Applications
===========================

After building the application, you will need to generate an APK that can be
deployed to an Android device. This module integrates androiddeployqt support
to help with this for Qt-based projects. To enable this, set the
``QTANDROID_EXPORTED_TARGET`` variable to the targets you wish to export as an
APK (in a ;-separed list), as well as ``ANDROID_APK_DIR`` to a directory
containing some basic information. This will create a ``create-apk-<target>``
target that will generate the APK file.  See the `Qt on Android deployment
documentation <https://doc.qt.io/qt-5/deployment-android.html>`_ for more
information.

For example, you could do::

  cmake \
    -DCMAKE_TOOLCHAIN_FILE=/usr/share/ECM/toolchain/Android.cmake \
    -DQTANDROID_EXPORTED_TARGET=myapp \
    -DANDROID_APK_DIR=myapp-apk
  make
  make create-apk-myapp

You can specify the APK output directory by setting ``ANDROID_APK_OUTPUT_DIR``.
Otherwise the APK can be found in ``myapp_build_apk/`` in the build directory.

The create-apk-myapp target will be able to take an ARGS parameter with further
arguments for androiddeployqt. For example, one can use::

  make create-apk-myapp ARGS="--install"

To install the apk to test. To generate a signed apk, one can do it with the
following syntax::

  make create-apk-myapp ARGS="--sign ~/my.keystore alias_name"

In case it's needed for your application to set the APK directory from cmake
scripting you can also set the directory as the ANDROID_APK_DIR property of
the create-apk-myapp target.

See Android documentation on how to create a keystore to use

Advanced Options
================

The following packaging options are mainly interesting for automation or integration
with CI/CD pipelines:

``ANDROID_APK_OUTPUT_DIR``
    Specifies a folder where the generated APK files should be placed.
``ANDROID_FASTLANE_METADATA_OUTPUT_DIR``
    Specifies a folder where the generated metadata for the F-Droid store
    should be placed.
``ANDROIDDEPLOYQT_EXTRA_ARGS``
    Allows to pass additional arguments to `androiddeployqt`. This is an alternative to
    the `ARGS=` argument for `make` and unlike that works with all CMake generators.
#]=======================================================================]

cmake_minimum_required(VERSION "3.18")

macro(set_deprecated_variable actual_variable deprecated_variable default_value)
    set(${deprecated_variable} "${default_value}" CACHE STRING "Deprecated. Use ${actual_variable}")
    if (NOT DEFINED ${actual_variable})
        set(${actual_variable} ${${deprecated_variable}})
    endif()
endmacro()

set_deprecated_variable(CMAKE_ANDROID_NDK ANDROID_NDK "$ENV{ANDROID_NDK}")
set_deprecated_variable(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION ANDROID_GCC_VERSION "clang")
set_deprecated_variable(CMAKE_ANDROID_API ANDROID_API_LEVEL "21")
if(NOT DEFINED ENV{ANDROID_ARCH})
    set(ENV{ANDROID_ARCH} "arm")
endif()
set_deprecated_variable(CMAKE_ANDROID_ARCH ANDROID_ARCHITECTURE $ENV{ANDROID_ARCH})
if(NOT DEFINED ENV{ANDROID_ARCH_ABI})
    set(ENV{ANDROID_ARCH_ABI} "armeabi-v7a")
endif()
set_deprecated_variable(CMAKE_ANDROID_ARCH_ABI ANDROID_ABI "$ENV{ANDROID_ARCH_ABI}")

set(ANDROID_SDK_ROOT "$ENV{ANDROID_SDK_ROOT}" CACHE PATH "Android SDK path")

file(GLOB platforms LIST_DIRECTORIES TRUE RELATIVE ${ANDROID_SDK_ROOT}/platforms ${ANDROID_SDK_ROOT}/platforms/*)
list(SORT platforms COMPARE NATURAL)
list(GET platforms -1 _default_platform)
set(ANDROID_SDK_COMPILE_API "${_default_platform}" CACHE STRING "Android API Level")
if(ANDROID_SDK_COMPILE_API MATCHES "^android-([0-9]+)$")
    set(ANDROID_SDK_COMPILE_API ${CMAKE_MATCH_1})
endif()

file(GLOB build-tools LIST_DIRECTORIES TRUE RELATIVE ${ANDROID_SDK_ROOT}/build-tools ${ANDROID_SDK_ROOT}/build-tools/*)
list(SORT build-tools COMPARE NATURAL)
list(GET build-tools -1 _default_sdk)
set(ANDROID_SDK_BUILD_TOOLS_REVISION "${_default_sdk}" CACHE STRING "Android Build Tools version")

set(CMAKE_SYSTEM_VERSION ${CMAKE_ANDROID_API})
set(CMAKE_SYSTEM_NAME Android)
if (NOT CMAKE_ANDROID_STL_TYPE)
    set(CMAKE_ANDROID_STL_TYPE c++_shared)
endif()

# Workaround link failure at FindThreads in CXX-only mode,
# armv7 really doesn't like mixing PIC/PIE code.
# Since we only have to care about a single compiler,
# hard-code the values here.
# Qt6 fixes this and breaks in nested CMake calls (e.g. try_compile) if we
# define Threads::Threads here, at least if the "C" language is enabled. In
# CXX-only projects we still need to do this unconditionally...
#
# We cannot use our usual Qt version check at this point though yet,
# so check whether we are chainloaded by the Qt toolchain as an indicator
# for Qt6.
# When building Qt6Base itself the check does not work, hence we have
# ECM_THREADS_WORKAROUND for that case which set to OFF in the Craft blueprints.
# As that doesn't propagate to nested CMake calls (e.g. tye_compile), we also check
# whether that is set via an environment variable (necessary with Qt >= 6.8.1).
if (NOT DEFINED ECM_THREADS_WORKAROUND AND NOT DEFINED ENV{ECM_THREADS_WORKAROUND})
    set(ECM_THREADS_WORKAROUND TRUE)
endif()
get_property(_languages GLOBAL PROPERTY ENABLED_LANGUAGES)
if (ECM_THREADS_WORKAROUND AND NOT TARGET Threads::Threads AND (NOT DEFINED __qt_chainload_toolchain_file OR NOT "C" IN_LIST _languages))
    set(Threads_FOUND TRUE)
    set(CMAKE_THREAD_LIBS_INIT "-pthread")
    add_library(Threads::Threads INTERFACE IMPORTED)
    set_property(TARGET Threads::Threads PROPERTY INTERFACE_COMPILE_OPTIONS "-pthread")
    set_property(TARGET Threads::Threads PROPERTY INTERFACE_LINK_LIBRARIES "-pthread")
endif()

# let the Android NDK toolchain file do the actual work
set(ANDROID_PLATFORM "android-${CMAKE_ANDROID_API}")
set(ANDROID_STL ${CMAKE_ANDROID_STL_TYPE})
include(${CMAKE_ANDROID_NDK}/build/cmake/android.toolchain.cmake REQUIRED)

# Export configurable variables for the try_compile() command.
list(APPEND CMAKE_TRY_COMPILE_PLATFORM_VARIABLES
  CMAKE_ANDROID_NDK
  CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION
  CMAKE_ANDROID_API
  CMAKE_ANDROID_ARCH
  CMAKE_ANDROID_ARCH_ABI
  ANDROID_SDK_ROOT
  ANDROID_SDK_COMPILE_API
)

# needed for androiddeployqt's stdcpp-path setting
if (ANDROID_TOOLCHAIN_ROOT)
    set(ANDROID_SYSROOT_PREFIX "${ANDROID_TOOLCHAIN_ROOT}/sysroot/usr")
else()
    set(ANDROID_SYSROOT_PREFIX "${CMAKE_NDK_ROOT}/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr")
endif()

## HACK: Remove when we can depend on NDK r23
# Workaround issue https://github.com/android/ndk/issues/929
if(ANDROID_NDK_MAJOR VERSION_LESS 23)
    unset(CMAKE_SYSROOT)

    list(APPEND CMAKE_SYSTEM_INCLUDE_PATH
      "${ANDROID_SYSROOT_PREFIX}/include/${CMAKE_LIBRARY_ARCHITECTURE}")
    list(APPEND CMAKE_SYSTEM_INCLUDE_PATH "${ANDROID_SYSROOT_PREFIX}/include")

    # Prepend in reverse order
    list(PREPEND CMAKE_SYSTEM_LIBRARY_PATH
      "${ANDROID_SYSROOT_PREFIX}/lib/${CMAKE_LIBRARY_ARCHITECTURE}")
    list(PREPEND CMAKE_SYSTEM_LIBRARY_PATH
      "${ANDROID_SYSROOT_PREFIX}/lib/${CMAKE_LIBRARY_ARCHITECTURE}/${ANDROID_PLATFORM_LEVEL}")
endif()

# Qt6 still expects ABI suffixes but only applies them in its own qt_add_[executable|library] macros
# as we typically don't use those we need another way to get those
if (DEFINED __qt_chainload_toolchain_file) # indicator for Qt6, see above
    set(CMAKE_MODULE_LIBRARY_SUFFIX_C "_${CMAKE_ANDROID_ARCH_ABI}.so")
    set(CMAKE_MODULE_LIBRARY_SUFFIX_CXX "_${CMAKE_ANDROID_ARCH_ABI}.so")
    set(CMAKE_SHARED_LIBRARY_SUFFIX_C "_${CMAKE_ANDROID_ARCH_ABI}.so")
    set(CMAKE_SHARED_LIBRARY_SUFFIX_CXX "_${CMAKE_ANDROID_ARCH_ABI}.so")
endif()

# these aren't set yet at this point by the Android toolchain, but without
# those the find_package() call in ECMAndroidDeployQt5 will fail
set(CMAKE_FIND_LIBRARY_PREFIXES "lib")
set(CMAKE_FIND_LIBRARY_SUFFIXES "_${CMAKE_ANDROID_ARCH_ABI}.so" ".so" ".a")

# Work around Qt messing with CMAKE_SHARED_LIBRARY_SUFFIX and thus breaking find_library()
# Unfortunately, just setting CMAKE_FIND_LIBRARY_SUFFIXES here won't help, as this will
# be subsequently overwritten.
macro(addAbiSuffix _var _access)
     if (${_access} STREQUAL "MODIFIED_ACCESS")
         list(PREPEND CMAKE_FIND_LIBRARY_SUFFIXES "_${CMAKE_ANDROID_ARCH_ABI}.so")
     endif()
endmacro()
variable_watch(CMAKE_FIND_LIBRARY_SUFFIXES addAbiSuffix)

# determine STL architecture, which is using a different format than ANDROID_ARCH_ABI
string(REGEX REPLACE "-(clang)?([0-9].[0-9])?$" "" ECM_ANDROID_STL_ARCH "${ANDROID_TOOLCHAIN_NAME}")

if (NOT DEFINED ECM_ADDITIONAL_FIND_ROOT_PATH)
    SET(ECM_ADDITIONAL_FIND_ROOT_PATH ${CMAKE_PREFIX_PATH})
endif()

LIST(APPEND CMAKE_FIND_ROOT_PATH ${ECM_ADDITIONAL_FIND_ROOT_PATH})

#we want executables to be shared libraries, hooks will invoke the exported cmake function
set(CMAKE_CXX_LINK_EXECUTABLE
    "<CMAKE_CXX_COMPILER> <CMAKE_SHARED_LIBRARY_CXX_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>"
)

# As our executables are shared libraries, we also need them build with position independent code (PIC).
# Qt 5 forces that anyway, but in Qt 6 that is no longer the case for exectuables (which we pretend to build here),
# and so we end up with just PIE (coming from CMake).
# And as subsequent steps overwrite that setting again, we have to watch for that and redo our change.
set(CMAKE_CXX_COMPILE_OPTIONS_PIE "-fPIC")
macro(resetPieOption _var _access)
    if (${_access} STREQUAL "MODIFIED_ACCESS")
        set(CMAKE_CXX_COMPILE_OPTIONS_PIE "-fPIC")
    endif()
endmacro()
variable_watch(CMAKE_CXX_COMPILE_OPTIONS_PIE resetPieOption)

set(ECM_DIR "${CMAKE_CURRENT_LIST_DIR}/../cmake" CACHE STRING "")

######### generation (Qt 5 only)

# Need to ensure we only get in here once, as this file is included twice:
# from CMakeDetermineSystem.cmake and from CMakeSystem.cmake generated within the
# build directory.
if(DEFINED QTANDROID_EXPORTED_TARGET AND NOT TARGET "create-apk" AND NOT __qt_chainload_toolchain_file)
    get_filename_component(_CMAKE_ANDROID_DIR "${CMAKE_TOOLCHAIN_FILE}" PATH)
    list(LENGTH QTANDROID_EXPORTED_TARGET targetsCount)
    include(${_CMAKE_ANDROID_DIR}/ECMAndroidDeployQt5.cmake)

    math(EXPR last "${targetsCount}-1")
    foreach(idx RANGE 0 ${last})
        list(GET QTANDROID_EXPORTED_TARGET ${idx} exportedTarget)
        list(GET ANDROID_APK_DIR ${idx} APK_DIR)
        if(APK_DIR AND NOT EXISTS "${ANDROID_APK_DIR}/AndroidManifest.xml" AND IS_ABSOLUTE ANDROID_APK_DIR)
            message(FATAL_ERROR "Cannot find ${APK_DIR}/AndroidManifest.xml according to ANDROID_APK_DIR. ${ANDROID_APK_DIR} ${exportedTarget}")
        elseif(NOT APK_DIR)
            get_filename_component(_qt5Core_install_prefix "${Qt5Core_DIR}/../../../" ABSOLUTE)
            set(APK_DIR "${_qt5Core_install_prefix}/src/android/templates/")
        endif()

        ecm_androiddeployqt5("${exportedTarget}" "${ECM_ADDITIONAL_FIND_ROOT_PATH}")
        set_target_properties(create-apk-${exportedTarget} PROPERTIES ANDROID_APK_DIR "${APK_DIR}")
    endforeach()
elseif (NOT __qt_chainload_toolchain_file)
    message(STATUS "You can export a target by specifying -DQTANDROID_EXPORTED_TARGET=<targetname> and -DANDROID_APK_DIR=<paths>")
endif()
cmake_minimum_required (VERSION 3.19 FATAL_ERROR)
find_package(Qt5Core REQUIRED)
find_package(Python3 COMPONENTS Interpreter REQUIRED)

# Taken from https://stackoverflow.com/a/62311397
function(_ecm_get_all_targets var)
    set(targets)
    _ecm_get_all_targets_recursive(targets ${CMAKE_CURRENT_SOURCE_DIR})
    set(${var} ${targets} PARENT_SCOPE)
endfunction()

macro(_ecm_get_all_targets_recursive targets dir)
    get_property(subdirectories DIRECTORY ${dir} PROPERTY SUBDIRECTORIES)
    foreach(subdir ${subdirectories})
        _ecm_get_all_targets_recursive(${targets} ${subdir})
    endforeach()

    get_property(current_targets DIRECTORY ${dir} PROPERTY BUILDSYSTEM_TARGETS)
    list(APPEND ${targets} ${current_targets})
endmacro()

function(_ecm_deferred_androiddeployqt)
    _ecm_get_all_targets(all_targets)
    set(module_targets)
    foreach(tgt ${all_targets})
        get_target_property(tgt_type ${tgt} TYPE)
        if(tgt_type STREQUAL "MODULE_LIBRARY")
            list(APPEND module_targets "$<TARGET_FILE:${tgt}>")
        endif()
    endforeach()
    file(GENERATE OUTPUT "module-plugins" CONTENT "${module_targets}")
endfunction()
cmake_language(DEFER DIRECTORY "${CMAKE_SOURCE_DIR}" CALL _ecm_deferred_androiddeployqt)

function(ecm_androiddeployqt5 QTANDROID_EXPORTED_TARGET ECM_ADDITIONAL_FIND_ROOT_PATH)
    set(EXPORT_DIR "${CMAKE_BINARY_DIR}/${QTANDROID_EXPORTED_TARGET}_build_apk/")
    if (Qt5Core_VERSION VERSION_LESS 5.14.0)
        set(EXECUTABLE_DESTINATION_PATH "${EXPORT_DIR}/libs/${CMAKE_ANDROID_ARCH_ABI}/lib${QTANDROID_EXPORTED_TARGET}.so")
    else()
        set(EXECUTABLE_DESTINATION_PATH "${EXPORT_DIR}/libs/${CMAKE_ANDROID_ARCH_ABI}/lib${QTANDROID_EXPORTED_TARGET}_${CMAKE_ANDROID_ARCH_ABI}.so")
    endif()
    set(QML_IMPORT_PATHS "")
    # add build directory to the search path as well, so this works without installation
    if (EXISTS ${CMAKE_BINARY_DIR}/lib)
        set(QML_IMPORT_PATHS ${CMAKE_BINARY_DIR}/lib)
    endif()
    foreach(prefix ${ECM_ADDITIONAL_FIND_ROOT_PATH})
        # qmlimportscanner chokes on symlinks, so we need to resolve those first
        get_filename_component(qml_path "${prefix}/lib/qml" REALPATH)
        if(EXISTS ${qml_path})
            if (QML_IMPORT_PATHS)
                set(QML_IMPORT_PATHS "${QML_IMPORT_PATHS},${qml_path}")
            else()
                set(QML_IMPORT_PATHS "${qml_path}")
            endif()
        endif()
    endforeach()
    if (QML_IMPORT_PATHS)
        set(DEFINE_QML_IMPORT_PATHS "\"qml-import-paths\": \"${QML_IMPORT_PATHS}\",")
    endif()

    set(EXTRA_PREFIX_DIRS "\"${CMAKE_BINARY_DIR}\"")
    foreach(prefix ${ECM_ADDITIONAL_FIND_ROOT_PATH})
        set(EXTRA_PREFIX_DIRS "${EXTRA_PREFIX_DIRS}, \"${prefix}\"")
    endforeach()

    if (Qt5Core_VERSION VERSION_LESS 5.14.0)
        set(_deployment_file_template "${_CMAKE_ANDROID_DIR}/deployment-file.json.in")
    else()
        set(_deployment_file_template "${_CMAKE_ANDROID_DIR}/deployment-file-qt514.json.in")
    endif()
    string(TOLOWER "${CMAKE_HOST_SYSTEM_NAME}" _LOWER_CMAKE_HOST_SYSTEM_NAME)
    configure_file("${_deployment_file_template}" "${CMAKE_BINARY_DIR}/${QTANDROID_EXPORTED_TARGET}-deployment.json.in1")
    file(GENERATE OUTPUT "${CMAKE_BINARY_DIR}/${QTANDROID_EXPORTED_TARGET}-deployment.json.in2"
                  INPUT  "${CMAKE_BINARY_DIR}/${QTANDROID_EXPORTED_TARGET}-deployment.json.in1")

    if (CMAKE_GENERATOR STREQUAL "Unix Makefiles")
        set(arguments "\\$(ARGS)")
    endif()

    function(havestl var access VALUE)
        if (NOT VALUE STREQUAL "")
            # look for ++ and .so as in libc++.so
            string (REGEX MATCH "\"[^ ]+\\+\\+[^ ]*\.so\"" OUT ${VALUE})
            file(WRITE ${CMAKE_BINARY_DIR}/stl "${OUT}")
        endif()
    endfunction()
    function(haveranlib var access VALUE)
        if (NOT VALUE STREQUAL "")
            file(WRITE ${CMAKE_BINARY_DIR}/ranlib "${VALUE}")
        endif()
    endfunction()
    variable_watch(CMAKE_CXX_STANDARD_LIBRARIES havestl)
    variable_watch(CMAKE_RANLIB haveranlib)

    if (NOT TARGET create-apk)
        add_custom_target(create-apk)
        if (NOT DEFINED ANDROID_FASTLANE_METADATA_OUTPUT_DIR)
            set(ANDROID_FASTLANE_METADATA_OUTPUT_DIR ${CMAKE_BINARY_DIR}/fastlane)
        endif()
        add_custom_target(create-fastlane
            COMMAND Python3::Interpreter ${CMAKE_CURRENT_LIST_DIR}/generate-fastlane-metadata.py --output ${ANDROID_FASTLANE_METADATA_OUTPUT_DIR} --source ${CMAKE_SOURCE_DIR}
        )
    endif()

    if (NOT DEFINED ANDROID_APK_OUTPUT_DIR)
        set(ANDROID_APK_OUTPUT_DIR ${EXPORT_DIR})
    endif()

    set(CREATEAPK_TARGET_NAME "create-apk-${QTANDROID_EXPORTED_TARGET}")
    add_custom_target(${CREATEAPK_TARGET_NAME}
        COMMAND ${CMAKE_COMMAND} -E echo "Generating $<TARGET_NAME:${QTANDROID_EXPORTED_TARGET}> with $<TARGET_FILE_DIR:Qt5::qmake>/androiddeployqt"
        COMMAND ${CMAKE_COMMAND} -E remove_directory "${EXPORT_DIR}"
        COMMAND ${CMAKE_COMMAND} -E copy_directory "$<TARGET_PROPERTY:create-apk-${QTANDROID_EXPORTED_TARGET},ANDROID_APK_DIR>" "${EXPORT_DIR}"
        COMMAND ${CMAKE_COMMAND} -E copy "$<TARGET_FILE:${QTANDROID_EXPORTED_TARGET}>" "${EXECUTABLE_DESTINATION_PATH}"
        COMMAND LANG=C ${CMAKE_COMMAND} "-DTARGET=$<TARGET_FILE:${QTANDROID_EXPORTED_TARGET}>" -P ${_CMAKE_ANDROID_DIR}/hasMainSymbol.cmake
        COMMAND LANG=C ${CMAKE_COMMAND} -DINPUT_FILE="${QTANDROID_EXPORTED_TARGET}-deployment.json.in2" -DOUTPUT_FILE="${QTANDROID_EXPORTED_TARGET}-deployment.json" "-DTARGET=$<TARGET_FILE:${QTANDROID_EXPORTED_TARGET}>" "-DOUTPUT_DIR=$<TARGET_FILE_DIR:${QTANDROID_EXPORTED_TARGET}>" "-DEXPORT_DIR=${CMAKE_INSTALL_PREFIX}" "-DECM_ADDITIONAL_FIND_ROOT_PATH=\"${ECM_ADDITIONAL_FIND_ROOT_PATH}\"" "-DANDROID_EXTRA_LIBS=\"${ANDROID_EXTRA_LIBS}\"" "-DUSE_LLVM=\"${USE_LLVM}\"" -P ${_CMAKE_ANDROID_DIR}/specifydependencies.cmake
        COMMAND $<TARGET_FILE_DIR:Qt5::qmake>/androiddeployqt ${ANDROIDDEPLOYQT_EXTRA_ARGS} --gradle --input "${QTANDROID_EXPORTED_TARGET}-deployment.json" --apk "${ANDROID_APK_OUTPUT_DIR}/${QTANDROID_EXPORTED_TARGET}-${CMAKE_ANDROID_ARCH_ABI}.apk" --output "${EXPORT_DIR}" --android-platform android-${ANDROID_SDK_COMPILE_API} --deployment bundled ${arguments}
    )
    # --android-platform above is only available as a command line option
    # This specifies the actual version of the SDK files to use, and
    # can be different from both the NDK target and the Java API target.

    add_custom_target(install-apk-${QTANDROID_EXPORTED_TARGET}
        COMMAND adb install -r "${ANDROID_APK_OUTPUT_DIR}/${QTANDROID_EXPORTED_TARGET}-${CMAKE_ANDROID_ARCH_ABI}.apk"
    )
    add_dependencies(create-apk ${CREATEAPK_TARGET_NAME})
    add_dependencies(${CREATEAPK_TARGET_NAME} create-fastlane)
endfunction()
{
   "qt": "@_qt5Core_install_prefix@",
   "sdk": "@ANDROID_SDK_ROOT@",
   "ndk": "@CMAKE_ANDROID_NDK@",
   "toolchain-prefix": "llvm",
   "tool-prefix": "llvm",
   "ndk-host": "@_LOWER_CMAKE_HOST_SYSTEM_NAME@-@CMAKE_HOST_SYSTEM_PROCESSOR@",
   "application-binary": "@QTANDROID_EXPORTED_TARGET@",
   "qml-root-path": "@CMAKE_SOURCE_DIR@",
   @DEFINE_QML_IMPORT_PATHS@
   ##EXTRALIBS##
   ##EXTRAPLUGINS##
   "android-package-source-directory": "$<TARGET_PROPERTY:create-apk-${QTANDROID_EXPORTED_TARGET},ANDROID_APK_DIR>",
   "stdcpp-path": "@ANDROID_SYSROOT_PREFIX@/lib",
   "sdkBuildToolsRevision": "@ANDROID_SDK_BUILD_TOOLS_REVISION@",
   "android-min-sdk-version": "@ANDROID_API_LEVEL@",
   "android-target-sdk-version": "@ANDROID_SDK_COMPILE_API@",
   "extraPrefixDirs": [ @EXTRA_PREFIX_DIRS@ ],
   "architectures": { "@CMAKE_ANDROID_ARCH_ABI@": "@ECM_ANDROID_STL_ARCH@" }
}
{
   "qt": "@ANDROID_QT6_INSTALL_PREFIX@",
   "qtDataDirectory": "@QT6_INSTALL_DATA@",
   "qtLibExecsDirectory": "@QT6_INSTALL_LIBEXECS@",
   "qtLibsDirectory": "@QT6_INSTALL_LIBS@",
   "qtPluginsDirectory": "@QT6_INSTALL_PLUGINS@",
   "qtQmlDirectory": "@QT6_INSTALL_QML@",
   "rcc-binary": "@QT6_RCC_BINARY@",
   "sdk": "@ANDROID_SDK_ROOT@",
   "ndk": "@CMAKE_ANDROID_NDK@",
   "toolchain-prefix": "llvm",
   "tool-prefix": "llvm",
   "toolchain-version": "@CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION@",
   "ndk-host": "@_LOWER_CMAKE_HOST_SYSTEM_NAME@-@CMAKE_HOST_SYSTEM_PROCESSOR@",
   "application-binary": "@APK_NAME@",
   "qml-root-path": "@CMAKE_SOURCE_DIR@",
   @DEFINE_QML_IMPORT_PATHS@
   ##EXTRALIBS##
   ##EXTRAPLUGINS##
   "android-package-source-directory": "@ANDROID_APK_DIR@",
   "stdcpp-path": "@ANDROID_SYSROOT_PREFIX@/lib",
   "sdkBuildToolsRevision": "@ANDROID_SDK_BUILD_TOOLS_REVISION@",
   "android-min-sdk-version": "@ANDROID_API_LEVEL@",
   "android-target-sdk-version": "@ANDROID_SDK_COMPILE_API@",
   "extraPrefixDirs": [ @EXTRA_PREFIX_DIRS@ ],
   "extraLibraryDirs": [ @EXTRA_LIB_DIRS@ ],
   "architectures": { "@CMAKE_ANDROID_ARCH_ABI@": "@ECM_ANDROID_STL_ARCH@" }
}
# SPDX-FileCopyrightText: 2023 Volker Krause <vkrause@kde.org>
# SPDX-License-Identifier: BSD-2-Clause
{
   "qt": "@_qt5Core_install_prefix@",
   "sdk": "@ANDROID_SDK_ROOT@",
   "ndk": "@CMAKE_ANDROID_NDK@",
   "toolchain-prefix": "##ANDROID_TOOL_PREFIX##",
   "tool-prefix": "##ANDROID_COMPILER_PREFIX##",
   "toolchain-version": "##ANDROID_TOOLCHAIN_VERSION##",
   "ndk-host": "@_LOWER_CMAKE_HOST_SYSTEM_NAME@-@CMAKE_HOST_SYSTEM_PROCESSOR@",
   "target-architecture": "@CMAKE_ANDROID_ARCH_ABI@",
   "application-binary": "@EXECUTABLE_DESTINATION_PATH@",
   "qml-root-path": "@CMAKE_SOURCE_DIR@",
   @DEFINE_QML_IMPORT_PATHS@
   ##EXTRALIBS##
   ##EXTRAPLUGINS##
   "android-package-source-directory": "$<TARGET_PROPERTY:create-apk-${QTANDROID_EXPORTED_TARGET},ANDROID_APK_DIR>",
   "stdcpp-path":##CMAKE_CXX_STANDARD_LIBRARIES##,
   "sdkBuildToolsRevision": "@ANDROID_SDK_BUILD_TOOLS_REVISION@",
   "android-min-sdk-version": "@ANDROID_API_LEVEL@",
   "android-target-sdk-version": "@ANDROID_SDK_COMPILE_API@",
   "extraPrefixDirs": [ @EXTRA_PREFIX_DIRS@ ],
   "useLLVM": ##USE_LLVM##
}
#!/usr/bin/env python3
#
# SPDX-FileCopyrightText: 2018-2020 Aleix Pol Gonzalez <aleixpol@kde.org>
# SPDX-FileCopyrightText: 2019-2020 Ben Cooksley <bcooksley@kde.org>
# SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org>
#
# SPDX-License-Identifier: GPL-2.0-or-later
#
# Generates fastlane metadata for Android apps from appstream files.
#

import argparse
import glob
import io
import os
import re
import requests
import shutil
import subprocess
import sys
import tempfile
import xdg.DesktopEntry
import xml.etree.ElementTree as ET
import yaml
import zipfile

# Constants used in this script
# map KDE's translated language codes to those expected by Android
# see https://f-droid.org/en/docs/Translation_and_Localization/
# F-Droid is more tolerant than the Play Store here, the latter rejects anything not exactly matching its known codes
# Android does do the expected fallbacks, so the seemingly "too specific" mappings here are still working as expected
# see https://developer.android.com/guide/topics/resources/multilingual-support#resource-resolution-examples
# The following is the list of languages/translations that can be selected on the page "Main store listing" under
# "Store presence" of Google Play Console (as of 2024-03-15).
# Afrikaans – af
# Albanian – sq
# Amharic – am
# Arabic – ar
# Armenian – hy-AM
# Azerbaijani – az-AZ
# Bangla – bn-BD
# Basque – eu-ES
# Belarusian – be
# Bulgarian – bg
# Burmese – my-MM
# Catalan – ca
# Chinese (Hong Kong) – zh-HK
# Chinese (Simplified) – zh-CN
# Chinese (Traditional) – zh-TW
# Croatian – hr
# Czech – cs-CZ
# Danish – da-DK
# Dutch – nl-NL
# English (Australia) – en-AU
# English (Canada) – en-CA
# English (United Kingdom) – en-GB
# English – en-IN
# English – en-SG
# English – en-ZA
# Estonian – et
# Filipino – fil
# Finnish – fi-FI
# French (Canada) – fr-CA
# French (France) – fr-FR
# Galician – gl-ES
# Georgian – ka-GE
# German – de-DE
# Greek – el-GR
# Gujarati – gu
# Hebrew – iw-IL
# Hindi – hi-IN
# Hungarian – hu-HU
# Icelandic – is-IS
# Indonesian – id
# Italian – it-IT
# Japanese – ja-JP
# Kannada – kn-IN
# Kazakh – kk
# Khmer – km-KH
# Korean – ko-KR
# Kyrgyz – ky-KG
# Lao – lo-LA
# Latvian – lv
# Lithuanian – lt
# Macedonian – mk-MK
# Malay (Malaysia) – ms-MY
# Malay – ms
# Malayalam – ml-IN
# Marathi – mr-IN
# Mongolian – mn-MN
# Nepali – ne-NP
# Norwegian – no-NO
# Persian – fa
# Persian – fa-AE
# Persian – fa-AF
# Persian – fa-IR
# Polish – pl-PL
# Portuguese (Brazil) – pt-BR
# Portuguese (Portugal) – pt-PT
# Punjabi – pa
# Romanian – ro
# Romansh – rm
# Russian – ru-RU
# Serbian – sr
# Sinhala – si-LK
# Slovak – sk
# Slovenian – sl
# Spanish (Latin America) – es-419
# Spanish (Spain) – es-ES
# Spanish (United States) – es-US
# Swahili – sw
# Swedish – sv-SE
# Tamil – ta-IN
# Telugu – te-IN
# Thai – th
# Turkish – tr-TR
# Ukrainian – uk
# Urdu – ur
# Vietnamese – vi
# Zulu – zu
languageMap = {
    None: "en-US",
    "ast": None, # not supported by Google Play for meta data
    "ca-valencia": None, # not supported by Android
    "cs": "cs-CZ",
    "da": "da-DK",
    "de": "de-DE",
    "el": "el-GR",
    "eo": None, # neither supported by Android nor by Google Play for meta data
    "es": "es-ES",
    "eu": "eu-ES",
    "fi": "fi-FI",
    "fr": "fr-FR",
    "gl": "gl-ES",
    "ia": None, # not supported by Google Play for meta data
    "it": "it-IT",
    "ka": "ka-GE",
    "ko": "ko-KR",
    "nl": "nl-NL",
    "nn": "no-NO", # Google Play only supports no-NO (no = macrolanguage for nb/Bokmal and nn/Nynorsk)
    "pl": "pl-PL",
    "pt": "pt-PT",
    "ru": "ru-RU",
    "sr": "sr-Cyrl-RS",
    "sr@latin": "sr-Latn-RS",
    "sv": "sv-SE",
    "tr": "tr-TR",
    'x-test': None
}

# The subset of supported rich text tags in F-Droid and Google Play
# - see https://f-droid.org/en/docs/All_About_Descriptions_Graphics_and_Screenshots/ for F-Droid
# - Google Play doesn't support lists
supportedRichTextTags = { 'b', 'u', 'i' }

# List all translated languages present in an Appstream XML file
def listAllLanguages(root, langs):
    for elem in root:
        lang = elem.get('{http://www.w3.org/XML/1998/namespace}lang')
        if not lang in langs:
            langs.add(lang)
        listAllLanguages(elem, langs)

# Apply language fallback to a map of translations
def applyLanguageFallback(data, allLanguages):
    for l in allLanguages:
        if not l in data or not data[l] or len(data[l]) == 0:
            data[l] = data[None]

# Android appdata.xml textual item parser
# This function handles reading standard text entries within an Android appdata.xml file
# In particular, it handles splitting out the various translations, and converts some HTML to something which F-Droid can make use of
# We have to handle incomplete translations both on top-level and intermediate tags,
# and fall back to the English default text where necessary.
def readText(elem, found, allLanguages):
    # Determine the language this entry is in
    lang = elem.get('{http://www.w3.org/XML/1998/namespace}lang')

    # Do we have any text for this language yet?
    # If not, get everything setup
    for l in allLanguages:
        if not l in found:
            found[l] = ""

    # If there is text available, we'll want to extract it
    # Additionally, if this element has any children, make sure we read those as well
    if elem.tag in supportedRichTextTags:
        if (elem.text and elem.text.strip()) or lang:
            found[lang] += '<' + elem.tag + '>'
        else:
            for l in allLanguages:
                found[l] += '<' + elem.tag + '>'
    elif elem.tag == 'li':
        found[lang] += '· '

    if elem.text and elem.text.strip():
        found[lang] += elem.text

    subOutput = {}
    for child in elem:
        if not child.get('{http://www.w3.org/XML/1998/namespace}lang') and len(subOutput) > 0:
            applyLanguageFallback(subOutput, allLanguages)
            for l in allLanguages:
                found[l] += subOutput[l]
            subOutput = {}
        readText(child, subOutput, allLanguages)
    if len(subOutput) > 0:
        applyLanguageFallback(subOutput, allLanguages)
        for l in allLanguages:
            found[l] += subOutput[l]

    if elem.tag in supportedRichTextTags:
        if (elem.text and elem.text.strip()) or lang:
            found[lang] += '</' + elem.tag + '>'
        else:
            for l in allLanguages:
                found[l] += '</' + elem.tag + '>'

    # Finally, if this element is a HTML Paragraph (p) or HTML List Item (li) make sure we add a new line for presentation purposes
    if elem.tag == 'li' or elem.tag == 'p':
        found[lang] += "\n"


# Create the various Fastlane format files per the information we've previously extracted
# These files are laid out following the Fastlane specification (links below)
# https://github.com/fastlane/fastlane/blob/2.28.7/supply/README.md#images-and-screenshots
# https://docs.fastlane.tools/actions/supply/
def createFastlaneFile( applicationName, filenameToPopulate, fileContent ):
    # Go through each language and content pair we've been given
    for lang, text in fileContent.items():
        # First, do we need to amend the language id, to turn the Android language ID into something more F-Droid/Fastlane friendly?
        languageCode = languageMap.get(lang, lang)
        if not languageCode:
            continue

        # Next we need to determine the path to the directory we're going to be writing the data into
        repositoryBasePath = arguments.output
        path = os.path.join( repositoryBasePath, 'metadata',  applicationName, languageCode )

        # Make sure the directory exists
        os.makedirs(path, exist_ok=True)

        # Now write out file contents!
        with open(path + '/' + filenameToPopulate, 'w') as f:
            f.write(text.strip()) # trim whitespaces, to avoid spurious differences after a Google Play roundtrip

# Create the summary appname.yml file used by F-Droid to summarise this particular entry in the repository
# see https://f-droid.org/en/docs/Build_Metadata_Reference/
def createYml(appname, data):
    # Prepare to retrieve the existing information
    info = {}

    # Determine the path to the appname.yml file
    repositoryBasePath = arguments.output
    path = os.path.join( repositoryBasePath, 'metadata', appname + '.yml' )

    # Update the categories first
    # Now is also a good time to add 'KDE' to the list of categories as well
    if 'categories' in data:
        info['Categories'] = data['categories'][None] + ['KDE']
    else:
        info['Categories']  = ['KDE']

    # Update the general summary as well
    info['Summary'] = data['summary'][None]

    # Check to see if we have a Homepage...
    if 'url-homepage' in data:
        info['WebSite'] = data['url-homepage'][None]

    # What about a bug tracker?
    if 'url-bugtracker' in data:
        info['IssueTracker'] = data['url-bugtracker'][None]

    if 'project_license' in data:
        info["License"] = data['project_license'][None]

    if 'source-repo' in data:
        info['SourceCode'] = data['source-repo']

    if 'url-donation' in data:
        info['Donate'] = data['url-donation'][None]
    else:
        info['Donate'] = 'https://kde.org/community/donations/'

    # static data
    info['Translation'] = 'https://l10n.kde.org/'

    # Finally, with our updates completed, we can save the updated appname.yml file back to disk
    with open(path, 'w') as output:
        yaml.dump(info, output, default_flow_style=False)

# Integrates locally existing image assets into the metadata
def processLocalImages(applicationName, data):
    if not os.path.exists(os.path.join(arguments.source, 'fastlane')):
        return

    outPath = os.path.abspath(arguments.output);
    oldcwd = os.getcwd()
    os.chdir(os.path.join(arguments.source, 'fastlane'))

    imageFiles = glob.glob('metadata/**/*.png', recursive=True)
    imageFiles.extend(glob.glob('metadata/**/*.jpg', recursive=True))
    for image in imageFiles:
        # noramlize single- vs multi-app layouts
        imageDestName = image.replace('metadata/android', 'metadata/' + applicationName)

        # copy image
        os.makedirs(os.path.dirname(os.path.join(outPath, imageDestName)), exist_ok=True)
        shutil.copy(image, os.path.join(outPath, imageDestName))

        # if the source already contains screenshots, those override whatever we found in the appstream file
        if 'phoneScreenshots' in image:
            data['screenshots'] = {}

    os.chdir(oldcwd)

# Attempt to find the application icon if we haven't gotten that explicitly from processLocalImages
def findIcon(applicationName, iconBaseName):
    iconPath = os.path.join(arguments.output, 'metadata', applicationName, 'en-US', 'images', 'icon.png')
    if os.path.exists(iconPath):
        return

    oldcwd = os.getcwd()
    os.chdir(arguments.source)

    iconFiles = glob.glob(f"**/{iconBaseName}-playstore.png", recursive=True)
    for icon in iconFiles:
        os.makedirs(os.path.dirname(iconPath), exist_ok=True)
        shutil.copy(icon, iconPath)
        break

    os.chdir(oldcwd)

# Download screenshots referenced in the appstream data
# see https://f-droid.org/en/docs/All_About_Descriptions_Graphics_and_Screenshots/
def downloadScreenshots(applicationName, data):
    if not 'screenshots' in data:
        return

    path = os.path.join(arguments.output, 'metadata',  applicationName, 'en-US', 'images', 'phoneScreenshots')
    os.makedirs(path, exist_ok=True)

    i = 1 # number screenshots starting at 1 rather than 0 to match what the fastlane tool does
    for screenshot in data['screenshots']:
        fileName = str(i) + '-' + screenshot[screenshot.rindex('/') + 1:]
        r = requests.get(screenshot)
        if r.status_code < 400:
            with open(os.path.join(path, fileName), 'wb') as f:
                f.write(r.content)
            i += 1

# Put all metadata for the given application name into an archive
# We need this to easily transfer the entire metadata to the signing machine for integration
# into the F-Droid nightly repository
def createMetadataArchive(applicationName):
    srcPath = os.path.join(arguments.output, 'metadata')
    zipFileName = os.path.join(srcPath, 'fastlane-' + applicationName + '.zip')
    if os.path.exists(zipFileName):
        os.unlink(zipFileName)
    archive = zipfile.ZipFile(zipFileName, 'w')
    archive.write(os.path.join(srcPath, applicationName + '.yml'), applicationName + '.yml')

    oldcwd = os.getcwd()
    os.chdir(srcPath)
    for file in glob.iglob(applicationName + '/**', recursive=True):
        archive.write(file, file)
    os.chdir(oldcwd)

# Generate metadata for the given appstream and desktop files
def processAppstreamFile(appstreamFileName, desktopFileName, iconBaseName):
    # appstreamFileName has the form <id>.appdata.xml or <id>.metainfo.xml, so we
    # have to strip off two extensions
    applicationName = os.path.splitext(os.path.splitext(os.path.basename(appstreamFileName))[0])[0]

    data = {}
    # Within this file we look at every entry, and where possible try to export it's content so we can use it later
    appstreamFile = open(appstreamFileName, "rb")
    root = ET.fromstring(appstreamFile.read())

    allLanguages = set()
    listAllLanguages(root, allLanguages)

    for child in root:
        # Make sure we start with a blank slate for this entry
        output = {}

        # Grab the name of this particular attribute we're looking at
        # Within the Fastlane specification, it is possible to have several items with the same name but as different types
        # We therefore include this within our extracted name for the attribute to differentiate them
        tag = child.tag
        if 'type' in child.attrib:
            tag += '-' + child.attrib['type']

        # Have we found some information already for this particular attribute?
        if tag in data:
            output = data[tag]

        # Are we dealing with category information here?
        # If so, then we need to look into this items children to find out all the categories this APK belongs in
        if tag == 'categories':
            cats = []
            for x in child:
                cats.append(x.text)
            output = { None: cats }

        # screenshot links
        elif tag == 'screenshots':
            output = []
            for screenshot in child:
                if screenshot.tag == 'screenshot':
                    for image in screenshot:
                        if image.tag == 'image':
                            output.append(image.text)

        # Otherwise this is just textual information we need to extract
        else:
            readText(child, output, allLanguages)

        # Save the information we've gathered!
        data[tag] = output

    applyLanguageFallback(data['name'], allLanguages)
    applyLanguageFallback(data['summary'], allLanguages)
    applyLanguageFallback(data['description'], allLanguages)

    # Did we find any categories?
    # Sometimes we don't find any within the Fastlane information, but without categories the F-Droid store isn't of much use
    # In the event this happens, fallback to the *.desktop file for the application to see if it can provide any insight.
    if not 'categories' in data and desktopFileName:
        # Parse the XDG format *.desktop file, and extract the categories within it
        desktopFile = xdg.DesktopEntry.DesktopEntry(desktopFileName)
        data['categories'] = { None: desktopFile.getCategories() }

    # Try to figure out the source repository
    if arguments.source and os.path.exists(os.path.join(arguments.source, '.git')):
        upstream_ref = subprocess.check_output(['git', 'rev-parse', '--symbolic-full-name', '@{u}'], cwd=arguments.source).decode('utf-8')
        remote = upstream_ref.split('/')[2]
        output = subprocess.check_output(['git', 'remote', 'get-url', remote], cwd=arguments.source).decode('utf-8')
        data['source-repo'] = output.strip()

    # write meta data
    createFastlaneFile( applicationName, "title.txt", data['name'] )
    createFastlaneFile( applicationName, "short_description.txt", data['summary'] )
    createFastlaneFile( applicationName, "full_description.txt", data['description'] )
    createYml(applicationName, data)

    # cleanup old image files before collecting new ones
    imagePath = os.path.join(arguments.output, 'metadata',  applicationName, 'en-US', 'images')
    shutil.rmtree(imagePath, ignore_errors=True)
    processLocalImages(applicationName, data)
    downloadScreenshots(applicationName, data)
    findIcon(applicationName, iconBaseName)

    # put the result in an archive file for easier use by Jenkins
    createMetadataArchive(applicationName)

# scan source directory for manifests/metadata we can work with
def scanSourceDir():
    files = glob.iglob(arguments.source + "/**/AndroidManifest.xml*", recursive=True)
    for file in files:
        # third-party libraries might contain AndroidManifests which we are not interested in
        if "3rdparty" in file:
            continue

        # find application id from manifest files
        root = ET.parse(file)
        appname = root.getroot().attrib['package']
        is_app = False
        prefix = '{http://schemas.android.com/apk/res/android}'
        for md in root.findall("application/activity/meta-data"):
            if md.attrib[prefix + 'name'] == 'android.app.lib_name':
                is_app = True

        if not appname or not is_app:
            continue

        iconBaseName = None
        for elem in root.findall('application'):
            if prefix + 'icon' in elem.attrib:
                iconBaseName = elem.attrib[prefix + 'icon'].split('/')[-1]

        # now that we have the app id, look for matching appdata/desktop files
        appdataFiles = glob.glob(arguments.source + "/**/" + appname + ".metainfo.xml", recursive=True)
        appdataFiles.extend(glob.glob(arguments.source + "/**/" + appname + ".appdata.xml", recursive=True))
        appdataFile = None
        for f in appdataFiles:
            appdataFile = f
            break
        if not appdataFile:
            continue

        desktopFiles = glob.iglob(arguments.source + "/**/" + appname + ".desktop", recursive=True)
        desktopFile = None
        for f in desktopFiles:
            desktopFile = f
            break

        processAppstreamFile(appdataFile, desktopFile, iconBaseName)


### Script Commences

# Parse the command line arguments we've been given
parser = argparse.ArgumentParser(description='Generate fastlane metadata for Android apps from appstream metadata')
parser.add_argument('--appstream', type=str, required=False, help='Appstream file to extract metadata from')
parser.add_argument('--desktop', type=str, required=False, help='Desktop file to extract additional metadata from')
parser.add_argument('--source', type=str, required=False, help='Source directory to find metadata in')
parser.add_argument('--output', type=str, required=True, help='Path to which the metadata output should be written to')
arguments = parser.parse_args()

# ensure the output path exists
os.makedirs(arguments.output, exist_ok=True)

# if we have an appstream file explicitly specified, let's use that one
if arguments.appstream and os.path.exists(arguments.appstream):
    processAppstreamFile(arguments.appstream, arguments.desktop)
    sys.exit(0)

# else, look in the source dir for appstream/desktop files
# this follows roughly what get-apk-args from binary factory does
if arguments.source and os.path.exists(arguments.source):
    scanSourceDir()
    sys.exit(0)

# else: missing arguments
print("Either one of --appstream or --source have to be provided!")
sys.exit(1)
execute_process(COMMAND nm --dynamic ${TARGET} ERROR_VARIABLE nm_errors OUTPUT_VARIABLE out RESULT_VARIABLE result)

if (NOT result EQUAL 0)
    message(FATAL_ERROR "nm failed on ${TARGET} exit(${result}): ${nm_errors}")
endif()

string(FIND ${out} " T main\n" found)
if(found LESS 0)
    message(FATAL_ERROR "Could not find a main() symbol on ${TARGET}")
endif()

function(list_dependencies target libs)
    execute_process(COMMAND readelf --wide --dynamic ${target} ERROR_VARIABLE readelf_errors OUTPUT_VARIABLE out RESULT_VARIABLE result)

    if (NOT result EQUAL 0)
        message(FATAL_ERROR "readelf failed on ${target} exit(${result}): ${readelf_errors}")
    endif()

    string(REPLACE "\n" ";" lines "${out}")
    set(extralibs ${${libs}})
    foreach(line ${lines})
        string(REGEX MATCH ".*\\(NEEDED\\) +Shared library: +\\[(.+)\\]$" matched ${line})
        set(currentLib ${CMAKE_MATCH_1})

        if(NOT ${currentLib} MATCHES "libQt5.*" AND matched)
            find_file(ourlib-${currentLib} ${currentLib} HINTS ${OUTPUT_DIR} ${EXPORT_DIR} ${ECM_ADDITIONAL_FIND_ROOT_PATH} NO_DEFAULT_PATH PATH_SUFFIXES lib)

            if(ourlib-${currentLib})
                list(APPEND extralibs "${ourlib-${currentLib}}")
            else()
                message(STATUS "could not find ${currentLib} in ${OUTPUT_DIR} ${EXPORT_DIR} ${ECM_ADDITIONAL_FIND_ROOT_PATH}")
            endif()
        endif()
    endforeach()
    set(${libs} ${extralibs} PARENT_SCOPE)
endfunction()

list_dependencies(${TARGET} extralibs)

function(contains_library libpath IS_EQUAL)
    get_filename_component (name ${libpath} NAME)
    unset (IS_EQUAL PARENT_SCOPE)

    foreach (extralib ${extralibs})
        get_filename_component (extralibname ${extralib} NAME)
        if (${extralibname} STREQUAL ${name})
            set (IS_EQUAL TRUE PARENT_SCOPE)
            break()
        endif()
    endforeach()
endfunction()

if (ANDROID_EXTRA_LIBS)
    foreach (extralib ${ANDROID_EXTRA_LIBS})
        contains_library(${extralib} IS_EQUAL)

        if (IS_EQUAL)
            message (STATUS "found duplicate, skipping: " ${extralib})
        else()
            message(STATUS "manually specified extra library: " ${extralib})
            list(APPEND extralibs ${extralib})
        endif()
    endforeach()
endif()

set(extraplugins)
foreach(folder "plugins" "share" "lib/qml" "translations") #now we check for folders with extra stuff
    set(plugin "${EXPORT_DIR}/${folder}")
    if(EXISTS "${plugin}")
        list(APPEND extraplugins "${plugin}")
    endif()
endforeach()

if(EXISTS "module-plugins")
    file(READ "module-plugins" moduleplugins)
    foreach(module ${moduleplugins})
        list_dependencies(${module} extralibs)
    endforeach()
    list(REMOVE_DUPLICATES extralibs)
endif()

if(extralibs)
    string(REPLACE ";" "," extralibs "${extralibs}")
    set(extralibs "\"android-extra-libs\": \"${extralibs}\",")
endif()

if(extraplugins)
    string(REPLACE ";" "," extraplugins "${extraplugins}")
    set(extraplugins "\"android-extra-plugins\": \"${extraplugins}\",")
endif()

file(READ "${INPUT_FILE}" CONTENTS)
if(EXISTS "stl") # only provided for legacy pre-Clang toolchains
    file(READ "stl" stl_contents)
endif()

file(READ "ranlib" ranlib_contents)
string(REGEX MATCH ".+/toolchains/llvm/prebuilt/.+/bin/(.+)-ranlib" USE_LLVM ${ranlib_contents})
if (USE_LLVM)
  string(REPLACE "##ANDROID_TOOL_PREFIX##" "llvm" NEWCONTENTS "${CONTENTS}")
  string(REPLACE "##ANDROID_COMPILER_PREFIX##" "${CMAKE_MATCH_1}" NEWCONTENTS "${NEWCONTENTS}")
  string(REPLACE "##USE_LLVM##" true NEWCONTENTS "${NEWCONTENTS}")
else()
  string(REGEX MATCH ".+/toolchains/(.+)-([^\\-]+)/prebuilt/.+/bin/(.+)-ranlib" RANLIB_PATH_MATCH ${ranlib_contents})
  if (NOT RANLIB_PATH_MATCH)
     message(FATAL_ERROR "Couldn't parse the components of the path to ${ranlib_contents}")
  endif()
  string(REPLACE "##ANDROID_TOOL_PREFIX##" "${CMAKE_MATCH_1}" NEWCONTENTS "${CONTENTS}")
  string(REPLACE "##ANDROID_COMPILER_PREFIX##" "${CMAKE_MATCH_3}" NEWCONTENTS "${NEWCONTENTS}")
  string(REPLACE "##USE_LLVM##" false NEWCONTENTS "${NEWCONTENTS}")
endif()

string(REPLACE "##ANDROID_TOOLCHAIN_VERSION##" "${CMAKE_MATCH_2}" NEWCONTENTS "${NEWCONTENTS}") # not used when USE_LLVM is set

string(REPLACE "##EXTRALIBS##" "${extralibs}" NEWCONTENTS "${NEWCONTENTS}")
string(REPLACE "##EXTRAPLUGINS##" "${extraplugins}" NEWCONTENTS "${NEWCONTENTS}")
string(REPLACE "##CMAKE_CXX_STANDARD_LIBRARIES##" "${stl_contents}" NEWCONTENTS "${NEWCONTENTS}")
file(WRITE "${OUTPUT_FILE}" ${NEWCONTENTS})
