summaryrefslogtreecommitdiffstats
path: root/cmake/scripts/common
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 18:07:22 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-10 18:07:22 +0000
commitc04dcc2e7d834218ef2d4194331e383402495ae1 (patch)
tree7333e38d10d75386e60f336b80c2443c1166031d /cmake/scripts/common
parentInitial commit. (diff)
downloadkodi-c04dcc2e7d834218ef2d4194331e383402495ae1.tar.xz
kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.zip
Adding upstream version 2:20.4+dfsg.upstream/2%20.4+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'cmake/scripts/common')
-rw-r--r--cmake/scripts/common/AddOptions.cmake78
-rw-r--r--cmake/scripts/common/AddonHelpers.cmake437
-rw-r--r--cmake/scripts/common/AddonHelpers.dox59
-rw-r--r--cmake/scripts/common/ArchSetup.cmake201
-rw-r--r--cmake/scripts/common/CMakeHelpers.cmake54
-rw-r--r--cmake/scripts/common/CheckCommits.cmake75
-rw-r--r--cmake/scripts/common/CheckTargetPlatform.cmake70
-rw-r--r--cmake/scripts/common/CompilerSettings.cmake5
-rw-r--r--cmake/scripts/common/DependencyOptions.cmake23
-rw-r--r--cmake/scripts/common/GenerateVersionedFiles.cmake35
-rw-r--r--cmake/scripts/common/GeneratorSetup.cmake49
-rw-r--r--cmake/scripts/common/HandleDepends.cmake301
-rw-r--r--cmake/scripts/common/Macros.cmake789
-rw-r--r--cmake/scripts/common/ModuleHelpers.cmake424
-rw-r--r--cmake/scripts/common/PathSetup.cmake13
-rw-r--r--cmake/scripts/common/Platform.cmake57
-rw-r--r--cmake/scripts/common/PrepareEnv.cmake107
-rw-r--r--cmake/scripts/common/ProjectMacros.cmake89
-rw-r--r--cmake/scripts/common/StaticAnalysis.cmake39
-rw-r--r--cmake/scripts/common/Uninstall.cmake58
20 files changed, 2963 insertions, 0 deletions
diff --git a/cmake/scripts/common/AddOptions.cmake b/cmake/scripts/common/AddOptions.cmake
new file mode 100644
index 0000000..96837c1
--- /dev/null
+++ b/cmake/scripts/common/AddOptions.cmake
@@ -0,0 +1,78 @@
+# - Add options without repeating them on the command line
+#
+# Synopsis:
+#
+# add_options (lang build opts)
+#
+# where:
+#
+# lang Name of the language whose compiler should receive the
+# options, e.g. CXX. If a comma-separated list is received
+# then the option is added for all those languages. Use the
+# special value ALL_LANGUAGES for these languages: CXX, C
+# and Fortran
+#
+# build Kind of build to which this options should apply,
+# such as DEBUG and RELEASE. This can also be a comma-
+# separated list. Use the special value ALL_BUILDS to apply
+# to all builds.
+#
+# opts List of options to add. Each should be quoted.
+#
+# Example:
+#
+# add_options (CXX RELEASE "-O3" "-DNDEBUG" "-Wall")
+
+function(add_options langs builds)
+ # special handling of empty language specification
+ if("${langs}" STREQUAL "ALL_LANGUAGES")
+ set(langs CXX C Fortran)
+ endif()
+ foreach(lang IN LISTS langs)
+ # prepend underscore if necessary
+ foreach(build IN LISTS builds)
+ if(NOT ("${build}" STREQUAL "ALL_BUILDS"))
+ set(_bld "_${build}")
+ string(TOUPPER "${_bld}" _bld)
+ else()
+ set(_bld "")
+ endif()
+ foreach(_opt IN LISTS ARGN)
+ set(_var "CMAKE_${lang}_FLAGS${_bld}")
+ #message(STATUS "Adding \"${_opt}\" to \${${_var}}")
+ # remove it first
+ string(REPLACE "${_opt}" "" _without "${${_var}}")
+ string(STRIP "${_without}" _without)
+ # we need to strip this one as well, so they are comparable
+ string(STRIP "${${_var}}" _stripped)
+ # if it wasn't there, then add it at the end
+ if("${_without}" STREQUAL "${_stripped}")
+ # don't add any extra spaces if no options yet are set
+ if(NOT ${_stripped} STREQUAL "")
+ set(${_var} "${_stripped} ${_opt}")
+ else()
+ set(${_var} "${_opt}")
+ endif()
+ set(${_var} "${${_var}}" PARENT_SCOPE)
+ endif()
+ endforeach()
+ endforeach()
+ endforeach()
+endfunction()
+
+# set varname to flag unless user has specified something that matches regex
+function(set_default_option varname flag regex)
+ if(NOT "$ENV{CXXFLAGS}" MATCHES "${regex}"
+ AND NOT "${CMAKE_CXX_FLAGS}" MATCHES "${regex}"
+ AND NOT "${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}}" MATCHES "${regex}")
+ set(${varname} ${flag} PARENT_SCOPE)
+ else()
+ set(${varname} PARENT_SCOPE)
+ endif()
+endfunction()
+
+# note: this must be called before project()
+macro(no_default_options)
+ # prevent the platform probe to set options
+ set(CMAKE_NOT_USING_CONFIG_FLAGS TRUE)
+endmacro()
diff --git a/cmake/scripts/common/AddonHelpers.cmake b/cmake/scripts/common/AddonHelpers.cmake
new file mode 100644
index 0000000..c541ad7
--- /dev/null
+++ b/cmake/scripts/common/AddonHelpers.cmake
@@ -0,0 +1,437 @@
+# Workaround for the fact that cpack's filenames are not customizable.
+# Each add-on is added as a separate component to facilitate zip/tgz packaging.
+# The filenames are always of the form basename-component, which is
+# incompatible with the addonid-version scheme we want. This hack renames
+# the files from the file names generated by the 'package' target.
+# Sadly we cannot extend the 'package' target, as it is a builtin target, see
+# http://public.kitware.com/Bug/view.php?id=8438
+# Thus, we have to add an 'addon-package' target.
+get_property(_isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
+if(_isMultiConfig)
+ add_custom_target(addon-package DEPENDS PACKAGE)
+else()
+ add_custom_target(addon-package
+ COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target package)
+endif()
+
+macro(add_cpack_workaround target version ext)
+ if(NOT PACKAGE_DIR)
+ set(PACKAGE_DIR "${CMAKE_INSTALL_PREFIX}/zips")
+ endif()
+
+ add_custom_command(TARGET addon-package POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${PACKAGE_DIR}
+ COMMAND ${CMAKE_COMMAND} -E copy ${CPACK_PACKAGE_DIRECTORY}/addon-${target}-${version}-${PLATFORM_TAG}.${ext} ${PACKAGE_DIR}/${target}+${PLATFORM_TAG}/${target}-${version}.${ext})
+endmacro()
+
+# Grab the version from a given add-on's addon.xml
+macro (addon_version dir prefix)
+ if(EXISTS ${PROJECT_SOURCE_DIR}/${dir}/addon.xml.in)
+ file(READ ${PROJECT_SOURCE_DIR}/${dir}/addon.xml.in ADDONXML)
+ else()
+ file(READ ${dir}/addon.xml ADDONXML)
+ endif()
+
+ string(REGEX MATCH "<addon[^>]*version.?=.?.[0-9\\.]+" VERSION_STRING ${ADDONXML})
+ string(REGEX REPLACE ".*version=.([0-9\\.]+).*" "\\1" ${prefix}_VERSION ${VERSION_STRING})
+ message(STATUS ${prefix}_VERSION=${${prefix}_VERSION})
+endmacro()
+
+# Build, link and optionally package an add-on
+macro (build_addon target prefix libs)
+ addon_version(${target} ${prefix})
+
+ # Below comes the generation of a list with used sources where the includes to
+ # kodi's headers becomes checked.
+ # This goes the following steps to identify them:
+ # 1. Check headers are at own depended on addon
+ # - If so, it is checked whether the whole folder is already inserted, if
+ # not, it is added.
+ # 2. If headers are not defined independently and there is more as one source
+ # file.
+ # - If yes, it is checked whether the headers with the sources together
+ # - In case no headers are inserted and more than one source file exists,
+ # the whole addon folder is searched for headers.
+ # 3. As a last step, the actual source files are checked.
+ if(${prefix}_SOURCES)
+ # Read used headers from addon, needed to identitfy used kodi addon interface headers
+ if(${prefix}_HEADERS)
+ # Add the used header files defined with CMakeLists.txt from addon itself
+ string(FIND "${${prefix}_HEADERS}" "${PROJECT_SOURCE_DIR}" position)
+ if(position GREATER -1)
+ # include path name already complete
+ list(APPEND USED_SOURCES ${${prefix}_HEADERS})
+ else()
+ # add the complete include path to begin
+ foreach(hdr_file ${${prefix}_HEADERS})
+ list(APPEND USED_SOURCES ${PROJECT_SOURCE_DIR}/${hdr_file})
+ endforeach()
+ endif()
+ else()
+ list(LENGTH ${prefix}_SOURCES _length)
+ if(${_length} GREATER 1)
+ string(REGEX MATCHALL "[.](h)" _length ${${prefix}_SOURCES}})
+ if(NOT _length)
+ file(GLOB_RECURSE USED_SOURCES ${PROJECT_SOURCE_DIR}/*.h*)
+ if(USED_SOURCES)
+ message(AUTHOR_WARNING "Header files not defined in your CMakeLists.txt. Please consider defining ${prefix}_HEADERS as list of all headers used by this addon. Falling back to recursive scan for *.h.")
+ endif()
+ endif()
+ endif()
+ endif()
+
+ # Add the used source files defined with CMakeLists.txt from addon itself
+ string(FIND "${${prefix}_SOURCES}" "${PROJECT_SOURCE_DIR}" position)
+ if(position GREATER -1)
+ # include path name already complete
+ list(APPEND USED_SOURCES ${${prefix}_SOURCES})
+ else()
+ # add the complete include path to begin
+ foreach(src_file ${${prefix}_SOURCES})
+ list(APPEND USED_SOURCES ${PROJECT_SOURCE_DIR}/${src_file})
+ endforeach()
+ endif()
+
+ message(STATUS "Addon dependency check ...")
+ # Set defines used in addon.xml.in and read from versions.h to set add-on
+ # version parts automatically
+ file(STRINGS ${KODI_INCLUDE_DIR}/versions.h BIN_ADDON_PARTS)
+ foreach(loop_var ${BIN_ADDON_PARTS})
+ # Only pass strings with "#define ADDON_" from versions.h
+ if(loop_var MATCHES "#define ADDON_")
+ string(REGEX REPLACE "\\\n" " " loop_var ${loop_var}) # remove header line breaks
+ string(REGEX REPLACE "#define " "" loop_var ${loop_var}) # remove the #define name from string
+ string(REGEX MATCHALL "[//a-zA-Z0-9._-]+" loop_var "${loop_var}") # separate the define values to a list
+
+ # Get the definition name
+ list(GET loop_var 0 include_name)
+ # Check definition are depends who is a bigger list
+ if("${include_name}" MATCHES "_DEPENDS")
+ # Use start definition name as base for other value type
+ list(GET loop_var 0 list_name)
+ string(REPLACE "_DEPENDS" "_MIN" depends_minver ${list_name})
+ string(REPLACE "_DEPENDS" "" depends_ver ${list_name})
+ string(REPLACE "_DEPENDS" "_XML_ID" xml_entry_name ${list_name})
+ string(REPLACE "_DEPENDS" "_USED" used_type_name ${list_name})
+
+ # remove the first value, not needed and wrong on "for" loop
+ list(REMOVE_AT loop_var 0)
+
+ foreach(depend_header ${loop_var})
+ string(STRIP ${depend_header} depend_header)
+ foreach(src_file ${USED_SOURCES})
+ file(STRINGS ${src_file} BIN_ADDON_SRC_PARTS)
+ foreach(loop_var ${BIN_ADDON_SRC_PARTS})
+ string(REGEX MATCH "^[ \t]*#[ \t]*(include|import)[ \t]*[<\"](kodi\/)?(.+)[\">]" include_name "${loop_var}")
+ if(include_name AND CMAKE_MATCH_3 MATCHES ^${depend_header})
+ get_directory_property(CURRENT_DEFS COMPILE_DEFINITIONS)
+ if(NOT used_type_name IN_LIST CURRENT_DEFS)
+ set(ADDON_DEPENDS "${ADDON_DEPENDS}\n<import addon=\"${${xml_entry_name}}\" minversion=\"${${depends_minver}}\" version=\"${${depends_ver}}\"/>")
+ # Inform with them the addon header about used type, if not present before
+ add_definitions(-D${used_type_name})
+ message(STATUS " - Added API usage definition: ${used_type_name} (Version: \"${${depends_ver}}\", Min. Version: \"${${depends_minver}}\")")
+ set(FOUND_HEADER_USAGE 1)
+ endif()
+ endif()
+ endforeach()
+ if(FOUND_HEADER_USAGE EQUAL 1) # break this loop if found but not unset, needed in parts where includes muddled up on addon
+ break()
+ endif()
+ endforeach()
+ # type is found and round becomes broken for next round with other type
+ if(FOUND_HEADER_USAGE EQUAL 1)
+ unset(FOUND_HEADER_USAGE)
+ break()
+ endif()
+ endforeach()
+ else()
+ # read the definition values and make it by the on version.h defined names public
+ list(GET loop_var 1 include_variable)
+ string(REGEX REPLACE ".*\"(.*)\"" "\\1" ${include_name} ${include_variable})
+ set(${include_name} ${${include_name}})
+ endif()
+ endif()
+ endforeach()
+
+ add_library(${target} ${${prefix}_SOURCES} ${${prefix}_HEADERS})
+ target_link_libraries(${target} ${${libs}})
+ set_target_properties(${target} PROPERTIES VERSION ${${prefix}_VERSION}
+ SOVERSION ${APP_VERSION_MAJOR}.${APP_VERSION_MINOR}
+ PREFIX ""
+ POSITION_INDEPENDENT_CODE 1)
+ if(OS STREQUAL "android")
+ set_target_properties(${target} PROPERTIES PREFIX "lib")
+ endif()
+ elseif(${prefix}_CUSTOM_BINARY)
+ add_custom_target(${target} ALL)
+ endif()
+
+ # get the library's location
+ if(${prefix}_CUSTOM_BINARY)
+ list(GET ${prefix}_CUSTOM_BINARY 0 LIBRARY_LOCATION)
+ list(GET ${prefix}_CUSTOM_BINARY 1 LIBRARY_FILENAME)
+ if(CORE_SYSTEM_NAME STREQUAL android)
+ set(LIBRARY_FILENAME "lib${LIBRARY_FILENAME}")
+ endif()
+ else()
+ set(LIBRARY_LOCATION $<TARGET_FILE:${target}>)
+ # get the library's filename
+ if(CORE_SYSTEM_NAME STREQUAL android)
+ # for android we need the filename without any version numbers
+ set(LIBRARY_FILENAME $<TARGET_LINKER_FILE_NAME:${target}>)
+ else()
+ set(LIBRARY_FILENAME $<TARGET_FILE_NAME:${target}>)
+ endif()
+ endif()
+
+ # if there's an addon.xml.in we need to generate the addon.xml
+ if(EXISTS ${PROJECT_SOURCE_DIR}/${target}/addon.xml.in)
+ set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${PROJECT_SOURCE_DIR}/${target}/addon.xml.in)
+
+ file(READ ${PROJECT_SOURCE_DIR}/${target}/addon.xml.in addon_file)
+
+ # If sources are present must be the depends set
+ if(${prefix}_SOURCES)
+ string(FIND "${addon_file}" "\@ADDON_DEPENDS\@" matchres)
+ if("${matchres}" EQUAL -1)
+ message(FATAL_ERROR "\"\@ADDON_DEPENDS\@\" not found in addon.xml.in.")
+ endif()
+ endif()
+
+ # TODO: remove this hack after v18
+ string(REPLACE "<platform>\@PLATFORM\@</platform>" "<platform>\@PLATFORM_TAG\@</platform>" addon_file "${addon_file}")
+
+ string(CONFIGURE "${addon_file}" addon_file_conf @ONLY)
+ file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${target}/addon.xml CONTENT "${addon_file_conf}")
+ if(${APP_NAME_UC}_BUILD_DIR)
+ file(GENERATE OUTPUT ${${APP_NAME_UC}_BUILD_DIR}/addons/${target}/addon.xml CONTENT "${addon_file_conf}")
+ endif()
+ endif()
+
+ # if there's an settings.xml.in we need to generate the settings.xml
+ if(EXISTS ${PROJECT_SOURCE_DIR}/${target}/resources/settings.xml.in)
+ set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${PROJECT_SOURCE_DIR}/${target}/resources/settings.xml.in)
+
+ file(READ ${PROJECT_SOURCE_DIR}/${target}/resources/settings.xml.in settings_file)
+ string(CONFIGURE "${settings_file}" settings_file_conf @ONLY)
+ file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${target}/resources/settings.xml CONTENT "${settings_file_conf}")
+ if(${APP_NAME_UC}_BUILD_DIR)
+ file(GENERATE OUTPUT ${${APP_NAME_UC}_BUILD_DIR}/addons/${target}/resources/settings.xml CONTENT "${settings_file_conf}")
+ endif()
+ endif()
+
+ # set zip as default if addon-package is called without PACKAGE_XXX
+ set(CPACK_GENERATOR "ZIP")
+ set(ext "zip")
+ if(PACKAGE_ZIP OR PACKAGE_TGZ)
+ if(PACKAGE_TGZ)
+ set(CPACK_GENERATOR "TGZ")
+ set(ext "tar.gz")
+ endif()
+ set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY OFF)
+ set(CPACK_PACKAGE_FILE_NAME addon)
+ if(CMAKE_BUILD_TYPE STREQUAL "Release")
+ set(CPACK_STRIP_FILES TRUE)
+ endif()
+ set(CPACK_ARCHIVE_COMPONENT_INSTALL ON)
+ set(CPACK_COMPONENTS_IGNORE_GROUPS 1)
+ list(APPEND CPACK_COMPONENTS_ALL ${target}-${${prefix}_VERSION}-${PLATFORM_TAG})
+ # Pack files together to create an archive
+ install(DIRECTORY ${target} ${CMAKE_CURRENT_BINARY_DIR}/${target} DESTINATION ./
+ COMPONENT ${target}-${${prefix}_VERSION}-${PLATFORM_TAG}
+ REGEX ".+\\.xml\\.in(clude)?$" EXCLUDE)
+ if(WIN32)
+ if(NOT CPACK_PACKAGE_DIRECTORY)
+ # determine the temporary path
+ file(TO_CMAKE_PATH "$ENV{TEMP}" WIN32_TEMP_PATH)
+ string(LENGTH "${WIN32_TEMP_PATH}" WIN32_TEMP_PATH_LENGTH)
+ string(LENGTH "${PROJECT_BINARY_DIR}" PROJECT_BINARY_DIR_LENGTH)
+
+ # check if the temporary path is shorter than the default packaging directory path
+ if(WIN32_TEMP_PATH_LENGTH GREATER 0 AND WIN32_TEMP_PATH_LENGTH LESS PROJECT_BINARY_DIR_LENGTH)
+ # set the directory used by CPack for packaging to the temp directory
+ set(CPACK_PACKAGE_DIRECTORY ${WIN32_TEMP_PATH})
+ endif()
+ endif()
+
+ if(${prefix}_SOURCES)
+ # install the generated DLL file
+ install(PROGRAMS ${LIBRARY_LOCATION} DESTINATION ${target}
+ COMPONENT ${target}-${${prefix}_VERSION}-${PLATFORM_TAG})
+
+ # for debug builds also install the PDB file
+ install(FILES $<TARGET_PDB_FILE:${target}> DESTINATION ${target}
+ CONFIGURATIONS Debug RelWithDebInfo
+ COMPONENT ${target}-${${prefix}_VERSION}-${PLATFORM_TAG})
+ endif()
+ if(${prefix}_CUSTOM_BINARY)
+ install(FILES ${LIBRARY_LOCATION} DESTINATION ${target} RENAME ${LIBRARY_FILENAME}
+ COMPONENT ${target}-${${prefix}_VERSION}-${PLATFORM_TAG})
+ endif()
+ if(${prefix}_CUSTOM_DATA)
+ install(DIRECTORY ${${prefix}_CUSTOM_DATA} DESTINATION ${target}/resources
+ COMPONENT ${target}-${${prefix}_VERSION}-${PLATFORM_TAG})
+ endif()
+ if(${prefix}_ADDITIONAL_BINARY)
+ install(FILES ${${prefix}_ADDITIONAL_BINARY} DESTINATION ${target}
+ COMPONENT ${target}-${${prefix}_VERSION}-${PLATFORM_TAG})
+ endif()
+ if(${prefix}_ADDITIONAL_BINARY_EXE)
+ install(PROGRAMS ${${prefix}_ADDITIONAL_BINARY_EXE} DESTINATION ${target}
+ COMPONENT ${target}-${${prefix}_VERSION}-${PLATFORM_TAG})
+ endif()
+ if(${prefix}_ADDITIONAL_BINARY_PARTS)
+ install(FILES ${${prefix}_ADDITIONAL_BINARY_PARTS} DESTINATION ${target}
+ COMPONENT ${target}-${${prefix}_VERSION}-${PLATFORM_TAG})
+ endif()
+ if(${prefix}_ADDITIONAL_BINARY_DIRS)
+ install(DIRECTORY ${${prefix}_ADDITIONAL_BINARY_DIRS} DESTINATION ${target} USE_SOURCE_PERMISSIONS
+ COMPONENT ${target}-${${prefix}_VERSION}-${PLATFORM_TAG})
+ endif()
+ else() # NOT WIN32
+ if(NOT CPACK_PACKAGE_DIRECTORY)
+ set(CPACK_PACKAGE_DIRECTORY ${CMAKE_BINARY_DIR})
+ endif()
+ if(${prefix}_SOURCES)
+ install(TARGETS ${target} DESTINATION ${target}
+ COMPONENT ${target}-${${prefix}_VERSION}-${PLATFORM_TAG})
+ endif()
+ if(${prefix}_CUSTOM_BINARY)
+ install(FILES ${LIBRARY_LOCATION} DESTINATION ${target} RENAME ${LIBRARY_FILENAME}
+ COMPONENT ${target}-${${prefix}_VERSION}-${PLATFORM_TAG})
+ endif()
+ if(${prefix}_CUSTOM_DATA)
+ install(DIRECTORY ${${prefix}_CUSTOM_DATA} DESTINATION ${target}/resources
+ COMPONENT ${target}-${${prefix}_VERSION}-${PLATFORM_TAG})
+ endif()
+ if(${prefix}_ADDITIONAL_BINARY)
+ install(FILES ${${prefix}_ADDITIONAL_BINARY} DESTINATION ${target}
+ COMPONENT ${target}-${${prefix}_VERSION}-${PLATFORM_TAG})
+ endif()
+ if(${prefix}_ADDITIONAL_BINARY_EXE)
+ install(PROGRAMS ${${prefix}_ADDITIONAL_BINARY_EXE} DESTINATION ${target}
+ COMPONENT ${target}-${${prefix}_VERSION}-${PLATFORM_TAG})
+ endif()
+ if(${prefix}_ADDITIONAL_BINARY_PARTS)
+ install(FILES ${${prefix}_ADDITIONAL_BINARY_PARTS} DESTINATION ${target}
+ COMPONENT ${target}-${${prefix}_VERSION}-${PLATFORM_TAG})
+ endif()
+ if(${prefix}_ADDITIONAL_BINARY_DIRS)
+ install(DIRECTORY ${${prefix}_ADDITIONAL_BINARY_DIRS} DESTINATION ${target} USE_SOURCE_PERMISSIONS
+ COMPONENT ${target}-${${prefix}_VERSION}-${PLATFORM_TAG})
+ endif()
+ endif()
+ add_cpack_workaround(${target} ${${prefix}_VERSION} ${ext})
+ else()
+ if(CORE_SYSTEM_NAME STREQUAL linux OR CORE_SYSTEM_NAME STREQUAL freebsd)
+ if(NOT OVERRIDE_PATHS)
+ if(CMAKE_INSTALL_PREFIX AND NOT CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT AND NOT CMAKE_INSTALL_PREFIX STREQUAL "${${APP_NAME_UC}_PREFIX}")
+ message(WARNING "CMAKE_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX} differs from ${APP_NAME} prefix, changing to ${${APP_NAME_UC}_PREFIX}. Please pass -DOVERRIDE_PATHS=1 to skip this check")
+ endif()
+ if(CMAKE_INSTALL_LIBDIR AND NOT CMAKE_INSTALL_LIBDIR STREQUAL "${${APP_NAME_UC}_LIB_DIR}")
+ message(WARNING "CMAKE_INSTALL_LIBDIR ${CMAKE_INSTALL_LIBDIR} differs from ${APP_NAME} libdir, changing to ${${APP_NAME_UC}_LIB_DIR}. Please pass -DOVERRIDE_PATHS=1 to skip this check")
+ endif()
+ if(CMAKE_INSTALL_DATADIR AND NOT CMAKE_INSTALL_DATADIR STREQUAL "${${APP_NAME_UC}_DATA_DIR}")
+ message(WARNING "CMAKE_INSTALL_DATADIR ${CMAKE_INSTALL_DATADIR} differs from ${APP_NAME} datadir, changing to ${${APP_NAME_UC}_DATA_DIR}. Please pass -DOVERRIDE_PATHS=1 to skip this check")
+ endif()
+ set(CMAKE_INSTALL_PREFIX "${${APP_NAME_UC}_PREFIX}" CACHE PATH "${APP_NAME} install prefix" FORCE)
+ set(CMAKE_INSTALL_LIBDIR "${${APP_NAME_UC}_LIB_DIR}" CACHE PATH "${APP_NAME} install libdir" FORCE)
+ set(CMAKE_INSTALL_DATADIR "${${APP_NAME_UC}_DATA_DIR}" CACHE PATH "${APP_NAME} install datadir" FORCE)
+ else()
+ if(NOT CMAKE_INSTALL_LIBDIR)
+ set(CMAKE_INSTALL_LIBDIR "${CMAKE_INSTALL_PREFIX}/lib/${APP_NAME_LC}")
+ endif()
+ if(NOT CMAKE_INSTALL_DATADIR)
+ set(CMAKE_INSTALL_DATADIR "${CMAKE_INSTALL_PREFIX}/share/${APP_NAME_LC}")
+ endif()
+ endif()
+ else()
+ set(CMAKE_INSTALL_LIBDIR "lib/${APP_NAME_LC}")
+ set(CMAKE_INSTALL_DATADIR "share/${APP_NAME_LC}")
+ endif()
+ if(${prefix}_SOURCES)
+ install(TARGETS ${target} DESTINATION ${CMAKE_INSTALL_LIBDIR}/addons/${target})
+ endif()
+ if (${prefix}_CUSTOM_BINARY)
+ install(FILES ${LIBRARY_LOCATION} DESTINATION ${CMAKE_INSTALL_LIBDIR}/addons/${target} RENAME ${LIBRARY_FILENAME})
+ endif()
+ install(DIRECTORY ${target} ${CMAKE_CURRENT_BINARY_DIR}/${target} DESTINATION ${CMAKE_INSTALL_DATADIR}/addons
+ REGEX ".+\\.xml\\.in(clude)?$" EXCLUDE)
+ if(${prefix}_CUSTOM_DATA)
+ install(DIRECTORY ${${prefix}_CUSTOM_DATA} DESTINATION ${CMAKE_INSTALL_DATADIR}/addons/${target}/resources)
+ endif()
+ if(${prefix}_ADDITIONAL_BINARY)
+ install(FILES ${${prefix}_ADDITIONAL_BINARY} DESTINATION ${CMAKE_INSTALL_LIBDIR}/addons/${target})
+ endif()
+ if(${prefix}_ADDITIONAL_BINARY_EXE)
+ install(PROGRAMS ${${prefix}_ADDITIONAL_BINARY_EXE} DESTINATION ${CMAKE_INSTALL_LIBDIR}/addons/${target})
+ endif()
+ if(${prefix}_ADDITIONAL_BINARY_PARTS)
+ install(FILES ${${prefix}_ADDITIONAL_BINARY_PARTS} DESTINATION ${CMAKE_INSTALL_LIBDIR}/addons/${target})
+ endif()
+ if(${prefix}_ADDITIONAL_BINARY_DIRS)
+ install(DIRECTORY ${${prefix}_ADDITIONAL_BINARY_DIRS} DESTINATION ${CMAKE_INSTALL_LIBDIR}/addons/${target} USE_SOURCE_PERMISSIONS)
+ endif()
+ endif()
+ if(${APP_NAME_UC}_BUILD_DIR)
+ file(GLOB_RECURSE files ${CMAKE_CURRENT_SOURCE_DIR}/${target}/*)
+ if(${prefix}_CUSTOM_DATA)
+ get_filename_component(dname ${${prefix}_CUSTOM_DATA} NAME)
+ add_custom_command(TARGET ${target} POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy_directory
+ ${${prefix}_CUSTOM_DATA}
+ ${${APP_NAME_UC}_BUILD_DIR}/addons/${target}/resources/${dname})
+ endif()
+ foreach(file ${files})
+ string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/${target}/" "" name "${file}")
+ # A good way to deal with () in filenames
+ if(NOT ${file} MATCHES xml.in)
+ configure_file(${file} ${${APP_NAME_UC}_BUILD_DIR}/addons/${target}/${name} COPYONLY)
+ endif()
+ endforeach()
+ add_custom_command(TARGET ${target} POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy
+ ${LIBRARY_LOCATION}
+ ${${APP_NAME_UC}_BUILD_DIR}/addons/${target}/${LIBRARY_FILENAME})
+ if(${prefix}_ADDITIONAL_BINARY)
+ add_custom_command(TARGET ${target} POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy
+ ${${prefix}_ADDITIONAL_BINARY}
+ ${${APP_NAME_UC}_BUILD_DIR}/addons/${target})
+ endif()
+ endif()
+endmacro()
+
+# finds a path to a given file (recursive)
+function (kodi_find_path var_name filename search_path strip_file)
+ file(GLOB_RECURSE PATH_TO_FILE ${search_path} ${filename})
+ if(strip_file)
+ string(REPLACE ${filename} "" PATH_TO_FILE ${PATH_TO_FILE})
+ endif()
+ set (${var_name} ${PATH_TO_FILE} PARENT_SCOPE)
+endfunction()
+
+# Cmake build options
+include(AddOptions)
+include(TestCXXAcceptsFlag)
+option(PACKAGE_ZIP "Package Zip file?" OFF)
+option(PACKAGE_TGZ "Package TGZ file?" OFF)
+option(BUILD_SHARED_LIBS "Build shared libs?" ON)
+
+# LTO support?
+CHECK_CXX_ACCEPTS_FLAG("-flto" HAVE_LTO)
+if(HAVE_LTO)
+ option(USE_LTO "use link time optimization" OFF)
+ if(USE_LTO)
+ add_options(ALL_LANGUAGES ALL_BUILDS "-flto")
+ endif()
+endif()
+
+# set this to try linking dependencies as static as possible
+if(ADDONS_PREFER_STATIC_LIBS)
+ set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
+endif()
+
+if(${APP_NAME_UC}_BUILD_DIR)
+ list(APPEND CMAKE_PREFIX_PATH ${${APP_NAME_UC}_BUILD_DIR}/build)
+endif()
diff --git a/cmake/scripts/common/AddonHelpers.dox b/cmake/scripts/common/AddonHelpers.dox
new file mode 100644
index 0000000..522e0e7
--- /dev/null
+++ b/cmake/scripts/common/AddonHelpers.dox
@@ -0,0 +1,59 @@
+/*!
+\addtogroup cpp_cmake
+
+Kodi which uses it as a library for its binary addons has a special build
+system for this.
+
+To implement this, a CMake macro brought by Kodi is used, this is
+"build_addon (...)". This processes various definitions passed by the addon to
+process the construction.
+
+
+--------------------------------------------------------------------------------
+
+<b>Here's a minimal example of the addon used for CMakeLists.txt:</b>
+
+~~~~~~~~~~~~~{.cmake}
+cmake_minimum_required(VERSION 3.5)
+project(example.addon)
+
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR})
+
+find_package(Kodi REQUIRED)
+
+include_directories(${KODI_INCLUDE_DIR}
+
+set(DEPLIBS ) # Here empty
+set(EXAMPLE_SOURCES src/main.cpp)
+set(EXAMPLE_HEADERS src/main.h)
+
+build_addon((example.addon EXAMPLE DEPLIBS)
+
+include(CPack)
+~~~~~~~~~~~~~
+
+
+--------------------------------------------------------------------------------
+
+This is a list of special variables that can be passed to the macro.
+The parts defined with "*" must be given the second name given to the macro.
+
+Here to define the necessary creation and installation files on addon CMakeLists.txt:
+| Name | Description
+|-----------------------------|-------------------------------------------------
+| *_SOURCES | List of source code files to be complicated.
+| *_HEADERS | List of used source code header files.
+| *_CUSTOM_BINARY | For special cases where an already created library from an external source is inserted, the <b>"* _SOURCES"</b> and <b>"* _HEADERS"</b> are unused in this case.<br>This is currently used primarily on game addons.
+| *_CUSTOM_DATA | To add additional required data from a folder, which are stored in the shared folder of the addon.<br>With a "/" at the end of the content given to the folder is used, without the folder itself.
+| *_ADDITIONAL_BINARY | In case the additional library has to be installed for the addon, the path or CMake name can be given here.
+| *_ADDITIONAL_BINARY_EXE | In case you need to addon an additional application you can give the path or CMake name, it will be in the same folder as the addon library.<br>The mode bits are set there as EXE.
+| *_ADDITIONAL_BINARY_DIRS | To add complete folders additionally to folders containing the addon library.<br>With a "/" at the end of the content given to the folder is used, without the folder itself.
+
+External creation Options, given by `-D...`:
+| Name | Description
+|-----------------------------|-------------------------------------------------
+| PACKAGE_ZIP | To create a package as a ZIP file. This is also used to install locally addon together.<br>Default is OFF.
+| PACKAGE_TGZ | To create a package as a TGZ file.<br>Default is OFF.
+| BUILD_SHARED_LIBS | To define if addon library is shared or static.<br>Default is ON to have shared.
+| USE_LTO | Use link time optimization.<br>Default is OFF.
+*/
diff --git a/cmake/scripts/common/ArchSetup.cmake b/cmake/scripts/common/ArchSetup.cmake
new file mode 100644
index 0000000..a59fcb5
--- /dev/null
+++ b/cmake/scripts/common/ArchSetup.cmake
@@ -0,0 +1,201 @@
+# This script configures the build for a given architecture.
+# Flags and stringified arch is set up.
+# General compiler tests belongs here.
+#
+# On return, the following variables are set:
+# CMAKE_SYSTEM_NAME - a lowercased system name
+# CPU - the CPU on the target
+# ARCH - the system architecture
+# ARCH_DEFINES - list of compiler definitions for this architecture
+# SYSTEM_DEFINES - list of compiler definitions for this system
+# DEP_DEFINES - compiler definitions for system dependencies (e.g. LIRC)
+# + the results of compiler tests etc.
+
+# workaround a bug in older cmake, where binutils wouldn't be set after deleting CMakeCache.txt
+include(CMakeFindBinUtils)
+
+include(CheckCXXSourceCompiles)
+include(CheckSymbolExists)
+include(CheckFunctionExists)
+include(CheckIncludeFile)
+include(CheckTypeSize)
+
+# Macro to check if a given builtin function exists
+# Arguments:
+# func the function to check
+# var the compiler definition to set if type exists
+# On return:
+# If type was found, the definition is added to SYSTEM_DEFINES
+macro(check_builtin func var)
+ check_cxx_source_compiles("
+ int main()
+ {
+ ${func};
+ }" ${var})
+ if(${var})
+ list(APPEND SYSTEM_DEFINES -D${var}=1)
+ endif()
+endmacro()
+
+
+# -------- Main script ---------
+message(STATUS "System type: ${CMAKE_SYSTEM_NAME}")
+
+if(WITH_CPU)
+ set(CPU ${WITH_CPU})
+elseif(NOT KODI_DEPENDSBUILD)
+ set(CPU ${CMAKE_SYSTEM_PROCESSOR})
+endif()
+
+if(CMAKE_TOOLCHAIN_FILE)
+ if(NOT EXISTS "${CMAKE_TOOLCHAIN_FILE}")
+ message(FATAL_ERROR "Toolchain file ${CMAKE_TOOLCHAIN_FILE} does not exist.")
+ elseif(KODI_DEPENDSBUILD AND (NOT DEPENDS_PATH OR NOT NATIVEPREFIX))
+ message(FATAL_ERROR "Toolchain did not define DEPENDS_PATH or NATIVEPREFIX. Possibly outdated depends.")
+ endif()
+endif()
+
+# While CMAKE_CROSSCOMPILING is set unconditionally if there's a toolchain file,
+# this variable is set if we can execute build artefacts on the host system (for example unit tests).
+if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL CMAKE_SYSTEM_PROCESSOR AND
+ CMAKE_HOST_SYSTEM_NAME STREQUAL CMAKE_SYSTEM_NAME)
+ if(NOT DEFINED HOST_CAN_EXECUTE_TARGET)
+ set(HOST_CAN_EXECUTE_TARGET TRUE)
+ endif()
+else()
+ if(NOT HOST_CAN_EXECUTE_TARGET)
+ set(HOST_CAN_EXECUTE_TARGET FALSE)
+ endif()
+endif()
+
+# system specific arch setup
+if(NOT EXISTS ${CMAKE_SOURCE_DIR}/cmake/scripts/${CORE_SYSTEM_NAME}/ArchSetup.cmake)
+ message(FATAL_ERROR "Couldn't find configuration for '${CORE_SYSTEM_NAME}' "
+ "Either the platform is not (yet) supported "
+ "or a toolchain file has to be specified. "
+ "Consult ${CMAKE_SOURCE_DIR}/cmake/README.md for instructions. "
+ "Note: Specifying a toolchain requires a clean build directory!")
+endif()
+include(${CMAKE_SOURCE_DIR}/cmake/scripts/${CORE_SYSTEM_NAME}/ArchSetup.cmake)
+
+# No TARBALL_DIR given, or no arch specific default set
+if(NOT TARBALL_DIR)
+ set(TARBALL_DIR ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/download)
+endif()
+
+message(STATUS "Core system type: ${CORE_SYSTEM_NAME}")
+message(STATUS "Platform: ${CORE_PLATFORM_NAME}")
+message(STATUS "CPU: ${CPU}, ARCH: ${ARCH}")
+message(STATUS "Cross-Compiling: ${CMAKE_CROSSCOMPILING}")
+message(STATUS "Execute build artefacts on host: ${CORE_HOST_IS_TARGET}")
+message(STATUS "Depends based build: ${KODI_DEPENDSBUILD}")
+
+check_symbol_exists(posix_fadvise fcntl.h HAVE_POSIX_FADVISE)
+check_symbol_exists(PRIdMAX inttypes.h HAVE_INTTYPES_H)
+check_builtin("long* temp=0; long ret=__sync_add_and_fetch(temp, 1)" HAS_BUILTIN_SYNC_ADD_AND_FETCH)
+check_builtin("long* temp=0; long ret=__sync_sub_and_fetch(temp, 1)" HAS_BUILTIN_SYNC_SUB_AND_FETCH)
+check_builtin("long* temp=0; long ret=__sync_val_compare_and_swap(temp, 1, 1)" HAS_BUILTIN_SYNC_VAL_COMPARE_AND_SWAP)
+check_include_file(sys/inotify.h HAVE_INOTIFY)
+if(HAVE_INOTIFY)
+ list(APPEND SYSTEM_DEFINES -DHAVE_INOTIFY=1)
+endif()
+if(HAVE_POSIX_FADVISE)
+ list(APPEND SYSTEM_DEFINES -DHAVE_POSIX_FADVISE=1)
+endif()
+check_function_exists(localtime_r HAVE_LOCALTIME_R)
+if(HAVE_LOCALTIME_R)
+ list(APPEND SYSTEM_DEFINES -DHAVE_LOCALTIME_R=1)
+endif()
+check_function_exists(gmtime_r HAVE_GMTIME_R)
+if(HAVE_GMTIME_R)
+list(APPEND SYSTEM_DEFINES -DHAVE_GMTIME_R=1)
+endif()
+if(HAVE_INTTYPES_H)
+ list(APPEND SYSTEM_DEFINES -DHAVE_INTTYPES_H=1)
+endif()
+
+set(CMAKE_REQUIRED_DEFINITIONS "-D_GNU_SOURCE")
+check_symbol_exists("STATX_BTIME" "linux/stat.h" HAVE_STATX)
+if(HAVE_STATX)
+ check_function_exists("statx" FOUND_STATX_FUNCTION)
+ if(FOUND_STATX_FUNCTION)
+ message(STATUS "statx is available")
+ list(APPEND ARCH_DEFINES "-DHAVE_STATX=1")
+ else()
+ message(STATUS "statx flags found but no linkable function : C library too old ?")
+ endif()
+else()
+ message(STATUS "statx() not found")
+endif()
+set(CMAKE_REQUIRED_DEFINITIONS "")
+
+find_package(SSE)
+foreach(_sse SSE SSE2 SSE3 SSSE3 SSE4_1 SSE4_2 AVX AVX2)
+ if(${${_sse}_FOUND})
+ # enable SSE versions up to 4.1 by default, if available
+ if(NOT ${_sse} MATCHES "AVX" AND NOT ${_sse} STREQUAL "SSE4_2")
+ option(ENABLE_${_sse} "Enable ${_sse}" ON)
+ else()
+ option(ENABLE_${_sse} "Enable ${_sse}" OFF)
+ endif()
+ endif()
+ if(ENABLE_${_sse})
+ set(HAVE_${_sse} TRUE CACHE STRING "${_sse} enabled")
+ list(APPEND ARCH_DEFINES -DHAVE_${_sse}=1)
+ endif()
+endforeach()
+
+if(NOT DEFINED NEON OR NEON)
+ option(ENABLE_NEON "Enable NEON optimization" ${NEON})
+ if(ENABLE_NEON)
+ message(STATUS "NEON optimization enabled")
+ add_definitions(-DHAS_NEON)
+ if(NEON_FLAGS)
+ add_options(ALL_LANGUAGES ALL_BUILDS ${NEON_FLAGS})
+ endif()
+ endif()
+endif()
+
+if(NOT MSVC)
+ # these options affect all code built by cmake including external projects.
+ add_options(ALL_LANGUAGES ALL_BUILDS
+ -Wall
+ -Wdouble-promotion
+ -Wmissing-field-initializers
+ -Wsign-compare
+ -Wextra
+ -Wno-unused-parameter # from -Wextra
+ )
+
+ if(CMAKE_COMPILER_IS_GNUCXX)
+ add_options(ALL_LANGUAGES ALL_BUILDS
+ -Wno-cast-function-type # from -Wextra
+ )
+ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ add_options(ALL_LANGUAGES ALL_BUILDS
+ -Wno-bad-function-cast
+ -Wno-deprecated
+ )
+ endif()
+
+ add_options(CXX ALL_BUILDS
+ -Wnon-virtual-dtor
+ )
+
+ add_options(ALL_LANGUAGES DEBUG
+ -g
+ -D_DEBUG
+ )
+
+ # these options affect only core code
+ if(NOT CORE_COMPILE_OPTIONS)
+ set(CORE_COMPILE_OPTIONS
+ -Werror=double-promotion
+ -Werror=missing-field-initializers
+ -Werror=sign-compare
+ )
+ endif()
+endif()
+
+# set for compile info to help detect binary addons
+set(APP_SHARED_LIBRARY_SUFFIX "${CMAKE_SHARED_LIBRARY_SUFFIX}")
diff --git a/cmake/scripts/common/CMakeHelpers.cmake b/cmake/scripts/common/CMakeHelpers.cmake
new file mode 100644
index 0000000..995c38a
--- /dev/null
+++ b/cmake/scripts/common/CMakeHelpers.cmake
@@ -0,0 +1,54 @@
+# This file contains functions that support the debugging of the CMake files.
+
+# This file shouldn't be included per default in any CMake file. It should be
+# included and used only on demand. All functions are prefixed with "debug_".
+#
+# Usage:
+# include(scripts/common/CMakeHelpers.cmake)
+# debug_print_variables()
+
+# Print all CMake variables.
+macro(debug_print_variables)
+ get_cmake_property(_variableNames VARIABLES)
+ foreach(_variableName ${_variableNames})
+ message(STATUS "${_variableName} = ${${_variableName}}")
+ endforeach()
+endmacro()
+
+# Get all properties that CMake supports and convert them to a list.
+function(debug_get_properties VAR)
+ execute_process(COMMAND cmake --help-property-list
+ OUTPUT_VARIABLE _properties)
+ string(REGEX REPLACE ";" "\\\\;" _properties "${_properties}")
+ string(REGEX REPLACE "\n" ";" _properties "${_properties}")
+ list(REMOVE_DUPLICATES _properties)
+ list(REMOVE_ITEM _properties LOCATION)
+ set(${VAR} ${_properties} PARENT_SCOPE)
+endfunction()
+
+# List all properties.
+function(debug_list_properties)
+ debug_get_properties(_properties)
+ message("CMake properties = ${_properties}")
+endfunction()
+
+# Print all set properties of a specified target.
+function(debug_print_target_properties target)
+ if(NOT TARGET ${target})
+ message(FATAL_ERROR "There is no target named '${target}'")
+ endif()
+
+ debug_get_properties(_properties)
+
+ # Reading LOCATION property is deprecated and triggers a fatal error.
+ string(REGEX REPLACE ";LOCATION;|LOCATION" "" _properties "${_properties}")
+ string(REGEX REPLACE "<CONFIG>" "${CMAKE_BUILD_TYPE}" _properties
+ "${_properties}")
+ foreach(_property ${_properties})
+ get_property(_value TARGET ${target} PROPERTY ${_property} SET)
+ if(_value)
+ get_target_property(_value ${target} ${_property})
+ message("${target} ${_property} = ${_value}")
+ endif()
+ endforeach()
+endfunction()
diff --git a/cmake/scripts/common/CheckCommits.cmake b/cmake/scripts/common/CheckCommits.cmake
new file mode 100644
index 0000000..304e623
--- /dev/null
+++ b/cmake/scripts/common/CheckCommits.cmake
@@ -0,0 +1,75 @@
+find_package(Git REQUIRED)
+
+macro(sanity_check message)
+ if(status_code)
+ message(FATAL_ERROR "${message}")
+ endif()
+endmacro()
+
+# Check that there are no changes in working-tree
+execute_process(COMMAND ${GIT_EXECUTABLE} diff --quiet
+ RESULT_VARIABLE status_code)
+sanity_check("Cannot run with working tree changes. Commit, stash or drop them.")
+
+# Setup base of tests
+set(check_base $ENV{CHECK_BASE})
+if(NOT check_base)
+ set(check_base origin/master)
+endif()
+
+# Setup end of tests
+set(check_head $ENV{CHECK_HEAD})
+if(NOT check_head)
+ set(check_head HEAD)
+endif()
+
+# Setup target to build
+set(check_target $ENV{CHECK_TARGET})
+if(NOT check_target)
+ set(check_target check)
+endif()
+
+# Build threads
+set(build_threads $ENV{CHECK_THREADS})
+if(NOT build_threads)
+ if(UNIX)
+ execute_process(COMMAND nproc
+ OUTPUT_VARIABLE build_threads)
+ string(REGEX REPLACE "(\r?\n)+$" "" build_threads "${build_threads}")
+ endif()
+endif()
+
+# Record current HEAD
+execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD
+ OUTPUT_VARIABLE current_branch)
+
+string(REGEX REPLACE "(\r?\n)+$" "" current_branch "${current_branch}")
+
+# Grab revision list
+execute_process(COMMAND ${GIT_EXECUTABLE} rev-list ${check_base}..${check_head} --reverse
+ OUTPUT_VARIABLE rev_list)
+
+string(REPLACE "\n" ";" rev_list ${rev_list})
+foreach(rev ${rev_list})
+ # Checkout
+ message("Testing revision ${rev}")
+ execute_process(COMMAND ${GIT_EXECUTABLE} checkout ${rev}
+ RESULT_VARIABLE status_code)
+ sanity_check("Failed to checkout ${rev}")
+
+ # Build
+ if(build_threads GREATER 2)
+ execute_process(COMMAND ${CMAKE_COMMAND} "--build" "${CMAKE_BINARY_DIR}" "--target" "${check_target}" "--use-stderr" "--" "-j${build_threads}"
+ RESULT_VARIABLE status_code)
+ else()
+ execute_process(COMMAND ${CMAKE_COMMAND} "--build" "${CMAKE_BINARY_DIR}" "--target" "${check_target}" "--use-stderr"
+ RESULT_VARIABLE status_code)
+ endif()
+ if(status_code)
+ execute_process(COMMAND ${GIT_EXECUTABLE} checkout ${current_branch})
+ endif()
+ sanity_check("Failed to build target for revision ${rev}")
+endforeach()
+
+message("Everything checks out fine")
+execute_process(COMMAND ${GIT_EXECUTABLE} checkout ${current_branch})
diff --git a/cmake/scripts/common/CheckTargetPlatform.cmake b/cmake/scripts/common/CheckTargetPlatform.cmake
new file mode 100644
index 0000000..29206c0
--- /dev/null
+++ b/cmake/scripts/common/CheckTargetPlatform.cmake
@@ -0,0 +1,70 @@
+# handle target platforms
+function(check_target_platform dir target_platform build)
+ # param[in] dir path/directory of the addon/dependency
+ # param[in] target_platform target platform of the build
+ # param[out] build Result whether the addon/dependency should be built for the specified target platform
+
+ set(${build} FALSE)
+ # check if the given directory exists and contains a platforms.txt
+ if(EXISTS ${dir} AND EXISTS ${dir}/platforms.txt)
+ # get all the specified platforms
+ file(STRINGS ${dir}/platforms.txt platforms)
+
+ list( LENGTH platforms listlen )
+ if(${listlen} EQUAL 1)
+ string(REPLACE " " ";" platforms ${platforms})
+ endif()
+
+ # check if the addon/dependency should be built for the current platform
+ foreach(platform ${platforms})
+ if(${platform} STREQUAL "all" OR ${platform} STREQUAL ${target_platform})
+ set(${build} TRUE)
+ else()
+ # check if the platform is defined as "!<platform>"
+ string(SUBSTRING ${platform} 0 1 platform_first)
+ if(${platform_first} STREQUAL "!")
+ # extract the platform
+ string(LENGTH ${platform} platform_length)
+ math(EXPR platform_length "${platform_length} - 1")
+ string(SUBSTRING ${platform} 1 ${platform_length} platform)
+
+ # check if the current platform does not match the extracted platform
+ if(${platform} STREQUAL ${target_platform})
+ set(${build} FALSE)
+ break()
+ elseif(NOT ${platform} STREQUAL ${target_platform})
+ set(${build} TRUE)
+ endif()
+ endif()
+ endif()
+ endforeach()
+ else()
+ set(${build} TRUE)
+ endif()
+
+ # make the ${build} variable available to the calling script
+ set(${build} "${${build}}" PARENT_SCOPE)
+endfunction()
+
+function(check_install_permissions install_dir have_perms)
+ # param[in] install_dir directory to check for write permissions
+ # param[out] have_perms whether we have permissions to install to install_dir
+
+ set(testfile_lib ${install_dir}/lib/kodi/.cmake-inst-test)
+ set(testfile_share ${install_dir}/share/kodi/.cmake-inst-test)
+ get_filename_component(testdir_lib ${testfile_lib} DIRECTORY)
+ get_filename_component(testdir_share ${testfile_share} DIRECTORY)
+
+ execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${testdir_lib})
+ execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${testdir_share})
+ execute_process(COMMAND ${CMAKE_COMMAND} -E touch ${testfile_lib})
+ execute_process(COMMAND ${CMAKE_COMMAND} -E touch ${testfile_share})
+
+ if(EXISTS ${testfile_lib} AND EXISTS ${testfile_share})
+ set(${have_perms} True PARENT_SCOPE)
+ else()
+ message(STATUS "check_install_permissions ${install_dir}: failed to create files")
+ set(${have_perms} False PARENT_SCOPE)
+ endif()
+ file(REMOVE ${testfile_lib} ${testfile_share})
+endfunction()
diff --git a/cmake/scripts/common/CompilerSettings.cmake b/cmake/scripts/common/CompilerSettings.cmake
new file mode 100644
index 0000000..bb0af92
--- /dev/null
+++ b/cmake/scripts/common/CompilerSettings.cmake
@@ -0,0 +1,5 @@
+# Languages and global compiler settings
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+set(CMAKE_CXX_EXTENSIONS OFF)
+set(CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS} -x assembler-with-cpp")
diff --git a/cmake/scripts/common/DependencyOptions.cmake b/cmake/scripts/common/DependencyOptions.cmake
new file mode 100644
index 0000000..a45dcec
--- /dev/null
+++ b/cmake/scripts/common/DependencyOptions.cmake
@@ -0,0 +1,23 @@
+# Set Option varname based on USE_INTERNAL_LIBS status
+#
+# Alternative to cmake_dependent_option
+# cmake_dependent_option is restrictive, in the fact that we cannot override the
+# set option value as a cache variable (-Dvar=foo)
+#
+# This allows us to have the same outcome as cmake_dependent_option whilst still allowing
+# user to override for platforms that would normally be forced ON
+#
+function(dependent_option varname optionmessage)
+
+ # If varname already set, accept that, as it was provided by the user
+ if(NOT DEFINED ${varname})
+ # Generally we only define USE_INTERNAL_LIBS as the exception for platforms
+ # we explicitly dont want to build internal libs (eg Linux/Freebsd)
+ if(NOT DEFINED USE_INTERNAL_LIBS)
+ option(${varname} ${optionmessage} ON)
+ else()
+ # Respect Value of USE_INTERNAL_LIBS for ON/OFF
+ option(${varname} ${optionmessage} ${USE_INTERNAL_LIBS})
+ endif()
+ endif()
+endfunction()
diff --git a/cmake/scripts/common/GenerateVersionedFiles.cmake b/cmake/scripts/common/GenerateVersionedFiles.cmake
new file mode 100644
index 0000000..d54b524
--- /dev/null
+++ b/cmake/scripts/common/GenerateVersionedFiles.cmake
@@ -0,0 +1,35 @@
+include(${CORE_SOURCE_DIR}/cmake/scripts/common/Macros.cmake)
+
+core_find_versions()
+
+# configure_file without dependency tracking
+# configure_file would register additional file dependencies that interfere
+# with the ones from add_custom_command (and the generation would happen twice)
+function(generate_versioned_file _SRC _DEST)
+ file(READ ${CORE_SOURCE_DIR}/${_SRC} file_content)
+ string(CONFIGURE "${file_content}" file_content @ONLY)
+ file(WRITE ${CMAKE_BINARY_DIR}/${_DEST} "${file_content}")
+endfunction()
+
+# add-on xml's
+file(GLOB ADDON_XML_IN_FILE ${CORE_SOURCE_DIR}/addons/*/addon.xml.in)
+
+# remove 'xbmc.json', will be created from 'xbmc/interfaces/json-rpc/schema/CMakeLists.txt'
+list(REMOVE_ITEM ADDON_XML_IN_FILE ${CORE_SOURCE_DIR}/addons/xbmc.json/addon.xml.in)
+
+foreach(loop_var ${ADDON_XML_IN_FILE})
+ list(GET loop_var 0 xml_name)
+
+ string(REPLACE "/addon.xml.in" "" source_dir ${xml_name})
+ string(REPLACE ${CORE_SOURCE_DIR} ${CMAKE_BINARY_DIR} dest_dir ${source_dir})
+ file(MAKE_DIRECTORY ${dest_dir})
+
+ configure_file(${source_dir}/addon.xml.in ${dest_dir}/addon.xml @ONLY)
+
+ unset(source_dir)
+ unset(dest_dir)
+ unset(xml_name)
+endforeach()
+
+
+generate_versioned_file(xbmc/CompileInfo.cpp.in ${CORE_BUILD_DIR}/xbmc/CompileInfo.cpp)
diff --git a/cmake/scripts/common/GeneratorSetup.cmake b/cmake/scripts/common/GeneratorSetup.cmake
new file mode 100644
index 0000000..304b504
--- /dev/null
+++ b/cmake/scripts/common/GeneratorSetup.cmake
@@ -0,0 +1,49 @@
+# Configure single-/multiconfiguration generators and variables
+#
+# CORE_BUILD_CONFIG that is set to
+# - CMAKE_BUILD_TYPE for single configuration generators such as make, nmake
+# - a variable that expands on build time to the current configuration for
+# multi configuration generators such as VS or Xcode
+if(CMAKE_CONFIGURATION_TYPES)
+ if(CMAKE_BUILD_TYPE)
+ message(FATAL_ERROR "CMAKE_BUILD_TYPE must not be defined for multi-configuration generators")
+ endif()
+ set(CORE_BUILD_CONFIG ${CMAKE_CFG_INTDIR})
+ message(STATUS "Generator: Multi-configuration (${CMAKE_GENERATOR})")
+else()
+ if(CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE}
+ CACHE STRING "Choose build type (${CMAKE_BUILD_TYPES})" FORCE)
+ else()
+ # Set default
+ set(CMAKE_BUILD_TYPE Release
+ CACHE STRING "Choose build type (${CMAKE_BUILD_TYPES})" FORCE)
+ endif()
+ set(CORE_BUILD_CONFIG ${CMAKE_BUILD_TYPE})
+ message(STATUS "Generator: Single-configuration: ${CMAKE_BUILD_TYPE} (${CMAKE_GENERATOR})")
+endif()
+
+# Print CMake version
+message(STATUS "CMake Version: ${CMAKE_VERSION}")
+
+# Deal with CMake special cases
+if(CMAKE_VERSION VERSION_EQUAL 3.5.1)
+ message(WARNING "CMake 3.5.1 introduced a crash during configuration. "
+ "Please consider upgrading to 3.5.2 (cmake.org/Bug/view.php?id=16044)")
+endif()
+
+# Darwin needs CMake 3.4
+if(APPLE AND CMAKE_VERSION VERSION_LESS 3.4)
+ message(WARNING "Build on Darwin requires CMake 3.4 or later (tdb library support) "
+ "or the usage of the patched version in depends.")
+endif()
+
+# Windows needs CMake 3.6 (VS_STARTUP_PROJECT)
+if(WIN32 AND CMAKE_VERSION VERSION_LESS 3.6)
+ message(FATAL_ERROR "Build on Windows needs CMake 3.6 or later")
+endif()
+
+# Ninja needs CMake 3.2 due to ExternalProject BUILD_BYPRODUCTS usage
+if(CMAKE_GENERATOR STREQUAL Ninja AND CMAKE_VERSION VERSION_LESS 3.2)
+ message(FATAL_ERROR "Generator: Ninja requires CMake 3.2 or later")
+endif()
diff --git a/cmake/scripts/common/HandleDepends.cmake b/cmake/scripts/common/HandleDepends.cmake
new file mode 100644
index 0000000..dc022ba
--- /dev/null
+++ b/cmake/scripts/common/HandleDepends.cmake
@@ -0,0 +1,301 @@
+include(${CORE_SOURCE_DIR}/cmake/scripts/common/CheckTargetPlatform.cmake)
+
+# handle addon depends
+function(add_addon_depends addon searchpath)
+ # input: string addon string searchpath
+
+ set(OUTPUT_DIR ${ADDON_DEPENDS_PATH})
+ # look for platform-specific dependencies
+ file(GLOB_RECURSE cmake_input_files ${searchpath}/${CORE_SYSTEM_NAME}/*.txt)
+ # backward compatibility
+ if(NOT cmake_input_files AND CORE_SYSTEM_NAME STREQUAL windowsstore)
+ file(GLOB_RECURSE cmake_input_files ${searchpath}/windows/*.txt)
+ endif()
+ file(GLOB_RECURSE cmake_input_files2 ${searchpath}/common/*.txt)
+ list(APPEND cmake_input_files ${cmake_input_files2})
+
+ foreach(file ${cmake_input_files})
+ set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${file})
+ if(NOT (file MATCHES CMakeLists.txt OR
+ file MATCHES install.txt OR
+ file MATCHES noinstall.txt OR
+ file MATCHES "flags.*[.]txt" OR
+ file MATCHES deps.txt OR
+ file MATCHES "[a-z]+-deps[.]txt" OR
+ file MATCHES platforms.txt))
+ message(STATUS "Processing ${file}")
+ file(STRINGS ${file} def)
+ string(REPLACE " " ";" def ${def})
+ list(LENGTH def deflength)
+ get_filename_component(dir ${file} DIRECTORY)
+
+ # get the id of the dependency
+ if(NOT "${def}" STREQUAL "")
+ # read the id from the file
+ list(GET def 0 id)
+ else()
+ # read the id from the filename
+ get_filename_component(id ${file} NAME_WE)
+ endif()
+
+ # check if the dependency has a platforms.txt
+ set(platform_found FALSE)
+ check_target_platform(${dir} ${CORE_SYSTEM_NAME} platform_found)
+
+ if(${platform_found} AND NOT TARGET ${id})
+ # determine the download URL of the dependency
+ set(url "")
+ if(deflength GREATER 1)
+ list(GET def 1 url)
+ message(STATUS "${id} url: ${url}")
+ endif()
+
+ # check if there are any library specific flags that need to be passed on
+ if(EXISTS ${dir}/flags.txt)
+ set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${dir}/flags.txt)
+ file(STRINGS ${dir}/flags.txt extraflags)
+ string(REPLACE " " ";" extraflags ${extraflags})
+
+ message(STATUS "${id} extraflags: ${extraflags}")
+ endif()
+
+ if(EXISTS ${dir}/flags-${CPU}.txt)
+ set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${dir}/flags-${CPU}.txt)
+ file(STRINGS ${dir}/flags-${CPU}.txt archextraflags)
+ string(REPLACE " " ";" archextraflags ${archextraflags})
+
+ message(STATUS "${id} ${CPU} extraflags: ${archextraflags}")
+ list(APPEND extraflags ${archextraflags})
+ endif()
+
+ set(BUILD_ARGS -DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}
+ -DOUTPUT_DIR=${OUTPUT_DIR}
+ -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
+ -DCMAKE_USER_MAKE_RULES_OVERRIDE=${CMAKE_USER_MAKE_RULES_OVERRIDE}
+ -DCMAKE_USER_MAKE_RULES_OVERRIDE_CXX=${CMAKE_USER_MAKE_RULES_OVERRIDE_CXX}
+ -DCMAKE_INSTALL_PREFIX=${OUTPUT_DIR}
+ -DCORE_SYSTEM_NAME=${CORE_SYSTEM_NAME}
+ -DENABLE_STATIC=1
+ -DBUILD_SHARED_LIBS=0)
+ # windows args
+ if (CMAKE_SYSTEM_NAME STREQUAL WindowsStore OR CMAKE_SYSTEM_NAME STREQUAL Windows)
+ list(APPEND BUILD_ARGS -DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}
+ -DCMAKE_SYSTEM_VERSION=${CMAKE_SYSTEM_VERSION})
+ endif()
+ # if there are no make rules override files available take care of manually passing on ARCH_DEFINES
+ if(NOT CMAKE_USER_MAKE_RULES_OVERRIDE AND NOT CMAKE_USER_MAKE_RULES_OVERRIDE_CXX)
+ # make sure we create strings, not lists
+ set(TMP_C_FLAGS "${CMAKE_C_FLAGS} ${ARCH_DEFINES}")
+ set(TMP_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ARCH_DEFINES}")
+ set(TMP_EXE_LINKER_FLAGS "-L${OUTPUT_DIR}/lib ${CMAKE_EXE_LINKER_FLAGS}")
+ list(APPEND BUILD_ARGS -DCMAKE_C_FLAGS=${TMP_C_FLAGS}
+ -DCMAKE_CXX_FLAGS=${TMP_CXX_FLAGS}
+ -DCMAKE_EXE_LINKER_FLAGS=${TMP_EXE_LINKER_FLAGS})
+ endif()
+
+ if(CMAKE_TOOLCHAIN_FILE)
+ list(APPEND BUILD_ARGS -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE})
+ message("toolchain specified")
+ message(${BUILD_ARGS})
+ endif()
+
+ if(ADDON_EXTRA_ARGS)
+ string(REPLACE " " ";" ADDON_EXTRA_ARGS ${ADDON_EXTRA_ARGS})
+ list(APPEND BUILD_ARGS ${ADDON_EXTRA_ARGS})
+ message("Addon Extra Args: ${ADDON_EXTRA_ARGS}")
+ endif()
+
+ # used for addons where need special folders to store there content (if
+ # not set the addon define it byself).
+ # e.g. Google Chromium addon where his git bring:
+ # - "unable to create file" ... "Filename too long"
+ # see also WARNING by Windows on: https://bitbucket.org/chromiumembedded/cef/wiki/MasterBuildQuickStart
+ if(THIRD_PARTY_PATH)
+ message(STATUS "Third party lib path specified")
+ message(STATUS ${THIRD_PARTY_PATH})
+ list(APPEND BUILD_ARGS -DTHIRD_PARTY_PATH=${THIRD_PARTY_PATH})
+ endif()
+
+ set(PATCH_COMMAND)
+
+ # if there's a CMakeLists.txt use it to prepare the build
+ if(EXISTS ${dir}/CMakeLists.txt)
+ set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${dir}/CMakeLists.txt)
+ list(APPEND PATCH_COMMAND COMMAND ${CMAKE_COMMAND} -E copy_if_different ${dir}/CMakeLists.txt ${BUILD_DIR}/${id}/src/${id})
+ endif()
+
+ # check if we have patches to apply
+ file(GLOB patches ${dir}/*.patch)
+ list(SORT patches)
+ foreach(patch ${patches})
+ if(NOT PATCH_PROGRAM OR "${PATCH_PROGRAM}" STREQUAL "")
+ if(NOT PATCH_EXECUTABLE)
+ # find the path to the patch executable
+
+ if(WIN32)
+ # On Windows prioritize Git patch.exe
+ find_package(Git)
+ if(Git_FOUND)
+ get_filename_component(GIT_DIR ${GIT_EXECUTABLE} DIRECTORY)
+ get_filename_component(GIT_DIR ${GIT_DIR} DIRECTORY)
+ endif()
+ find_program(PATCH_EXECUTABLE NAMES patch.exe HINTS ${GIT_DIR} PATH_SUFFIXES usr/bin)
+ else()
+ find_program(PATCH_EXECUTABLE NAMES patch)
+ endif()
+ if(NOT PATCH_EXECUTABLE)
+ message(FATAL_ERROR "Missing patch command (we looked in ${CMAKE_PREFIX_PATH})")
+ endif()
+ endif()
+
+ set(PATCH_PROGRAM ${PATCH_EXECUTABLE})
+
+ # On Windows "patch.exe" can only handle CR-LF line-endings.
+ # Our patches have LF-only line endings - except when they
+ # have been checked out as part of a dependency hosted on Git
+ # and core.autocrlf=true.
+ if(WIN32)
+ file(READ ${patch} patch_content_hex HEX)
+ # Force handle LF-only line endings
+ if(NOT patch_content_hex MATCHES "0d0a")
+ list(APPEND PATCH_PROGRAM --binary)
+ endif()
+ endif()
+ endif()
+
+ set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${patch})
+ list(APPEND PATCH_COMMAND COMMAND ${PATCH_PROGRAM} -p1 -i ${patch})
+ endforeach()
+
+
+ # if there's an install.txt use it to properly install the built files
+ set(INSTALL_COMMAND "")
+ if(EXISTS ${dir}/install.txt)
+ set(INSTALL_COMMAND INSTALL_COMMAND ${CMAKE_COMMAND}
+ -DINPUTDIR=${BUILD_DIR}/${id}/src/${id}-build/
+ -DINPUTFILE=${dir}/install.txt
+ -DDESTDIR=${OUTPUT_DIR}
+ -DENABLE_STATIC=1
+ "${extraflags}"
+ -P ${PROJECT_SOURCE_DIR}/install.cmake)
+ elseif(EXISTS ${dir}/noinstall.txt)
+ set(INSTALL_COMMAND INSTALL_COMMAND "")
+ endif()
+
+ # check if there's a platform-specific or generic deps.txt containing dependencies on other libraries
+ if(EXISTS ${dir}/${CORE_SYSTEM_NAME}-deps.txt)
+ file(STRINGS ${dir}/${CORE_SYSTEM_NAME}-deps.txt deps)
+ message(STATUS "${id} depends: ${deps}")
+ # backward compatibility
+ elseif(CORE_SYSTEM_NAME STREQUAL windowsstore AND EXISTS ${dir}/windows-deps.txt)
+ file(STRINGS ${dir}/windows-deps.txt deps)
+ message(STATUS "${id} depends: ${deps}")
+ elseif(EXISTS ${dir}/deps.txt)
+ set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${dir}/deps.txt)
+ file(STRINGS ${dir}/deps.txt deps)
+ message(STATUS "${id} depends: ${deps}")
+ else()
+ set(deps)
+ endif()
+
+ if(CROSS_AUTOCONF AND AUTOCONF_FILES)
+ foreach(afile ${AUTOCONF_FILES})
+ set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${afile})
+ list(APPEND PATCH_COMMAND COMMAND ${CMAKE_COMMAND} -E echo "AUTOCONF: copying ${afile} to ${BUILD_DIR}/${id}/src/${id}")
+ list(APPEND PATCH_COMMAND COMMAND ${CMAKE_COMMAND} -E copy_if_different ${afile} ${BUILD_DIR}/${id}/src/${id})
+ endforeach()
+ endif()
+
+ # prepare the setup of the call to externalproject_add()
+ set(EXTERNALPROJECT_SETUP PREFIX ${BUILD_DIR}/${id}
+ CMAKE_ARGS ${extraflags} ${BUILD_ARGS}
+ PATCH_COMMAND ${PATCH_COMMAND}
+ ${INSTALL_COMMAND})
+
+ if(CMAKE_VERSION VERSION_GREATER 3.5.9)
+ list(APPEND EXTERNALPROJECT_SETUP GIT_SHALLOW 1)
+ endif()
+
+ # if there's an url defined we need to pass that to externalproject_add()
+ if(DEFINED url AND NOT "${url}" STREQUAL "")
+ # check if there's a third parameter in the file
+ if(deflength GREATER 2)
+ # the third parameter is considered as a revision of a git repository
+ list(GET def 2 revision)
+
+ externalproject_add(${id}
+ GIT_REPOSITORY ${url}
+ GIT_TAG ${revision}
+ ${EXTERNALPROJECT_SETUP})
+
+ # For patchfiles to work, disable (users globally set) autocrlf=true
+ if(CMAKE_MINIMUM_REQUIRED_VERSION VERSION_GREATER 3.7)
+ message(AUTHOR_WARNING "Make use of GIT_CONFIG")
+ endif()
+ if(WIN32 AND patches)
+ externalproject_add_step(${id} gitconfig
+ COMMAND git config core.autocrlf false
+ COMMAND git rm -rf --cached .
+ COMMAND git reset --hard HEAD
+ COMMENT "Performing gitconfig step: Disabling autocrlf to enable patching for '${id}'"
+ DEPENDERS patch
+ WORKING_DIRECTORY <SOURCE_DIR>)
+ endif()
+ else()
+ set(CONFIGURE_COMMAND "")
+ if(NOT WIN32)
+ # manually specify the configure command to be able to pass in the custom PKG_CONFIG_PATH
+ set(CONFIGURE_COMMAND PKG_CONFIG_PATH=${OUTPUT_DIR}/lib/pkgconfig
+ ${CMAKE_COMMAND} -DCMAKE_LIBRARY_PATH=${OUTPUT_DIR}/lib ${extraflags} ${BUILD_ARGS}
+ ${BUILD_DIR}/${id}/src/${id}
+ -DPACKAGE_CONFIG_PATH=${OUTPUT_DIR}/lib/pkgconfig
+ -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
+ -DOUTPUT_DIR=${OUTPUT_DIR}
+ -DCMAKE_PREFIX_PATH=${OUTPUT_DIR}
+ -DCMAKE_INSTALL_PREFIX=${OUTPUT_DIR}
+ -DCMAKE_INCLUDE_PATH=${OUTPUT_DIR}/include)
+ endif()
+
+ set(DOWNLOAD_DIR ${BUILD_DIR}/download)
+ if(EXISTS ${dir}/${id}.sha256)
+ file(STRINGS ${dir}/${id}.sha256 sha256sum)
+ list(GET sha256sum 0 sha256sum)
+ set(URL_HASH_COMMAND URL_HASH SHA256=${sha256sum})
+ if(TARBALL_DIR)
+ set(DOWNLOAD_DIR ${TARBALL_DIR})
+ endif()
+ else()
+ unset(URL_HASH_COMMAND)
+ message(AUTHOR_WARNING "${dir}/${id}.sha256 is missing")
+ endif()
+
+ externalproject_add(${id}
+ URL ${url}
+ "${URL_HASH_COMMAND}"
+ DOWNLOAD_DIR ${DOWNLOAD_DIR}
+ CONFIGURE_COMMAND ${CONFIGURE_COMMAND}
+ ${EXTERNALPROJECT_SETUP})
+ endif()
+ else()
+ externalproject_add(${id}
+ SOURCE_DIR ${dir}
+ ${EXTERNALPROJECT_SETUP})
+ endif()
+
+ if(deps)
+ add_dependencies(${id} ${deps})
+ endif()
+ endif()
+
+ # if the dependency is available for the target platform add it to the list of the addon's dependencies
+ # (even if the target already exists as it still has to be built before the addon)
+ if(${platform_found})
+ list(APPEND ${addon}_DEPS ${id})
+ endif()
+ endif()
+ endforeach()
+
+ # make the ${addon}_DEPS variable available to the calling script
+ set(${addon}_DEPS "${${addon}_DEPS}" PARENT_SCOPE)
+endfunction()
+
diff --git a/cmake/scripts/common/Macros.cmake b/cmake/scripts/common/Macros.cmake
new file mode 100644
index 0000000..49198a1
--- /dev/null
+++ b/cmake/scripts/common/Macros.cmake
@@ -0,0 +1,789 @@
+# This script holds the main functions used to construct the build system
+
+# Include system specific macros but only if this file is included from
+# kodi main project. It's not needed for kodi-addons project
+# If CORE_SOURCE_DIR is set, it was called from kodi-addons project
+# TODO: drop check if we ever integrate kodi-addons into kodi project
+if(NOT CORE_SOURCE_DIR)
+ include(${CMAKE_SOURCE_DIR}/cmake/scripts/${CORE_SYSTEM_NAME}/Macros.cmake)
+endif()
+
+# IDEs: Group source files in target in folders (file system hierarchy)
+# Source: http://blog.audio-tk.com/2015/09/01/sorting-source-files-and-projects-in-folders-with-cmake-and-visual-studioxcode/
+# Arguments:
+# target The target that shall be grouped by folders.
+# Optional Arguments:
+# RELATIVE allows to specify a different reference folder.
+function(source_group_by_folder target)
+ if(NOT TARGET ${target})
+ message(FATAL_ERROR "There is no target named '${target}'")
+ endif()
+
+ set(SOURCE_GROUP_DELIMITER "/")
+
+ cmake_parse_arguments(arg "" "RELATIVE" "" ${ARGN})
+ if(arg_RELATIVE)
+ set(relative_dir ${arg_RELATIVE})
+ else()
+ set(relative_dir ${CMAKE_CURRENT_SOURCE_DIR})
+ endif()
+
+ get_property(files TARGET ${target} PROPERTY SOURCES)
+ if(files)
+ list(SORT files)
+
+ if(CMAKE_GENERATOR STREQUAL Xcode)
+ set_target_properties(${target} PROPERTIES SOURCES "${files}")
+ endif()
+ endif()
+ foreach(file ${files})
+ if(NOT IS_ABSOLUTE ${file})
+ set(file ${CMAKE_CURRENT_SOURCE_DIR}/${file})
+ endif()
+ file(RELATIVE_PATH relative_file ${relative_dir} ${file})
+ get_filename_component(dir "${relative_file}" DIRECTORY)
+ if(NOT dir STREQUAL "${last_dir}")
+ if(files)
+ source_group("${last_dir}" FILES ${files})
+ endif()
+ set(files "")
+ endif()
+ set(files ${files} ${file})
+ set(last_dir "${dir}")
+ endforeach(file)
+ if(files)
+ source_group("${last_dir}" FILES ${files})
+ endif()
+endfunction()
+
+# Add sources to main application
+# Arguments:
+# name name of the library to add
+# Implicit arguments:
+# ENABLE_STATIC_LIBS Build static libraries per directory
+# SOURCES the sources of the library
+# HEADERS the headers of the library (only for IDE support)
+# OTHERS other library related files (only for IDE support)
+# On return:
+# Library will be built, optionally added to ${core_DEPENDS}
+# Sets CORE_LIBRARY for calls for setting target specific options
+function(core_add_library name)
+ if(ENABLE_STATIC_LIBS)
+ add_library(${name} STATIC ${SOURCES} ${HEADERS} ${OTHERS})
+ set_target_properties(${name} PROPERTIES PREFIX "")
+ set(core_DEPENDS ${name} ${core_DEPENDS} CACHE STRING "" FORCE)
+ add_dependencies(${name} ${GLOBAL_TARGET_DEPS})
+ set(CORE_LIBRARY ${name} PARENT_SCOPE)
+
+ if(NOT MSVC)
+ target_compile_options(${name} PUBLIC ${CORE_COMPILE_OPTIONS})
+ endif()
+
+ # Add precompiled headers to Kodi main libraries
+ if(CORE_SYSTEM_NAME MATCHES windows)
+ add_precompiled_header(${name} pch.h ${CMAKE_SOURCE_DIR}/xbmc/platform/win32/pch.cpp PCH_TARGET kodi)
+ set_language_cxx(${name})
+ target_link_libraries(${name} PUBLIC effects11)
+ endif()
+ else()
+ foreach(src IN LISTS SOURCES HEADERS OTHERS)
+ get_filename_component(src_path "${src}" ABSOLUTE)
+ list(APPEND FILES ${src_path})
+ endforeach()
+ target_sources(lib${APP_NAME_LC} PRIVATE ${FILES})
+ set(CORE_LIBRARY lib${APP_NAME_LC} PARENT_SCOPE)
+ endif()
+endfunction()
+
+# Add a test library, and add sources to list for gtest integration macros
+function(core_add_test_library name)
+ if(ENABLE_STATIC_LIBS)
+ add_library(${name} STATIC ${SOURCES} ${SUPPORTED_SOURCES} ${HEADERS} ${OTHERS})
+ set_target_properties(${name} PROPERTIES PREFIX ""
+ EXCLUDE_FROM_ALL 1
+ FOLDER "Build Utilities/tests")
+ add_dependencies(${name} ${GLOBAL_TARGET_DEPS})
+ set(test_archives ${test_archives} ${name} CACHE STRING "" FORCE)
+
+ if(NOT MSVC)
+ target_compile_options(${name} PUBLIC ${CORE_COMPILE_OPTIONS})
+ endif()
+
+ endif()
+ foreach(src IN LISTS SOURCES SUPPORTED_SOURCES HEADERS OTHERS)
+ get_filename_component(src_path "${src}" ABSOLUTE)
+ set(test_sources "${src_path}" ${test_sources} CACHE STRING "" FORCE)
+ endforeach()
+endfunction()
+
+# Add addon dev kit headers to main application
+# Arguments:
+# name name of the header part to add
+function(core_add_devkit_header name)
+ if(NOT ENABLE_STATIC_LIBS)
+ core_add_library(addons_kodi-dev-kit_include_${name})
+ endif()
+endfunction()
+
+# Add an dl-loaded shared library
+# Arguments:
+# name name of the library to add
+# Optional arguments:
+# WRAPPED wrap this library on POSIX platforms to add VFS support for
+# libraries that would otherwise not support it.
+# OUTPUT_DIRECTORY where to create the library in the build dir
+# (default: system)
+# Implicit arguments:
+# SOURCES the sources of the library
+# HEADERS the headers of the library (only for IDE support)
+# OTHERS other library related files (only for IDE support)
+# On return:
+# Library target is defined and added to LIBRARY_FILES
+function(core_add_shared_library name)
+ cmake_parse_arguments(arg "WRAPPED" "OUTPUT_DIRECTORY" "" ${ARGN})
+ if(arg_OUTPUT_DIRECTORY)
+ set(OUTPUT_DIRECTORY ${arg_OUTPUT_DIRECTORY})
+ else()
+ if(NOT CORE_SYSTEM_NAME STREQUAL windows)
+ set(OUTPUT_DIRECTORY system)
+ endif()
+ endif()
+ if(CORE_SYSTEM_NAME STREQUAL windows)
+ set(OUTPUT_NAME lib${name})
+ else()
+ set(OUTPUT_NAME lib${name}-${ARCH})
+ endif()
+
+ if(NOT arg_WRAPPED OR CORE_SYSTEM_NAME STREQUAL windows)
+ add_library(${name} SHARED ${SOURCES} ${HEADERS} ${OTHERS})
+ set_target_properties(${name} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${OUTPUT_DIRECTORY}
+ RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${OUTPUT_DIRECTORY}
+ OUTPUT_NAME ${OUTPUT_NAME} PREFIX "")
+ foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES})
+ string(TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG)
+ set_target_properties(${name} PROPERTIES LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_BINARY_DIR}/${OUTPUT_DIRECTORY}
+ RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_BINARY_DIR}/${OUTPUT_DIRECTORY})
+ endforeach()
+
+ set(LIBRARY_FILES ${LIBRARY_FILES} ${CMAKE_BINARY_DIR}/${OUTPUT_DIRECTORY}/${OUTPUT_NAME}${CMAKE_SHARED_LIBRARY_SUFFIX} CACHE STRING "" FORCE)
+ add_dependencies(${APP_NAME_LC}-libraries ${name})
+ else()
+ add_library(${name} STATIC ${SOURCES} ${HEADERS} ${OTHERS})
+ set_target_properties(${name} PROPERTIES POSITION_INDEPENDENT_CODE 1)
+ core_link_library(${name} ${OUTPUT_DIRECTORY}/lib${name})
+
+ if(NOT MSVC)
+ target_compile_options(${name} PUBLIC ${CORE_COMPILE_OPTIONS})
+ endif()
+ endif()
+endfunction()
+
+# Sets the compile language for all C source files in a target to CXX.
+# Needs to be called from the CMakeLists.txt that defines the target.
+# Arguments:
+# target target
+function(set_language_cxx target)
+ get_property(sources TARGET ${target} PROPERTY SOURCES)
+ foreach(file IN LISTS sources)
+ if(file MATCHES "\.c$")
+ set_source_files_properties(${file} PROPERTIES LANGUAGE CXX)
+ endif()
+ endforeach()
+endfunction()
+
+# Add a data file to installation list with a mirror in build tree
+# Mirroring files in the buildtree allows to execute the app from there.
+# Arguments:
+# file full path to file to mirror
+# Optional Arguments:
+# NO_INSTALL: exclude file from installation target (only mirror)
+# DIRECTORY: directory where the file should be mirrored to
+# (default: preserve tree structure relative to CMAKE_SOURCE_DIR)
+# KEEP_DIR_STRUCTURE: preserve tree structure even when DIRECTORY is set
+# On return:
+# Files is mirrored to the build tree and added to ${install_data}
+# (if NO_INSTALL is not given).
+function(copy_file_to_buildtree file)
+ cmake_parse_arguments(arg "NO_INSTALL" "DIRECTORY;KEEP_DIR_STRUCTURE" "" ${ARGN})
+ if(arg_DIRECTORY)
+ set(outdir ${arg_DIRECTORY})
+ if(arg_KEEP_DIR_STRUCTURE)
+ get_filename_component(srcdir ${arg_KEEP_DIR_STRUCTURE} DIRECTORY)
+ string(REPLACE "${CMAKE_SOURCE_DIR}/${srcdir}/" "" outfile ${file})
+ if(NOT IS_DIRECTORY ${file})
+ set(outdir ${outdir}/${outfile})
+ endif()
+ else()
+ get_filename_component(outfile ${file} NAME)
+ set(outfile ${outdir}/${outfile})
+ endif()
+ else()
+ string(REPLACE "${CMAKE_SOURCE_DIR}/" "" outfile ${file})
+ get_filename_component(outdir ${outfile} DIRECTORY)
+ endif()
+
+ if(NOT TARGET export-files)
+ file(REMOVE ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/ExportFiles.cmake)
+ add_custom_target(export-files ALL COMMENT "Copying files into build tree"
+ COMMAND ${CMAKE_COMMAND} -P ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/ExportFiles.cmake)
+ set_target_properties(export-files PROPERTIES FOLDER "Build Utilities")
+ file(APPEND ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/ExportFiles.cmake "# Export files to build tree\n")
+ endif()
+
+ # Exclude autotools build artefacts and other blacklisted files in source tree.
+ if(file MATCHES "(Makefile|\\.in|\\.xbt|\\.so|\\.dylib|\\.gitignore)$")
+ if(VERBOSE)
+ message(STATUS "copy_file_to_buildtree - ignoring file: ${file}")
+ endif()
+ return()
+ endif()
+
+ if(NOT file STREQUAL ${CMAKE_BINARY_DIR}/${outfile})
+ if(NOT CMAKE_SYSTEM_NAME STREQUAL "Windows" OR NOT IS_SYMLINK "${file}")
+ if(VERBOSE)
+ message(STATUS "copy_file_to_buildtree - copying file: ${file} -> ${CMAKE_BINARY_DIR}/${outfile}")
+ endif()
+ file(APPEND ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/ExportFiles.cmake
+ "file(COPY \"${file}\" DESTINATION \"${CMAKE_BINARY_DIR}/${outdir}\")\n" )
+ else()
+ if(VERBOSE)
+ message(STATUS "copy_file_to_buildtree - copying symlinked file: ${file} -> ${CMAKE_BINARY_DIR}/${outfile}")
+ endif()
+ file(APPEND ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/ExportFiles.cmake
+ "execute_process(COMMAND \"\${CMAKE_COMMAND}\" -E copy_if_different \"${file}\" \"${CMAKE_BINARY_DIR}/${outfile}\")\n")
+ endif()
+ endif()
+
+ if(NOT arg_NO_INSTALL)
+ list(APPEND install_data ${outfile})
+ set(install_data ${install_data} PARENT_SCOPE)
+ endif()
+endfunction()
+
+# Add data files to installation list with a mirror in build tree.
+# reads list of files to install from a given list of text files.
+# Arguments:
+# pattern globbing pattern for text files to read
+# Optional Arguments:
+# NO_INSTALL: exclude files from installation target
+# Implicit arguments:
+# CMAKE_SOURCE_DIR - root of source tree
+# On return:
+# Files are mirrored to the build tree and added to ${install_data}
+# (if NO_INSTALL is not given).
+function(copy_files_from_filelist_to_buildtree pattern)
+ # copies files listed in text files to the buildtree
+ # Input: [glob pattern: filepattern]
+ cmake_parse_arguments(arg "NO_INSTALL" "" "" ${ARGN})
+ list(APPEND pattern ${ARGN})
+ list(SORT pattern)
+ if(VERBOSE)
+ message(STATUS "copy_files_from_filelist_to_buildtree - got pattern: ${pattern}")
+ endif()
+ foreach(pat ${pattern})
+ file(GLOB filenames ${pat})
+ foreach(filename ${filenames})
+ string(STRIP ${filename} filename)
+ core_file_read_filtered(fstrings ${filename})
+ foreach(dir ${fstrings})
+ string(CONFIGURE ${dir} dir)
+ string(REPLACE " " ";" dir ${dir})
+ list(GET dir 0 src)
+ list(LENGTH dir len)
+ if(len EQUAL 1)
+ set(dest)
+ elseif(len EQUAL 3)
+ list(GET dir 1 opt)
+ if(opt STREQUAL "KEEP_DIR_STRUCTURE")
+ set(DIR_OPTION ${opt} ${src})
+ if(VERBOSE)
+ message(STATUS "copy_files_from_filelist_to_buildtree - DIR_OPTION: ${DIR_OPTION}")
+ endif()
+ endif()
+ list(GET dir -1 dest)
+ else()
+ list(GET dir -1 dest)
+ endif()
+
+ # If the full path to an existing file is specified then add that single file.
+ # Don't recursively add all files with the given name.
+ if(EXISTS ${CMAKE_SOURCE_DIR}/${src} AND (NOT IS_DIRECTORY ${CMAKE_SOURCE_DIR}/${src} OR DIR_OPTION))
+ set(files ${src})
+ else()
+ file(GLOB_RECURSE files RELATIVE ${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/${src})
+ endif()
+
+ foreach(file ${files})
+ if(arg_NO_INSTALL)
+ copy_file_to_buildtree(${CMAKE_SOURCE_DIR}/${file} DIRECTORY ${dest} NO_INSTALL ${DIR_OPTION})
+ else()
+ copy_file_to_buildtree(${CMAKE_SOURCE_DIR}/${file} DIRECTORY ${dest} ${DIR_OPTION})
+ endif()
+ endforeach()
+ set(DIR_OPTION)
+ endforeach()
+ endforeach()
+ endforeach()
+ set(install_data ${install_data} PARENT_SCOPE)
+endfunction()
+
+# helper macro to set modified variables in parent scope
+macro(export_dep)
+ set(SYSTEM_INCLUDES ${SYSTEM_INCLUDES} PARENT_SCOPE)
+ set(DEPLIBS ${DEPLIBS} PARENT_SCOPE)
+ set(DEP_DEFINES ${DEP_DEFINES} PARENT_SCOPE)
+ set(${depup}_FOUND ${${depup}_FOUND} PARENT_SCOPE)
+ mark_as_advanced(${depup}_LIBRARIES)
+endmacro()
+
+# split dependency specification to name and version
+# Arguments:
+# depspec dependency specification that can optionally include a required
+# package version
+# syntax: [package name], [package name]>=[version] (minimum version),
+# or [package name]=[version] (exact version)
+# name_outvar variable that should receive the package name
+# version_outvar variable that should receive the package version part (>=[version])
+# On return:
+# ${name_outvar} and ${version_outvar} in caller scope are set to respective values.
+# ${version_outvar} may be unset if there is no specific version requested.
+function(split_dependency_specification depspec name_outvar version_outvar)
+ if(${depspec} MATCHES "^([^>]*)(>?=[0-9.]+)$")
+ set(${name_outvar} ${CMAKE_MATCH_1} PARENT_SCOPE)
+ set(${version_outvar} ${CMAKE_MATCH_2} PARENT_SCOPE)
+ else()
+ set(${name_outvar} ${depspec} PARENT_SCOPE)
+ unset(${version_outvar} PARENT_SCOPE)
+ endif()
+endfunction()
+
+# helper macro to split version info from req and call find_package
+macro(find_package_with_ver package)
+ set(_find_arguments "${ARGN}")
+ if("${ARGV1}" MATCHES "^(>)?=([0-9.]+)$")
+ # We have a version spec, parse it
+ list(REMOVE_AT _find_arguments 0)
+ # ">" not present? -> exact match
+ if(NOT CMAKE_MATCH_1)
+ list(INSERT _find_arguments 0 "EXACT")
+ endif()
+ find_package(${package} ${CMAKE_MATCH_2} ${_find_arguments})
+ else()
+ find_package(${package} ${_find_arguments})
+ endif()
+ unset(_find_arguments)
+endmacro()
+
+# add required dependencies of main application
+# Arguments:
+# dep_list One or many dependency specifications (see split_dependency_specification)
+# for syntax). The dependency name is used uppercased as variable prefix.
+# On return:
+# dependencies added to ${SYSTEM_INCLUDES}, ${DEPLIBS} and ${DEP_DEFINES}
+function(core_require_dep)
+ foreach(depspec ${ARGN})
+ split_dependency_specification(${depspec} dep version)
+ find_package_with_ver(${dep} ${version} REQUIRED)
+ string(TOUPPER ${dep} depup)
+ list(APPEND SYSTEM_INCLUDES ${${depup}_INCLUDE_DIRS})
+ list(APPEND DEPLIBS ${${depup}_LIBRARIES})
+ list(APPEND DEP_DEFINES ${${depup}_DEFINITIONS})
+ export_dep()
+ endforeach()
+endfunction()
+
+# helper macro for optional deps
+macro(setup_enable_switch)
+ string(TOUPPER ${dep} depup)
+ if(${ARGV1})
+ set(enable_switch ${ARGV1})
+ else()
+ set(enable_switch ENABLE_${depup})
+ endif()
+ # normal options are boolean, so we override set our ENABLE_FOO var to allow "auto" handling
+ set(${enable_switch} "AUTO" CACHE STRING "Enable ${depup} support?")
+endmacro()
+
+# add optional dependencies of main application
+# Arguments:
+# dep_list One or many dependency specifications (see split_dependency_specification)
+# for syntax). The dependency name is used uppercased as variable prefix.
+# On return:
+# dependency optionally added to ${SYSTEM_INCLUDES}, ${DEPLIBS} and ${DEP_DEFINES}
+function(core_optional_dep)
+ foreach(depspec ${ARGN})
+ set(_required False)
+ split_dependency_specification(${depspec} dep version)
+ setup_enable_switch()
+ if(${enable_switch} STREQUAL AUTO)
+ find_package_with_ver(${dep} ${version})
+ elseif(${${enable_switch}})
+ find_package_with_ver(${dep} ${version} REQUIRED)
+ set(_required True)
+ endif()
+
+ if(${depup}_FOUND)
+ list(APPEND SYSTEM_INCLUDES ${${depup}_INCLUDE_DIRS})
+ list(APPEND DEPLIBS ${${depup}_LIBRARIES})
+ list(APPEND DEP_DEFINES ${${depup}_DEFINITIONS})
+ set(final_message ${final_message} "${depup} enabled: Yes")
+ export_dep()
+ elseif(_required)
+ message(FATAL_ERROR "${depup} enabled but not found")
+ else()
+ set(final_message ${final_message} "${depup} enabled: No")
+ endif()
+ endforeach()
+ set(final_message ${final_message} PARENT_SCOPE)
+endfunction()
+
+function(core_file_read_filtered result filepattern)
+ # Reads STRINGS from text files
+ # with comments filtered out
+ # Result: [list: result]
+ # Input: [glob pattern: filepattern]
+ file(GLOB filenames ${filepattern})
+ list(SORT filenames)
+ foreach(filename ${filenames})
+ if(VERBOSE)
+ message(STATUS "core_file_read_filtered - filename: ${filename}")
+ endif()
+ set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${filename})
+ file(STRINGS ${filename} fstrings REGEX "^[^#//]")
+ foreach(fstring ${fstrings})
+ string(REGEX REPLACE "^(.*)#(.*)" "\\1" fstring ${fstring})
+ string(REGEX REPLACE "[ \n\r\t]//.*" "" fstring ${fstring})
+ string(STRIP ${fstring} fstring)
+ list(APPEND filename_strings ${fstring})
+ endforeach()
+ endforeach()
+ set(${result} ${filename_strings} PARENT_SCOPE)
+endfunction()
+
+function(core_add_subdirs_from_filelist files)
+ # Adds subdirectories from a sorted list of files
+ # Input: [list: filenames] [bool: sort]
+ foreach(arg ${ARGN})
+ list(APPEND files ${arg})
+ endforeach()
+ list(SORT files)
+ if(VERBOSE)
+ message(STATUS "core_add_subdirs_from_filelist - got pattern: ${files}")
+ endif()
+ foreach(filename ${files})
+ string(STRIP ${filename} filename)
+ core_file_read_filtered(fstrings ${filename})
+ foreach(subdir ${fstrings})
+ string(REPLACE " " ";" subdir ${subdir})
+ list(GET subdir 0 subdir_src)
+ list(GET subdir -1 subdir_dest)
+ if(VERBOSE)
+ message(STATUS " core_add_subdirs_from_filelist - adding subdir: ${CMAKE_SOURCE_DIR}/${subdir_src} -> ${CORE_BUILD_DIR}/${subdir_dest}")
+ endif()
+ add_subdirectory(${CMAKE_SOURCE_DIR}/${subdir_src} ${CORE_BUILD_DIR}/${subdir_dest})
+ endforeach()
+ endforeach()
+endfunction()
+
+macro(core_add_optional_subdirs_from_filelist pattern)
+ # Adds subdirectories from text files
+ # if the option(s) in the 3rd field are enabled
+ # Input: [glob pattern: filepattern]
+ foreach(arg ${ARGN})
+ list(APPEND pattern ${arg})
+ endforeach()
+ foreach(elem ${pattern})
+ string(STRIP ${elem} elem)
+ list(APPEND filepattern ${elem})
+ endforeach()
+
+ file(GLOB filenames ${filepattern})
+ list(SORT filenames)
+ if(VERBOSE)
+ message(STATUS "core_add_optional_subdirs_from_filelist - got pattern: ${filenames}")
+ endif()
+
+ foreach(filename ${filenames})
+ if(VERBOSE)
+ message(STATUS "core_add_optional_subdirs_from_filelist - reading file: ${filename}")
+ endif()
+ set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${filename})
+ file(STRINGS ${filename} fstrings REGEX "^[^#//]")
+ foreach(line ${fstrings})
+ string(REPLACE " " ";" line "${line}")
+ list(GET line 0 subdir_src)
+ list(GET line 1 subdir_dest)
+ list(GET line 3 opts)
+ foreach(opt ${opts})
+ if(ENABLE_${opt})
+ if(VERBOSE)
+ message(STATUS " core_add_optional_subdirs_from_filelist - adding subdir: ${CMAKE_SOURCE_DIR}/${subdir_src} -> ${CORE_BUILD_DIR}/${subdir_dest}")
+ endif()
+ add_subdirectory(${CMAKE_SOURCE_DIR}/${subdir_src} ${CORE_BUILD_DIR}/${subdir_dest})
+ else()
+ if(VERBOSE)
+ message(STATUS " core_add_optional_subdirs_from_filelist: OPTION ${opt} not enabled for ${subdir_src}, skipping subdir")
+ endif()
+ endif()
+ endforeach()
+ endforeach()
+ endforeach()
+endmacro()
+
+# Generates an RFC2822 timestamp
+#
+# The following variable is set:
+# RFC2822_TIMESTAMP
+function(rfc2822stamp)
+ execute_process(COMMAND date -R
+ OUTPUT_VARIABLE RESULT)
+ set(RFC2822_TIMESTAMP ${RESULT} PARENT_SCOPE)
+endfunction()
+
+# Generates an user stamp from git config info
+#
+# The following variable is set:
+# PACKAGE_MAINTAINER - user stamp in the form of "username <username@example.com>"
+# if no git tree is found, value is set to "nobody <nobody@example.com>"
+function(userstamp)
+ find_package(Git)
+ if(GIT_FOUND AND EXISTS ${CMAKE_SOURCE_DIR}/.git)
+ execute_process(COMMAND ${GIT_EXECUTABLE} config user.name
+ OUTPUT_VARIABLE username
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ execute_process(COMMAND ${GIT_EXECUTABLE} config user.email
+ OUTPUT_VARIABLE useremail
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ set(PACKAGE_MAINTAINER "${username} <${useremail}>" PARENT_SCOPE)
+ else()
+ set(PACKAGE_MAINTAINER "nobody <nobody@example.com>" PARENT_SCOPE)
+ endif()
+endfunction()
+
+# Parses git info and sets variables used to identify the build
+# Arguments:
+# stamp variable name to return
+# Optional Arguments:
+# FULL: generate git HEAD commit in the form of 'YYYYMMDD-hash'
+# if git tree is dirty, value is set in the form of 'YYYYMMDD-hash-dirty'
+# if no git tree is found, value is set in the form of 'YYYYMMDD-nogitfound'
+# if FULL is not given, stamp is generated following the same process as above
+# but without 'YYYYMMDD'
+# On return:
+# Variable is set with generated stamp to PARENT_SCOPE
+function(core_find_git_rev stamp)
+ # allow manual setting GIT_VERSION
+ if(GIT_VERSION)
+ set(${stamp} ${GIT_VERSION} PARENT_SCOPE)
+ string(TIMESTAMP APP_BUILD_DATE "%Y%m%d" UTC)
+ set(APP_BUILD_DATE ${APP_BUILD_DATE} PARENT_SCOPE)
+ else()
+ find_package(Git)
+ if(GIT_FOUND AND EXISTS ${CMAKE_SOURCE_DIR}/.git)
+ # get tree status i.e. clean working tree vs dirty (uncommitted or unstashed changes, etc.)
+ execute_process(COMMAND ${GIT_EXECUTABLE} update-index --ignore-submodules -q --refresh
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
+ execute_process(COMMAND ${GIT_EXECUTABLE} diff-files --ignore-submodules --quiet --
+ RESULT_VARIABLE status_code
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
+ if(NOT status_code)
+ execute_process(COMMAND ${GIT_EXECUTABLE} diff-index --ignore-submodules --quiet HEAD --
+ RESULT_VARIABLE status_code
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
+ endif()
+ # get HEAD commit SHA-1
+ execute_process(COMMAND ${GIT_EXECUTABLE} log -n 1 --pretty=format:"%h" HEAD
+ OUTPUT_VARIABLE HASH
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
+ string(REPLACE "\"" "" HASH ${HASH})
+
+ if(status_code)
+ string(CONCAT HASH ${HASH} "-dirty")
+ endif()
+
+ # get HEAD commit date
+ execute_process(COMMAND ${GIT_EXECUTABLE} log -1 --pretty=format:"%cd" --date=short HEAD
+ OUTPUT_VARIABLE DATE
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
+ string(REPLACE "\"" "" DATE ${DATE})
+ string(REPLACE "-" "" DATE ${DATE})
+
+ # build date
+ string(TIMESTAMP APP_BUILD_DATE "%Y%m%d" UTC)
+ set(APP_BUILD_DATE ${APP_BUILD_DATE} PARENT_SCOPE)
+ else()
+ if(EXISTS ${CMAKE_SOURCE_DIR}/BUILDDATE)
+ file(STRINGS ${CMAKE_SOURCE_DIR}/BUILDDATE DATE LIMIT_INPUT 8)
+ else()
+ string(TIMESTAMP DATE "%Y%m%d" UTC)
+ endif()
+ set(APP_BUILD_DATE ${DATE} PARENT_SCOPE)
+
+ if(EXISTS ${CMAKE_SOURCE_DIR}/VERSION)
+ file(STRINGS ${CMAKE_SOURCE_DIR}/VERSION HASH LIMIT_INPUT 16)
+ else()
+ set(HASH "nogitfound")
+ endif()
+ endif()
+ cmake_parse_arguments(arg "FULL" "" "" ${ARGN})
+ if(arg_FULL)
+ set(${stamp} ${DATE}-${HASH} PARENT_SCOPE)
+ else()
+ set(${stamp} ${HASH} PARENT_SCOPE)
+ endif()
+ endif()
+endfunction()
+
+# Parses version.txt and versions.h and sets variables
+# used to construct dirs structure, file naming, API version, etc.
+#
+# The following variables are set from version.txt:
+# APP_NAME - app name
+# APP_NAME_LC - lowercased app name
+# APP_NAME_UC - uppercased app name
+# APP_PACKAGE - Android full package name
+# COMPANY_NAME - company name
+# APP_WEBSITE - site url
+# APP_VERSION_MAJOR - the app version major
+# APP_VERSION_MINOR - the app version minor
+# APP_VERSION_TAG - the app version tag
+# APP_VERSION_TAG_LC - lowercased app version tag
+# APP_VERSION - the app version (${APP_VERSION_MAJOR}.${APP_VERSION_MINOR}-${APP_VERSION_TAG})
+# APP_ADDON_API - the addon API version in the form of 16.9.702
+# ADDON_REPOS - official addon repositories and their origin path delimited by pipe
+# - e.g. repository.xbmc.org|https://mirrors.kodi.tv -
+# (multiple repo/path-sets are delimited by comma)
+# FILE_VERSION - file version in the form of 16,9,702,0 - Windows only
+# JSONRPC_VERSION - the json api version in the form of 8.3.0
+#
+# Set various variables defined in "versions.h"
+macro(core_find_versions)
+ # kodi-addons project also calls this macro and uses CORE_SOURCE_DIR
+ # to point to core base dir
+ # Set CORE_SOURCE_DIR here, otherwise kodi main project fails
+ # TODO: drop this code block and refactor the rest to use CMAKE_SOURCE_DIR
+ # if we ever integrate kodi-addons into kodi project
+ if(NOT CORE_SOURCE_DIR)
+ set(CORE_SOURCE_DIR ${CMAKE_SOURCE_DIR})
+ endif()
+
+ include(CMakeParseArguments)
+ core_file_read_filtered(version_list ${CORE_SOURCE_DIR}/version.txt)
+ core_file_read_filtered(json_version ${CORE_SOURCE_DIR}/xbmc/interfaces/json-rpc/schema/version.txt)
+ string(REGEX REPLACE "([^ ;]*) ([^;]*)" "\\1;\\2" version_list "${version_list};${json_version}")
+ set(version_props
+ ADDON_API
+ ADDON_REPOS
+ APP_NAME
+ APP_PACKAGE
+ COMPANY_NAME
+ COPYRIGHT_YEARS
+ JSONRPC_VERSION
+ PACKAGE_DESCRIPTION
+ PACKAGE_IDENTITY
+ PACKAGE_PUBLISHER
+ VERSION_MAJOR
+ VERSION_MINOR
+ VERSION_TAG
+ VERSION_CODE
+ WEBSITE
+ )
+ cmake_parse_arguments(APP "" "${version_props}" "" ${version_list})
+
+ if(NOT ${APP_VERSION_CODE} MATCHES "^[0-9]+\\.[0-9][0-9]?\\.[0-9][0-9]?[0-9]?$")
+ message(FATAL_ERROR "VERSION_CODE was set to ${APP_VERSION_CODE} in version.txt, but it has to match '^\\d+\\.\\d{1,2}\\.\\d{1,3}$'")
+ endif()
+ set(APP_NAME ${APP_APP_NAME}) # inconsistency but APP_APP_NAME looks weird
+ string(TOLOWER ${APP_APP_NAME} APP_NAME_LC)
+ string(TOUPPER ${APP_APP_NAME} APP_NAME_UC)
+ set(COMPANY_NAME ${APP_COMPANY_NAME})
+ set(APP_VERSION ${APP_VERSION_MAJOR}.${APP_VERSION_MINOR})
+ # Let Flatpak builders etc override APP_PACKAGE
+ # NOTE: We cannot declare an option() in top-level CMakeLists.txt
+ # because of CMP0077.
+ if(NOT APP_PACKAGE)
+ set(APP_PACKAGE ${APP_APP_PACKAGE})
+ endif()
+ list(APPEND final_message "App package: ${APP_PACKAGE}")
+ if(APP_VERSION_TAG)
+ set(APP_VERSION ${APP_VERSION}-${APP_VERSION_TAG})
+ string(TOLOWER ${APP_VERSION_TAG} APP_VERSION_TAG_LC)
+ endif()
+ string(REPLACE "." "," FILE_VERSION ${APP_ADDON_API}.0)
+ set(ADDON_REPOS ${APP_ADDON_REPOS})
+ set(JSONRPC_VERSION ${APP_JSONRPC_VERSION})
+
+ # Set defines used in addon.xml.in and read from versions.h to set add-on
+ # version parts automatically
+ # This part is nearly identical to "AddonHelpers.cmake", except location of versions.h
+ file(STRINGS ${CORE_SOURCE_DIR}/xbmc/addons/kodi-dev-kit/include/kodi/versions.h BIN_ADDON_PARTS)
+ foreach(loop_var ${BIN_ADDON_PARTS})
+ string(FIND "${loop_var}" "#define ADDON_" matchres)
+ if("${matchres}" EQUAL 0)
+ string(REGEX MATCHALL "[A-Z0-9._]+|[A-Z0-9._]+$" loop_var "${loop_var}")
+ list(GET loop_var 0 include_name)
+ list(GET loop_var 1 include_version)
+ string(REGEX REPLACE ".*\"(.*)\"" "\\1" ${include_name} ${include_version})
+ endif()
+ endforeach(loop_var)
+
+ # unset variables not used anywhere else
+ unset(version_list)
+ unset(APP_APP_NAME)
+ unset(APP_COMPANY_NAME)
+ unset(APP_APP_PACKAGE)
+ unset(APP_JSONRPC_VERSION)
+ unset(BIN_ADDON_PARTS)
+
+ # bail if we can't parse version.txt
+ if(NOT DEFINED APP_VERSION_MAJOR OR NOT DEFINED APP_VERSION_MINOR)
+ message(FATAL_ERROR "Could not determine app version! Make sure that ${CORE_SOURCE_DIR}/version.txt exists")
+ endif()
+ if(NOT DEFINED JSONRPC_VERSION)
+ message(FATAL_ERROR "Could not determine json-rpc version! Make sure that ${CORE_SOURCE_DIR}/xbmc/interfaces/json-rpc/schema/version.txt exists")
+ endif()
+endmacro()
+
+# add-on xml's
+# find all folders containing addon.xml.in and used to define
+# ADDON_XML_OUTPUTS, ADDON_XML_DEPENDS and ADDON_INSTALL_DATA
+macro(find_addon_xml_in_files)
+ set(filter ${ARGV0})
+
+ if(filter AND VERBOSE)
+ message(STATUS "find_addon_xml_in_files: filtering ${filter}")
+ endif()
+
+ file(GLOB ADDON_XML_IN_FILE ${CMAKE_SOURCE_DIR}/addons/*/addon.xml.in)
+ foreach(loop_var ${ADDON_XML_IN_FILE})
+ list(GET loop_var 0 xml_name)
+
+ string(REPLACE "/addon.xml.in" "" xml_name ${xml_name})
+ string(REPLACE "${CORE_SOURCE_DIR}/" "" xml_name ${xml_name})
+
+ list(APPEND ADDON_XML_DEPENDS "${CORE_SOURCE_DIR}/${xml_name}/addon.xml.in")
+ if(filter AND NOT xml_name MATCHES ${filter})
+ list(APPEND ADDON_XML_OUTPUTS "${CMAKE_BINARY_DIR}/${xml_name}/addon.xml")
+ endif()
+
+ # Read content of add-on folder to have on install
+ file(GLOB ADDON_FILES "${CORE_SOURCE_DIR}/${xml_name}/*")
+ foreach(loop_var ${ADDON_FILES})
+ if(loop_var MATCHES "addon.xml.in")
+ string(REPLACE "addon.xml.in" "addon.xml" loop_var ${loop_var})
+
+ list(GET loop_var 0 file_name)
+ string(REPLACE "${CORE_SOURCE_DIR}/" "" file_name ${file_name})
+ list(APPEND ADDON_INSTALL_DATA "${file_name}")
+
+ unset(file_name)
+ endif()
+ endforeach()
+ unset(xml_name)
+ endforeach()
+
+ # Append also versions.h to depends
+ list(APPEND ADDON_XML_DEPENDS "${CORE_SOURCE_DIR}/xbmc/addons/kodi-dev-kit/include/kodi/versions.h")
+endmacro()
diff --git a/cmake/scripts/common/ModuleHelpers.cmake b/cmake/scripts/common/ModuleHelpers.cmake
new file mode 100644
index 0000000..97a3901
--- /dev/null
+++ b/cmake/scripts/common/ModuleHelpers.cmake
@@ -0,0 +1,424 @@
+# This script provides helper functions for FindModules
+
+# Parse and set variables from VERSION dependency file
+# On return:
+# MODULENAME_ARCHIVE will be set to parent scope
+# MODULENAME_VER will be set to parent scope (eg FFMPEG_VER, DAV1D_VER)
+# MODULENAME_BASE_URL will be set to parent scope if exists in VERSION file (eg FFMPEG_BASE_URL)
+# MODULENAME_HASH will be set if either SHA256 or SHA512 exists in VERSION file
+# MODULENAME_BYPRODUCT will be set to parent scope
+function(get_versionfile_data)
+
+ # Dependency path
+ set(MODULE_PATH "${PROJECTSOURCE}/tools/depends/${LIB_TYPE}/${MODULE_LC}")
+
+ if(NOT EXISTS "${MODULE_PATH}/${MODULE}-VERSION")
+ MESSAGE(FATAL_ERROR "${MODULE}-VERSION does not exist at ${MODULE_PATH}.")
+ else()
+ set(${MODULE}_FILE "${MODULE_PATH}/${MODULE}-VERSION")
+ endif()
+
+ file(STRINGS ${${MODULE}_FILE} ${MODULE}_LNAME REGEX "^[ \t]*LIBNAME=")
+ file(STRINGS ${${MODULE}_FILE} ${MODULE}_VER REGEX "^[ \t]*VERSION=")
+ file(STRINGS ${${MODULE}_FILE} ${MODULE}_ARCHIVE REGEX "^[ \t]*ARCHIVE=")
+ file(STRINGS ${${MODULE}_FILE} ${MODULE}_BASE_URL REGEX "^[ \t]*BASE_URL=")
+ if(WIN32 OR WINDOWS_STORE)
+ file(STRINGS ${${MODULE}_FILE} ${MODULE}_BYPRODUCT REGEX "^[ \t]*BYPRODUCT_WIN=")
+ else()
+ file(STRINGS ${${MODULE}_FILE} ${MODULE}_BYPRODUCT REGEX "^[ \t]*BYPRODUCT=")
+ endif()
+
+ # Tarball Hash
+ file(STRINGS ${${MODULE}_FILE} ${MODULE}_HASH_SHA256 REGEX "^[ \t]*SHA256=")
+ file(STRINGS ${${MODULE}_FILE} ${MODULE}_HASH_SHA512 REGEX "^[ \t]*SHA512=")
+
+ string(REGEX REPLACE ".*LIBNAME=([^ \t]*).*" "\\1" ${MODULE}_LNAME "${${MODULE}_LNAME}")
+ string(REGEX REPLACE ".*VERSION=([^ \t]*).*" "\\1" ${MODULE}_VER "${${MODULE}_VER}")
+ string(REGEX REPLACE ".*ARCHIVE=([^ \t]*).*" "\\1" ${MODULE}_ARCHIVE "${${MODULE}_ARCHIVE}")
+ string(REGEX REPLACE ".*BASE_URL=([^ \t]*).*" "\\1" ${MODULE}_BASE_URL "${${MODULE}_BASE_URL}")
+ if(WIN32 OR WINDOWS_STORE)
+ string(REGEX REPLACE ".*BYPRODUCT_WIN=([^ \t]*).*" "\\1" ${MODULE}_BYPRODUCT "${${MODULE}_BYPRODUCT}")
+ else()
+ string(REGEX REPLACE ".*BYPRODUCT=([^ \t]*).*" "\\1" ${MODULE}_BYPRODUCT "${${MODULE}_BYPRODUCT}")
+ endif()
+
+ string(REGEX REPLACE "\\$\\(LIBNAME\\)" "${${MODULE}_LNAME}" ${MODULE}_ARCHIVE "${${MODULE}_ARCHIVE}")
+ string(REGEX REPLACE "\\$\\(VERSION\\)" "${${MODULE}_VER}" ${MODULE}_ARCHIVE "${${MODULE}_ARCHIVE}")
+
+ set(${MODULE}_ARCHIVE ${${MODULE}_ARCHIVE} PARENT_SCOPE)
+
+ set(${MODULE}_VER ${${MODULE}_VER} PARENT_SCOPE)
+
+ if (${MODULE}_BASE_URL)
+ set(${MODULE}_BASE_URL ${${MODULE}_BASE_URL} PARENT_SCOPE)
+ else()
+ set(${MODULE}_BASE_URL "http://mirrors.kodi.tv/build-deps/sources" PARENT_SCOPE)
+ endif()
+ set(${MODULE}_BYPRODUCT ${${MODULE}_BYPRODUCT} PARENT_SCOPE)
+
+ # allow user to override the download URL hash with a local tarball hash
+ # needed for offline build envs
+ if (NOT DEFINED ${MODULE}_HASH)
+ if (${MODULE}_HASH_SHA256)
+ set(${MODULE}_HASH ${${MODULE}_HASH_SHA256} PARENT_SCOPE)
+ elseif(${MODULE}_HASH_SHA512)
+ set(${MODULE}_HASH ${${MODULE}_HASH_SHA512} PARENT_SCOPE)
+ endif()
+ endif()
+endfunction()
+
+# Parse and set Version from VERSION dependency file
+# Used for retrieving version numbers for dependency libs to allow setting
+# a required version for find_package call
+# On return:
+# LIB_MODULENAME_VER will be set to parent scope (eg LIB_FMT_VER)
+function(get_libversion_data module libtype)
+
+ # Dependency path
+ set(LIB_MODULE_PATH "${CMAKE_SOURCE_DIR}/tools/depends/${libtype}/${module}")
+ string(TOUPPER ${module} MOD_UPPER)
+
+ if(NOT EXISTS "${LIB_MODULE_PATH}/${MOD_UPPER}-VERSION")
+ MESSAGE(FATAL_ERROR "${MOD_UPPER}-VERSION does not exist at ${LIB_MODULE_PATH}.")
+ else()
+ set(${MOD_UPPER}_FILE "${LIB_MODULE_PATH}/${MOD_UPPER}-VERSION")
+ endif()
+
+ file(STRINGS ${${MOD_UPPER}_FILE} ${MOD_UPPER}_VER REGEX "^[ \t]*VERSION=")
+
+ string(REGEX REPLACE ".*VERSION=([^ \t]*).*" "\\1" ${MOD_UPPER}_VER "${${MOD_UPPER}_VER}")
+
+ set(LIB_${MOD_UPPER}_VER ${${MOD_UPPER}_VER} PARENT_SCOPE)
+endfunction()
+
+# Function to loop through list of patch files (full path)
+# Sets to a PATCH_COMMAND variable and set to parent scope (caller)
+# Used to test windows line endings and set appropriate patch commands
+function(generate_patchcommand _patchlist)
+ # find the path to the patch executable
+ find_package(Patch MODULE REQUIRED)
+
+ # Loop through patches and add to PATCH_COMMAND
+ # for windows, check CRLF/LF state
+
+ set(_count 0)
+ foreach(patch ${_patchlist})
+ if(WIN32 OR WINDOWS_STORE)
+ PATCH_LF_CHECK(${patch})
+ endif()
+ if(${_count} EQUAL "0")
+ set(_patch_command ${PATCH_EXECUTABLE} -p1 -i ${patch})
+ else()
+ list(APPEND _patch_command COMMAND ${PATCH_EXECUTABLE} -p1 -i ${patch})
+ endif()
+
+ math(EXPR _count "${_count}+1")
+ endforeach()
+ set(PATCH_COMMAND ${_patch_command} PARENT_SCOPE)
+ unset(_count)
+ unset(_patch_command)
+endfunction()
+
+# Macro to factor out the repetitive URL setup
+macro(SETUP_BUILD_VARS)
+ string(TOUPPER ${MODULE_LC} MODULE)
+
+ # Fall through to target build module dir if not explicitly set
+ if(NOT DEFINED LIB_TYPE)
+ set(LIB_TYPE "target")
+ endif()
+
+ # Location for build type, native or target
+ if(LIB_TYPE STREQUAL "target")
+ set(DEP_LOCATION "${DEPENDS_PATH}")
+ else()
+ set(DEP_LOCATION "${NATIVEPREFIX}")
+ endif()
+
+ # PROJECTSOURCE used in native toolchain to provide core project sourcedir
+ # to externalproject_add targets that have a different CMAKE_SOURCE_DIR (eg jsonschema/texturepacker in-tree)
+ if(NOT PROJECTSOURCE)
+ set(PROJECTSOURCE ${CMAKE_SOURCE_DIR})
+ endif()
+
+ # populate variables of data from VERSION file for MODULE
+ get_versionfile_data()
+
+ # allow user to override the download URL with a local tarball
+ # needed for offline build envs
+ if(${MODULE}_URL)
+ get_filename_component(${MODULE}_URL "${${MODULE}_URL}" ABSOLUTE)
+ else()
+ set(${MODULE}_URL ${${MODULE}_BASE_URL}/${${MODULE}_ARCHIVE})
+ endif()
+ if(VERBOSE)
+ message(STATUS "MODULE: ${MODULE}")
+ message(STATUS "LIB_TYPE: ${LIB_TYPE}")
+ message(STATUS "DEP_LOCATION: ${DEP_LOCATION}")
+ message(STATUS "PROJECTSOURCE: ${PROJECTSOURCE}")
+ message(STATUS "${MODULE}_URL: ${${MODULE}_URL}")
+ endif()
+endmacro()
+
+macro(CLEAR_BUILD_VARS)
+ # unset all generic variables to insure clean state between macro calls
+ # Potentially an issue with scope when a macro is used inside a dep that uses a macro
+ unset(PROJECTSOURCE)
+ unset(LIB_TYPE)
+ unset(BUILD_NAME)
+ unset(INSTALL_DIR)
+ unset(CMAKE_ARGS)
+ unset(PATCH_COMMAND)
+ unset(CONFIGURE_COMMAND)
+ unset(BUILD_COMMAND)
+ unset(INSTALL_COMMAND)
+ unset(BUILD_IN_SOURCE)
+ unset(BUILD_BYPRODUCTS)
+ unset(WIN_DISABLE_PROJECT_FLAGS)
+
+ # unset all module specific variables to insure clean state between macro calls
+ # potentially an issue when a native and a target of the same module exists
+ unset(${MODULE}_LIST_SEPARATOR)
+ unset(${MODULE}_GENERATOR)
+ unset(${MODULE}_GENERATOR_PLATFORM)
+ unset(${MODULE}_INSTALL_PREFIX)
+ unset(${MODULE}_TOOLCHAIN_FILE)
+endmacro()
+
+# Macro to create externalproject_add target
+#
+# Common usage
+#
+# CMAKE_ARGS: cmake(required)
+# PATCH_COMMAND: ALL(optional)
+# CONFIGURE_COMMAND: autoconf(required), meson(required)
+# BUILD_COMMAND: autoconf(required), meson(required), cmake(optional)
+# INSTALL_COMMAND: autoconf(required), meson(required), cmake(optional)
+# BUILD_IN_SOURCE: ALL(optional)
+# BUILD_BYPRODUCTS: ALL(optional)
+#
+# Windows Specific
+# WIN_DISABLE_PROJECT_FLAGS - Set to not use core compiler flags for externalproject_add target
+# This removes CMAKE_C_FLAGS CMAKE_CXX_FLAGS CMAKE_EXE_LINKER_FLAGS
+# from the externalproject_add target. Primarily used for HOST build
+# tools that may have different arch/build requirements to the core app
+# target (eg flatc)
+#
+macro(BUILD_DEP_TARGET)
+ include(ExternalProject)
+
+ # Remove cmake warning when Xcode generator used with "New" build system
+ if(CMAKE_GENERATOR STREQUAL Xcode)
+ # Policy CMP0114 is not set to NEW. In order to support the Xcode "new build
+ # system", this project must be updated to set policy CMP0114 to NEW.
+ if(CMAKE_XCODE_BUILD_SYSTEM STREQUAL 12)
+ cmake_policy(SET CMP0114 NEW)
+ else()
+ cmake_policy(SET CMP0114 OLD)
+ endif()
+ endif()
+
+ if(CMAKE_ARGS)
+ set(CMAKE_ARGS CMAKE_ARGS ${CMAKE_ARGS}
+ -DCMAKE_INSTALL_LIBDIR=lib
+ -DPROJECTSOURCE=${PROJECTSOURCE}
+ "-DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}")
+
+ # We dont have a toolchain for windows, so manually add all the cmake
+ # build arguments we may want
+ # We can disable adding them with WIN_DISABLE_PROJECT_FLAGS. This is potentially required
+ # for host build tools (eg flatc) that may be a different arch to the core app
+ if(WIN32 OR WINDOWS_STORE)
+ if(NOT DEFINED WIN_DISABLE_PROJECT_FLAGS)
+ list(APPEND CMAKE_ARGS "-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS} $<$<CONFIG:Debug>:${CMAKE_C_FLAGS_DEBUG}> $<$<CONFIG:Release>:${CMAKE_C_FLAGS_RELEASE}> ${${MODULE}_C_FLAGS}"
+ "-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS} $<$<CONFIG:Debug>:${CMAKE_CXX_FLAGS_DEBUG}> $<$<CONFIG:Release>:${CMAKE_CXX_FLAGS_RELEASE}> ${${MODULE}_CXX_FLAGS}"
+ "-DCMAKE_EXE_LINKER_FLAGS=${CMAKE_EXE_LINKER_FLAGS} $<$<CONFIG:Debug>:${CMAKE_EXE_LINKER_FLAGS_DEBUG}> $<$<CONFIG:Release>:${CMAKE_EXE_LINKER_FLAGS_RELEASE}> ${${MODULE}_EXE_LINKER_FLAGS}")
+ endif()
+ endif()
+
+ if(${MODULE}_INSTALL_PREFIX)
+ list(APPEND CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${${MODULE}_INSTALL_PREFIX})
+ else()
+ list(APPEND CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${DEP_LOCATION})
+ endif()
+
+ if(DEFINED ${MODULE}_TOOLCHAIN_FILE)
+ list(APPEND CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${${MODULE}_TOOLCHAIN_FILE})
+ elseif(CMAKE_TOOLCHAIN_FILE)
+ list(APPEND CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE})
+ endif()
+
+ # Set build type for dep build.
+ # if MODULE has set a manual build type, use it, otherwise use project build type
+ if(${MODULE}_BUILD_TYPE)
+ list(APPEND CMAKE_ARGS "-DCMAKE_BUILD_TYPE=${${MODULE}_BUILD_TYPE}")
+ # Build_type is forced, so unset the opposite <MODULE>_LIBRARY_<TYPE> to only give
+ # select_library_configurations one library name to choose from
+ if(${MODULE}_BUILD_TYPE STREQUAL "Release")
+ unset(${MODULE}_LIBRARY_DEBUG)
+ else()
+ unset(${MODULE}_LIBRARY_RELEASE)
+ endif()
+ else()
+ # single config generator (ie Make, Ninja)
+ if(CMAKE_BUILD_TYPE)
+ list(APPEND CMAKE_ARGS "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}")
+ else()
+ # Multi-config generators (eg VS, Xcode, Ninja Multi-Config) will not have CMAKE_BUILD_TYPE
+ # Use config genex to generate the types
+ # Potential issue if Build type isnt supported by lib project
+ # eg lib supports Debug/Release, however users selects RelWithDebInfo in project
+ list(APPEND CMAKE_ARGS "-DCMAKE_BUILD_TYPE=$<CONFIG>")
+ endif()
+ endif()
+
+ # Xcode - Default sub projects to makefile builds. More consistent
+ # Windows - Default to same generator version used in parent
+ if(CMAKE_GENERATOR STREQUAL Xcode)
+ if(NOT ${MODULE}_GENERATOR)
+ set(${MODULE}_GENERATOR CMAKE_GENERATOR "Unix Makefiles")
+ endif()
+ elseif(MSVC)
+ if(NOT ${MODULE}_GENERATOR)
+ set(${MODULE}_GENERATOR CMAKE_GENERATOR "${CMAKE_GENERATOR}")
+ endif()
+ if(NOT ${MODULE}_GENERATOR_PLATFORM)
+ set(${MODULE}_GENERATOR_PLATFORM CMAKE_GENERATOR_PLATFORM ${CMAKE_GENERATOR_PLATFORM})
+ endif()
+ endif()
+ endif()
+
+ if(PATCH_COMMAND)
+ set(PATCH_COMMAND PATCH_COMMAND ${PATCH_COMMAND})
+ endif()
+
+ if(CONFIGURE_COMMAND)
+ if(NOT CMAKE_ARGS AND DEP_BUILDENV)
+ # DEP_BUILDENV only used for non cmake externalproject_add builds
+ # iterate through CONFIGURE_COMMAND looking for multiple COMMAND, we need to
+ # add DEP_BUILDENV for each distinct COMMAND
+ set(tmp_config_command ${DEP_BUILDENV})
+ foreach(item ${CONFIGURE_COMMAND})
+ list(APPEND tmp_config_command ${item})
+ if(item STREQUAL "COMMAND")
+ list(APPEND tmp_config_command ${DEP_BUILDENV})
+ endif()
+ endforeach()
+ set(CONFIGURE_COMMAND CONFIGURE_COMMAND ${tmp_config_command})
+ unset(tmp_config_command)
+ else()
+ set(CONFIGURE_COMMAND CONFIGURE_COMMAND ${CONFIGURE_COMMAND})
+ endif()
+ endif()
+
+ if(BUILD_COMMAND)
+ set(BUILD_COMMAND BUILD_COMMAND ${BUILD_COMMAND})
+ endif()
+
+ if(INSTALL_COMMAND)
+ set(INSTALL_COMMAND INSTALL_COMMAND ${INSTALL_COMMAND})
+ endif()
+
+ if(BUILD_IN_SOURCE)
+ set(BUILD_IN_SOURCE BUILD_IN_SOURCE ${BUILD_IN_SOURCE})
+ endif()
+
+ # Set Library names.
+ if(DEFINED ${MODULE}_DEBUG_POSTFIX)
+ set(_POSTFIX ${${MODULE}_DEBUG_POSTFIX})
+ string(REGEX REPLACE "\\.[^.]*$" "" _LIBNAME ${${MODULE}_BYPRODUCT})
+ string(REGEX REPLACE "^.*\\." "" _LIBEXT ${${MODULE}_BYPRODUCT})
+ set(${MODULE}_LIBRARY_DEBUG ${DEP_LOCATION}/lib/${_LIBNAME}${${MODULE}_DEBUG_POSTFIX}.${_LIBEXT})
+ endif()
+ # set <MODULE>_LIBRARY_RELEASE for use of select_library_configurations
+ # any modules that dont use select_library_configurations, we set <MODULE>_LIBRARY
+ # No harm in having either set for both potential paths
+ set(${MODULE}_LIBRARY_RELEASE ${DEP_LOCATION}/lib/${${MODULE}_BYPRODUCT})
+ set(${MODULE}_LIBRARY ${${MODULE}_LIBRARY_RELEASE})
+
+ if(NOT ${MODULE}_INCLUDE_DIR)
+ set(${MODULE}_INCLUDE_DIR ${DEP_LOCATION}/include)
+ endif()
+
+ if(BUILD_BYPRODUCTS)
+ set(BUILD_BYPRODUCTS BUILD_BYPRODUCTS ${BUILD_BYPRODUCTS})
+ else()
+ if(DEFINED ${MODULE}_LIBRARY_DEBUG)
+ if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.20")
+ set(BUILD_BYPRODUCTS BUILD_BYPRODUCTS "$<IF:$<CONFIG:Debug,RelWithDebInfo>,${${MODULE}_LIBRARY_DEBUG},${${MODULE}_LIBRARY_RELEASE}>")
+ else()
+ if(DEFINED CMAKE_BUILD_TYPE)
+ if(NOT CMAKE_BUILD_TYPE STREQUAL "Release" AND DEFINED ${MODULE}_LIBRARY_DEBUG)
+ set(BUILD_BYPRODUCTS BUILD_BYPRODUCTS "${${MODULE}_LIBRARY_DEBUG}")
+ else()
+ set(BUILD_BYPRODUCTS BUILD_BYPRODUCTS "${${MODULE}_LIBRARY}")
+ endif()
+ else()
+ message(FATAL_ERROR "MultiConfig Generator usage requires CMake >= 3.20.0 - Generator Expressions in BYPRODUCT option")
+ endif()
+ endif()
+ else()
+ set(BUILD_BYPRODUCTS BUILD_BYPRODUCTS "${${MODULE}_LIBRARY}")
+ endif()
+ endif()
+
+ if(NOT BUILD_NAME)
+ set(BUILD_NAME ${MODULE_LC})
+ endif()
+
+ if(NOT INSTALL_DIR)
+ set(INSTALL_DIR ${DEP_LOCATION})
+ endif()
+
+ # Allow a target to supply in-tree source location. eg TexturePacker, JsonSchemaBuilder
+ if(${MODULE}_SOURCE_DIR)
+ set(BUILD_DOWNLOAD_STEPS SOURCE_DIR "${${MODULE}_SOURCE_DIR}")
+ else()
+ set(BUILD_DOWNLOAD_STEPS URL ${${MODULE}_URL}
+ URL_HASH ${${MODULE}_HASH}
+ DOWNLOAD_DIR ${TARBALL_DIR}
+ DOWNLOAD_NAME ${${MODULE}_ARCHIVE})
+ endif()
+
+ externalproject_add(${BUILD_NAME}
+ ${BUILD_DOWNLOAD_STEPS}
+ PREFIX ${CORE_BUILD_DIR}/${BUILD_NAME}
+ INSTALL_DIR ${INSTALL_DIR}
+ ${${MODULE}_LIST_SEPARATOR}
+ ${CMAKE_ARGS}
+ ${${MODULE}_GENERATOR}
+ ${${MODULE}_GENERATOR_PLATFORM}
+ ${PATCH_COMMAND}
+ ${CONFIGURE_COMMAND}
+ ${BUILD_COMMAND}
+ ${INSTALL_COMMAND}
+ ${BUILD_BYPRODUCTS}
+ ${BUILD_IN_SOURCE})
+
+ set_target_properties(${BUILD_NAME} PROPERTIES FOLDER "External Projects")
+
+ CLEAR_BUILD_VARS()
+endmacro()
+
+# Macro to test format of line endings of a patch
+# Windows Specific
+macro(PATCH_LF_CHECK patch)
+ if(CMAKE_HOST_WIN32)
+ # On Windows "patch.exe" can only handle CR-LF line-endings.
+ # Our patches have LF-only line endings - except when they
+ # have been checked out as part of a dependency hosted on Git
+ # and core.autocrlf=true.
+ file(READ ${ARGV0} patch_content_hex HEX)
+ # Force handle LF-only line endings
+ if(NOT patch_content_hex MATCHES "0d0a")
+ if (NOT "--binary" IN_LIST PATCH_EXECUTABLE)
+ list(APPEND PATCH_EXECUTABLE --binary)
+ endif()
+ else()
+ if ("--binary" IN_LIST PATCH_EXECUTABLE)
+ list(REMOVE_ITEM PATCH_EXECUTABLE --binary)
+ endif()
+ endif()
+ endif()
+ unset(patch_content_hex)
+endmacro()
diff --git a/cmake/scripts/common/PathSetup.cmake b/cmake/scripts/common/PathSetup.cmake
new file mode 100644
index 0000000..4fc888e
--- /dev/null
+++ b/cmake/scripts/common/PathSetup.cmake
@@ -0,0 +1,13 @@
+# Platform path setup
+include(cmake/scripts/${CORE_SYSTEM_NAME}/PathSetup.cmake)
+
+# Fallback install location for dependencies built
+if(NOT DEPENDS_PATH)
+ set(DEPENDS_PATH "${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}")
+endif()
+
+# If a platform sets a Depends_path for libs, prepend to cmake prefix path
+# for when searching for libs (eg find_package)
+if(DEPENDS_PATH)
+ list(PREPEND CMAKE_PREFIX_PATH ${DEPENDS_PATH})
+endif()
diff --git a/cmake/scripts/common/Platform.cmake b/cmake/scripts/common/Platform.cmake
new file mode 100644
index 0000000..397d8d4
--- /dev/null
+++ b/cmake/scripts/common/Platform.cmake
@@ -0,0 +1,57 @@
+if(NOT CORE_SYSTEM_NAME)
+ string(TOLOWER ${CMAKE_SYSTEM_NAME} CORE_SYSTEM_NAME)
+endif()
+
+if(CORE_SYSTEM_NAME STREQUAL linux OR CORE_SYSTEM_NAME STREQUAL freebsd)
+ # Set default CORE_PLATFORM_NAME to X11 WAYLAND GBM
+ # This is overridden by user setting -DCORE_PLATFORM_NAME=<platform>
+ set(_DEFAULT_PLATFORM X11 WAYLAND GBM)
+
+ if(NOT APP_RENDER_SYSTEM)
+ message(SEND_ERROR "You need to decide whether you want to use GL- or GLES-based rendering. Please set APP_RENDER_SYSTEM to either \"gl\" or \"gles\". For normal desktop systems, you will usually want to use \"gl\".")
+ endif()
+else()
+ string(TOLOWER ${CORE_SYSTEM_NAME} _DEFAULT_PLATFORM)
+endif()
+
+set(APP_BINARY_SUFFIX ".bin")
+
+#
+# Note: please do not use CORE_PLATFORM_NAME in any checks,
+# use the normalized to lower case CORE_PLATFORM_NAME_LC (see below) instead
+#
+if(NOT CORE_PLATFORM_NAME)
+ set(CORE_PLATFORM_NAME ${_DEFAULT_PLATFORM})
+endif()
+set(CORE_PLATFORM_NAME ${CORE_PLATFORM_NAME} CACHE STRING "Platform port to build" FORCE)
+unset(_DEFAULT_PLATFORM)
+
+string(REPLACE " " ";" CORE_PLATFORM_NAME "${CORE_PLATFORM_NAME}")
+foreach(platform IN LISTS CORE_PLATFORM_NAME)
+ string(TOLOWER ${platform} platform)
+ list(APPEND CORE_PLATFORM_NAME_LC ${platform})
+endforeach()
+
+string(REPLACE ";" " " CORE_PLATFORM_STRING "${CORE_PLATFORM_NAME_LC}")
+list(APPEND final_message "Platforms: ${CORE_PLATFORM_STRING}")
+
+if(CORE_SYSTEM_NAME STREQUAL linux OR CORE_SYSTEM_NAME STREQUAL freebsd)
+ list(LENGTH CORE_PLATFORM_NAME_LC PLATFORM_COUNT)
+ if(PLATFORM_COUNT EQUAL 1)
+ option(ENABLE_APP_AUTONAME "Enable renaming the binary according to windowing?" ON)
+ if(ENABLE_APP_AUTONAME)
+ set(APP_BINARY_SUFFIX "-${CORE_PLATFORM_NAME_LC}")
+ endif()
+ endif()
+endif()
+
+foreach(CORE_PLATFORM_LC IN LISTS CORE_PLATFORM_NAME_LC)
+ if(EXISTS ${CMAKE_SOURCE_DIR}/cmake/platform/${CORE_SYSTEM_NAME}/${CORE_PLATFORM_LC}.cmake)
+ include(${CMAKE_SOURCE_DIR}/cmake/platform/${CORE_SYSTEM_NAME}/${CORE_PLATFORM_LC}.cmake)
+ else()
+ file(GLOB _platformnames RELATIVE ${CMAKE_SOURCE_DIR}/cmake/platform/${CORE_SYSTEM_NAME}/
+ ${CMAKE_SOURCE_DIR}/cmake/platform/${CORE_SYSTEM_NAME}/*.cmake)
+ string(REPLACE ".cmake" " " _platformnames ${_platformnames})
+ message(FATAL_ERROR "invalid CORE_PLATFORM_NAME: ${CORE_PLATFORM_NAME_LC}\nValid platforms: ${_platformnames}")
+ endif()
+endforeach()
diff --git a/cmake/scripts/common/PrepareEnv.cmake b/cmake/scripts/common/PrepareEnv.cmake
new file mode 100644
index 0000000..559788f
--- /dev/null
+++ b/cmake/scripts/common/PrepareEnv.cmake
@@ -0,0 +1,107 @@
+# parse version.txt and versions.h to get the version and API info
+include(${CORE_SOURCE_DIR}/cmake/scripts/common/Macros.cmake)
+core_find_versions()
+
+# in case we need to download something, set KODI_MIRROR to the default if not already set
+if(NOT DEFINED KODI_MIRROR)
+ set(KODI_MIRROR "http://mirrors.kodi.tv")
+endif()
+
+### copy all the addon binding header files to include/kodi
+# make sure include/kodi exists and is empty
+set(APP_LIB_DIR ${ADDON_DEPENDS_PATH}/lib/${APP_NAME_LC})
+if(NOT EXISTS "${APP_LIB_DIR}/")
+ file(MAKE_DIRECTORY ${APP_LIB_DIR})
+endif()
+
+set(APP_DATA_DIR ${ADDON_DEPENDS_PATH}/share/${APP_NAME_LC})
+if(NOT EXISTS "${APP_DATA_DIR}/")
+ file(MAKE_DIRECTORY ${APP_DATA_DIR})
+endif()
+
+set(APP_INCLUDE_DIR ${ADDON_DEPENDS_PATH}/include/${APP_NAME_LC})
+if(NOT EXISTS "${APP_INCLUDE_DIR}/")
+ file(MAKE_DIRECTORY ${APP_INCLUDE_DIR})
+endif()
+
+if(NOT CORE_SYSTEM_NAME)
+ if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
+ set(CORE_SYSTEM_NAME "osx")
+ else()
+ string(TOLOWER ${CMAKE_SYSTEM_NAME} CORE_SYSTEM_NAME)
+ endif()
+endif()
+
+set(PLATFORM_TAG ${CORE_SYSTEM_NAME})
+
+# The CPU variable is given either by ./tools/depends or by the
+# ./cmake/scripts/common/ArchSetup.cmake (which refers to the Kodi building
+# itself). However, this file is only used by addons, so CPU can not always
+# be defined, so in this case, if empty, the base CPU will be used.
+if(NOT CPU)
+ set(CPU ${CMAKE_SYSTEM_PROCESSOR})
+endif()
+
+if(CORE_SYSTEM_NAME STREQUAL android)
+ if (CPU MATCHES "v7a")
+ set(PLATFORM_TAG ${PLATFORM_TAG}-armv7)
+ elseif (CPU MATCHES "arm64")
+ set(PLATFORM_TAG ${PLATFORM_TAG}-aarch64)
+ elseif (CPU MATCHES "i686")
+ set(PLATFORM_TAG ${PLATFORM_TAG}-i686)
+ elseif (CPU MATCHES "x86_64")
+ set(PLATFORM_TAG ${PLATFORM_TAG}-x86_64)
+ else()
+ message(FATAL_ERROR "Unsupported architecture")
+ endif()
+elseif(CORE_SYSTEM_NAME STREQUAL darwin_embedded)
+ set(PLATFORM_TAG ${CORE_PLATFORM_NAME})
+ if (CPU MATCHES arm64)
+ set(PLATFORM_TAG ${PLATFORM_TAG}-aarch64)
+ else()
+ message(FATAL_ERROR "Unsupported architecture")
+ endif()
+elseif(CORE_SYSTEM_NAME STREQUAL osx)
+ set(PLATFORM_TAG ${PLATFORM_TAG}-${CPU})
+elseif(CORE_SYSTEM_NAME STREQUAL windows)
+ include(CheckSymbolExists)
+ check_symbol_exists(_X86_ "Windows.h" _X86_)
+ check_symbol_exists(_AMD64_ "Windows.h" _AMD64_)
+
+ if(_X86_)
+ set(PLATFORM_TAG ${PLATFORM_TAG}-i686)
+ elseif(_AMD64_)
+ set(PLATFORM_TAG ${PLATFORM_TAG}-x86_64)
+ else()
+ message(FATAL_ERROR "Unsupported architecture")
+ endif()
+
+ unset(_X86_)
+ unset(_AMD64_)
+endif()
+
+# generate the proper KodiConfig.cmake file
+configure_file(${CORE_SOURCE_DIR}/cmake/KodiConfig.cmake.in ${APP_LIB_DIR}/KodiConfig.cmake @ONLY)
+
+# copy cmake helpers to lib/kodi
+file(COPY ${CORE_SOURCE_DIR}/cmake/scripts/common/AddonHelpers.cmake
+ ${CORE_SOURCE_DIR}/cmake/scripts/common/AddOptions.cmake
+ DESTINATION ${APP_LIB_DIR})
+
+### copy all the addon binding header files to include/kodi
+include(${CORE_SOURCE_DIR}/xbmc/addons/AddonBindings.cmake)
+file(COPY ${CORE_ADDON_BINDINGS_FILES} ${CORE_ADDON_BINDINGS_DIRS}/
+ DESTINATION ${APP_INCLUDE_DIR}
+ REGEX ".txt" EXCLUDE)
+
+### processing additional tools required by the platform
+if(EXISTS ${CORE_SOURCE_DIR}/cmake/scripts/${CORE_SYSTEM_NAME}/tools/)
+ file(GLOB platform_tools ${CORE_SOURCE_DIR}/cmake/scripts/${CORE_SYSTEM_NAME}/tools/*.cmake)
+ foreach(platform_tool ${platform_tools})
+ get_filename_component(platform_tool_name ${platform_tool} NAME_WE)
+ message(STATUS "Processing ${CORE_SYSTEM_NAME} specific tool: ${platform_tool_name}")
+
+ # include the file
+ include(${platform_tool})
+ endforeach()
+endif()
diff --git a/cmake/scripts/common/ProjectMacros.cmake b/cmake/scripts/common/ProjectMacros.cmake
new file mode 100644
index 0000000..3a1910c
--- /dev/null
+++ b/cmake/scripts/common/ProjectMacros.cmake
@@ -0,0 +1,89 @@
+# This script holds macros which are project specific
+
+# Pack a skin xbt file
+# Arguments:
+# input input directory to pack
+# output output xbt file
+# On return:
+# xbt is added to ${XBT_FILES}
+function(pack_xbt input output)
+ file(GLOB_RECURSE MEDIA_FILES ${input}/*)
+ get_filename_component(dir ${output} DIRECTORY)
+ add_custom_command(OUTPUT ${output}
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${dir}
+ COMMAND TexturePacker::TexturePacker::Executable
+ ARGS -input ${input}
+ -output ${output}
+ -dupecheck
+ DEPENDS ${MEDIA_FILES})
+ list(APPEND XBT_FILES ${output})
+ set(XBT_FILES ${XBT_FILES} PARENT_SCOPE)
+endfunction()
+
+# Add a skin to installation list, mirroring it in build tree, packing textures
+# Arguments:
+# skin skin directory
+# On return:
+# xbt is added to ${XBT_FILES}, data added to ${install_data}, mirror in build tree
+function(copy_skin_to_buildtree skin)
+ file(GLOB_RECURSE FILES ${skin}/*)
+ file(GLOB_RECURSE MEDIA_FILES ${skin}/media/*)
+ list(REMOVE_ITEM FILES ${MEDIA_FILES})
+ foreach(file ${FILES})
+ copy_file_to_buildtree(${file})
+ endforeach()
+ file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/${dest}/media)
+ string(REPLACE "${CMAKE_SOURCE_DIR}/" "" dest ${skin})
+ pack_xbt(${skin}/media ${CMAKE_BINARY_DIR}/${dest}/media/Textures.xbt)
+
+ file(GLOB THEMES RELATIVE ${skin}/themes ${skin}/themes/*)
+ foreach(theme ${THEMES})
+ pack_xbt(${skin}/themes/${theme} ${CMAKE_BINARY_DIR}/${dest}/media/${theme}.xbt)
+ endforeach()
+
+ set(XBT_FILES ${XBT_FILES} PARENT_SCOPE)
+ set(install_data ${install_data} PARENT_SCOPE)
+endfunction()
+
+# Get GTest tests as CMake tests.
+# Copied from FindGTest.cmake
+# Thanks to Daniel Blezek <blezek@gmail.com> for the GTEST_ADD_TESTS code
+function(GTEST_ADD_TESTS executable extra_args)
+ if(NOT ARGN)
+ message(FATAL_ERROR "Missing ARGN: Read the documentation for GTEST_ADD_TESTS")
+ endif()
+ foreach(source ${ARGN})
+ # This assumes that every source file passed in exists. Consider using
+ # SUPPORT_SOURCES for source files which do not contain tests and might
+ # have to be generated.
+ file(READ "${source}" contents)
+ string(REGEX MATCHALL "TEST_?[F]?\\(([A-Za-z_0-9 ,]+)\\)" found_tests ${contents})
+ foreach(hit ${found_tests})
+ string(REGEX REPLACE ".*\\( *([A-Za-z_0-9]+), *([A-Za-z_0-9]+) *\\).*" "\\1.\\2" test_name ${hit})
+ add_test(${test_name} ${executable} --gtest_filter=${test_name} ${extra_args})
+ endforeach()
+ # Groups parametrized tests under a single ctest entry
+ string(REGEX MATCHALL "INSTANTIATE_TEST_CASE_P\\(([^,]+), *([^,]+)" found_tests2 ${contents})
+ foreach(hit ${found_tests2})
+ string(SUBSTRING ${hit} 24 -1 test_name)
+ string(REPLACE "," ";" test_name "${test_name}")
+ list(GET test_name 0 filter_name)
+ list(GET test_name 1 test_prefix)
+ string(STRIP ${test_prefix} test_prefix)
+ add_test(${test_prefix}.${filter_name} ${executable} --gtest_filter=${filter_name}* ${extra_args})
+ endforeach()
+ endforeach()
+endfunction()
+
+function(whole_archive output)
+ if(CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang)
+ set(${output} -Wl,--whole-archive ${ARGN} -Wl,--no-whole-archive PARENT_SCOPE)
+ elseif(CMAKE_CXX_COMPILER_ID STREQUAL AppleClang)
+ foreach(library ${ARGN})
+ list(APPEND ${output} -Wl,-force_load ${library})
+ set(${output} ${${output}} PARENT_SCOPE)
+ endforeach()
+ else()
+ set(${output} ${ARGN} PARENT_SCOPE)
+ endif()
+endfunction()
diff --git a/cmake/scripts/common/StaticAnalysis.cmake b/cmake/scripts/common/StaticAnalysis.cmake
new file mode 100644
index 0000000..f7ffa39
--- /dev/null
+++ b/cmake/scripts/common/StaticAnalysis.cmake
@@ -0,0 +1,39 @@
+include(ProcessorCount)
+ProcessorCount(CPU_CORES)
+
+find_program(CPPCHECK_EXECUTABLE cppcheck)
+
+if(CPPCHECK_EXECUTABLE)
+ add_custom_target(analyze-cppcheck
+ DEPENDS ${APP_NAME_LC} ${APP_NAME_LC}-test
+ COMMAND ${CPPCHECK_EXECUTABLE}
+ -j${CPU_CORES}
+ --project=${CMAKE_BINARY_DIR}/compile_commands.json
+ --std=c++${CMAKE_CXX_STANDARD}
+ --enable=all
+ --xml
+ --xml-version=2
+ --language=c++
+ --relative-paths=${CMAKE_SOURCE_DIR}
+ --rule-file=${CMAKE_SOURCE_DIR}/tools/static-analysis/cppcheck/cppcheck-rules.xml
+ --suppress-xml=${CMAKE_SOURCE_DIR}/tools/static-analysis/cppcheck/cppcheck-suppressions.xml
+ --output-file=${CMAKE_BINARY_DIR}/cppcheck-result.xml
+ COMMENT "Static code analysis using cppcheck")
+endif()
+
+find_program(CLANG_TIDY_EXECUTABLE NAMES clang-tidy)
+find_program(RUN_CLANG_TIDY NAMES run-clang-tidy.py run-clang-tidy
+ PATHS /usr/share/clang /usr/bin)
+
+if(RUN_CLANG_TIDY AND CLANG_TIDY_EXECUTABLE)
+ add_custom_target(analyze-clang-tidy
+ DEPENDS ${APP_NAME_LC} ${APP_NAME_LC}-test
+ COMMAND ${RUN_CLANG_TIDY}
+ -j${CPU_CORES}
+ -clang-tidy-binary=${CLANG_TIDY_EXECUTABLE}
+ -p=${CMAKE_BINARY_DIR}
+ -header-filter='${CMAKE_BINARY_DIR}/.*/include/.*'
+ | tee ${CMAKE_BINARY_DIR}/clangtidy-result.xml
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+ COMMENT "Static code analysis using clang-tidy")
+endif()
diff --git a/cmake/scripts/common/Uninstall.cmake b/cmake/scripts/common/Uninstall.cmake
new file mode 100644
index 0000000..5753857
--- /dev/null
+++ b/cmake/scripts/common/Uninstall.cmake
@@ -0,0 +1,58 @@
+macro(remove_empty_dirs)
+ list(REMOVE_DUPLICATES DIRECTORIES)
+ unset(PDIRECTORIES)
+ foreach(dir IN LISTS DIRECTORIES)
+ if(EXISTS $ENV{DESTDIR}${dir})
+ file(GLOB _res $ENV{DESTDIR}${dir}/*)
+ list(LENGTH _res _len)
+ if(_len EQUAL 0 AND EXISTS $ENV{DESTDIR}${dir})
+ message(STATUS "Removing empty dir: ${dir}")
+ execute_process(
+ COMMAND ${CMAKE_COMMAND} -E remove_directory $ENV{DESTDIR}${dir}
+ OUTPUT_VARIABLE rm_out
+ RESULT_VARIABLE rm_retval
+ )
+ if(NOT "${rm_retval}" STREQUAL 0)
+ message(FATAL_ERROR "Failed to remove directory: $ENV{DESTDIR}${dir}")
+ endif()
+ get_filename_component(_pdir $ENV{DESTDIR}${dir} DIRECTORY)
+ list(APPEND PDIRECTORIES ${_pdir})
+ endif()
+ endif()
+ endforeach()
+ list(LENGTH PDIRECTORIES _plen)
+ if(_plen GREATER 0)
+ set(DIRECTORIES ${PDIRECTORIES})
+ remove_empty_dirs()
+ endif()
+endmacro()
+
+# Uninstall target
+set(MANIFEST ${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt)
+if(EXISTS ${MANIFEST})
+ file(STRINGS ${MANIFEST} files)
+ foreach(file IN LISTS files)
+ if(EXISTS $ENV{DESTDIR}${file})
+ get_filename_component(_dir $ENV{DESTDIR}${file} DIRECTORY)
+ list(APPEND DIRECTORIES $ENV{DESTDIR}${_dir})
+ message(STATUS "Uninstalling: ${file}")
+ execute_process(
+ COMMAND ${CMAKE_COMMAND} -E remove $ENV{DESTDIR}${file}
+ OUTPUT_VARIABLE rm_out
+ RESULT_VARIABLE rm_retval
+ )
+ if(NOT "${rm_retval}" STREQUAL 0)
+ message(FATAL_ERROR "Failed to remove file: $ENV{DESTDIR}${file}")
+ endif()
+ else()
+ message(STATUS "File does not exist: $ENV{DESTDIR}${file}")
+ endif()
+ endforeach(file)
+
+ # delete empty dirs
+ if(DIRECTORIES)
+ remove_empty_dirs()
+ endif()
+else()
+ message(STATUS "Cannot find install manifest: '${MANIFEST}'")
+endif()