diff options
Diffstat (limited to 'cmake/scripts')
61 files changed, 5546 insertions, 0 deletions
diff --git a/cmake/scripts/android/ArchSetup.cmake b/cmake/scripts/android/ArchSetup.cmake new file mode 100644 index 0000000..2fe85fe --- /dev/null +++ b/cmake/scripts/android/ArchSetup.cmake @@ -0,0 +1,45 @@ +if(NOT CMAKE_TOOLCHAIN_FILE) + message(FATAL_ERROR "CMAKE_TOOLCHAIN_FILE required for android. See ${CMAKE_SOURCE_DIR}/cmake/README.md") +endif() + +set(ARCH_DEFINES -DTARGET_POSIX -DTARGET_LINUX -DTARGET_ANDROID) +set(SYSTEM_DEFINES -D__STDC_CONSTANT_MACROS -D_LARGEFILE64_SOURCE + -D_FILE_OFFSET_BITS=64 -D__USE_FILE_OFFSET64=1) + +# Main cpp +set(CORE_MAIN_SOURCE ${CMAKE_SOURCE_DIR}/xbmc/platform/android/activity/XBMCApp.cpp) + +set(PLATFORM_DIR platform/linux) +set(PLATFORMDEFS_DIR platform/posix) +if(WITH_ARCH) + set(ARCH ${WITH_ARCH}) +else() + if(CPU STREQUAL armeabi-v7a) + set(ARCH arm) + set(NEON True) + set(NEON_FLAGS "-mfpu=neon") + if(CMAKE_COMPILER_IS_GNUCC AND CMAKE_COMPILER_IS_GNUCXX) + set(NEON_FLAGS "${NEON_FLAGS} -mvectorize-with-neon-quad") + endif() + elseif(CPU STREQUAL arm64-v8a) + set(ARCH aarch64) + set(NEON True) + elseif(CPU STREQUAL i686) + set(ARCH i486-linux) + set(NEON False) + elseif(CPU STREQUAL x86_64) + set(ARCH x86_64) + set(NEON False) + else() + message(SEND_ERROR "Unknown CPU: ${CPU}") + endif() +endif() + +# Additional SYSTEM_DEFINES +list(APPEND SYSTEM_DEFINES -DHAS_ZEROCONF) + +set(ENABLE_X11 OFF CACHE BOOL "" FORCE) +set(ENABLE_OPTICAL OFF CACHE BOOL "" FORCE) +set(ENABLE_MDNS OFF CACHE BOOL "" FORCE) + +list(APPEND DEPLIBS android log jnigraphics mediandk) diff --git a/cmake/scripts/android/Install.cmake b/cmake/scripts/android/Install.cmake new file mode 100644 index 0000000..f39b858 --- /dev/null +++ b/cmake/scripts/android/Install.cmake @@ -0,0 +1,174 @@ +# Android packaging + +if(CMAKE_BUILD_TYPE STREQUAL Debug) + set(ANDROID_DEBUGGABLE true) +else() + set(ANDROID_DEBUGGABLE false) +endif() + +# Configure files into packaging environment. +configure_file(${CMAKE_SOURCE_DIR}/tools/android/packaging/Makefile.in + ${CMAKE_BINARY_DIR}/tools/android/packaging/Makefile @ONLY) +configure_file(${CMAKE_SOURCE_DIR}/tools/android/packaging/gradle.properties + ${CMAKE_BINARY_DIR}/tools/android/packaging/gradle.properties COPYONLY) +configure_file(${CMAKE_SOURCE_DIR}/tools/android/packaging/build.gradle + ${CMAKE_BINARY_DIR}/tools/android/packaging/build.gradle COPYONLY) +configure_file(${CMAKE_SOURCE_DIR}/tools/android/packaging/gradlew + ${CMAKE_BINARY_DIR}/tools/android/packaging/gradlew COPYONLY) +configure_file(${CMAKE_SOURCE_DIR}/tools/android/packaging/settings.gradle + ${CMAKE_BINARY_DIR}/tools/android/packaging/settings.gradle COPYONLY) +configure_file(${CMAKE_SOURCE_DIR}/tools/android/packaging/gradle/wrapper/gradle-wrapper.jar + ${CMAKE_BINARY_DIR}/tools/android/packaging/gradle/wrapper/gradle-wrapper.jar COPYONLY) +configure_file(${CMAKE_SOURCE_DIR}/tools/android/packaging/gradle/wrapper/gradle-wrapper.properties + ${CMAKE_BINARY_DIR}/tools/android/packaging/gradle/wrapper/gradle-wrapper.properties COPYONLY) +configure_file(${CMAKE_SOURCE_DIR}/tools/android/packaging/xbmc/jni/Android.mk + ${CMAKE_BINARY_DIR}/tools/android/packaging/xbmc/jni/Android.mk COPYONLY) +file(WRITE ${CMAKE_BINARY_DIR}/tools/depends/Makefile.include + "$(PREFIX)/lib/${APP_NAME_LC}/lib${APP_NAME_LC}.so: ;\n") + +string(REPLACE "." ";" APP_VERSION_CODE_LIST ${APP_VERSION_CODE}) +list(GET APP_VERSION_CODE_LIST 0 major) +list(GET APP_VERSION_CODE_LIST 1 minor) +list(GET APP_VERSION_CODE_LIST 2 patch) +unset(APP_VERSION_CODE_LIST) +math(EXPR APP_VERSION_CODE_ANDROID "(${major} * 100 + ${minor}) * 1000 + ${patch}") +unset(major) +unset(minor) +if(ARCH STREQUAL aarch64 AND patch LESS 999) + math(EXPR APP_VERSION_CODE_ANDROID "${APP_VERSION_CODE_ANDROID} + 1") +endif() +unset(patch) + +set(package_files strings.xml + colors.xml + searchable.xml + AndroidManifest.xml + build.gradle + src/Splash.java + src/Main.java + src/XBMCBroadcastReceiver.java + src/XBMCInputDeviceListener.java + src/XBMCJsonRPC.java + src/XBMCMainView.java + src/XBMCMediaSession.java + src/XBMCRecommendationBuilder.java + src/XBMCSearchableActivity.java + src/XBMCSettingsContentObserver.java + src/XBMCProperties.java + src/XBMCVideoView.java + src/XBMCFile.java + src/XBMCURIUtils.java + src/channels/SyncChannelJobService.java + src/channels/SyncProgramsJobService.java + src/channels/model/XBMCDatabase.java + src/channels/model/Subscription.java + src/channels/util/SharedPreferencesHelper.java + src/channels/util/TvUtil.java + src/interfaces/XBMCAudioManagerOnAudioFocusChangeListener.java + src/interfaces/XBMCSurfaceTextureOnFrameAvailableListener.java + src/interfaces/XBMCNsdManagerResolveListener.java + src/interfaces/XBMCNsdManagerRegistrationListener.java + src/interfaces/XBMCNsdManagerDiscoveryListener.java + src/interfaces/XBMCMediaDrmOnEventListener.java + src/interfaces/XBMCDisplayManagerDisplayListener.java + src/interfaces/XBMCSpeechRecognitionListener.java + src/model/TVEpisode.java + src/model/Movie.java + src/model/TVShow.java + src/model/File.java + src/model/Album.java + src/model/Song.java + src/model/MusicVideo.java + src/model/Media.java + src/content/XBMCFileContentProvider.java + src/content/XBMCMediaContentProvider.java + src/content/XBMCContentProvider.java + src/content/XBMCYTDLContentProvider.java + ) +foreach(file IN LISTS package_files) + configure_file(${CMAKE_SOURCE_DIR}/tools/android/packaging/xbmc/${file}.in + ${CMAKE_BINARY_DIR}/tools/android/packaging/xbmc/${file} @ONLY) +endforeach() + +# Copy files to the location expected by the Android packaging scripts. +add_custom_target(bundle + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/tools/android/packaging/media + ${CMAKE_BINARY_DIR}/tools/android/packaging/media + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/tools/android/packaging/xbmc/res + ${CMAKE_BINARY_DIR}/tools/android/packaging/xbmc/res + COMMAND ${CMAKE_COMMAND} -E copy_directory ${DEPENDS_PATH}/lib/python${PYTHON_VERSION} ${libdir}/python${PYTHON_VERSION} + COMMAND ${CMAKE_COMMAND} -E copy_directory ${DEPENDS_PATH}/share/${APP_NAME_LC} ${datadir}/${APP_NAME_LC} + COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:${APP_NAME_LC}> + ${libdir}/${APP_NAME_LC}/$<TARGET_FILE_NAME:${APP_NAME_LC}>) +add_dependencies(bundle ${APP_NAME_LC}) + +# This function is used to prepare a prefix expected by the Android packaging +# scripts. It creates a bundle_files command that is added to the bundle target. +function(add_bundle_file file destination relative) + if(NOT TARGET bundle_files) + file(REMOVE ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/BundleFiles.cmake) + add_custom_target(bundle_files COMMAND ${CMAKE_COMMAND} -P ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/BundleFiles.cmake) + add_dependencies(bundle bundle_files) + add_dependencies(bundle_files ${APP_NAME_LC}) + endif() + + string(REPLACE "${relative}/" "" outfile ${file}) + get_filename_component(file ${file} REALPATH) + get_filename_component(outdir ${outfile} DIRECTORY) + file(APPEND ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/BundleFiles.cmake + "file(COPY \"${file}\" DESTINATION \"${destination}/${outdir}\")\n") + if(file MATCHES "\\.so\\..+$") + get_filename_component(srcfile "${file}" NAME) + string(REGEX REPLACE "\\.so\\..+$" "\.so" destfile ${srcfile}) + file(APPEND ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/BundleFiles.cmake + "file(RENAME \"${destination}/${outdir}/${srcfile}\" \"${destination}/${outdir}/${destfile}\")\n") + endif() +endfunction() + +# Copy files into prefix +foreach(file IN LISTS XBT_FILES install_data) + string(REPLACE "${CMAKE_BINARY_DIR}/" "" file ${file}) + add_bundle_file(${CMAKE_BINARY_DIR}/${file} ${datarootdir}/${APP_NAME_LC} ${CMAKE_BINARY_DIR}) +endforeach() + +foreach(library IN LISTS LIBRARY_FILES) + add_bundle_file(${library} ${libdir}/${APP_NAME_LC} ${CMAKE_BINARY_DIR}) +endforeach() + +foreach(lib IN LISTS required_dyload dyload_optional ITEMS Shairplay) + string(TOUPPER ${lib} lib_up) + set(lib_so ${${lib_up}_SONAME}) + if(lib_so AND EXISTS ${DEPENDS_PATH}/lib/${lib_so}) + add_bundle_file(${DEPENDS_PATH}/lib/${lib_so} ${libdir} "") + endif() +endforeach() +add_bundle_file(${ASS_LIBRARY} ${libdir} "") +add_bundle_file(${SHAIRPLAY_LIBRARY} ${libdir} "") +add_bundle_file(${SMBCLIENT_LIBRARY} ${libdir} "") + +# Main targets from Makefile.in +if(CPU MATCHES i686) + set(CPU x86) +endif() +foreach(target apk apk-clean) + add_custom_target(${target} + COMMAND env PATH=${NATIVEPREFIX}/bin:$ENV{PATH} ${CMAKE_MAKE_PROGRAM} -j1 + -C ${CMAKE_BINARY_DIR}/tools/android/packaging + CMAKE_SOURCE_DIR=${CMAKE_SOURCE_DIR} + CC=${CMAKE_C_COMPILER} + CPU=${CPU} + HOST=${HOST} + TOOLCHAIN=${TOOLCHAIN} + PREFIX=${prefix} + DEPENDS_PATH=${DEPENDS_PATH} + NDKROOT=${NDKROOT} + SDKROOT=${SDKROOT} + STRIP=${CMAKE_STRIP} + ${target} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/tools/android/packaging + VERBATIM + ) + if(NOT target STREQUAL apk-clean) + add_dependencies(${target} bundle) + endif() +endforeach() diff --git a/cmake/scripts/android/Macros.cmake b/cmake/scripts/android/Macros.cmake new file mode 120000 index 0000000..2fdbb25 --- /dev/null +++ b/cmake/scripts/android/Macros.cmake @@ -0,0 +1 @@ +../linux/Macros.cmake
\ No newline at end of file diff --git a/cmake/scripts/android/PathSetup.cmake b/cmake/scripts/android/PathSetup.cmake new file mode 100644 index 0000000..6115781 --- /dev/null +++ b/cmake/scripts/android/PathSetup.cmake @@ -0,0 +1,33 @@ +if(NOT prefix) + set(prefix ${DEPENDS_PATH}) +endif() +set(CMAKE_INSTALL_PREFIX ${prefix}) +if(NOT exec_prefix) + set(exec_prefix ${prefix}) +endif() +if(NOT libdir) + set(libdir ${prefix}/lib) +endif() +if(NOT bindir) + set(bindir ${prefix}/bin) +endif() +if(NOT includedir) + set(includedir ${prefix}/include) +endif() +if(NOT datarootdir) + set(datarootdir ${prefix}/share) +endif() +if(NOT datadir) + set(datadir ${datarootdir}) +endif() + +list(APPEND final_message "-- PATH config --") +list(APPEND final_message "Prefix: ${prefix}") +list(APPEND final_message "Libdir: ${libdir}") +list(APPEND final_message "Bindir: ${bindir}") +list(APPEND final_message "Includedir: ${includedir}") +list(APPEND final_message "Datarootdir: ${datarootdir}") +list(APPEND final_message "Datadir: ${datadir}") + +set(PATH_DEFINES -DBIN_INSTALL_PATH=\"${libdir}/${APP_NAME_LC}\" + -DINSTALL_PATH=\"${datarootdir}/${APP_NAME_LC}\") 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() diff --git a/cmake/scripts/darwin/Macros.cmake b/cmake/scripts/darwin/Macros.cmake new file mode 100644 index 0000000..9a805c4 --- /dev/null +++ b/cmake/scripts/darwin/Macros.cmake @@ -0,0 +1,8 @@ +macro(enable_arc) + if(CMAKE_GENERATOR STREQUAL Xcode) + set(CMAKE_XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES) + else() + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fobjc-arc") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fobjc-arc") + endif() +endmacro() diff --git a/cmake/scripts/darwin_embedded/ArchSetup.cmake b/cmake/scripts/darwin_embedded/ArchSetup.cmake new file mode 100644 index 0000000..b3258be --- /dev/null +++ b/cmake/scripts/darwin_embedded/ArchSetup.cmake @@ -0,0 +1,68 @@ +if(NOT CMAKE_TOOLCHAIN_FILE) + message(FATAL_ERROR "CMAKE_TOOLCHAIN_FILE required for ios/tvos. See ${CMAKE_SOURCE_DIR}/cmake/README.md") +endif() + +set(CORE_MAIN_SOURCE ${CMAKE_SOURCE_DIR}/xbmc/platform/darwin/${CORE_PLATFORM_NAME_LC}/XBMCApplication.mm) +set(PLATFORM_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/xbmc/platform/darwin/${CORE_PLATFORM_NAME_LC}/Info.plist.in) + +list(APPEND ARCH_DEFINES -DTARGET_POSIX -DTARGET_DARWIN -DTARGET_DARWIN_EMBEDDED) +set(SYSTEM_DEFINES -D_REENTRANT -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE + -D__STDC_CONSTANT_MACROS -DHAS_IOS_NETWORK -DHAS_ZEROCONF) +set(PLATFORM_DIR platform/darwin) +set(PLATFORMDEFS_DIR platform/posix) +set(CMAKE_SYSTEM_NAME Darwin) +if(WITH_ARCH) + set(ARCH ${WITH_ARCH}) +else() + if(CPU STREQUAL arm64) + set(ARCH aarch64) + else() + message(SEND_ERROR "Unknown CPU: ${CPU}") + endif() + set(CMAKE_OSX_ARCHITECTURES ${CPU}) + set(NEON True) +endif() + +if(NOT APP_RENDER_SYSTEM OR APP_RENDER_SYSTEM STREQUAL "gles") + set(PLATFORM_REQUIRED_DEPS OpenGLES) + set(APP_RENDER_SYSTEM gles) + list(APPEND SYSTEM_DEFINES -DGL_DO_NOT_WARN_IF_MULTI_GL_VERSION_HEADERS_INCLUDED) +else() + message(SEND_ERROR "Currently only OpenGLES rendering is supported. Please set APP_RENDER_SYSTEM to \"gles\"") +endif() + +list(APPEND CMAKE_SYSTEM_PREFIX_PATH ${NATIVEPREFIX}) + +list(APPEND DEPLIBS "-framework CoreFoundation" "-framework CoreVideo" + "-framework CoreAudio" "-framework AudioToolbox" + "-framework QuartzCore" "-framework MediaPlayer" + "-framework CFNetwork" "-framework CoreGraphics" + "-framework Foundation" "-framework UIKit" + "-framework CoreMedia" "-framework AVFoundation" + "-framework VideoToolbox" "-lresolv" "-ObjC" + "-framework AVKit" "-framework GameController") + +# Speech not available on tvOS +if(NOT CORE_PLATFORM_NAME_LC STREQUAL tvos) + list(APPEND DEPLIBS "-framework Speech") +endif() + +set(ENABLE_OPTICAL OFF CACHE BOOL "" FORCE) +set(CMAKE_XCODE_ATTRIBUTE_INLINES_ARE_PRIVATE_EXTERN OFF) +set(CMAKE_XCODE_ATTRIBUTE_GCC_SYMBOLS_PRIVATE_EXTERN OFF) +set(CMAKE_XCODE_ATTRIBUTE_COPY_PHASE_STRIP OFF) + +include(cmake/scripts/darwin/Macros.cmake) +enable_arc() + +# Xcode strips dead code by default which breaks wrapping +set(CMAKE_XCODE_ATTRIBUTE_DEAD_CODE_STRIPPING OFF) + +option(ENABLE_XCODE_ADDONBUILD "Enable Xcode automatic addon building?" OFF) + +# Unify output directories for iOS/tvOS packaging scripts +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CORE_BUILD_DIR}/${CORE_BUILD_CONFIG}) +foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES}) + string(TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CORE_BUILD_DIR}/${CORE_BUILD_CONFIG}) +endforeach() diff --git a/cmake/scripts/darwin_embedded/ExtraTargets.cmake b/cmake/scripts/darwin_embedded/ExtraTargets.cmake new file mode 100644 index 0000000..01ab632 --- /dev/null +++ b/cmake/scripts/darwin_embedded/ExtraTargets.cmake @@ -0,0 +1,32 @@ +if(CORE_PLATFORM_NAME_LC STREQUAL tvos) + # top shelf extension + set(TOPSHELF_EXTENSION_NAME "${APP_NAME_LC}-topshelf") + set(TOPSHELF_BUNDLE_EXTENSION appex) + set(TOPSHELF_DIR "${CMAKE_SOURCE_DIR}/xbmc/platform/darwin/tvos/TopShelf") + # same path as the output Info.plist, taken from cmGlobalXCodeGenerator::ComputeInfoPListLocation() + set(ENTITLEMENTS_OUT_PATH "${CMAKE_BINARY_DIR}/CMakeFiles/${TOPSHELF_EXTENSION_NAME}.dir/TopShelf.entitlements") + + set(SOURCES + ${TOPSHELF_DIR}/../../ios-common/DarwinEmbedUtils.mm + ${TOPSHELF_DIR}/ServiceProvider.mm + ${TOPSHELF_DIR}/../tvosShared.mm) + set(HEADERS + ${TOPSHELF_DIR}/../../ios-common/DarwinEmbedUtils.h + ${TOPSHELF_DIR}/ServiceProvider.h + ${TOPSHELF_DIR}/../tvosShared.h) + add_executable(${TOPSHELF_EXTENSION_NAME} MACOSX_BUNDLE ${SOURCES} ${HEADERS}) + + configure_file(${TOPSHELF_DIR}/TopShelf.entitlements.in ${ENTITLEMENTS_OUT_PATH} @ONLY) + set_target_properties(${TOPSHELF_EXTENSION_NAME} PROPERTIES BUNDLE_EXTENSION ${TOPSHELF_BUNDLE_EXTENSION} + MACOSX_BUNDLE_INFO_PLIST ${TOPSHELF_DIR}/Info.plist.in + XCODE_PRODUCT_TYPE com.apple.product-type.tv-app-extension + XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS ${ENTITLEMENTS_OUT_PATH}) + target_link_libraries(${TOPSHELF_EXTENSION_NAME} "-framework TVServices" "-framework Foundation") + + add_custom_command(TARGET ${TOPSHELF_EXTENSION_NAME} POST_BUILD + COMMAND "NATIVEPREFIX=${NATIVEPREFIX}" + ${CMAKE_SOURCE_DIR}/tools/darwin/Support/Codesign-topshelf.command + ) + + add_dependencies(${APP_NAME_LC} ${TOPSHELF_EXTENSION_NAME}) +endif() diff --git a/cmake/scripts/darwin_embedded/Install.cmake b/cmake/scripts/darwin_embedded/Install.cmake new file mode 100644 index 0000000..02464ee --- /dev/null +++ b/cmake/scripts/darwin_embedded/Install.cmake @@ -0,0 +1,130 @@ +# IOS/TVOS packaging +if(CORE_PLATFORM_NAME_LC STREQUAL tvos) + # asset catalog + set(ASSET_CATALOG "${CMAKE_SOURCE_DIR}/xbmc/platform/darwin/tvos/Assets.xcassets") + set(ASSET_CATALOG_ASSETS Assets) + set(ASSET_CATALOG_LAUNCH_IMAGE LaunchImage) + + message("generating missing asset catalog images...") + execute_process(COMMAND ${CMAKE_SOURCE_DIR}/tools/darwin/Support/GenerateMissingImages-tvos.py "${ASSET_CATALOG}" ${ASSET_CATALOG_ASSETS} ${ASSET_CATALOG_LAUNCH_IMAGE}) + + target_sources(${APP_NAME_LC} PRIVATE "${ASSET_CATALOG}") + set_source_files_properties("${ASSET_CATALOG}" PROPERTIES MACOSX_PACKAGE_LOCATION "Resources") # adds to Copy Bundle Resources build phase + + # entitlements + set(ENTITLEMENTS_OUT_PATH "${CMAKE_BINARY_DIR}/CMakeFiles/${APP_NAME_LC}.dir/Kodi.entitlements") + configure_file(${CMAKE_SOURCE_DIR}/xbmc/platform/darwin/tvos/Kodi.entitlements.in ${ENTITLEMENTS_OUT_PATH} @ONLY) + + set_target_properties(${APP_NAME_LC} PROPERTIES XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_APPICON_NAME ${ASSET_CATALOG_ASSETS} + XCODE_ATTRIBUTE_ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME ${ASSET_CATALOG_LAUNCH_IMAGE} + XCODE_ATTRIBUTE_CODE_SIGN_ENTITLEMENTS ${ENTITLEMENTS_OUT_PATH}) + +else() + set(BUNDLE_RESOURCES ${CMAKE_SOURCE_DIR}/media/splash.jpg + ${CMAKE_SOURCE_DIR}/tools/darwin/packaging/media/ios/rounded/AppIcon29x29.png + ${CMAKE_SOURCE_DIR}/tools/darwin/packaging/media/ios/rounded/AppIcon29x29@2x.png + ${CMAKE_SOURCE_DIR}/tools/darwin/packaging/media/ios/rounded/AppIcon40x40.png + ${CMAKE_SOURCE_DIR}/tools/darwin/packaging/media/ios/rounded/AppIcon40x40@2x.png + ${CMAKE_SOURCE_DIR}/tools/darwin/packaging/media/ios/rounded/AppIcon50x50.png + ${CMAKE_SOURCE_DIR}/tools/darwin/packaging/media/ios/rounded/AppIcon50x50@2x.png + ${CMAKE_SOURCE_DIR}/tools/darwin/packaging/media/ios/rounded/AppIcon57x57.png + ${CMAKE_SOURCE_DIR}/tools/darwin/packaging/media/ios/rounded/AppIcon57x57@2x.png + ${CMAKE_SOURCE_DIR}/tools/darwin/packaging/media/ios/rounded/AppIcon60x60.png + ${CMAKE_SOURCE_DIR}/tools/darwin/packaging/media/ios/rounded/AppIcon60x60@2x.png + ${CMAKE_SOURCE_DIR}/tools/darwin/packaging/media/ios/rounded/AppIcon72x72.png + ${CMAKE_SOURCE_DIR}/tools/darwin/packaging/media/ios/rounded/AppIcon72x72@2x.png + ${CMAKE_SOURCE_DIR}/tools/darwin/packaging/media/ios/rounded/AppIcon76x76.png + ${CMAKE_SOURCE_DIR}/tools/darwin/packaging/media/ios/rounded/AppIcon76x76@2x.png) + + target_sources(${APP_NAME_LC} PRIVATE ${BUNDLE_RESOURCES}) + foreach(file IN LISTS BUNDLE_RESOURCES) + set_source_files_properties(${file} PROPERTIES MACOSX_PACKAGE_LOCATION .) + endforeach() + + target_sources(${APP_NAME_LC} PRIVATE ${CMAKE_SOURCE_DIR}/xbmc/platform/darwin/ios/LaunchScreen.storyboard) + set_source_files_properties(${CMAKE_SOURCE_DIR}/xbmc/platform/darwin/ios/LaunchScreen.storyboard PROPERTIES MACOSX_PACKAGE_LOCATION "Resources") + +endif() + +# setup code signing +# dev team ID / identity (certificate) +set(DEVELOPMENT_TEAM "" CACHE STRING "Development Team") +set(CODE_SIGN_IDENTITY $<IF:$<BOOL:${DEVELOPMENT_TEAM}>,iPhone\ Developer,> CACHE STRING "Code Sign Identity") + +# app provisioning profile +set(CODE_SIGN_STYLE_APP Automatic) +set(PROVISIONING_PROFILE_APP "" CACHE STRING "Provisioning profile name for the Kodi app") +if(PROVISIONING_PROFILE_APP) + set(CODE_SIGN_STYLE_APP Manual) +endif() + +# top shelf provisioning profile +if(CORE_PLATFORM_NAME_LC STREQUAL tvos) + set(CODE_SIGN_STYLE_TOPSHELF Automatic) + set(PROVISIONING_PROFILE_TOPSHELF "" CACHE STRING "Provisioning profile name for the Top Shelf") + if(PROVISIONING_PROFILE_TOPSHELF) + set(CODE_SIGN_STYLE_TOPSHELF Manual) + endif() + set_target_properties(${TOPSHELF_EXTENSION_NAME} PROPERTIES XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "${CODE_SIGN_IDENTITY}" + XCODE_ATTRIBUTE_CODE_SIGN_STYLE ${CODE_SIGN_STYLE_TOPSHELF} + XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "${DEVELOPMENT_TEAM}" + XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER "${PROVISIONING_PROFILE_TOPSHELF}") + # copy extension inside PlugIns dir of the app bundle + add_custom_command(TARGET ${APP_NAME_LC} POST_BUILD + COMMAND ${CMAKE_COMMAND} ARGS -E copy_directory $<TARGET_BUNDLE_DIR:${TOPSHELF_EXTENSION_NAME}> + $<TARGET_BUNDLE_DIR:${APP_NAME_LC}>/PlugIns/${TOPSHELF_EXTENSION_NAME}.${TOPSHELF_BUNDLE_EXTENSION} + MAIN_DEPENDENCY ${TOPSHELF_EXTENSION_NAME}) +endif() +set_target_properties(${APP_NAME_LC} PROPERTIES XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "${CODE_SIGN_IDENTITY}" + XCODE_ATTRIBUTE_CODE_SIGN_STYLE ${CODE_SIGN_STYLE_APP} + XCODE_ATTRIBUTE_DEVELOPMENT_TEAM "${DEVELOPMENT_TEAM}" + XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER "${PROVISIONING_PROFILE_APP}") + +# Create xcode target that allows to build binary-addons. +if(ADDONS_TO_BUILD) + set(_addons "ADDONS=${ADDONS_TO_BUILD}") +endif() +add_custom_target(binary-addons + COMMAND $(MAKE) -C ${CMAKE_SOURCE_DIR}/tools/depends/target/binary-addons clean + COMMAND $(MAKE) -C ${CMAKE_SOURCE_DIR}/tools/depends/target/binary-addons VERBOSE=1 V=99 + INSTALL_PREFIX="${CMAKE_BINARY_DIR}/addons" CROSS_COMPILING=yes ${_addons}) +if(ENABLE_XCODE_ADDONBUILD) + add_dependencies(${APP_NAME_LC} binary-addons) +endif() +unset(_addons) + +add_custom_command(TARGET ${APP_NAME_LC} POST_BUILD + # TODO: Remove in sync with CopyRootFiles-darwin_embedded expecting the ".bin" file + COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:${APP_NAME_LC}> + $<TARGET_FILE_DIR:${APP_NAME_LC}>/${APP_NAME}.bin + + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/DllPaths_generated.h + ${CMAKE_BINARY_DIR}/xbmc/DllPaths_generated.h + COMMAND "ACTION=build" + "APP_NAME=${APP_NAME}" + "XBMC_DEPENDS=${DEPENDS_PATH}" + ${CMAKE_SOURCE_DIR}/tools/darwin/Support/CopyRootFiles-darwin_embedded.command + COMMAND "XBMC_DEPENDS=${DEPENDS_PATH}" + "PYTHON_VERSION=${PYTHON_VERSION}" + ${CMAKE_SOURCE_DIR}/tools/darwin/Support/copyframeworks-darwin_embedded.command + COMMAND ${CMAKE_SOURCE_DIR}/tools/darwin/Support/copyframeworks-dylibs2frameworks.command + COMMAND "XBMC_DEPENDS=${DEPENDS_PATH}" + "NATIVEPREFIX=${NATIVEPREFIX}" + ${CMAKE_SOURCE_DIR}/tools/darwin/Support/Codesign.command +) + +if(CORE_PLATFORM_NAME_LC STREQUAL tvos) + add_custom_command(TARGET ${APP_NAME_LC} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory ${DEPENDS_PATH}/share/${APP_NAME_LC} $<TARGET_FILE_DIR:${APP_NAME_LC}>/AppData/AppHome + ) +endif() + +set(DEPENDS_ROOT_FOR_XCODE ${NATIVEPREFIX}/..) +configure_file(${CMAKE_SOURCE_DIR}/tools/darwin/packaging/darwin_embedded/mkdeb-darwin_embedded.sh.in + ${CMAKE_BINARY_DIR}/tools/darwin/packaging/darwin_embedded/mkdeb-darwin_embedded.sh @ONLY) + +add_custom_target(deb + COMMAND sh ./mkdeb-darwin_embedded.sh ${CORE_BUILD_CONFIG} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/tools/darwin/packaging/darwin_embedded) +add_dependencies(deb ${APP_NAME_LC}) + diff --git a/cmake/scripts/darwin_embedded/Macros.cmake b/cmake/scripts/darwin_embedded/Macros.cmake new file mode 100644 index 0000000..3e58b0d --- /dev/null +++ b/cmake/scripts/darwin_embedded/Macros.cmake @@ -0,0 +1,119 @@ +function(core_link_library lib wraplib) + if(CMAKE_GENERATOR MATCHES "Unix Makefiles" OR CMAKE_GENERATOR STREQUAL Ninja) + set(wrapper_obj cores/dll-loader/exports/CMakeFiles/wrapper.dir/wrapper.c.o) + elseif(CMAKE_GENERATOR MATCHES "Xcode") + # CURRENT_VARIANT is an Xcode env var + # CPU is a project cmake var + # Xcode new build system (CMAKE_XCODE_BUILD_SYSTEM=12) requires the env var CURRENT_VARIANT to be passed WITHOUT brackets + # Xcode Legacy build system (CMAKE_XCODE_BUILD_SYSTEM=1) requires the env var CURRENT_VARIANT to be passed WITH brackets + if(CMAKE_XCODE_BUILD_SYSTEM STREQUAL 12) + set(wrapper_obj cores/dll-loader/exports/kodi.build/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/wrapper.build/Objects-$CURRENT_VARIANT/${CPU}/wrapper.o) + else() + set(wrapper_obj cores/dll-loader/exports/kodi.build/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/wrapper.build/Objects-$(CURRENT_VARIANT)/${CPU}/wrapper.o) + endif() + else() + message(FATAL_ERROR "Unsupported generator in core_link_library") + endif() + + set(export -bundle -undefined dynamic_lookup + -Wl,-alias_list,${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/cores/dll-loader/exports/wrapper.def + ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/${wrapper_obj}) + set(extension ${CMAKE_SHARED_MODULE_SUFFIX}) + set(check_arg "") + if(TARGET ${lib}) + set(target ${lib}) + set(link_lib $<TARGET_FILE:${lib}>) + set(check_arg ${ARGV2}) + set(data_arg ${ARGV3}) + + else() + set(target ${ARGV2}) + set(link_lib ${lib}) + set(check_arg ${ARGV3}) + set(data_arg ${ARGV4}) + endif() + if(check_arg STREQUAL export) + set(export ${export} + -Wl,--version-script=${ARGV3}) + elseif(check_arg STREQUAL extras) + foreach(arg ${data_arg}) + list(APPEND export ${arg}) + endforeach() + elseif(check_arg STREQUAL archives) + set(extra_libs ${data_arg}) + endif() + get_filename_component(dir ${wraplib} DIRECTORY) + + # We can't simply pass the linker flags to the args section of the custom command + # because cmake will add quotes around it (and the linker will fail due to those). + # We need to do this handstand first ... + string(REPLACE " " ";" CUSTOM_COMMAND_ARGS_LDFLAGS ${CMAKE_SHARED_LINKER_FLAGS}) + + add_custom_command(OUTPUT ${wraplib}-${ARCH}${extension} + COMMAND ${CMAKE_COMMAND} -E make_directory ${dir} + COMMAND ${CMAKE_C_COMPILER} + ARGS ${CUSTOM_COMMAND_ARGS_LDFLAGS} ${export} -Wl,-force_load ${link_lib} ${extra_libs} + -o ${CMAKE_BINARY_DIR}/${wraplib}-${ARCH}${extension} + DEPENDS ${target} wrapper.def wrapper) + + get_filename_component(libname ${wraplib} NAME_WE) + add_custom_target(wrap_${libname} ALL DEPENDS ${wraplib}-${ARCH}${extension}) + set_target_properties(wrap_${libname} PROPERTIES FOLDER lib/wrapped) + add_dependencies(${APP_NAME_LC}-libraries wrap_${libname}) + + set(LIBRARY_FILES ${LIBRARY_FILES} ${CMAKE_BINARY_DIR}/${wraplib}-${ARCH}${extension} CACHE STRING "" FORCE) +endfunction() + +function(find_soname lib) + cmake_parse_arguments(arg "REQUIRED" "" "" ${ARGN}) + + string(TOLOWER ${lib} liblow) + if(${lib}_LDFLAGS) + set(link_lib "${${lib}_LDFLAGS}") + else() + set(link_lib "${${lib}_LIBRARIES}") + endif() + + execute_process(COMMAND ${CMAKE_C_COMPILER} -print-search-dirs + COMMAND fgrep libraries: + COMMAND sed "s/[^=]*=\\(.*\\)/\\1/" + COMMAND sed "s/:/ /g" + ERROR_QUIET + OUTPUT_VARIABLE cc_lib_path + OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND echo ${link_lib} + COMMAND sed "s/-L[ ]*//g" + COMMAND sed "s/-l[^ ]*//g" + ERROR_QUIET + OUTPUT_VARIABLE env_lib_path + OUTPUT_STRIP_TRAILING_WHITESPACE) + + foreach(path ${cc_lib_path} ${env_lib_path}) + if(IS_DIRECTORY ${path}) + execute_process(COMMAND ls -- ${path}/lib${liblow}.dylib + ERROR_QUIET + OUTPUT_VARIABLE lib_file + OUTPUT_STRIP_TRAILING_WHITESPACE) + else() + set(lib_file ${path}) + endif() + if(lib_file) + # we want the path/name that is embedded in the dylib + execute_process(COMMAND otool -L ${lib_file} + COMMAND grep -v lib${liblow}.dylib + COMMAND grep ${liblow} + COMMAND awk "{V=1; print $V}" + ERROR_QUIET + OUTPUT_VARIABLE filename + OUTPUT_STRIP_TRAILING_WHITESPACE) + get_filename_component(${lib}_SONAME "${filename}" NAME) + if(VERBOSE) + message(STATUS "${lib} soname: ${${lib}_SONAME}") + endif() + endif() + endforeach() + if(arg_REQUIRED AND NOT ${lib}_SONAME) + message(FATAL_ERROR "Could not find dynamically loadable library ${lib}") + endif() + set(${lib}_SONAME ${${lib}_SONAME} PARENT_SCOPE) +endfunction() diff --git a/cmake/scripts/darwin_embedded/PathSetup.cmake b/cmake/scripts/darwin_embedded/PathSetup.cmake new file mode 100644 index 0000000..efaca0b --- /dev/null +++ b/cmake/scripts/darwin_embedded/PathSetup.cmake @@ -0,0 +1,7 @@ +set(BUNDLE_IDENTIFIER_DESC "Bundle ID") +if(CORE_PLATFORM_NAME_LC STREQUAL tvos) + string(CONCAT BUNDLE_IDENTIFIER_DESC "${BUNDLE_IDENTIFIER_DESC}" " (app, top shelf, group ID)") +endif() +set(PLATFORM_BUNDLE_IDENTIFIER "${APP_PACKAGE}-${CORE_PLATFORM_NAME_LC}" CACHE STRING "${BUNDLE_IDENTIFIER_DESC}") +list(APPEND final_message "Bundle ID: ${PLATFORM_BUNDLE_IDENTIFIER}") +include(cmake/scripts/osx/PathSetup.cmake) diff --git a/cmake/scripts/freebsd/ArchSetup.cmake b/cmake/scripts/freebsd/ArchSetup.cmake new file mode 100644 index 0000000..87f4f0c --- /dev/null +++ b/cmake/scripts/freebsd/ArchSetup.cmake @@ -0,0 +1,46 @@ +# Main cpp +set(CORE_MAIN_SOURCE ${CMAKE_SOURCE_DIR}/xbmc/platform/posix/main.cpp) + +set(ARCH_DEFINES -DTARGET_POSIX -DTARGET_FREEBSD) +set(SYSTEM_DEFINES -D__STDC_CONSTANT_MACROS -D_LARGEFILE64_SOURCE + -D_FILE_OFFSET_BITS=64 -DHAS_OSS) +set(PLATFORM_DIR platform/linux) +set(PLATFORMDEFS_DIR platform/posix) +set(SYSTEM_LDFLAGS -L/usr/local/lib) +if(WITH_ARCH) + set(ARCH ${WITH_ARCH}) +else() + if(CMAKE_SYSTEM_PROCESSOR STREQUAL amd64) + set(ARCH x86_64-freebsd) + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "i.86") + set(ARCH x86-freebsd) + elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL armv6) + set(ARCH armv6-freebsd) + set(NEON True) + elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL armv7) + set(ARCH armv7-freebsd) + set(NEON True) + elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL aarch64) + set(ARCH aarch64-freebsd) + set(NEON True) + else() + message(WARNING "unknown CPU: ${CPU}") + endif() +endif() + +# Disable ALSA by default +if(NOT ENABLE_ALSA) + option(ENABLE_ALSA "Enable alsa support?" OFF) +endif() + +# Additional SYSTEM_DEFINES +list(APPEND SYSTEM_DEFINES -DHAS_POSIX_NETWORK -DHAS_FREEBSD_NETWORK) + +# Build internal libs +if(NOT USE_INTERNAL_LIBS) + if(KODI_DEPENDSBUILD) + set(USE_INTERNAL_LIBS ON) + else() + set(USE_INTERNAL_LIBS OFF) + endif() +endif() diff --git a/cmake/scripts/freebsd/ExtraTargets.cmake b/cmake/scripts/freebsd/ExtraTargets.cmake new file mode 100644 index 0000000..9d5d214 --- /dev/null +++ b/cmake/scripts/freebsd/ExtraTargets.cmake @@ -0,0 +1 @@ +include(cmake/scripts/linux/ExtraTargets.cmake) diff --git a/cmake/scripts/freebsd/Install.cmake b/cmake/scripts/freebsd/Install.cmake new file mode 120000 index 0000000..28ce012 --- /dev/null +++ b/cmake/scripts/freebsd/Install.cmake @@ -0,0 +1 @@ +../linux/Install.cmake
\ No newline at end of file diff --git a/cmake/scripts/freebsd/Macros.cmake b/cmake/scripts/freebsd/Macros.cmake new file mode 100644 index 0000000..ef5aed3 --- /dev/null +++ b/cmake/scripts/freebsd/Macros.cmake @@ -0,0 +1,95 @@ +function(core_link_library lib wraplib) + set(export -Wl,--unresolved-symbols=ignore-all + `cat ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/cores/dll-loader/exports/wrapper.def` + ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/cores/dll-loader/exports/CMakeFiles/wrapper.dir/wrapper.c.o) + set(check_arg "") + if(TARGET ${lib}) + set(target ${lib}) + set(link_lib $<TARGET_FILE:${lib}>) + set(check_arg ${ARGV2}) + set(data_arg ${ARGV3}) + else() + set(target ${ARGV2}) + set(link_lib ${lib}) + set(check_arg ${ARGV3}) + set(data_arg ${ARGV4}) + endif() + + # wrapper has to be adapted in order to support coverage. + if(CMAKE_BUILD_TYPE STREQUAL Coverage) + set(export "") + endif() + + if(check_arg STREQUAL export) + set(export ${export} + -Wl,--version-script=${ARGV3}) + elseif(check_arg STREQUAL extras) + foreach(arg ${data_arg}) + list(APPEND export ${arg}) + endforeach() + elseif(check_arg STREQUAL archives) + set(extra_libs ${data_arg}) + endif() + + string(REGEX REPLACE "[ ]+" ";" _flags "${CMAKE_SHARED_LINKER_FLAGS}") + get_filename_component(dir ${wraplib} DIRECTORY) + add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/${wraplib}-${ARCH}${CMAKE_SHARED_MODULE_SUFFIX} + COMMAND ${CMAKE_COMMAND} -E make_directory ${dir} + COMMAND ${CMAKE_C_COMPILER} + ARGS ${_flags} -Wl,--whole-archive + "${link_lib}" ${extra_libs} + -Wl,--no-whole-archive -lm + -Wl,-soname,${wraplib}-${ARCH}${CMAKE_SHARED_MODULE_SUFFIX} + -shared -o ${CMAKE_BINARY_DIR}/${wraplib}-${ARCH}${CMAKE_SHARED_MODULE_SUFFIX} + ${export} + DEPENDS ${target} wrapper.def wrapper) + + get_filename_component(libname ${wraplib} NAME_WE) + add_custom_target(wrap_${libname} ALL DEPENDS ${CMAKE_BINARY_DIR}/${wraplib}-${ARCH}${CMAKE_SHARED_MODULE_SUFFIX}) + set_target_properties(wrap_${libname} PROPERTIES FOLDER lib/wrapped) + add_dependencies(${APP_NAME_LC}-libraries wrap_${libname}) + + set(LIBRARY_FILES ${LIBRARY_FILES} ${CMAKE_BINARY_DIR}/${wraplib}-${ARCH}${CMAKE_SHARED_MODULE_SUFFIX} CACHE STRING "" FORCE) +endfunction() + +function(find_soname lib) + cmake_parse_arguments(arg "REQUIRED" "" "" ${ARGN}) + + string(TOLOWER ${lib} liblow) + if(${lib}_LDFLAGS) + set(link_lib "${${lib}_LDFLAGS}") + else() + if(IS_ABSOLUTE "${${lib}_LIBRARIES}") + set(link_lib "${${lib}_LIBRARIES}") + else() + set(link_lib -l${${lib}_LIBRARIES}) + endif() + endif() + execute_process(COMMAND ${CMAKE_C_COMPILER} -nostdlib -o /dev/null -Wl,-M ${link_lib} + COMMAND grep LOAD.*${liblow} + ERROR_QUIET + OUTPUT_VARIABLE ${lib}_FILENAME) + string(REPLACE "LOAD " "" ${lib}_FILENAME "${${lib}_FILENAME}") + string(STRIP "${${lib}_FILENAME}" ${lib}_FILENAME) + if(NOT ${lib}_FILENAME) + execute_process(COMMAND ${CMAKE_C_COMPILER} -nostdlib -o /dev/null -Wl,-t ${link_lib} + ERROR_QUIET + OUTPUT_VARIABLE _TMP_FILENAME) + string(REGEX MATCH ".*lib${liblow}.so" ${lib}_FILENAME ${_TMP_FILENAME}) + endif() + if(${lib}_FILENAME) + execute_process(COMMAND ${CMAKE_OBJDUMP} -p ${${lib}_FILENAME} + COMMAND grep SONAME.*${liblow} + ERROR_QUIET + OUTPUT_VARIABLE ${lib}_SONAME) + string(REPLACE "SONAME " "" ${lib}_SONAME ${${lib}_SONAME}) + string(STRIP ${${lib}_SONAME} ${lib}_SONAME) + if(VERBOSE) + message(STATUS "${lib} soname: ${${lib}_SONAME}") + endif() + set(${lib}_SONAME ${${lib}_SONAME} PARENT_SCOPE) + endif() + if(arg_REQUIRED AND NOT ${lib}_SONAME) + message(FATAL_ERROR "Could not find dynamically loadable library ${lib}") + endif() +endfunction() diff --git a/cmake/scripts/freebsd/PathSetup.cmake b/cmake/scripts/freebsd/PathSetup.cmake new file mode 120000 index 0000000..6786c1c --- /dev/null +++ b/cmake/scripts/freebsd/PathSetup.cmake @@ -0,0 +1 @@ +../linux/PathSetup.cmake
\ No newline at end of file diff --git a/cmake/scripts/linux/ArchSetup.cmake b/cmake/scripts/linux/ArchSetup.cmake new file mode 100644 index 0000000..4083483 --- /dev/null +++ b/cmake/scripts/linux/ArchSetup.cmake @@ -0,0 +1,207 @@ +include(cmake/scripts/linux/Linkers.txt) + +# Main cpp +set(CORE_MAIN_SOURCE ${CMAKE_SOURCE_DIR}/xbmc/platform/posix/main.cpp) + +# we always want to use GNU features if available, so set _GNU_SOURCE +set(ARCH_DEFINES -DTARGET_POSIX -DTARGET_LINUX -D_GNU_SOURCE) +set(SYSTEM_DEFINES -D__STDC_CONSTANT_MACROS -D_FILE_OFFSET_BITS=64) +set(PLATFORM_DIR platform/linux) +set(PLATFORMDEFS_DIR platform/posix) +set(CMAKE_SYSTEM_NAME Linux) +if(WITH_ARCH) + set(ARCH ${WITH_ARCH}) +else() + if(CPU STREQUAL x86_64) + set(ARCH x86_64-linux) + set(NEON False) + elseif(CPU MATCHES "i.86") + set(ARCH i486-linux) + set(NEON False) + add_options(CXX ALL_BUILDS "-msse") + elseif(CPU STREQUAL arm1176jzf-s) + set(ARCH arm) + set(NEON False) + set(NEON_FLAGS "-mcpu=arm1176jzf-s -mtune=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp") + elseif(CPU MATCHES "cortex-a7") + set(ARCH arm) + set(NEON True) + set(NEON_FLAGS "-fPIC -mcpu=cortex-a7") + elseif(CPU MATCHES "cortex-a53") + set(ARCH arm) + set(NEON True) + set(NEON_FLAGS "-fPIC -mcpu=cortex-a53") + elseif(CPU MATCHES arm) + set(ARCH arm) + set(NEON True) + elseif(CPU MATCHES aarch64 OR CPU MATCHES arm64) + set(ARCH aarch64) + set(NEON True) + elseif(CPU MATCHES riscv64) + set(ARCH riscv64) + set(NEON False) + elseif(CPU MATCHES ppc64le) + set(ARCH ppc64le) + set(NEON False) + elseif(CPU MATCHES loongarch64) + set(ARCH loongarch64) + set(NEON False) + else() + message(SEND_ERROR "Unknown CPU: ${CPU}") + endif() +endif() + +# disable the default gold linker when an alternative was enabled by the user +if(ENABLE_LLD OR ENABLE_MOLD) + set(ENABLE_GOLD OFF CACHE BOOL "" FORCE) +elseif(ENABLE_GOLD) + include(LDGOLD) +endif() +if(ENABLE_LLD) + set(ENABLE_MOLD OFF CACHE BOOL "" FORCE) + include(LLD) +elseif(ENABLE_MOLD) + set(ENABLE_LLD OFF CACHE BOOL "" FORCE) + include(MOLD) +endif() + + +if(CMAKE_BUILD_TYPE STREQUAL Release OR CMAKE_BUILD_TYPE STREQUAL MinSizeRel) + + # LTO Support, requires cmake >= 3.9 + if(CMAKE_VERSION VERSION_EQUAL 3.9.0 OR CMAKE_VERSION VERSION_GREATER 3.9.0) + option(USE_LTO "Enable link time optimization. Specify an int for number of parallel jobs" OFF) + if(USE_LTO) + include(CheckIPOSupported) + check_ipo_supported(RESULT HAVE_LTO OUTPUT _output) + if(HAVE_LTO) + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) + + # override flags to enable parallel processing + set(NJOBS 2) + if(USE_LTO MATCHES "^[0-9]+$") + set(NJOBS ${USE_LTO}) + endif() + + if(CMAKE_COMPILER_IS_GNUCXX) + # GCC + # Make sure we strip binaries in Release build + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -s") + set(CMAKE_CXX_COMPILE_OPTIONS_IPO -flto=${NJOBS} -fno-fat-lto-objects) + set(CMAKE_C_COMPILE_OPTIONS_IPO -flto=${NJOBS} -fno-fat-lto-objects) + elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + # CLANG + set(ENABLE_GOLD OFF CACHE BOOL "gold linker forced to off" FORCE) + + find_package(LLVM REQUIRED) + + if(NOT CLANG_LTO_CACHE) + set(CLANG_LTO_CACHE ${PROJECT_BINARY_DIR}/.clang-lto.cache) + endif() + if(USE_LTO STREQUAL "all") + set(NJOBS ${USE_LTO}) + endif() + + set(CMAKE_CXX_COMPILE_OPTIONS_IPO -flto=thin) + set(CMAKE_C_COMPILE_OPTIONS_IPO -flto=thin) + if(LLD_FOUND) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--thinlto-jobs=${NJOBS},--thinlto-cache-dir=${CLANG_LTO_CACHE}") + elseif(MOLD_FOUND) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--plugin-opt=jobs=${NJOBS},--plugin-opt=cache-dir=${CLANG_LTO_CACHE}") + endif() + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}") + set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}") + endif() + else() + message(WARNING "LTO optimization not supported: ${_output}") + unset(_output) + endif() + endif() + endif() +endif() + +if(KODI_DEPENDSBUILD) + # Binaries should be directly runnable from host, so include rpath to depends + set(CMAKE_INSTALL_RPATH "${DEPENDS_PATH}/lib") + set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) +endif() + +include(CheckIncludeFiles) +check_include_files("linux/udmabuf.h" HAVE_LINUX_UDMABUF) +if(HAVE_LINUX_UDMABUF) + list(APPEND ARCH_DEFINES "-DHAVE_LINUX_UDMABUF=1") +else() + message(STATUS "include/linux/udmabuf.h not found") +endif() + +check_include_files("linux/dma-heap.h" HAVE_LINUX_DMA_HEAP) +if(HAVE_LINUX_DMA_HEAP) + list(APPEND ARCH_DEFINES "-DHAVE_LINUX_DMA_HEAP=1") +else() + message(STATUS "include/linux/dma-heap.h not found") +endif() + +check_include_files("linux/dma-buf.h" HAVE_LINUX_DMA_BUF) +if(HAVE_LINUX_DMA_BUF) + list(APPEND ARCH_DEFINES "-DHAVE_LINUX_DMA_BUF=1") +else() + message(STATUS "include/linux/dma-buf.h not found") +endif() + +include(CheckSymbolExists) +set(CMAKE_REQUIRED_DEFINITIONS "-D_GNU_SOURCE") +check_symbol_exists("mkostemp" "stdlib.h" HAVE_MKOSTEMP) +set(CMAKE_REQUIRED_DEFINITIONS "") +if(HAVE_MKOSTEMP) + list(APPEND ARCH_DEFINES "-DHAVE_MKOSTEMP=1") +endif() + +set(CMAKE_REQUIRED_DEFINITIONS "-D_GNU_SOURCE") +check_symbol_exists("memfd_create" "sys/mman.h" HAVE_LINUX_MEMFD) +set(CMAKE_REQUIRED_DEFINITIONS "") +if(HAVE_LINUX_MEMFD) + list(APPEND ARCH_DEFINES "-DHAVE_LINUX_MEMFD=1") +else() + message(STATUS "memfd_create() not found") +endif() + +# Additional SYSTEM_DEFINES +list(APPEND SYSTEM_DEFINES -DHAS_POSIX_NETWORK -DHAS_LINUX_NETWORK) + +# Code Coverage +if(CMAKE_BUILD_TYPE STREQUAL Coverage) + set(COVERAGE_TEST_BINARY ${APP_NAME_LC}-test) + set(COVERAGE_SOURCE_DIR ${CMAKE_SOURCE_DIR}) + set(COVERAGE_DEPENDS "\${APP_NAME_LC}" "\${APP_NAME_LC}-test") + set(COVERAGE_EXCLUDES */test/* lib/* */lib/*) +endif() + +if(NOT "x11" IN_LIST CORE_PLATFORM_NAME_LC) + set(ENABLE_VDPAU OFF CACHE BOOL "Disabling VDPAU" FORCE) +endif() + +if("x11" IN_LIST CORE_PLATFORM_NAME_LC AND ENABLE_VDPAU) + set(ENABLE_GLX ON CACHE BOOL "Enabling GLX" FORCE) +endif() + +# Architecture endianness detector +include(TestBigEndian) +TEST_BIG_ENDIAN(ARCH_IS_BIGENDIAN) +if(ARCH_IS_BIGENDIAN) + message(STATUS "Host architecture is big-endian") + list(APPEND ARCH_DEFINES "-DWORDS_BIGENDIAN=1") +else() + message(STATUS "Host architecture is little-endian") +endif() + +# Build internal libs +if(NOT USE_INTERNAL_LIBS) + if(KODI_DEPENDSBUILD) + set(USE_INTERNAL_LIBS ON) + else() + set(USE_INTERNAL_LIBS OFF) + endif() +endif() + +# Atomic library +list(APPEND PLATFORM_REQUIRED_DEPS Atomic) diff --git a/cmake/scripts/linux/CodeCoverage.cmake b/cmake/scripts/linux/CodeCoverage.cmake new file mode 100644 index 0000000..f0a36fc --- /dev/null +++ b/cmake/scripts/linux/CodeCoverage.cmake @@ -0,0 +1,97 @@ +# - CodeCoverage +# Generate code coverage reports with LCOV and GCovr. +# +# Configuration: +# COVERAGE_SOURCE_DIR - Source root directory (default ${CMAKE_SOURCE_DIR}). +# COVERAGE_BINARY_DIR - Directory where the coverage reports (and intermediate files) +# are generated to. +# COVERAGE_EXCLUDES - List of exclude patterns (for example '*/tests/*'). +# +# The following targets will be generated: +# coverage - Builds an html report. Requires LCOV. +# coverage_xml - Builds an xml report (in Cobertura format for Jenkins). +# Requires Gcovr. +# +# Inspired by https://github.com/bilke/cmake-modules/blob/master/CodeCoverage.cmake + +# Compiler and linker setup +set(CMAKE_C_FLAGS_COVERAGE "-g -O0 --coverage" CACHE STRING + "Flags used by the C compiler during coverage builds." FORCE) +set(CMAKE_CXX_FLAGS_COVERAGE "-g -O0 --coverage" CACHE STRING + "Flags used by the C++ compiler during coverage builds." FORCE) +set(CMAKE_EXE_LINKER_FLAGS_COVERAGE "--coverage" CACHE STRING + "Flags used for linking binaries during coverage builds." FORCE) +set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE "--coverage" CACHE STRING + "Flags used by the shared libraries linker during coverage builds." FORCE) +mark_as_advanced( + CMAKE_C_FLAGS_COVERAGE CMAKE_CXX_FLAGS_COVERAGE CMAKE_EXE_LINKER_FLAGS_COVERAGE + CMAKE_SHARED_LINKER_FLAGS_COVERAGE CMAKE_STATIC_LINKER_FLAGS_COVERAGE +) + +find_program(LCOV_EXECUTABLE lcov) +find_program(GENINFO_EXECUTABLE geninfo) +find_program(GENHTML_EXECUTABLE genhtml) +find_program(GCOVR_EXECUTABLE gcovr) +mark_as_advanced(LCOV_EXECUTABLE GENINFO_EXECUTABLE GENHTML_EXECUTABLE GCOVR_EXECUTABLE) + +# Default options +if(NOT COVERAGE_SOURCE_DIR) + set(COVERAGE_SOURCE_DIR ${CMAKE_SOURCE_DIR}) +endif() +if(NOT COVERAGE_BINARY_DIR) + set(COVERAGE_BINARY_DIR ${CMAKE_BINARY_DIR}/coverage) +endif() +if(NOT COVERAGE_EXCLUDES) + set(COVERAGE_EXCLUDES) +endif() + +# Allow variables in COVERAGE_DEPENDS that are not evaluated before this file is included. +string(CONFIGURE "${COVERAGE_DEPENDS}" COVERAGE_DEPENDS) + +# Add coverage target that generates an HTML report using LCOV +if(LCOV_EXECUTABLE AND GENINFO_EXECUTABLE AND GENHTML_EXECUTABLE) + file(MAKE_DIRECTORY ${COVERAGE_BINARY_DIR}) + add_custom_target(coverage + COMMAND ${CMAKE_COMMAND} -E make_directory ${COVERAGE_BINARY_DIR} + COMMAND ${LCOV_EXECUTABLE} -z -q -d ${CMAKE_BINARY_DIR} + COMMAND ${LCOV_EXECUTABLE} -c -q -i -d ${CMAKE_BINARY_DIR} -b ${COVERAGE_SOURCE_DIR} + -o ${COVERAGE_BINARY_DIR}/${PROJECT_NAME}.coverage_base.info + COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target test || true + COMMAND ${LCOV_EXECUTABLE} -c -q -d ${CMAKE_BINARY_DIR} -b ${COVERAGE_SOURCE_DIR} + -o ${COVERAGE_BINARY_DIR}/${PROJECT_NAME}.coverage_test.info + COMMAND ${LCOV_EXECUTABLE} -a ${COVERAGE_BINARY_DIR}/${PROJECT_NAME}.coverage_base.info + -a ${COVERAGE_BINARY_DIR}/${PROJECT_NAME}.coverage_test.info + -o ${COVERAGE_BINARY_DIR}/${PROJECT_NAME}.coverage.info -q + COMMAND ${LCOV_EXECUTABLE} -q -r ${COVERAGE_BINARY_DIR}/${PROJECT_NAME}.coverage.info + /usr/include/* ${CMAKE_BINARY_DIR}/* ${COVERAGE_EXCLUDES} + -o ${COVERAGE_BINARY_DIR}/${PROJECT_NAME}.coverage.info + COMMAND ${GENHTML_EXECUTABLE} ${COVERAGE_BINARY_DIR}/${PROJECT_NAME}.coverage.info + -o ${COVERAGE_BINARY_DIR}/html -s --legend --highlight --demangle-cpp + COMMAND ${CMAKE_COMMAND} -E echo "Coverage report: file://${COVERAGE_BINARY_DIR}/html/index.html" + WORKING_DIRECTORY ${COVERAGE_BINARY_DIR} + VERBATIM + DEPENDS ${COVERAGE_DEPENDS} + COMMENT "Generate code coverage html report" + ) +else() + message(WARNING "Target coverage not available (lcov, geninfo and genhtml needed).") +endif() + +# Add coverage target that generates an XML report using Gcovr +if(GCOVR_EXECUTABLE) + file(MAKE_DIRECTORY ${COVERAGE_BINARY_DIR}) + string(REGEX REPLACE "([^;]+)" "--exclude=\"\\1\"" _gcovr_excludes "${COVERAGE_EXCLUDES}") + string(REPLACE "*" ".*" _gcovr_excludes "${_gcovr_excludes}") + add_custom_target(coverage_xml + COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target test || true + COMMAND ${GCOVR_EXECUTABLE} -x -r ${COVERAGE_SOURCE_DIR} -o ${COVERAGE_BINARY_DIR}/coverage.xml + --object-directory ${CMAKE_BINARY_DIR} ${_gcovr_excludes} ${CMAKE_BINARY_DIR} + COMMAND ${CMAKE_COMMAND} -E echo "Coverage report: file://${COVERAGE_BINARY_DIR}/coverage.xml" + WORKING_DIRECTORY ${COVERAGE_BINARY_DIR} + DEPENDS ${COVERAGE_DEPENDS} + COMMENT "Generate code coverage xml report" + ) + unset(_gcovr_excludes) +else() + message(WARNING "Target coverage_xml not available (gcovr needed).") +endif() diff --git a/cmake/scripts/linux/ExtraTargets.cmake b/cmake/scripts/linux/ExtraTargets.cmake new file mode 100644 index 0000000..4f5078b --- /dev/null +++ b/cmake/scripts/linux/ExtraTargets.cmake @@ -0,0 +1,32 @@ +# xrandr +if(X_FOUND AND XRANDR_FOUND) + find_package(X QUIET) + find_package(XRandR QUIET) + add_executable(${APP_NAME_LC}-xrandr ${CMAKE_SOURCE_DIR}/xbmc-xrandr.c) + target_link_libraries(${APP_NAME_LC}-xrandr ${SYSTEM_LDFLAGS} ${X_LIBRARIES} m ${XRANDR_LIBRARIES}) +endif() + +# WiiRemote +if(ENABLE_EVENTCLIENTS AND BLUETOOTH_FOUND) + find_package(CWiid QUIET) + find_package(GLU QUIET) + if(CWIID_FOUND AND GLU_FOUND) + add_subdirectory(${CMAKE_SOURCE_DIR}/tools/EventClients/Clients/WiiRemote build/WiiRemote) + endif() +endif() + +if("wayland" IN_LIST CORE_PLATFORM_NAME_LC) + # This cannot go into wayland.cmake since it requires the Wayland dependencies + # to already be resolved + set(PROTOCOL_XMLS "${WAYLANDPP_PROTOCOLS_DIR}/presentation-time.xml" + "${WAYLANDPP_PROTOCOLS_DIR}/xdg-shell.xml" + "${WAYLAND_PROTOCOLS_DIR}/unstable/xdg-shell/xdg-shell-unstable-v6.xml" + "${WAYLAND_PROTOCOLS_DIR}/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml") + add_custom_command(OUTPUT "${WAYLAND_EXTRA_PROTOCOL_GENERATED_DIR}/wayland-extra-protocols.hpp" "${WAYLAND_EXTRA_PROTOCOL_GENERATED_DIR}/wayland-extra-protocols.cpp" + COMMAND "${WAYLANDPP_SCANNER}" ${PROTOCOL_XMLS} "${WAYLAND_EXTRA_PROTOCOL_GENERATED_DIR}/wayland-extra-protocols.hpp" "${WAYLAND_EXTRA_PROTOCOL_GENERATED_DIR}/wayland-extra-protocols.cpp" + DEPENDS "${WAYLANDPP_SCANNER}" ${PROTOCOL_XMLS} + COMMENT "Generating wayland-protocols C++ wrappers") + + # Dummy target for dependencies + add_custom_target(generate-wayland-extra-protocols DEPENDS wayland-extra-protocols.hpp) +endif() diff --git a/cmake/scripts/linux/Install.cmake b/cmake/scripts/linux/Install.cmake new file mode 100644 index 0000000..331722c --- /dev/null +++ b/cmake/scripts/linux/Install.cmake @@ -0,0 +1,329 @@ +if(X_FOUND) + set(USE_X11 1) +else() + set(USE_X11 0) +endif() +if(OPENGL_FOUND) + set(USE_OPENGL 1) +else() + set(USE_OPENGL 0) +endif() +if(OPENGLES_FOUND) + set(USE_OPENGLES 1) +else() + set(USE_OPENGLES 0) +endif() + +# CMake config +set(APP_BINARY ${APP_NAME_LC}${APP_BINARY_SUFFIX}) +set(APP_PREFIX ${prefix}) +set(APP_LIB_DIR ${libdir}/${APP_NAME_LC}) +set(APP_DATA_DIR ${datarootdir}/${APP_NAME_LC}) +set(APP_INCLUDE_DIR ${includedir}/${APP_NAME_LC}) + +# Set XBMC_STANDALONE_SH_PULSE so we can insert PulseAudio block into kodi-standalone +if(EXISTS ${CMAKE_SOURCE_DIR}/tools/Linux/kodi-standalone.sh.pulse) + if(ENABLE_PULSEAUDIO AND PULSEAUDIO_FOUND) + file(READ "${CMAKE_SOURCE_DIR}/tools/Linux/kodi-standalone.sh.pulse" pulse_content) + set(XBMC_STANDALONE_SH_PULSE ${pulse_content}) + endif() +endif() + +# Configure startup scripts +configure_file(${CMAKE_SOURCE_DIR}/tools/Linux/kodi.sh.in + ${CORE_BUILD_DIR}/scripts/${APP_NAME_LC} @ONLY) +configure_file(${CMAKE_SOURCE_DIR}/tools/Linux/kodi-standalone.sh.in + ${CORE_BUILD_DIR}/scripts/${APP_NAME_LC}-standalone @ONLY) + +# Configure cmake files +configure_file(${CMAKE_SOURCE_DIR}/cmake/KodiConfig.cmake.in + ${CORE_BUILD_DIR}/scripts/${APP_NAME}Config.cmake @ONLY) + +# Configure xsession entry +configure_file(${CMAKE_SOURCE_DIR}/tools/Linux/kodi-xsession.desktop.in + ${CORE_BUILD_DIR}/${APP_NAME_LC}-xsession.desktop @ONLY) + +# Configure desktop entry +configure_file(${CMAKE_SOURCE_DIR}/tools/Linux/kodi.desktop.in + ${CORE_BUILD_DIR}/${APP_NAME_LC}.desktop @ONLY) + +# Configure metainfo +configure_file(${CMAKE_SOURCE_DIR}/tools/Linux/kodi.metainfo.xml.in + ${CORE_BUILD_DIR}/${APP_PACKAGE}.metainfo.xml @ONLY) + +# Install app +install(TARGETS ${APP_NAME_LC} + DESTINATION ${libdir}/${APP_NAME_LC} + COMPONENT kodi-bin) +if(X_FOUND AND XRANDR_FOUND) + install(TARGETS ${APP_NAME_LC}-xrandr + DESTINATION ${libdir}/${APP_NAME_LC} + COMPONENT kodi-bin) +endif() + +# Install scripts +install(PROGRAMS ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/scripts/${APP_NAME_LC} + ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/scripts/${APP_NAME_LC}-standalone + DESTINATION ${bindir} + COMPONENT kodi-bin) + +# Install libraries +foreach(library ${LIBRARY_FILES}) + get_filename_component(dir ${library} DIRECTORY) + string(REPLACE "${CMAKE_BINARY_DIR}/" "" dir ${dir}) + install(PROGRAMS ${library} + DESTINATION ${libdir}/${APP_NAME_LC}/${dir} + COMPONENT kodi-bin) +endforeach() + +# Install add-ons, fonts, icons, keyboard maps, keymaps, etc +# (addons, media, system, userdata folders in share/kodi/) +foreach(file ${install_data}) + get_filename_component(dir ${file} DIRECTORY) + install(FILES ${CMAKE_BINARY_DIR}/${file} + DESTINATION ${datarootdir}/${APP_NAME_LC}/${dir} + COMPONENT kodi) +endforeach() + +# Install xsession entry +install(FILES ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/${APP_NAME_LC}-xsession.desktop + RENAME ${APP_NAME_LC}.desktop + DESTINATION ${datarootdir}/xsessions + COMPONENT kodi) + +# Install desktop entry +install(FILES ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/${APP_NAME_LC}.desktop + DESTINATION ${datarootdir}/applications + COMPONENT kodi) + +# Install metainfo +install(FILES ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/${APP_PACKAGE}.metainfo.xml + DESTINATION ${datarootdir}/metainfo + COMPONENT kodi) + +# Install icons +install(FILES ${CMAKE_SOURCE_DIR}/tools/Linux/packaging/media/icon16x16.png + RENAME ${APP_NAME_LC}.png + DESTINATION ${datarootdir}/icons/hicolor/16x16/apps + COMPONENT kodi) +install(FILES ${CMAKE_SOURCE_DIR}/tools/Linux/packaging/media/icon22x22.png + RENAME ${APP_NAME_LC}.png + DESTINATION ${datarootdir}/icons/hicolor/22x22/apps + COMPONENT kodi) +install(FILES ${CMAKE_SOURCE_DIR}/tools/Linux/packaging/media/icon24x24.png + RENAME ${APP_NAME_LC}.png + DESTINATION ${datarootdir}/icons/hicolor/24x24/apps + COMPONENT kodi) +install(FILES ${CMAKE_SOURCE_DIR}/tools/Linux/packaging/media/icon32x32.png + RENAME ${APP_NAME_LC}.png + DESTINATION ${datarootdir}/icons/hicolor/32x32/apps + COMPONENT kodi) +install(FILES ${CMAKE_SOURCE_DIR}/tools/Linux/packaging/media/icon48x48.png + RENAME ${APP_NAME_LC}.png + DESTINATION ${datarootdir}/icons/hicolor/48x48/apps + COMPONENT kodi) +install(FILES ${CMAKE_SOURCE_DIR}/tools/Linux/packaging/media/icon64x64.png + RENAME ${APP_NAME_LC}.png + DESTINATION ${datarootdir}/icons/hicolor/64x64/apps + COMPONENT kodi) +install(FILES ${CMAKE_SOURCE_DIR}/tools/Linux/packaging/media/icon128x128.png + RENAME ${APP_NAME_LC}.png + DESTINATION ${datarootdir}/icons/hicolor/128x128/apps + COMPONENT kodi) +install(FILES ${CMAKE_SOURCE_DIR}/tools/Linux/packaging/media/icon256x256.png + RENAME ${APP_NAME_LC}.png + DESTINATION ${datarootdir}/icons/hicolor/256x256/apps + COMPONENT kodi) + +# Install firewalld service definitions +install(FILES ${CMAKE_SOURCE_DIR}/tools/Linux/firewalld-services/kodi-eventserver.xml + ${CMAKE_SOURCE_DIR}/tools/Linux/firewalld-services/kodi-http.xml + ${CMAKE_SOURCE_DIR}/tools/Linux/firewalld-services/kodi-jsonrpc.xml + DESTINATION ${prefix}/lib/firewalld/services + COMPONENT kodi) + +# Install docs +install(FILES ${CMAKE_SOURCE_DIR}/LICENSE.md + ${CMAKE_SOURCE_DIR}/version.txt + ${CMAKE_SOURCE_DIR}/docs/README.Linux.md + DESTINATION ${docdir} + COMPONENT kodi) + +install(FILES ${CMAKE_SOURCE_DIR}/privacy-policy.txt + DESTINATION ${datarootdir}/${APP_NAME_LC} + COMPONENT kodi) + +# Install kodi-tools-texturepacker +if(INTERNAL_TEXTUREPACKER_INSTALLABLE) + install(PROGRAMS $<TARGET_FILE:TexturePacker::TexturePacker::Installable> + DESTINATION ${bindir} + RENAME "${APP_NAME_LC}-TexturePacker" + COMPONENT kodi-tools-texturepacker) +endif() + +# Install kodi-addon-dev headers +include(${CMAKE_SOURCE_DIR}/xbmc/addons/AddonBindings.cmake) +install(DIRECTORY ${CORE_ADDON_BINDINGS_DIRS}/ + DESTINATION ${includedir}/${APP_NAME_LC} + COMPONENT kodi-addon-dev + REGEX ".txt" EXCLUDE) + +install(FILES ${CORE_ADDON_BINDINGS_FILES} + DESTINATION ${includedir}/${APP_NAME_LC} + COMPONENT kodi-addon-dev) + +# Install kodi-addon-dev add-on bindings +install(FILES ${CMAKE_SOURCE_DIR}/cmake/scripts/common/AddonHelpers.cmake + ${CMAKE_SOURCE_DIR}/cmake/scripts/common/AddOptions.cmake + ${CMAKE_SOURCE_DIR}/cmake/scripts/common/ArchSetup.cmake + ${CMAKE_SOURCE_DIR}/cmake/scripts/common/CheckCommits.cmake + ${CMAKE_SOURCE_DIR}/cmake/scripts/common/CheckTargetPlatform.cmake + ${CMAKE_SOURCE_DIR}/cmake/scripts/common/GenerateVersionedFiles.cmake + ${CMAKE_SOURCE_DIR}/cmake/scripts/common/GeneratorSetup.cmake + ${CMAKE_SOURCE_DIR}/cmake/scripts/common/HandleDepends.cmake + ${CMAKE_SOURCE_DIR}/cmake/scripts/common/Macros.cmake + ${CMAKE_SOURCE_DIR}/cmake/scripts/common/PrepareEnv.cmake + ${CMAKE_SOURCE_DIR}/cmake/scripts/common/ProjectMacros.cmake + ${CMAKE_SOURCE_DIR}/cmake/scripts/linux/PathSetup.cmake + DESTINATION ${datarootdir}/${APP_NAME_LC}/cmake + COMPONENT kodi-addon-dev) +# ${APP_NAME}Config.cmake contains architecture-specific paths so it +# should be installed in ${libdir}/${APP_NAME_LC}/${dir} +install(FILES ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/scripts/${APP_NAME}Config.cmake + DESTINATION ${libdir}/${APP_NAME_LC}/cmake + COMPONENT kodi-addon-dev) + +if(ENABLE_EVENTCLIENTS) + execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(prefix=''))" + OUTPUT_VARIABLE PYTHON_LIB_PATH OUTPUT_STRIP_TRAILING_WHITESPACE) + # Install kodi-eventclients-common BT python files + install(PROGRAMS ${CMAKE_SOURCE_DIR}/tools/EventClients/lib/python/bt/__init__.py + ${CMAKE_SOURCE_DIR}/tools/EventClients/lib/python/bt/bt.py + ${CMAKE_SOURCE_DIR}/tools/EventClients/lib/python/bt/hid.py + DESTINATION ${PYTHON_LIB_PATH}/${APP_NAME_LC}/bt + COMPONENT kodi-eventclients-common) + + # Install kodi-eventclients-common PS3 python files + install(PROGRAMS ${CMAKE_SOURCE_DIR}/tools/EventClients/lib/python/ps3/__init__.py + ${CMAKE_SOURCE_DIR}/tools/EventClients/lib/python/ps3/keymaps.py + ${CMAKE_SOURCE_DIR}/tools/EventClients/lib/python/ps3/sixaxis.py + ${CMAKE_SOURCE_DIR}/tools/EventClients/lib/python/ps3/sixpair.py + ${CMAKE_SOURCE_DIR}/tools/EventClients/lib/python/ps3/sixwatch.py + DESTINATION ${PYTHON_LIB_PATH}/${APP_NAME_LC}/ps3 + COMPONENT kodi-eventclients-common) + + # Install kodi-eventclients-common python files + file(WRITE ${CMAKE_BINARY_DIR}/packages/deb/defs.py ICON_PATH="/usr/share/pixmaps/${APP_NAME_LC}/") + install(PROGRAMS ${CMAKE_BINARY_DIR}/packages/deb/defs.py + ${CMAKE_SOURCE_DIR}/tools/EventClients/lib/python/__init__.py + ${CMAKE_SOURCE_DIR}/tools/EventClients/Clients/PS3BDRemote/ps3_remote.py + ${CMAKE_SOURCE_DIR}/tools/EventClients/lib/python/xbmcclient.py + ${CMAKE_SOURCE_DIR}/tools/EventClients/lib/python/zeroconf.py + DESTINATION ${PYTHON_LIB_PATH}/${APP_NAME_LC} + COMPONENT kodi-eventclients-common) + + # Install kodi-eventclients-common icons + install(FILES ${CMAKE_SOURCE_DIR}/tools/EventClients/icons/bluetooth.png + ${CMAKE_SOURCE_DIR}/tools/EventClients/icons/phone.png + ${CMAKE_SOURCE_DIR}/tools/EventClients/icons/mail.png + ${CMAKE_SOURCE_DIR}/tools/EventClients/icons/mouse.png + DESTINATION ${datarootdir}/pixmaps/${APP_NAME_LC} + COMPONENT kodi-eventclients-common) + + # Install kodi-eventclients-dev headers + install(FILES ${CMAKE_SOURCE_DIR}/tools/EventClients/lib/c++/xbmcclient.h + DESTINATION ${includedir}/${APP_NAME_LC} + COMPONENT kodi-eventclients-dev) + + # Install kodi-eventclients-dev C# examples + install(FILES "${CMAKE_SOURCE_DIR}/tools/EventClients/examples/c#/XBMCDemoClient1.cs" + DESTINATION "${docdir}/${APP_NAME_LC}-eventclients-dev/examples/C#" + COMPONENT kodi-eventclients-dev) + + # Install kodi-eventclients-dev C++ examples + install(FILES ${CMAKE_SOURCE_DIR}/tools/EventClients/examples/c++/example_notification.cpp + ${CMAKE_SOURCE_DIR}/tools/EventClients/examples/c++/example_log.cpp + ${CMAKE_SOURCE_DIR}/tools/EventClients/examples/c++/example_button1.cpp + ${CMAKE_SOURCE_DIR}/tools/EventClients/examples/c++/example_mouse.cpp + ${CMAKE_SOURCE_DIR}/tools/EventClients/examples/c++/example_button2.cpp + DESTINATION ${docdir}/${APP_NAME_LC}-eventclients-dev/examples/C++ + COMPONENT kodi-eventclients-dev) + + # Install kodi-eventclients-dev java examples + install(FILES ${CMAKE_SOURCE_DIR}/tools/EventClients/examples/java/XBMCDemoClient1.java + DESTINATION ${docdir}/${APP_NAME_LC}-eventclients-dev/examples/java + COMPONENT kodi-eventclients-dev) + + # Install kodi-eventclients-dev python examples + install(PROGRAMS ${CMAKE_SOURCE_DIR}/tools/EventClients/examples/python/example_mouse.py + ${CMAKE_SOURCE_DIR}/tools/EventClients/examples/python/example_button1.py + ${CMAKE_SOURCE_DIR}/tools/EventClients/examples/python/example_notification.py + ${CMAKE_SOURCE_DIR}/tools/EventClients/examples/python/example_action.py + ${CMAKE_SOURCE_DIR}/tools/EventClients/examples/python/example_button2.py + ${CMAKE_SOURCE_DIR}/tools/EventClients/examples/python/example_simple.py + DESTINATION ${docdir}/${APP_NAME_LC}-eventclients-dev/examples/python + COMPONENT kodi-eventclients-dev) + + # Install kodi-eventclients-ps3 + install(PROGRAMS ${CMAKE_SOURCE_DIR}/tools/EventClients/Clients/PS3BDRemote/ps3_remote.py + RENAME ${APP_NAME_LC}-ps3remote + DESTINATION ${bindir} + COMPONENT kodi-eventclients-ps3) + + if(BLUETOOTH_FOUND AND CWIID_FOUND AND GLU_FOUND) + # Install kodi-eventclients-wiiremote + install(PROGRAMS ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/WiiRemote/${APP_NAME_LC}-wiiremote + DESTINATION ${bindir} + COMPONENT kodi-eventclients-wiiremote) + endif() + + # Install kodi-eventclients-kodi-send + install(PROGRAMS ${CMAKE_SOURCE_DIR}/tools/EventClients/Clients/KodiSend/kodi-send.py + RENAME ${APP_NAME_LC}-send + DESTINATION ${bindir} + COMPONENT kodi-eventclients-kodi-send) +endif() + +# Install XBT skin files +foreach(texture ${XBT_FILES}) + string(REPLACE "${CMAKE_BINARY_DIR}/" "" dir ${texture}) + get_filename_component(dir ${dir} DIRECTORY) + install(FILES ${texture} + DESTINATION ${datarootdir}/${APP_NAME_LC}/${dir} + COMPONENT kodi) +endforeach() + +# Install extra stuff if it exists +if(EXISTS ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/extra-installs) + install(CODE "file(STRINGS ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/extra-installs dirs) + foreach(dir \${dirs}) + file(GLOB_RECURSE FILES RELATIVE ${CMAKE_BINARY_DIR} \${dir}/*) + foreach(file \${FILES}) + get_filename_component(dir \${file} DIRECTORY) + file(INSTALL \${file} DESTINATION ${datarootdir}/${APP_NAME_LC}/\${dir}) + endforeach() + endforeach()") +endif() + +if(NOT "$ENV{DESTDIR}" STREQUAL "") + set(DESTDIR ${CMAKE_BINARY_DIR}/$ENV{DESTDIR}) +endif() +foreach(subdir ${build_dirs}) + if(NOT subdir MATCHES kodi-platform) + string(REPLACE " " ";" subdir ${subdir}) + list(GET subdir 0 id) + install(CODE "execute_process(COMMAND ${CMAKE_MAKE_PROGRAM} -C ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/${id}/src/${id}-build install DESTDIR=${DESTDIR})") + endif() +endforeach() + +# generate packages? yes please, if everything checks out +if(CPACK_GENERATOR) + if(CPACK_GENERATOR STREQUAL DEB AND CORE_SYSTEM_NAME STREQUAL linux) + if(CMAKE_BUILD_TYPE STREQUAL Debug) + message(STATUS "DEB Generator: Build type is set to 'Debug'. Packaged binaries will be unstripped.") + endif() + include(${CMAKE_SOURCE_DIR}/cmake/cpack/CPackConfigDEB.cmake) + else() + message(FATAL_ERROR "DEB Generator: Can't configure CPack to generate Debian packages on non-linux systems.") + endif() +endif() diff --git a/cmake/scripts/linux/Linkers.txt b/cmake/scripts/linux/Linkers.txt new file mode 100644 index 0000000..c947ec4 --- /dev/null +++ b/cmake/scripts/linux/Linkers.txt @@ -0,0 +1,4 @@ +# Linkers +option(ENABLE_GOLD "Enable gnu gold linker?" ON) +option(ENABLE_LLD "Enable llvm lld linker?" OFF) +option(ENABLE_MOLD "Enable mold linker?" OFF) diff --git a/cmake/scripts/linux/Macros.cmake b/cmake/scripts/linux/Macros.cmake new file mode 100644 index 0000000..37243a7 --- /dev/null +++ b/cmake/scripts/linux/Macros.cmake @@ -0,0 +1,95 @@ +function(core_link_library lib wraplib) + set(export -Wl,--unresolved-symbols=ignore-all + `cat ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/cores/dll-loader/exports/wrapper.def` + ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/cores/dll-loader/exports/CMakeFiles/wrapper.dir/wrapper.c.o) + set(check_arg "") + if(TARGET ${lib}) + set(target ${lib}) + set(link_lib $<TARGET_FILE:${lib}>) + set(check_arg ${ARGV2}) + set(data_arg ${ARGV3}) + else() + set(target ${ARGV2}) + set(link_lib ${lib}) + set(check_arg ${ARGV3}) + set(data_arg ${ARGV4}) + endif() + + # wrapper has to be adapted in order to support coverage. + if(CMAKE_BUILD_TYPE STREQUAL Coverage) + set(export "") + endif() + + if(check_arg STREQUAL export) + set(export ${export} + -Wl,--version-script=${ARGV3}) + elseif(check_arg STREQUAL extras) + foreach(arg ${data_arg}) + list(APPEND export ${arg}) + endforeach() + elseif(check_arg STREQUAL archives) + set(extra_libs ${data_arg}) + endif() + + string(REGEX REPLACE "[ ]+" ";" _flags "${CMAKE_SHARED_LINKER_FLAGS}") + get_filename_component(dir ${wraplib} DIRECTORY) + add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/${wraplib}-${ARCH}${CMAKE_SHARED_MODULE_SUFFIX} + COMMAND ${CMAKE_COMMAND} -E make_directory ${dir} + COMMAND ${CMAKE_C_COMPILER} + ARGS ${_flags} -Wl,--whole-archive + "${link_lib}" ${extra_libs} + -Wl,--no-whole-archive -lm + -Wl,-soname,${wraplib}-${ARCH}${CMAKE_SHARED_MODULE_SUFFIX} + -shared -o ${CMAKE_BINARY_DIR}/${wraplib}-${ARCH}${CMAKE_SHARED_MODULE_SUFFIX} + ${export} + DEPENDS ${target} wrapper.def wrapper) + + get_filename_component(libname ${wraplib} NAME_WE) + add_custom_target(wrap_${libname} ALL DEPENDS ${CMAKE_BINARY_DIR}/${wraplib}-${ARCH}${CMAKE_SHARED_MODULE_SUFFIX}) + set_target_properties(wrap_${libname} PROPERTIES FOLDER lib/wrapped) + add_dependencies(${APP_NAME_LC}-libraries wrap_${libname}) + + set(LIBRARY_FILES ${LIBRARY_FILES} ${CMAKE_BINARY_DIR}/${wraplib}-${ARCH}${CMAKE_SHARED_MODULE_SUFFIX} CACHE STRING "" FORCE) +endfunction() + +function(find_soname lib) + cmake_parse_arguments(arg "REQUIRED" "" "" ${ARGN}) + + string(TOLOWER ${lib} liblow) + if(${lib}_LDFLAGS) + set(link_lib "${${lib}_LDFLAGS}") + else() + if(IS_ABSOLUTE "${${lib}_LIBRARIES}") + set(link_lib "${${lib}_LIBRARIES}") + else() + set(link_lib -l${${lib}_LIBRARIES}) + endif() + endif() + execute_process(COMMAND ${CMAKE_C_COMPILER} -nostdlib -o /dev/null -Wl,-M ${link_lib} + COMMAND grep LOAD.*${liblow} + ERROR_QUIET + OUTPUT_VARIABLE ${lib}_FILENAME) + string(REPLACE "LOAD " "" ${lib}_FILENAME "${${lib}_FILENAME}") + string(STRIP "${${lib}_FILENAME}" ${lib}_FILENAME) + if(NOT ${lib}_FILENAME) + execute_process(COMMAND ${CMAKE_C_COMPILER} -nostdlib -o /dev/null -Wl,-t ${link_lib} + OUTPUT_QUIET + ERROR_VARIABLE _TMP_FILENAME) + string(REGEX MATCH ".*lib${liblow}.so" ${lib}_FILENAME ${_TMP_FILENAME}) + endif() + if(${lib}_FILENAME) + execute_process(COMMAND ${CMAKE_OBJDUMP} -p ${${lib}_FILENAME} + COMMAND grep SONAME.*${liblow} + ERROR_QUIET + OUTPUT_VARIABLE ${lib}_SONAME) + string(REPLACE "SONAME " "" ${lib}_SONAME ${${lib}_SONAME}) + string(STRIP ${${lib}_SONAME} ${lib}_SONAME) + if(VERBOSE) + message(STATUS "${lib} soname: ${${lib}_SONAME}") + endif() + set(${lib}_SONAME ${${lib}_SONAME} PARENT_SCOPE) + endif() + if(arg_REQUIRED AND NOT ${lib}_SONAME) + message(FATAL_ERROR "Could not find dynamically loadable library ${lib}") + endif() +endfunction() diff --git a/cmake/scripts/linux/PathSetup.cmake b/cmake/scripts/linux/PathSetup.cmake new file mode 100644 index 0000000..f9f78ba --- /dev/null +++ b/cmake/scripts/linux/PathSetup.cmake @@ -0,0 +1,40 @@ +include(GNUInstallDirs) + +if(NOT prefix) + set(prefix ${CMAKE_INSTALL_PREFIX}) +else() + set(CMAKE_INSTALL_PREFIX ${prefix}) +endif() +if(NOT exec_prefix) + set(exec_prefix ${prefix}) +endif() +if(NOT libdir) + set(libdir ${CMAKE_INSTALL_FULL_LIBDIR}) +endif() +if(NOT bindir) + set(bindir ${CMAKE_INSTALL_FULL_BINDIR}) +endif() +if(NOT includedir) + set(includedir ${CMAKE_INSTALL_FULL_INCLUDEDIR}) +endif() +if(NOT datarootdir) + set(datarootdir ${CMAKE_INSTALL_FULL_DATAROOTDIR}) +endif() +if(NOT datadir) + set(datadir ${CMAKE_INSTALL_FULL_DATADIR}) +endif() +if(NOT docdir) + set(docdir ${CMAKE_INSTALL_FULL_DOCDIR}) +endif() + +list(APPEND final_message "-- PATH config --") +list(APPEND final_message "Prefix: ${prefix}") +list(APPEND final_message "Libdir: ${libdir}") +list(APPEND final_message "Bindir: ${bindir}") +list(APPEND final_message "Includedir: ${includedir}") +list(APPEND final_message "Datarootdir: ${datarootdir}") +list(APPEND final_message "Datadir: ${datadir}") +list(APPEND final_message "Docdir: ${docdir}") + +set(PATH_DEFINES -DBIN_INSTALL_PATH=\"${libdir}/${APP_NAME_LC}\" + -DINSTALL_PATH=\"${datarootdir}/${APP_NAME_LC}\") diff --git a/cmake/scripts/osx/ArchSetup.cmake b/cmake/scripts/osx/ArchSetup.cmake new file mode 100644 index 0000000..17f8583 --- /dev/null +++ b/cmake/scripts/osx/ArchSetup.cmake @@ -0,0 +1,56 @@ +if(NOT CMAKE_TOOLCHAIN_FILE) + message(FATAL_ERROR "CMAKE_TOOLCHAIN_FILE required for osx. See ${CMAKE_SOURCE_DIR}/cmake/README.md") +endif() + +list(APPEND CORE_MAIN_SOURCE ${CMAKE_SOURCE_DIR}/xbmc/platform/darwin/osx/XBMCApplication.h) + +set(ARCH_DEFINES -DTARGET_POSIX -DTARGET_DARWIN -DTARGET_DARWIN_OSX) +list(APPEND SYSTEM_DEFINES -D_REENTRANT -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE + -D__STDC_CONSTANT_MACROS) +set(PLATFORM_DIR platform/darwin) +set(PLATFORMDEFS_DIR platform/posix) +set(CMAKE_SYSTEM_NAME Darwin) +if(WITH_ARCH) + set(ARCH ${WITH_ARCH}) +else() + if(CPU STREQUAL x86_64 OR CPU STREQUAL i386) + set(ARCH x86-osx) + set(NEON False) + elseif(CPU STREQUAL arm64) + set(ARCH aarch64) + else() + message(SEND_ERROR "Unknown CPU: ${CPU}") + endif() +endif() + +# m1 macs can execute x86_64 code via rosetta +if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "arm64" AND + CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin") + set(HOST_CAN_EXECUTE_TARGET TRUE) +endif() + +set(CMAKE_OSX_ARCHITECTURES ${CPU}) + +# Additional SYSTEM_DEFINES +list(APPEND SYSTEM_DEFINES -DHAS_POSIX_NETWORK -DHAS_OSX_NETWORK -DHAS_ZEROCONF) + +list(APPEND CMAKE_SYSTEM_PREFIX_PATH ${NATIVEPREFIX}) + +list(APPEND DEPLIBS "-framework DiskArbitration" "-framework IOKit" + "-framework IOSurface" "-framework SystemConfiguration" + "-framework ApplicationServices" "-framework AppKit" + "-framework CoreAudio" "-framework AudioToolbox" + "-framework CoreGraphics" "-framework CoreMedia" + "-framework VideoToolbox" "-framework Security" + "-framework GameController" "-framework Speech" + "-framework AVFoundation") + +if(ARCH STREQUAL aarch64) + set(CMAKE_OSX_DEPLOYMENT_TARGET 11.0) +else() + set(CMAKE_OSX_DEPLOYMENT_TARGET 10.13) +endif() +set(CMAKE_XCODE_ATTRIBUTE_CLANG_LINK_OBJC_RUNTIME OFF) + +include(cmake/scripts/darwin/Macros.cmake) +enable_arc() diff --git a/cmake/scripts/osx/ExtraTargets.cmake b/cmake/scripts/osx/ExtraTargets.cmake new file mode 100644 index 0000000..28c1e74 --- /dev/null +++ b/cmake/scripts/osx/ExtraTargets.cmake @@ -0,0 +1,3 @@ +# XBMCHelper +add_subdirectory(${CMAKE_SOURCE_DIR}/tools/EventClients/Clients/OSXRemote build/XBMCHelper) +add_dependencies(${APP_NAME_LC} XBMCHelper) diff --git a/cmake/scripts/osx/Install.cmake b/cmake/scripts/osx/Install.cmake new file mode 100644 index 0000000..b4c4cc8 --- /dev/null +++ b/cmake/scripts/osx/Install.cmake @@ -0,0 +1,73 @@ +# OSX packaging + +set(PACKAGE_OUTPUT_DIR ${CMAKE_BINARY_DIR}/build/${CORE_BUILD_CONFIG}) + +configure_file(${CMAKE_SOURCE_DIR}/xbmc/platform/darwin/osx/Info.plist.in + ${CMAKE_BINARY_DIR}/xbmc/platform/darwin/osx/Info.plist @ONLY) +execute_process(COMMAND perl -p -i -e "s/r####/${APP_SCMID}/" ${CMAKE_BINARY_DIR}/xbmc/platform/darwin/osx/Info.plist) + +# Create xcode target that allows to build binary-addons. +if(CMAKE_GENERATOR MATCHES "Xcode") + if(ADDONS_TO_BUILD) + set(_addons "ADDONS=${ADDONS_TO_BUILD}") + endif() + add_custom_target(binary-addons + COMMAND $(MAKE) -C ${CMAKE_SOURCE_DIR}/tools/depends/target/binary-addons clean + COMMAND $(MAKE) -C ${CMAKE_SOURCE_DIR}/tools/depends/target/binary-addons VERBOSE=1 V=99 + INSTALL_PREFIX="${CMAKE_BINARY_DIR}/addons" CROSS_COMPILING=yes ${_addons}) + if(ENABLE_XCODE_ADDONBUILD) + add_dependencies(${APP_NAME_LC} binary-addons) + endif() + unset(_addons) +endif() + +add_custom_target(bundle + COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:${APP_NAME_LC}> ${PACKAGE_OUTPUT_DIR}/${APP_NAME} + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/DllPaths_generated.h + ${CMAKE_BINARY_DIR}/xbmc/DllPaths_generated.h + COMMAND "ACTION=build" + "TARGET_BUILD_DIR=${PACKAGE_OUTPUT_DIR}" + "TARGET_NAME=${APP_NAME}.app" + "APP_NAME=${APP_NAME}" + "SRCROOT=${CMAKE_BINARY_DIR}" + ${CMAKE_SOURCE_DIR}/tools/darwin/Support/CopyRootFiles-osx.command + COMMAND "XBMC_DEPENDS=${DEPENDS_PATH}" + "TARGET_BUILD_DIR=${PACKAGE_OUTPUT_DIR}" + "TARGET_NAME=${APP_NAME}.app" + "APP_NAME=${APP_NAME}" + "FULL_PRODUCT_NAME=${APP_NAME}.app" + "SRCROOT=${CMAKE_BINARY_DIR}" + "PYTHON_VERSION=${PYTHON_VERSION}" + ${CMAKE_SOURCE_DIR}/tools/darwin/Support/copyframeworks-osx.command) +set_target_properties(bundle PROPERTIES FOLDER "Build Utilities") +add_dependencies(bundle ${APP_NAME_LC}) + +configure_file(${CMAKE_SOURCE_DIR}/tools/darwin/packaging/osx/mkdmg-osx.sh.in + ${CMAKE_BINARY_DIR}/tools/darwin/packaging/osx/mkdmg-osx.sh @ONLY) + +string(TOLOWER ${CORE_BUILD_CONFIG} CORE_BUILD_CONFIG_LOWERCASED) +if(${CORE_BUILD_CONFIG_LOWERCASED} STREQUAL "release") + set(ALLOW_DEBUGGER "false") +else() + set(ALLOW_DEBUGGER "true") +endif() +configure_file(${CMAKE_SOURCE_DIR}/tools/darwin/packaging/osx/Kodi.entitlements.in + ${CMAKE_BINARY_DIR}/tools/darwin/packaging/osx/Kodi.entitlements @ONLY) + +add_custom_target(dmg + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/tools/darwin/packaging/osx/ + ${CMAKE_BINARY_DIR}/tools/darwin/packaging/osx/ + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/tools/darwin/packaging/media/osx/ + ${CMAKE_BINARY_DIR}/tools/darwin/packaging/media/osx/ + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/tools/darwin/Support/Codesign.command + ${CMAKE_BINARY_DIR}/tools/darwin/packaging/osx/Codesign.command + COMMAND "CODESIGNING_FOLDER_PATH=${PACKAGE_OUTPUT_DIR}/${APP_NAME}.app" + "NOTARYTOOL_KEYCHAIN_PROFILE=${NOTARYTOOL_KEYCHAIN_PROFILE}" + "NOTARYTOOL_KEYCHAIN_PATH=${NOTARYTOOL_KEYCHAIN_PATH}" + "EXPANDED_CODE_SIGN_IDENTITY_NAME=${CODE_SIGN_IDENTITY}" + "PLATFORM_NAME=${PLATFORM}" + "XCODE_BUILDTYPE=${CMAKE_CFG_INTDIR}" + ./mkdmg-osx.sh ${CORE_BUILD_CONFIG_LOWERCASED} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/tools/darwin/packaging/osx) +set_target_properties(dmg PROPERTIES FOLDER "Build Utilities") +add_dependencies(dmg bundle) diff --git a/cmake/scripts/osx/Macros.cmake b/cmake/scripts/osx/Macros.cmake new file mode 100644 index 0000000..f81e218 --- /dev/null +++ b/cmake/scripts/osx/Macros.cmake @@ -0,0 +1,119 @@ +function(core_link_library lib wraplib) + if(CMAKE_GENERATOR MATCHES "Unix Makefiles" OR CMAKE_GENERATOR STREQUAL Ninja) + set(wrapper_obj cores/dll-loader/exports/CMakeFiles/wrapper.dir/wrapper.c.o) + elseif(CMAKE_GENERATOR MATCHES "Xcode") + # CURRENT_VARIANT is an Xcode env var + # CPU is a project cmake var + # Xcode new build system (CMAKE_XCODE_BUILD_SYSTEM=12) requires the env var CURRENT_VARIANT to be passed WITHOUT brackets + # Xcode Legacy build system (CMAKE_XCODE_BUILD_SYSTEM=1) requires the env var CURRENT_VARIANT to be passed WITH brackets + if(CMAKE_XCODE_BUILD_SYSTEM STREQUAL 12) + set(wrapper_obj cores/dll-loader/exports/kodi.build/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/wrapper.build/Objects-$CURRENT_VARIANT/${CPU}/wrapper.o) + else() + set(wrapper_obj cores/dll-loader/exports/kodi.build/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/wrapper.build/Objects-$(CURRENT_VARIANT)/${CPU}/wrapper.o) + endif() + else() + message(FATAL_ERROR "Unsupported generator in core_link_library") + endif() + + set(export -bundle -undefined dynamic_lookup -read_only_relocs suppress + -Wl,-alias_list,${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/cores/dll-loader/exports/wrapper.def + ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/${wrapper_obj}) + set(extension ${CMAKE_SHARED_MODULE_SUFFIX}) + set(check_arg "") + if(TARGET ${lib}) + set(target ${lib}) + set(link_lib $<TARGET_FILE:${lib}>) + set(check_arg ${ARGV2}) + set(data_arg ${ARGV3}) + + else() + set(target ${ARGV2}) + set(link_lib ${lib}) + set(check_arg ${ARGV3}) + set(data_arg ${ARGV4}) + endif() + if(check_arg STREQUAL export) + set(export ${export} + -Wl,--version-script=${ARGV3}) + elseif(check_arg STREQUAL extras) + foreach(arg ${data_arg}) + list(APPEND export ${arg}) + endforeach() + elseif(check_arg STREQUAL archives) + set(extra_libs ${data_arg}) + endif() + get_filename_component(dir ${wraplib} DIRECTORY) + + # We can't simply pass the linker flags to the args section of the custom command + # because cmake will add quotes around it (and the linker will fail due to those). + # We need to do this handstand first ... + string(REPLACE " " ";" CUSTOM_COMMAND_ARGS_LDFLAGS ${CMAKE_SHARED_LINKER_FLAGS}) + + add_custom_command(OUTPUT ${wraplib}-${ARCH}${extension} + COMMAND ${CMAKE_COMMAND} -E make_directory ${dir} + COMMAND ${CMAKE_C_COMPILER} + ARGS ${CUSTOM_COMMAND_ARGS_LDFLAGS} ${export} -Wl,-force_load ${link_lib} ${extra_libs} + -o ${CMAKE_BINARY_DIR}/${wraplib}-${ARCH}${extension} + DEPENDS ${target} wrapper.def wrapper) + + get_filename_component(libname ${wraplib} NAME_WE) + add_custom_target(wrap_${libname} ALL DEPENDS ${wraplib}-${ARCH}${extension}) + set_target_properties(wrap_${libname} PROPERTIES FOLDER lib/wrapped) + add_dependencies(${APP_NAME_LC}-libraries wrap_${libname}) + + set(LIBRARY_FILES ${LIBRARY_FILES} ${CMAKE_BINARY_DIR}/${wraplib}-${ARCH}${extension} CACHE STRING "" FORCE) +endfunction() + +function(find_soname lib) + cmake_parse_arguments(arg "REQUIRED" "" "" ${ARGN}) + + string(TOLOWER ${lib} liblow) + if(${lib}_LDFLAGS) + set(link_lib "${${lib}_LDFLAGS}") + else() + set(link_lib "${${lib}_LIBRARIES}") + endif() + + execute_process(COMMAND ${CMAKE_C_COMPILER} -print-search-dirs + COMMAND fgrep libraries: + COMMAND sed "s/[^=]*=\\(.*\\)/\\1/" + COMMAND sed "s/:/ /g" + ERROR_QUIET + OUTPUT_VARIABLE cc_lib_path + OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process(COMMAND echo ${link_lib} + COMMAND sed "s/-L[ ]*//g" + COMMAND sed "s/-l[^ ]*//g" + ERROR_QUIET + OUTPUT_VARIABLE env_lib_path + OUTPUT_STRIP_TRAILING_WHITESPACE) + + foreach(path ${cc_lib_path} ${env_lib_path}) + if(IS_DIRECTORY ${path}) + execute_process(COMMAND ls -- ${path}/lib${liblow}.dylib + ERROR_QUIET + OUTPUT_VARIABLE lib_file + OUTPUT_STRIP_TRAILING_WHITESPACE) + else() + set(lib_file ${path}) + endif() + if(lib_file) + # we want the path/name that is embedded in the dylib + execute_process(COMMAND otool -L ${lib_file} + COMMAND grep -v lib${liblow}.dylib + COMMAND grep ${liblow} + COMMAND awk "{V=1; print $V}" + ERROR_QUIET + OUTPUT_VARIABLE filename + OUTPUT_STRIP_TRAILING_WHITESPACE) + get_filename_component(${lib}_SONAME "${filename}" NAME) + if(VERBOSE) + message(STATUS "${lib} soname: ${${lib}_SONAME}") + endif() + endif() + endforeach() + if(arg_REQUIRED AND NOT ${lib}_SONAME) + message(FATAL_ERROR "Could not find dynamically loadable library ${lib}") + endif() + set(${lib}_SONAME ${${lib}_SONAME} PARENT_SCOPE) +endfunction() diff --git a/cmake/scripts/osx/PathSetup.cmake b/cmake/scripts/osx/PathSetup.cmake new file mode 100644 index 0000000..ddb4176 --- /dev/null +++ b/cmake/scripts/osx/PathSetup.cmake @@ -0,0 +1,32 @@ +if(NOT prefix) + set(prefix ${DEPENDS_PATH}) +endif() +if(NOT exec_prefix) + set(exec_prefix ${prefix}) +endif() +if(NOT libdir) + set(libdir ${prefix}/lib) +endif() +if(NOT bindir) + set(bindir ${prefix}/bin) +endif() +if(NOT includedir) + set(includedir ${prefix}/include) +endif() +if(NOT datarootdir) + set(datarootdir ${prefix}/share) +endif() +if(NOT datadir) + set(datadir ${datarootdir}) +endif() + +list(APPEND final_message "-- PATH config --") +list(APPEND final_message "Prefix: ${prefix}") +list(APPEND final_message "Libdir: ${libdir}") +list(APPEND final_message "Bindir: ${bindir}") +list(APPEND final_message "Includedir: ${includedir}") +list(APPEND final_message "Datarootdir: ${datarootdir}") +list(APPEND final_message "Datadir: ${datadir}") + +set(PATH_DEFINES -DBIN_INSTALL_PATH=\"${libdir}/${APP_NAME_LC}\" + -DINSTALL_PATH=\"${datarootdir}/${APP_NAME_LC}\") diff --git a/cmake/scripts/windows/ArchSetup.cmake b/cmake/scripts/windows/ArchSetup.cmake new file mode 100644 index 0000000..f0f8a08 --- /dev/null +++ b/cmake/scripts/windows/ArchSetup.cmake @@ -0,0 +1,128 @@ +# Minimum SDK version we support +set(VS_MINIMUM_SDK_VERSION 10.0.14393.0) + +if(CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION VERSION_LESS VS_MINIMUM_SDK_VERSION) + message(FATAL_ERROR "Detected Windows SDK version is ${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}.\n" + "Windows SDK ${VS_MINIMUM_SDK_VERSION} or higher is required.\n" + "INFO: Windows SDKs can be installed from the Visual Studio installer.") +endif() + +# -------- Host Settings --------- + +set(_gentoolset ${CMAKE_GENERATOR_TOOLSET}) +string(REPLACE "host=" "" HOSTTOOLSET "${_gentoolset}") +unset(_gentoolset) + +# -------- Architecture settings --------- + +if(CMAKE_SIZEOF_VOID_P EQUAL 4) + set(ARCH win32) + set(SDK_TARGET_ARCH x86) +elseif(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(ARCH x64) + set(SDK_TARGET_ARCH x64) +endif() + + +# -------- Paths (mainly for find_package) --------- + +set(PLATFORM_DIR platform/win32) +set(APP_RENDER_SYSTEM dx11) + +set(CORE_MAIN_SOURCE ${CMAKE_SOURCE_DIR}/xbmc/platform/win32/WinMain.cpp) + +# Precompiled headers fail with per target output directory. (needs CMake 3.1) +set(PRECOMPILEDHEADER_DIR ${PROJECT_BINARY_DIR}/${CORE_BUILD_CONFIG}/objs) +set(CMAKE_SYSTEM_NAME Windows) +set(DEPS_FOLDER_RELATIVE project/BuildDependencies) +set(NATIVEPREFIX ${CMAKE_SOURCE_DIR}/${DEPS_FOLDER_RELATIVE}/tools) +set(DEPENDS_PATH ${CMAKE_SOURCE_DIR}/${DEPS_FOLDER_RELATIVE}/${ARCH}) +set(MINGW_LIBS_DIR ${CMAKE_SOURCE_DIR}/${DEPS_FOLDER_RELATIVE}/mingwlibs/${ARCH}) + +# mingw libs +list(APPEND CMAKE_PREFIX_PATH ${MINGW_LIBS_DIR}) +list(APPEND CMAKE_LIBRARY_PATH ${MINGW_LIBS_DIR}/bin) + +if(NOT TARBALL_DIR) + set(TARBALL_DIR "${CMAKE_SOURCE_DIR}/project/BuildDependencies/downloads") +endif() + +# -------- Compiler options --------- + +add_options(CXX ALL_BUILDS "/wd\"4996\"") +set(ARCH_DEFINES -D_WINDOWS -DTARGET_WINDOWS -DTARGET_WINDOWS_DESKTOP -D__SSE__ -D__SSE2__) +set(SYSTEM_DEFINES -DWIN32_LEAN_AND_MEAN -DNOMINMAX -DHAS_DX -D__STDC_CONSTANT_MACROS + -DTAGLIB_STATIC -DNPT_CONFIG_ENABLE_LOGGING + -DPLT_HTTP_DEFAULT_USER_AGENT="UPnP/1.0 DLNADOC/1.50 Kodi" + -DPLT_HTTP_DEFAULT_SERVER="UPnP/1.0 DLNADOC/1.50 Kodi" + -DUNICODE -D_UNICODE + -DFRIBIDI_STATIC + $<$<CONFIG:Debug>:-DD3D_DEBUG_INFO>) + +# Additional SYSTEM_DEFINES +list(APPEND SYSTEM_DEFINES -DHAS_WIN32_NETWORK -DHAS_FILESYSTEM_SMB) + +# The /MP option enables /FS by default. +if(CMAKE_GENERATOR MATCHES "Visual Studio") + if(DEFINED ENV{MAXTHREADS}) + set(MP_FLAG "/MP$ENV{MAXTHREADS}") + else() + set(MP_FLAG "/MP") + endif() + + set(CMAKE_CXX_FLAGS "/permissive- ${MP_FLAG} ${CMAKE_CXX_FLAGS}") +endif() + +# Google Test needs to use shared version of runtime libraries +set(gtest_force_shared_crt ON CACHE STRING "" FORCE) + + +# -------- Linker options --------- + +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO") + +# For #pragma comment(lib X) +# TODO: It would certainly be better to handle these libraries via CMake modules. +link_directories(${DEPENDS_PATH}/lib) + +# Additional libraries +list(APPEND DEPLIBS bcrypt.lib d3d11.lib DInput8.lib DSound.lib winmm.lib Mpr.lib Iphlpapi.lib WS2_32.lib + PowrProf.lib setupapi.lib Shlwapi.lib dwmapi.lib dxguid.lib DelayImp.lib version.lib + crypt32.lib) + +# NODEFAULTLIB option +set(_nodefaultlibs_RELEASE libcmt) +set(_nodefaultlibs_DEBUG libcmt msvcrt) +foreach(_lib ${_nodefaultlibs_RELEASE}) + set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /NODEFAULTLIB:\"${_lib}\"") +endforeach() +foreach(_lib ${_nodefaultlibs_DEBUG}) + set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} /NODEFAULTLIB:\"${_lib}\"") +endforeach() + +# DELAYLOAD option +set(_delayloadlibs zlib.dll libmariadb.dll libxslt.dll dnssd.dll dwmapi.dll sqlite3.dll + d3dcompiler_47.dll) +foreach(_lib ${_delayloadlibs}) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /DELAYLOAD:\"${_lib}\"") +endforeach() + +# Make the Release version create a PDB +set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Zi") +# Minimize the size or the resulting DLLs +set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG /OPT:REF") + + +# -------- Visual Studio options --------- + +if(CMAKE_GENERATOR MATCHES "Visual Studio") + set_property(GLOBAL PROPERTY USE_FOLDERS ON) + + # Generate a batch file that opens Visual Studio with the necessary env variables set. + file(WRITE ${CMAKE_BINARY_DIR}/kodi-sln.bat + "@echo off\n" + "set KODI_HOME=%~dp0\n" + "set PATH=%~dp0\\system\n" + "set PreferredToolArchitecture=x64\n" + "start %~dp0\\${PROJECT_NAME}.sln") +endif() diff --git a/cmake/scripts/windows/CFlagOverrides.cmake b/cmake/scripts/windows/CFlagOverrides.cmake new file mode 100644 index 0000000..cd96689 --- /dev/null +++ b/cmake/scripts/windows/CFlagOverrides.cmake @@ -0,0 +1,10 @@ +if(MSVC) + if(DEFINED ENV{MAXTHREADS}) + set(MP_FLAG "/MP$ENV{MAXTHREADS}") + else() + set(MP_FLAG "/MP") + endif() + set(CMAKE_C_FLAGS "/D_UNICODE /DUNICODE /DRPC_USE_NATIVE_WCHAR ${MP_FLAG} /DWIN32 /D_WINDOWS /W3 /Zi /arch:SSE2") + set(CMAKE_C_FLAGS_DEBUG "/D_DEBUG /MDd /Ob0 /Od /RTC1 /D_ITERATOR_DEBUG_LEVEL=0") + set(CMAKE_C_FLAGS_RELEASE "/MD /Ox /Ob2 /Oi /Ot /Oy /GL /DNDEBUG") +endif() diff --git a/cmake/scripts/windows/CXXFlagOverrides.cmake b/cmake/scripts/windows/CXXFlagOverrides.cmake new file mode 100644 index 0000000..72df9de --- /dev/null +++ b/cmake/scripts/windows/CXXFlagOverrides.cmake @@ -0,0 +1,10 @@ +if(MSVC) + if(DEFINED ENV{MAXTHREADS}) + set(MP_FLAG "/MP$ENV{MAXTHREADS}") + else() + set(MP_FLAG "/MP") + endif() + set(CMAKE_CXX_FLAGS "/D_UNICODE /DUNICODE /DRPC_USE_NATIVE_WCHAR ${MP_FLAG} /DWIN32 /D_WINDOWS /W3 /GR /Zi /EHsc /arch:SSE2") + set(CMAKE_CXX_FLAGS_DEBUG "/D_DEBUG /MDd /Ob0 /Od /RTC1 /D_ITERATOR_DEBUG_LEVEL=0") + set(CMAKE_CXX_FLAGS_RELEASE "/MD /Ox /Ob2 /Oi /Ot /Oy /GL /DNDEBUG") +endif() diff --git a/cmake/scripts/windows/Install.cmake b/cmake/scripts/windows/Install.cmake new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/cmake/scripts/windows/Install.cmake diff --git a/cmake/scripts/windows/Macros.cmake b/cmake/scripts/windows/Macros.cmake new file mode 100644 index 0000000..2d3500d --- /dev/null +++ b/cmake/scripts/windows/Macros.cmake @@ -0,0 +1,66 @@ +function(core_link_library lib wraplib) + message(AUTHOR_WARNING "core_link_library is not compatible with windows.") +endfunction() + +function(find_soname lib) + # Windows uses hardcoded dlls in xbmc/DllPaths_win32.h. + # Therefore the output of this function is unused. +endfunction() + +# Add precompiled header to target +# Arguments: +# target existing target that will be set up to compile with a precompiled header +# pch_header the precompiled header file +# pch_source the precompiled header source file +# Optional Arguments: +# PCH_TARGET build precompiled header as separate target with the given name +# so that the same precompiled header can be used for multiple libraries +# EXCLUDE_SOURCES if not all target sources shall use the precompiled header, +# the relevant files can be listed here +# On return: +# Compiles the pch_source into a precompiled header and adds the header to +# the given target +function(add_precompiled_header target pch_header pch_source) + cmake_parse_arguments(PCH "" "PCH_TARGET" "EXCLUDE_SOURCES" ${ARGN}) + + if(PCH_PCH_TARGET) + set(pch_binary ${PRECOMPILEDHEADER_DIR}/${PCH_PCH_TARGET}.pch) + else() + set(pch_binary ${PRECOMPILEDHEADER_DIR}/${target}.pch) + endif() + + # Set compile options and dependency for sources + get_target_property(sources ${target} SOURCES) + list(REMOVE_ITEM sources ${pch_source}) + foreach(exclude_source IN LISTS PCH_EXCLUDE_SOURCES) + list(REMOVE_ITEM sources ${exclude_source}) + endforeach() + set_source_files_properties(${sources} + PROPERTIES COMPILE_FLAGS "/Yu\"${pch_header}\" /Fp\"${pch_binary}\" /FI\"${pch_header}\"" + OBJECT_DEPENDS "${pch_binary}") + + # Set compile options for precompiled header + if(NOT PCH_PCH_TARGET OR NOT TARGET ${PCH_PCH_TARGET}_pch) + set_source_files_properties(${pch_source} + PROPERTIES COMPILE_FLAGS "/Yc\"${pch_header}\" /Fp\"${pch_binary}\"" + OBJECT_OUTPUTS "${pch_binary}") + endif() + + # Compile precompiled header + if(PCH_PCH_TARGET) + # As own target for usage in multiple libraries + if(NOT TARGET ${PCH_PCH_TARGET}_pch) + add_library(${PCH_PCH_TARGET}_pch STATIC ${pch_source}) + set_target_properties(${PCH_PCH_TARGET}_pch PROPERTIES COMPILE_PDB_NAME vc140 + COMPILE_PDB_OUTPUT_DIRECTORY ${PRECOMPILEDHEADER_DIR} + FOLDER "Build Utilities") + endif() + # From VS2012 onwards, precompiled headers have to be linked against (LNK2011). + target_link_libraries(${target} PUBLIC ${PCH_PCH_TARGET}_pch) + set_target_properties(${target} PROPERTIES COMPILE_PDB_NAME vc140 + COMPILE_PDB_OUTPUT_DIRECTORY ${PRECOMPILEDHEADER_DIR}) + else() + # As part of the target + target_sources(${target} PRIVATE ${pch_source}) + endif() +endfunction() diff --git a/cmake/scripts/windows/PathSetup.cmake b/cmake/scripts/windows/PathSetup.cmake new file mode 100644 index 0000000..f6defde --- /dev/null +++ b/cmake/scripts/windows/PathSetup.cmake @@ -0,0 +1,34 @@ +if(NOT prefix) + set(prefix ${CMAKE_INSTALL_PREFIX}) +else() + set(CMAKE_INSTALL_PREFIX ${prefix}) +endif() +if(NOT exec_prefix) + set(exec_prefix ${prefix}) +endif() +if(NOT libdir) + set(libdir ${prefix}/lib) +endif() +if(NOT bindir) + set(bindir ${prefix}/bin) +endif() +if(NOT includedir) + set(includedir ${prefix}/include) +endif() +if(NOT datarootdir) + set(datarootdir ${prefix}/share) +endif() +if(NOT datadir) + set(datadir ${datarootdir}) +endif() + +list(APPEND final_message "-- PATH config --") +list(APPEND final_message "Prefix: ${prefix}") +list(APPEND final_message "Libdir: ${libdir}") +list(APPEND final_message "Bindir: ${bindir}") +list(APPEND final_message "Includedir: ${includedir}") +list(APPEND final_message "Datarootdir: ${datarootdir}") +list(APPEND final_message "Datadir: ${datadir}") + +set(PATH_DEFINES -DBIN_INSTALL_PATH=\"${libdir}/${APP_NAME_LC}\" + -DINSTALL_PATH=\"${datarootdir}/${APP_NAME_LC}\") diff --git a/cmake/scripts/windows/tools/patch.cmake b/cmake/scripts/windows/tools/patch.cmake new file mode 100644 index 0000000..451fc66 --- /dev/null +++ b/cmake/scripts/windows/tools/patch.cmake @@ -0,0 +1,50 @@ +# 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_FOUND NAMES patch.exe HINTS ${GIT_DIR} PATH_SUFFIXES usr/bin) + +if(PATCH_FOUND) + message(STATUS "patch utility found at ${PATCH_FOUND}") +else() + set(PATCH_ARCHIVE_NAME "patch-2.7.6-bin") + set(PATCH_ARCHIVE "${PATCH_ARCHIVE_NAME}.zip") + set(PATCH_URL "${KODI_MIRROR}/build-deps/win32/${PATCH_ARCHIVE}") + set(PATCH_DOWNLOAD ${BUILD_DIR}/download/${PATCH_ARCHIVE}) + + # download the archive containing patch.exe + message(STATUS "Downloading patch utility from ${PATCH_URL}...") + file(DOWNLOAD "${PATCH_URL}" "${PATCH_DOWNLOAD}" STATUS PATCH_DL_STATUS LOG PATCH_LOG SHOW_PROGRESS) + list(GET PATCH_DL_STATUS 0 PATCH_RETCODE) + if(NOT PATCH_RETCODE EQUAL 0) + message(FATAL_ERROR "ERROR downloading ${PATCH_URL} - status: ${PATCH_DL_STATUS} log: ${PATCH_LOG}") + endif() + + # extract the archive containing patch.exe + execute_process(COMMAND ${CMAKE_COMMAND} -E tar xzvf ${PATCH_DOWNLOAD} + WORKING_DIRECTORY ${BUILD_DIR}) + + # make sure the extraction worked and that patch.exe is there + set(PATCH_PATH ${BUILD_DIR}/${PATCH_ARCHIVE_NAME}) + set(PATCH_BINARY_PATH ${PATCH_PATH}/bin/patch.exe) + if(NOT EXISTS ${PATCH_PATH} OR NOT EXISTS ${PATCH_BINARY_PATH}) + message(FATAL_ERROR "ERROR extracting patch utility from ${PATCH_PATH}") + endif() + + # copy patch.exe into the output directory + file(INSTALL ${PATCH_BINARY_PATH} DESTINATION ${ADDON_DEPENDS_PATH}/bin) + # copy patch depends + file(GLOB PATCH_BINARIES ${PATCH_PATH}/bin/*.dll) + if(NOT "${PATCH_BINARIES}" STREQUAL "") + file(INSTALL ${PATCH_BINARIES} DESTINATION ${ADDON_DEPENDS_PATH}/bin) + endif() + + # make sure that cmake can find the copied patch.exe + find_program(PATCH_FOUND NAMES patch patch.exe) + if(NOT PATCH_FOUND) + message(FATAL_ERROR "ERROR installing patch utility from ${PATCH_BINARY_PATH} to ${ADDON_DEPENDS_PATH}/bin") + endif() +endif() diff --git a/cmake/scripts/windowsstore/ArchSetup.cmake b/cmake/scripts/windowsstore/ArchSetup.cmake new file mode 100644 index 0000000..f71ca7a --- /dev/null +++ b/cmake/scripts/windowsstore/ArchSetup.cmake @@ -0,0 +1,127 @@ +# Minimum SDK version we support +set(VS_MINIMUM_SDK_VERSION 10.0.17763.0) + +if(CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION VERSION_LESS VS_MINIMUM_SDK_VERSION) + message(FATAL_ERROR "Detected Windows SDK version is ${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}.\n" + "Windows SDK ${VS_MINIMUM_SDK_VERSION} or higher is required.\n" + "INFO: Windows SDKs can be installed from the Visual Studio installer.") +endif() + +# -------- Host Settings --------- + +set(_gentoolset ${CMAKE_GENERATOR_TOOLSET}) +string(REPLACE "host=" "" HOSTTOOLSET ${_gentoolset}) +unset(_gentoolset) + +# -------- Architecture settings --------- + +check_symbol_exists(_X86_ "Windows.h" _X86_) +check_symbol_exists(_AMD64_ "Windows.h" _AMD64_) +check_symbol_exists(_ARM_ "Windows.h" _ARM_) + +if(_X86_) + set(ARCH win32) + set(SDK_TARGET_ARCH x86) +elseif(_AMD64_) + set(ARCH x64) + set(SDK_TARGET_ARCH x64) +elseif(_ARM_) + set(ARCH arm) + set(SDK_TARGET_ARCH arm) +else() + message(FATAL_ERROR "Unsupported architecture") +endif() + +unset(_X86_) +unset(_AMD64_) +unset(_ARM_) + +# -------- Paths (mainly for find_package) --------- + +set(PLATFORM_DIR platform/win32) +set(APP_RENDER_SYSTEM dx11) +set(CORE_MAIN_SOURCE ${CMAKE_SOURCE_DIR}/xbmc/platform/win10/main.cpp) + +# Precompiled headers fail with per target output directory. (needs CMake 3.1) +set(PRECOMPILEDHEADER_DIR ${PROJECT_BINARY_DIR}/${CORE_BUILD_CONFIG}/objs) + +set(CMAKE_SYSTEM_NAME WindowsStore) +set(CORE_SYSTEM_NAME "windowsstore") +set(PACKAGE_GUID "281d668b-5739-4abd-b3c2-ed1cda572ed2") +set(APP_MANIFEST_NAME package.appxmanifest) +set(DEPS_FOLDER_RELATIVE project/BuildDependencies) + +set(NATIVEPREFIX ${CMAKE_SOURCE_DIR}/${DEPS_FOLDER_RELATIVE}/tools) +set(DEPENDS_PATH ${CMAKE_SOURCE_DIR}/${DEPS_FOLDER_RELATIVE}/win10-${ARCH}) +set(MINGW_LIBS_DIR ${CMAKE_SOURCE_DIR}/${DEPS_FOLDER_RELATIVE}/mingwlibs/win10-${ARCH}) + +# mingw libs +list(APPEND CMAKE_PREFIX_PATH ${MINGW_LIBS_DIR}) +list(APPEND CMAKE_LIBRARY_PATH ${MINGW_LIBS_DIR}/bin) + +if(NOT TARBALL_DIR) + set(TARBALL_DIR "${CMAKE_SOURCE_DIR}/project/BuildDependencies/downloads") +endif() + +# -------- Compiler options --------- + +add_options(CXX ALL_BUILDS "/wd\"4996\"") +add_options(CXX ALL_BUILDS "/wd\"4146\"") +add_options(CXX ALL_BUILDS "/wd\"4251\"") +add_options(CXX ALL_BUILDS "/wd\"4668\"") +add_options(CXX ALL_BUILDS "/wd\"5033\"") +set(ARCH_DEFINES -D_WINDOWS -DTARGET_WINDOWS -DTARGET_WINDOWS_STORE -DXBMC_EXPORT -DMS_UWP -DMS_STORE) +if(NOT SDK_TARGET_ARCH STREQUAL arm) + list(APPEND ARCH_DEFINES -D__SSE__ -D__SSE2__) +endif() +set(SYSTEM_DEFINES -DWIN32_LEAN_AND_MEAN -DNOMINMAX -DHAS_DX -D__STDC_CONSTANT_MACROS + -DTAGLIB_STATIC -DNPT_CONFIG_ENABLE_LOGGING + -DPLT_HTTP_DEFAULT_USER_AGENT="UPnP/1.0 DLNADOC/1.50 Kodi" + -DPLT_HTTP_DEFAULT_SERVER="UPnP/1.0 DLNADOC/1.50 Kodi" + -DUNICODE -D_UNICODE + -DFRIBIDI_STATIC + $<$<CONFIG:Debug>:-DD3D_DEBUG_INFO>) + +# Additional SYSTEM_DEFINES +list(APPEND SYSTEM_DEFINES -DHAS_WIN10_NETWORK) + +# The /MP option enables /FS by default. +if(DEFINED ENV{MAXTHREADS}) + set(MP_FLAG "/MP$ENV{MAXTHREADS}") +else() + set(MP_FLAG "/MP") +endif() +set(CMAKE_CXX_FLAGS "${MP_FLAG} ${CMAKE_CXX_FLAGS} /EHsc /await /permissive-") +# Google Test needs to use shared version of runtime libraries +set(gtest_force_shared_crt ON CACHE STRING "" FORCE) + + +# -------- Linker options --------- + +# For #pragma comment(lib X) +# TODO: It would certainly be better to handle these libraries via CMake modules. +link_directories(${MINGW_LIBS_DIR}/lib + ${DEPENDS_PATH}/lib) + +list(APPEND DEPLIBS bcrypt.lib d3d11.lib WS2_32.lib dxguid.lib dloadhelper.lib WindowsApp.lib) + +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /WINMD:NO") +set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} /NODEFAULTLIB:msvcrt /DEBUG:FASTLINK /OPT:NOREF /OPT:NOICF") + +# Make the Release version create a PDB +set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Zi") +# Minimize the size or the resulting DLLs +set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG /OPT:REF") +# remove warning +set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /ignore:4264") + + +# -------- Visual Studio options --------- + +if(CMAKE_GENERATOR MATCHES "Visual Studio") + set_property(GLOBAL PROPERTY USE_FOLDERS ON) +endif() + +# -------- Build options --------- + +set(ENABLE_OPTICAL OFF CACHE BOOL "" FORCE) diff --git a/cmake/scripts/windowsstore/CFlagOverrides.cmake b/cmake/scripts/windowsstore/CFlagOverrides.cmake new file mode 100644 index 0000000..ab2f59c --- /dev/null +++ b/cmake/scripts/windowsstore/CFlagOverrides.cmake @@ -0,0 +1,17 @@ +# compiler flags +if(DEFINED ENV{MAXTHREADS}) + set(MP_FLAG "/MP$ENV{MAXTHREADS}") +else() + set(MP_FLAG "/MP") +endif() +string(APPEND CMAKE_C_FLAGS_INIT " /D_UNICODE /DUNICODE ${MP_FLAG} /DWIN32 /D_WINDOWS /W3 /Zi /DTARGET_WINDOWS") +string(APPEND CMAKE_C_FLAGS_INIT " /DWINAPI_FAMILY=2 /DTARGET_WINDOWS_STORE /D_WINSOCK_DEPRECATED_NO_WARNINGS /D_CRT_NONSTDC_NO_DEPRECATE") +string(APPEND CMAKE_C_FLAGS_DEBUG_INIT " /D_DEBUG /MDd /Ob0 /Od /RTC1 /D_ITERATOR_DEBUG_LEVEL=0") +string(APPEND CMAKE_C_FLAGS_RELEASE_INIT " /MD /Ox /Ob2 /Oi /Ot /Oy /GL /DNDEBUG") +# linker flags +string(APPEND CMAKE_SHARED_LINKER_FLAGS_INIT " /DYNAMICBASE /NXCOMPAT /APPCONTAINER") +# win32 specific flags +if("$ENV{Platform}" STREQUAL X86) + string(APPEND CMAKE_C_FLAGS_INIT " /arch:SSE2") + string(APPEND CMAKE_SHARED_LINKER_FLAGS_INIT " /SAFESEH") +endif() diff --git a/cmake/scripts/windowsstore/CXXFlagOverrides.cmake b/cmake/scripts/windowsstore/CXXFlagOverrides.cmake new file mode 100644 index 0000000..4ae3ac3 --- /dev/null +++ b/cmake/scripts/windowsstore/CXXFlagOverrides.cmake @@ -0,0 +1,17 @@ +# compiler flags +if(DEFINED ENV{MAXTHREADS}) + set(MP_FLAG "/MP$ENV{MAXTHREADS}") +else() + set(MP_FLAG "/MP") +endif() +string(APPEND CMAKE_CXX_FLAGS_INIT " /D_UNICODE /DUNICODE ${MP_FLAG} /DWIN32 /D_WINDOWS /W3 /GR /Zi /EHsc /DTARGET_WINDOWS") +string(APPEND CMAKE_CXX_FLAGS_INIT " /DWINAPI_FAMILY=2 /DTARGET_WINDOWS_STORE /D_WINSOCK_DEPRECATED_NO_WARNINGS /D_CRT_NONSTDC_NO_DEPRECATE") +string(APPEND CMAKE_CXX_FLAGS_DEBUG_INIT " /D_DEBUG /MDd /Ob0 /Od /RTC1 /D_ITERATOR_DEBUG_LEVEL=0") +string(APPEND CMAKE_CXX_FLAGS_RELEASE_INIT " /MD /Ox /Ob2 /Oi /Ot /Oy /GL /DNDEBUG") +# linker flags +string(APPEND CMAKE_SHARED_LINKER_FLAGS_INIT " /DYNAMICBASE /NXCOMPAT /APPCONTAINER") +# win32 specific flags +if("$ENV{Platform}" STREQUAL X86) + string(APPEND CMAKE_CXX_FLAGS_INIT " /arch:SSE2") + string(APPEND CMAKE_SHARED_LINKER_FLAGS_INIT " /SAFESEH") +endif() diff --git a/cmake/scripts/windowsstore/Install.cmake b/cmake/scripts/windowsstore/Install.cmake new file mode 100644 index 0000000..a0522d3 --- /dev/null +++ b/cmake/scripts/windowsstore/Install.cmake @@ -0,0 +1,10 @@ +# Fix UWP addons security issue caused by empty __init__.py Python Lib files packaged with Kodi +set(uwp_pythonlibinit_filepattern "${DEPENDS_PATH}/bin/Python/Lib/__init__.py") +file(GLOB_RECURSE uwp_pythonlibinit_foundfiles "${uwp_pythonlibinit_filepattern}") +foreach(uwp_pythonlibinit_file ${uwp_pythonlibinit_foundfiles}) + file(SIZE "${uwp_pythonlibinit_file}" uwp_pythonlibinit_filesize) + if(${uwp_pythonlibinit_filesize} EQUAL 0) + message("Adding hash comment character in the following empty file: ${uwp_pythonlibinit_file}") + file(APPEND ${uwp_pythonlibinit_file} "#") + endif() +endforeach() diff --git a/cmake/scripts/windowsstore/Macros.cmake b/cmake/scripts/windowsstore/Macros.cmake new file mode 100644 index 0000000..713e878 --- /dev/null +++ b/cmake/scripts/windowsstore/Macros.cmake @@ -0,0 +1,182 @@ +function(core_link_library lib wraplib) + message(AUTHOR_WARNING "core_link_library is not compatible with windows.") +endfunction() + +function(find_soname lib) + # Windows uses hardcoded dlls in xbmc/DllPaths_win32.h. + # Therefore the output of this function is unused. +endfunction() + +# Add precompiled header to target +# Arguments: +# target existing target that will be set up to compile with a precompiled header +# pch_header the precompiled header file +# pch_source the precompiled header source file +# Optional Arguments: +# PCH_TARGET build precompiled header as separate target with the given name +# so that the same precompiled header can be used for multiple libraries +# EXCLUDE_SOURCES if not all target sources shall use the precompiled header, +# the relevant files can be listed here +# On return: +# Compiles the pch_source into a precompiled header and adds the header to +# the given target +function(add_precompiled_header target pch_header pch_source) + cmake_parse_arguments(PCH "" "PCH_TARGET" "EXCLUDE_SOURCES" ${ARGN}) + + if(PCH_PCH_TARGET) + set(pch_binary ${PRECOMPILEDHEADER_DIR}/${PCH_PCH_TARGET}.pch) + else() + set(pch_binary ${PRECOMPILEDHEADER_DIR}/${target}.pch) + endif() + + # Set compile options and dependency for sources + get_target_property(sources ${target} SOURCES) + list(REMOVE_ITEM sources ${pch_source}) + foreach(exclude_source IN LISTS PCH_EXCLUDE_SOURCES) + list(REMOVE_ITEM sources ${exclude_source}) + endforeach() + set_source_files_properties(${sources} + PROPERTIES COMPILE_FLAGS "/Yu\"${pch_header}\" /Fp\"${pch_binary}\" /FI\"${pch_header}\"" + OBJECT_DEPENDS "${pch_binary}") + + # Set compile options for precompiled header + if(NOT PCH_PCH_TARGET OR NOT TARGET ${PCH_PCH_TARGET}_pch) + set_source_files_properties(${pch_source} + PROPERTIES COMPILE_FLAGS "/Yc\"${pch_header}\" /Fp\"${pch_binary}\"" + OBJECT_OUTPUTS "${pch_binary}") + endif() + + # Compile precompiled header + if(PCH_PCH_TARGET) + # As own target for usage in multiple libraries + if(NOT TARGET ${PCH_PCH_TARGET}_pch) + add_library(${PCH_PCH_TARGET}_pch STATIC ${pch_source}) + set_target_properties(${PCH_PCH_TARGET}_pch PROPERTIES COMPILE_PDB_NAME vc140 + COMPILE_PDB_OUTPUT_DIRECTORY ${PRECOMPILEDHEADER_DIR} + FOLDER "Build Utilities") + endif() + # From VS2012 onwards, precompiled headers have to be linked against (LNK2011). + target_link_libraries(${target} PUBLIC ${PCH_PCH_TARGET}_pch) + set_target_properties(${target} PROPERTIES COMPILE_PDB_NAME vc140 + COMPILE_PDB_OUTPUT_DIRECTORY ${PRECOMPILEDHEADER_DIR}) + else() + # As part of the target + target_sources(${target} PRIVATE ${pch_source}) + endif() +endfunction() + +macro(winstore_set_assets target) + file(GLOB ASSET_FILES "${CMAKE_SOURCE_DIR}/tools/windows/packaging/uwp/media/*.png") + set_property(SOURCE ${ASSET_FILES} PROPERTY VS_DEPLOYMENT_CONTENT 1) + set_property(SOURCE ${ASSET_FILES} PROPERTY VS_DEPLOYMENT_LOCATION "media") + source_group("media" FILES ${ASSET_FILES}) + set(RESOURCES ${RESOURCES} ${ASSET_FILES} + "${CMAKE_SOURCE_DIR}/tools/windows/packaging/uwp/kodi_temp_key.pfx") + + set(LICENSE_FILES + ${CMAKE_SOURCE_DIR}/LICENSE.md + ${CMAKE_SOURCE_DIR}/privacy-policy.txt) + if(EXISTS "${CMAKE_SOURCE_DIR}/known_issues.txt") + list(APPEND LICENSE_FILES ${CMAKE_SOURCE_DIR}/known_issues.txt) + endif() + set_property(SOURCE ${LICENSE_FILES} PROPERTY VS_DEPLOYMENT_CONTENT 1) + list(APPEND RESOURCES ${LICENSE_FILES}) +endmacro() + +macro(winstore_generate_manifest target) + configure_file( + ${CMAKE_SOURCE_DIR}/tools/windows/packaging/uwp/${APP_MANIFEST_NAME}.in + ${CMAKE_CURRENT_BINARY_DIR}/${APP_MANIFEST_NAME} + @ONLY) + set(RESOURCES ${RESOURCES} ${CMAKE_CURRENT_BINARY_DIR}/${APP_MANIFEST_NAME}) +endmacro() + +macro(add_deployment_content_group path link match exclude) + set(_link "") + set(_exclude "") + file(TO_NATIVE_PATH ${path} _path) + file(TO_NATIVE_PATH ${match} _match) + if (NOT "${link}" STREQUAL "") + file(TO_NATIVE_PATH ${link} _link) + set(_link "${_link}\\") + endif() + if(NOT "${exclude}" STREQUAL "") + string(REPLACE "/" "\\" _exclude ${exclude}) + endif() + string(CONCAT UWP_DEPLOYMENT_CONTENT_STR "${UWP_DEPLOYMENT_CONTENT_STR}" + " <EmbedResources Include=\"${_path}\\${_match}\" Exclude=\"${_exclude}\">\n" + " <Link>${_link}%(RecursiveDir)%(FileName)%(Extension)</Link>\n" + " <DeploymentContent>true</DeploymentContent>\n" + " </EmbedResources>\n") +endmacro() + +macro(winstore_append_props target) + # exclude debug dlls from packaging + set(DEBUG_DLLS zlibd.dll) + foreach(_dll ${DEBUG_DLLS}) + if (DEBUG_DLLS_EXCLUDE) + list(APPEND DEBUG_DLLS_EXCLUDE "\;$(BuildRootPath)/dlls/${_dll}") + else() + list(APPEND DEBUG_DLLS_EXCLUDE "$(BuildRootPath)/dlls/${_dll}") + endif() + string(CONCAT DEBUG_DLLS_LINKAGE_PROPS "${DEBUG_DLLS_LINKAGE_PROPS}" + " <ItemGroup Label=\"Binaries\">\n" + " <None Include=\"$(BinPath)\\${_dll}\" Condition=\"'$(Configuration)'=='Debug'\">\n" + " <DeploymentContent>true</DeploymentContent>\n" + " </None>\n" + " </ItemGroup>\n") + endforeach(_dll DEBUG_DLLS) + + add_deployment_content_group($(BuildRootPath)/dlls "" *.dll "${DEBUG_DLLS_EXCLUDE}") + add_deployment_content_group($(BuildRootPath)/system system **/* "$(BuildRootPath)/**/shaders/**") + add_deployment_content_group($(BuildRootPath)/system/shaders system/shaders **/*.fx "") + add_deployment_content_group($(BuildRootPath)/media media **/* "") + add_deployment_content_group($(BuildRootPath)/userdata userdata **/* "") + add_deployment_content_group($(BuildRootPath)/addons addons **/* "") + add_deployment_content_group($(BinaryAddonsPath) addons **/* "") + + foreach(xbt_file ${XBT_FILES}) + file(RELATIVE_PATH relative ${CMAKE_CURRENT_BINARY_DIR} ${xbt_file}) + file(TO_NATIVE_PATH ${relative} relative) + string(CONCAT XBT_FILE_PROPS "${XBT_FILE_PROPS}" + " <ItemGroup Label=\"SkinsMedia\">\n" + " <None Include=\"$(BuildRootPath)\\${relative}\">\n" + " <Link>${relative}</Link>\n" + " <DeploymentContent>true</DeploymentContent>\n" + " </None>\n" + " </ItemGroup>\n") + endforeach() + + set(VCPROJECT_PROPS_FILE "${CMAKE_CURRENT_BINARY_DIR}/${target}.props") + file(TO_NATIVE_PATH ${DEPENDS_PATH} DEPENDENCIES_DIR_NATIVE) + file(TO_NATIVE_PATH ${CMAKE_CURRENT_BINARY_DIR} CMAKE_CURRENT_BINARY_DIR_NATIVE) + file(TO_NATIVE_PATH ${CMAKE_SOURCE_DIR}/project/Win32BuildSetup/BUILD_WIN32/addons BINARY_ADDONS_DIR_NATIVE) + + file(WRITE ${VCPROJECT_PROPS_FILE} + "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + "<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n" + " <ImportGroup Label=\"PropertySheets\" />\n" + " <PropertyGroup Label=\"APP_DLLS\">\n" + " <BinPath>${DEPENDENCIES_DIR_NATIVE}\\bin</BinPath>\n" + " <BuildRootPath>${CMAKE_CURRENT_BINARY_DIR_NATIVE}</BuildRootPath>\n" + " <BinaryAddonsPath>${BINARY_ADDONS_DIR_NATIVE}</BinaryAddonsPath>\n" + " </PropertyGroup>\n" + "${DEBUG_DLLS_LINKAGE_PROPS}" + "${XBT_FILE_PROPS}" + " <ItemGroup>\n" + "${UWP_DEPLOYMENT_CONTENT_STR}" + " </ItemGroup>\n" + " <Target Name=\"_CollectCustomResources\" Inputs=\"@(EmbedResources)\" Outputs=\"@(EmbedResources->'$(OutputPath)\\PackageLayout\\%(Link)')\" BeforeTargets=\"AssignTargetPaths\">\n" + " <Message Text=\"Collecting package resources...\"/>\n" + " <ItemGroup>\n" + " <None Include=\"@(EmbedResources)\" />\n" + " </ItemGroup>\n" + " </Target>\n" + "</Project>") +endmacro() + +macro(winstore_add_target_properties target) + winstore_set_assets(${target}) + winstore_generate_manifest(${target}) + winstore_append_props(${target}) +endmacro() diff --git a/cmake/scripts/windowsstore/PathSetup.cmake b/cmake/scripts/windowsstore/PathSetup.cmake new file mode 100644 index 0000000..8550616 --- /dev/null +++ b/cmake/scripts/windowsstore/PathSetup.cmake @@ -0,0 +1,34 @@ +if(NOT prefix) + set(prefix ${CMAKE_INSTALL_PREFIX}) +else() + set(CMAKE_INSTALL_PREFIX ${prefix}) +endif() +if(NOT exec_prefix) + set(exec_prefix ${prefix}) +endif() +if(NOT libdir) + set(libdir ${prefix}/lib) +endif() +if(NOT bindir) + set(bindir ${prefix}/bin) +endif() +if(NOT includedir) + set(includedir ${prefix}/include) +endif() +if(NOT datarootdir) + set(datarootdir ${prefix}/share) +endif() +if(NOT datadir) + set(datadir ${datarootdir}) +endif() + +list(APPEND final_message "-- PATH config --") +list(APPEND final_message "Prefix: ${prefix}") +list(APPEND final_message "Libdir: ${libdir}") +list(APPEND final_message "Bindir: ${bindir}") +list(APPEND final_message "Includedir: ${includedir}") +list(APPEND final_message "Datarootdir: ${datarootdir}") +list(APPEND final_message "Datadir: ${datadir}") + +set(PATH_DEFINES -DBIN_INSTALL_PATH=\"${libdir}/kodi\" + -DINSTALL_PATH=\"${datarootdir}/kodi\") diff --git a/cmake/scripts/windowsstore/tools/patch.cmake b/cmake/scripts/windowsstore/tools/patch.cmake new file mode 100644 index 0000000..451fc66 --- /dev/null +++ b/cmake/scripts/windowsstore/tools/patch.cmake @@ -0,0 +1,50 @@ +# 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_FOUND NAMES patch.exe HINTS ${GIT_DIR} PATH_SUFFIXES usr/bin) + +if(PATCH_FOUND) + message(STATUS "patch utility found at ${PATCH_FOUND}") +else() + set(PATCH_ARCHIVE_NAME "patch-2.7.6-bin") + set(PATCH_ARCHIVE "${PATCH_ARCHIVE_NAME}.zip") + set(PATCH_URL "${KODI_MIRROR}/build-deps/win32/${PATCH_ARCHIVE}") + set(PATCH_DOWNLOAD ${BUILD_DIR}/download/${PATCH_ARCHIVE}) + + # download the archive containing patch.exe + message(STATUS "Downloading patch utility from ${PATCH_URL}...") + file(DOWNLOAD "${PATCH_URL}" "${PATCH_DOWNLOAD}" STATUS PATCH_DL_STATUS LOG PATCH_LOG SHOW_PROGRESS) + list(GET PATCH_DL_STATUS 0 PATCH_RETCODE) + if(NOT PATCH_RETCODE EQUAL 0) + message(FATAL_ERROR "ERROR downloading ${PATCH_URL} - status: ${PATCH_DL_STATUS} log: ${PATCH_LOG}") + endif() + + # extract the archive containing patch.exe + execute_process(COMMAND ${CMAKE_COMMAND} -E tar xzvf ${PATCH_DOWNLOAD} + WORKING_DIRECTORY ${BUILD_DIR}) + + # make sure the extraction worked and that patch.exe is there + set(PATCH_PATH ${BUILD_DIR}/${PATCH_ARCHIVE_NAME}) + set(PATCH_BINARY_PATH ${PATCH_PATH}/bin/patch.exe) + if(NOT EXISTS ${PATCH_PATH} OR NOT EXISTS ${PATCH_BINARY_PATH}) + message(FATAL_ERROR "ERROR extracting patch utility from ${PATCH_PATH}") + endif() + + # copy patch.exe into the output directory + file(INSTALL ${PATCH_BINARY_PATH} DESTINATION ${ADDON_DEPENDS_PATH}/bin) + # copy patch depends + file(GLOB PATCH_BINARIES ${PATCH_PATH}/bin/*.dll) + if(NOT "${PATCH_BINARIES}" STREQUAL "") + file(INSTALL ${PATCH_BINARIES} DESTINATION ${ADDON_DEPENDS_PATH}/bin) + endif() + + # make sure that cmake can find the copied patch.exe + find_program(PATCH_FOUND NAMES patch patch.exe) + if(NOT PATCH_FOUND) + message(FATAL_ERROR "ERROR installing patch utility from ${PATCH_BINARY_PATH} to ${ADDON_DEPENDS_PATH}/bin") + endif() +endif() |