summaryrefslogtreecommitdiffstats
path: root/cmake/scripts/common
diff options
context:
space:
mode:
authormanuel <manuel@mausz.at>2017-06-04 16:57:49 +0200
committermanuel <manuel@mausz.at>2017-06-04 16:57:49 +0200
commitf44ecaa4f27e7538ddcad66d40e543bffa2d2d86 (patch)
treed8de60fc7e17edeb6f0921726c038ee54b281445 /cmake/scripts/common
parentae08c8b7221bc965ac40d70e53fc8fcddb050c46 (diff)
downloadkodi-pvr-build-f44ecaa4f27e7538ddcad66d40e543bffa2d2d86.tar.gz
kodi-pvr-build-f44ecaa4f27e7538ddcad66d40e543bffa2d2d86.tar.bz2
kodi-pvr-build-f44ecaa4f27e7538ddcad66d40e543bffa2d2d86.zip
sync with upstream
Diffstat (limited to 'cmake/scripts/common')
-rw-r--r--cmake/scripts/common/AddOptions.cmake78
-rw-r--r--cmake/scripts/common/AddonHelpers.cmake378
-rw-r--r--cmake/scripts/common/ArchSetup.cmake159
-rw-r--r--cmake/scripts/common/CMakeHelpers.cmake54
-rw-r--r--cmake/scripts/common/CheckCommits.cmake75
-rw-r--r--cmake/scripts/common/CheckTargetPlatform.cmake67
-rw-r--r--cmake/scripts/common/GenerateVersionedFiles.cmake38
-rw-r--r--cmake/scripts/common/GeneratorSetup.cmake49
-rw-r--r--cmake/scripts/common/HandleDepends.cmake252
-rw-r--r--cmake/scripts/common/Macros.cmake722
-rw-r--r--cmake/scripts/common/PrepareEnv.cmake65
-rw-r--r--cmake/scripts/common/ProjectMacros.cmake89
-rw-r--r--cmake/scripts/common/Uninstall.cmake22
13 files changed, 2048 insertions, 0 deletions
diff --git a/cmake/scripts/common/AddOptions.cmake b/cmake/scripts/common/AddOptions.cmake
new file mode 100644
index 0000000..96837c1
--- /dev/null
+++ b/cmake/scripts/common/AddOptions.cmake
@@ -0,0 +1,78 @@
1# - Add options without repeating them on the command line
2#
3# Synopsis:
4#
5# add_options (lang build opts)
6#
7# where:
8#
9# lang Name of the language whose compiler should receive the
10# options, e.g. CXX. If a comma-separated list is received
11# then the option is added for all those languages. Use the
12# special value ALL_LANGUAGES for these languages: CXX, C
13# and Fortran
14#
15# build Kind of build to which this options should apply,
16# such as DEBUG and RELEASE. This can also be a comma-
17# separated list. Use the special value ALL_BUILDS to apply
18# to all builds.
19#
20# opts List of options to add. Each should be quoted.
21#
22# Example:
23#
24# add_options (CXX RELEASE "-O3" "-DNDEBUG" "-Wall")
25
26function(add_options langs builds)
27 # special handling of empty language specification
28 if("${langs}" STREQUAL "ALL_LANGUAGES")
29 set(langs CXX C Fortran)
30 endif()
31 foreach(lang IN LISTS langs)
32 # prepend underscore if necessary
33 foreach(build IN LISTS builds)
34 if(NOT ("${build}" STREQUAL "ALL_BUILDS"))
35 set(_bld "_${build}")
36 string(TOUPPER "${_bld}" _bld)
37 else()
38 set(_bld "")
39 endif()
40 foreach(_opt IN LISTS ARGN)
41 set(_var "CMAKE_${lang}_FLAGS${_bld}")
42 #message(STATUS "Adding \"${_opt}\" to \${${_var}}")
43 # remove it first
44 string(REPLACE "${_opt}" "" _without "${${_var}}")
45 string(STRIP "${_without}" _without)
46 # we need to strip this one as well, so they are comparable
47 string(STRIP "${${_var}}" _stripped)
48 # if it wasn't there, then add it at the end
49 if("${_without}" STREQUAL "${_stripped}")
50 # don't add any extra spaces if no options yet are set
51 if(NOT ${_stripped} STREQUAL "")
52 set(${_var} "${_stripped} ${_opt}")
53 else()
54 set(${_var} "${_opt}")
55 endif()
56 set(${_var} "${${_var}}" PARENT_SCOPE)
57 endif()
58 endforeach()
59 endforeach()
60 endforeach()
61endfunction()
62
63# set varname to flag unless user has specified something that matches regex
64function(set_default_option varname flag regex)
65 if(NOT "$ENV{CXXFLAGS}" MATCHES "${regex}"
66 AND NOT "${CMAKE_CXX_FLAGS}" MATCHES "${regex}"
67 AND NOT "${CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}}" MATCHES "${regex}")
68 set(${varname} ${flag} PARENT_SCOPE)
69 else()
70 set(${varname} PARENT_SCOPE)
71 endif()
72endfunction()
73
74# note: this must be called before project()
75macro(no_default_options)
76 # prevent the platform probe to set options
77 set(CMAKE_NOT_USING_CONFIG_FLAGS TRUE)
78endmacro()
diff --git a/cmake/scripts/common/AddonHelpers.cmake b/cmake/scripts/common/AddonHelpers.cmake
new file mode 100644
index 0000000..8772057
--- /dev/null
+++ b/cmake/scripts/common/AddonHelpers.cmake
@@ -0,0 +1,378 @@
1# Workaround for the fact that cpack's filenames are not customizable.
2# Each add-on is added as a separate component to facilitate zip/tgz packaging.
3# The filenames are always of the form basename-component, which is
4# incompatible with the addonid-version scheme we want. This hack renames
5# the files from the file names generated by the 'package' target.
6# Sadly we cannot extend the 'package' target, as it is a builtin target, see
7# http://public.kitware.com/Bug/view.php?id=8438
8# Thus, we have to add an 'addon-package' target.
9add_custom_target(addon-package
10 COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target package)
11
12macro(add_cpack_workaround target version ext)
13 if(NOT PACKAGE_DIR)
14 set(PACKAGE_DIR "${CMAKE_INSTALL_PREFIX}/zips")
15 endif()
16
17 add_custom_command(TARGET addon-package PRE_BUILD
18 COMMAND ${CMAKE_COMMAND} -E make_directory ${PACKAGE_DIR}
19 COMMAND ${CMAKE_COMMAND} -E copy ${CPACK_PACKAGE_DIRECTORY}/addon-${target}-${version}.${ext} ${PACKAGE_DIR}/${target}-${version}.${ext})
20endmacro()
21
22# Grab the version from a given add-on's addon.xml
23macro (addon_version dir prefix)
24 if(EXISTS ${PROJECT_SOURCE_DIR}/${dir}/addon.xml.in)
25 file(READ ${PROJECT_SOURCE_DIR}/${dir}/addon.xml.in ADDONXML)
26 else()
27 file(READ ${dir}/addon.xml ADDONXML)
28 endif()
29
30 string(REGEX MATCH "<addon[^>]*version.?=.?.[0-9\\.]+" VERSION_STRING ${ADDONXML})
31 string(REGEX REPLACE ".*version=.([0-9\\.]+).*" "\\1" ${prefix}_VERSION ${VERSION_STRING})
32 message(STATUS ${prefix}_VERSION=${${prefix}_VERSION})
33endmacro()
34
35# Build, link and optionally package an add-on
36macro (build_addon target prefix libs)
37 addon_version(${target} ${prefix})
38
39 # Below comes the generation of a list with used sources where the includes to
40 # kodi's headers becomes checked.
41 # This goes the following steps to identify them:
42 # 1. Check headers are at own depended on addon
43 # - If so, it is checked whether the whole folder is already inserted, if
44 # not, it is added.
45 # 2. If headers are not defined independently and there is more as one source
46 # file.
47 # - If yes, it is checked whether the headers with the sources together
48 # - In case no headers are inserted and more than one source file exists,
49 # the whole addon folder is searched for headers.
50 # 3. As a last step, the actual source files are checked.
51 if(${prefix}_SOURCES)
52 # Read used headers from addon, needed to identitfy used kodi addon interface headers
53 if(${prefix}_HEADERS)
54 # Add the used header files defined with CMakeLists.txt from addon itself
55 if(${prefix}_HEADERS MATCHES ${PROJECT_SOURCE_DIR})
56 # include path name already complete
57 list(APPEND USED_SOURCES ${${prefix}_HEADERS})
58 else()
59 # add the complete include path to begin
60 foreach(hdr_file ${${prefix}_HEADERS})
61 list(APPEND USED_SOURCES ${PROJECT_SOURCE_DIR}/${hdr_file})
62 endforeach()
63 endif()
64 else()
65 list(LENGTH ${prefix}_SOURCES _length)
66 if(${_length} GREATER 1)
67 string(REGEX MATCHALL "[.](h)" _length ${${prefix}_SOURCES}})
68 if(NOT _length)
69 file(GLOB_RECURSE USED_SOURCES ${PROJECT_SOURCE_DIR}/*.h*)
70 if(USED_SOURCES)
71 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.")
72 endif()
73 endif()
74 endif()
75 endif()
76
77 # Add the used source files defined with CMakeLists.txt from addon itself
78 if(${prefix}_SOURCES MATCHES ${PROJECT_SOURCE_DIR})
79 # include path name already complete
80 list(APPEND USED_SOURCES ${${prefix}_SOURCES})
81 else()
82 # add the complete include path to begin
83 foreach(src_file ${${prefix}_SOURCES})
84 list(APPEND USED_SOURCES ${PROJECT_SOURCE_DIR}/${src_file})
85 endforeach()
86 endif()
87
88 # Set defines used in addon.xml.in and read from versions.h to set add-on
89 # version parts automatically
90 file(STRINGS ${KODI_INCLUDE_DIR}/versions.h BIN_ADDON_PARTS)
91 foreach(loop_var ${BIN_ADDON_PARTS})
92 # Only pass strings with "#define ADDON_" from versions.h
93 if(loop_var MATCHES "#define ADDON_")
94 string(REGEX REPLACE "\\\n" " " loop_var ${loop_var}) # remove header line breaks
95 string(REGEX REPLACE "#define " "" loop_var ${loop_var}) # remove the #define name from string
96 string(REGEX MATCHALL "[//a-zA-Z0-9._-]+" loop_var "${loop_var}") # separate the define values to a list
97
98 # Get the definition name
99 list(GET loop_var 0 include_name)
100 # Check definition are depends who is a bigger list
101 if("${include_name}" MATCHES "_DEPENDS")
102 # Use start definition name as base for other value type
103 list(GET loop_var 0 list_name)
104 string(REPLACE "_DEPENDS" "" depends_name ${list_name})
105 string(REPLACE "_DEPENDS" "_XML_ID" xml_entry_name ${list_name})
106 string(REPLACE "_DEPENDS" "_USED" used_type_name ${list_name})
107
108 # remove the first value, not needed and wrong on "for" loop
109 list(REMOVE_AT loop_var 0)
110
111 foreach(depend_header ${loop_var})
112 string(STRIP ${depend_header} depend_header)
113 foreach(src_file ${USED_SOURCES})
114 file(STRINGS ${src_file} BIN_ADDON_SRC_PARTS)
115 foreach(loop_var ${BIN_ADDON_SRC_PARTS})
116 string(FIND "${loop_var}" "#include" matchres)
117 if("${matchres}" EQUAL 0)
118 string(REPLACE " " ";" loop_var "${loop_var}")
119 list(GET loop_var 1 include_name)
120 string(REGEX REPLACE "[<>\"]|kodi/" "" include_name "${include_name}")
121 if(include_name MATCHES ${depend_header})
122 set(ADDON_DEPENDS "${ADDON_DEPENDS}\n<import addon=\"${${xml_entry_name}}\" version=\"${${depends_name}}\"/>")
123 # Inform with them the addon header about used type
124 add_definitions(-D${used_type_name})
125 message(STATUS "Added usage definition: ${used_type_name}")
126 set(FOUND_HEADER_USAGE 1)
127 endif()
128 endif()
129 endforeach()
130 if(FOUND_HEADER_USAGE EQUAL 1) # break this loop if found but not unset, needed in parts where includes muddled up on addon
131 break()
132 endif()
133 endforeach()
134 # type is found and round becomes broken for next round with other type
135 if(FOUND_HEADER_USAGE EQUAL 1)
136 unset(FOUND_HEADER_USAGE)
137 break()
138 endif()
139 endforeach()
140 else()
141 # read the definition values and make it by the on version.h defined names public
142 list(GET loop_var 1 include_variable)
143 string(REGEX REPLACE ".*\"(.*)\"" "\\1" ${include_name} ${include_variable})
144 set(${include_name} ${${include_name}})
145 endif()
146 endif()
147 endforeach()
148
149 add_library(${target} ${${prefix}_SOURCES})
150 target_link_libraries(${target} ${${libs}})
151 set_target_properties(${target} PROPERTIES VERSION ${${prefix}_VERSION}
152 SOVERSION ${APP_VERSION_MAJOR}.${APP_VERSION_MINOR}
153 PREFIX "")
154 if(OS STREQUAL "android")
155 set_target_properties(${target} PROPERTIES PREFIX "lib")
156 endif()
157 elseif(${prefix}_CUSTOM_BINARY)
158 add_custom_target(${target} ALL)
159 endif()
160
161 # get the library's location
162 if(${prefix}_CUSTOM_BINARY)
163 list(GET ${prefix}_CUSTOM_BINARY 0 LIBRARY_LOCATION)
164 list(GET ${prefix}_CUSTOM_BINARY 1 LIBRARY_FILENAME)
165 if(CORE_SYSTEM_NAME STREQUAL android)
166 set(LIBRARY_FILENAME "lib${LIBRARY_FILENAME}")
167 endif()
168 else()
169 set(LIBRARY_LOCATION $<TARGET_FILE:${target}>)
170 # get the library's filename
171 if(CORE_SYSTEM_NAME STREQUAL android)
172 # for android we need the filename without any version numbers
173 set(LIBRARY_FILENAME $<TARGET_LINKER_FILE_NAME:${target}>)
174 else()
175 set(LIBRARY_FILENAME $<TARGET_FILE_NAME:${target}>)
176 endif()
177 endif()
178
179 # if there's an addon.xml.in we need to generate the addon.xml
180 if(EXISTS ${PROJECT_SOURCE_DIR}/${target}/addon.xml.in)
181 set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${PROJECT_SOURCE_DIR}/${target}/addon.xml.in)
182 set(PLATFORM ${CORE_SYSTEM_NAME})
183
184 file(READ ${PROJECT_SOURCE_DIR}/${target}/addon.xml.in addon_file)
185
186 # If sources are present must be the depends set
187 if(${prefix}_SOURCES)
188 string(FIND "${addon_file}" "\@ADDON_DEPENDS\@" matchres)
189 if("${matchres}" EQUAL -1)
190 message(FATAL_ERROR "\"\@ADDON_DEPENDS\@\" not found in addon.xml.in.")
191 endif()
192 endif()
193
194 string(CONFIGURE "${addon_file}" addon_file_conf @ONLY)
195 file(GENERATE OUTPUT ${PROJECT_SOURCE_DIR}/${target}/addon.xml CONTENT "${addon_file_conf}")
196 if(${APP_NAME_UC}_BUILD_DIR)
197 file(GENERATE OUTPUT ${${APP_NAME_UC}_BUILD_DIR}/addons/${target}/addon.xml CONTENT "${addon_file_conf}")
198 endif()
199 endif()
200
201 # if there's an settings.xml.in we need to generate the settings.xml
202 if(EXISTS ${PROJECT_SOURCE_DIR}/${target}/resources/settings.xml.in)
203 set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${PROJECT_SOURCE_DIR}/${target}/resources/settings.xml.in)
204 set(PLATFORM ${CORE_SYSTEM_NAME})
205
206 file(READ ${PROJECT_SOURCE_DIR}/${target}/resources/settings.xml.in settings_file)
207 string(CONFIGURE "${settings_file}" settings_file_conf @ONLY)
208 file(GENERATE OUTPUT ${PROJECT_SOURCE_DIR}/${target}/resources/settings.xml CONTENT "${settings_file_conf}")
209 if(${APP_NAME_UC}_BUILD_DIR)
210 file(GENERATE OUTPUT ${${APP_NAME_UC}_BUILD_DIR}/addons/${target}/resources/settings.xml CONTENT "${settings_file_conf}")
211 endif()
212 endif()
213
214 # set zip as default if addon-package is called without PACKAGE_XXX
215 set(CPACK_GENERATOR "ZIP")
216 set(ext "zip")
217 if(PACKAGE_ZIP OR PACKAGE_TGZ)
218 if(PACKAGE_TGZ)
219 set(CPACK_GENERATOR "TGZ")
220 set(ext "tar.gz")
221 endif()
222 set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY OFF)
223 set(CPACK_PACKAGE_FILE_NAME addon)
224 if(CMAKE_BUILD_TYPE STREQUAL "Release")
225 set(CPACK_STRIP_FILES TRUE)
226 endif()
227 set(CPACK_ARCHIVE_COMPONENT_INSTALL ON)
228 set(CPACK_COMPONENTS_IGNORE_GROUPS 1)
229 list(APPEND CPACK_COMPONENTS_ALL ${target}-${${prefix}_VERSION})
230 # Pack files together to create an archive
231 install(DIRECTORY ${target} DESTINATION ./ COMPONENT ${target}-${${prefix}_VERSION} PATTERN "xml.in" EXCLUDE)
232 if(WIN32)
233 if(NOT CPACK_PACKAGE_DIRECTORY)
234 # determine the temporary path
235 file(TO_CMAKE_PATH "$ENV{TEMP}" WIN32_TEMP_PATH)
236 string(LENGTH "${WIN32_TEMP_PATH}" WIN32_TEMP_PATH_LENGTH)
237 string(LENGTH "${PROJECT_BINARY_DIR}" PROJECT_BINARY_DIR_LENGTH)
238
239 # check if the temporary path is shorter than the default packaging directory path
240 if(WIN32_TEMP_PATH_LENGTH GREATER 0 AND WIN32_TEMP_PATH_LENGTH LESS PROJECT_BINARY_DIR_LENGTH)
241 # set the directory used by CPack for packaging to the temp directory
242 set(CPACK_PACKAGE_DIRECTORY ${WIN32_TEMP_PATH})
243 endif()
244 endif()
245
246 # in case of a VC++ project the installation location contains a $(Configuration) VS variable
247 # we replace it with ${CMAKE_BUILD_TYPE} (which doesn't cover the case when the build configuration
248 # is changed within Visual Studio)
249 string(REPLACE "$(Configuration)" "${CMAKE_BUILD_TYPE}" LIBRARY_LOCATION "${LIBRARY_LOCATION}")
250
251 if(${prefix}_SOURCES)
252 # install the generated DLL file
253 install(PROGRAMS ${LIBRARY_LOCATION} DESTINATION ${target}
254 COMPONENT ${target}-${${prefix}_VERSION})
255
256 if(CMAKE_BUILD_TYPE MATCHES Debug)
257 # for debug builds also install the PDB file
258 get_filename_component(LIBRARY_DIR ${LIBRARY_LOCATION} DIRECTORY)
259 install(FILES $<TARGET_PDB_FILE:${target}> DESTINATION ${target}
260 COMPONENT ${target}-${${prefix}_VERSION})
261 endif()
262 endif()
263 if(${prefix}_CUSTOM_BINARY)
264 install(FILES ${LIBRARY_LOCATION} DESTINATION ${target} RENAME ${LIBRARY_FILENAME})
265 endif()
266 if(${prefix}_CUSTOM_DATA)
267 install(DIRECTORY ${${prefix}_CUSTOM_DATA} DESTINATION ${target}/resources)
268 endif()
269 else() # NOT WIN32
270 if(NOT CPACK_PACKAGE_DIRECTORY)
271 set(CPACK_PACKAGE_DIRECTORY ${CMAKE_BINARY_DIR})
272 endif()
273 if(${prefix}_SOURCES)
274 install(TARGETS ${target} DESTINATION ${target}
275 COMPONENT ${target}-${${prefix}_VERSION})
276 endif()
277 if(${prefix}_CUSTOM_BINARY)
278 install(FILES ${LIBRARY_LOCATION} DESTINATION ${target} RENAME ${LIBRARY_FILENAME}
279 COMPONENT ${target}-${${prefix}_VERSION})
280 endif()
281 if(${prefix}_CUSTOM_DATA)
282 install(DIRECTORY ${${prefix}_CUSTOM_DATA} DESTINATION ${target}/resources)
283 endif()
284 endif()
285 add_cpack_workaround(${target} ${${prefix}_VERSION} ${ext})
286 else()
287 if(CORE_SYSTEM_NAME STREQUAL linux OR CORE_SYSTEM_NAME STREQUAL rbpi OR CORE_SYSTEM_NAME STREQUAL freebsd)
288 if(NOT OVERRIDE_PATHS)
289 if(CMAKE_INSTALL_PREFIX AND NOT CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT AND NOT CMAKE_INSTALL_PREFIX STREQUAL "${${APP_NAME_UC}_PREFIX}")
290 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")
291 endif()
292 if(CMAKE_INSTALL_LIBDIR AND NOT CMAKE_INSTALL_LIBDIR STREQUAL "${${APP_NAME_UC}_LIB_DIR}")
293 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")
294 endif()
295 if(CMAKE_INSTALL_DATADIR AND NOT CMAKE_INSTALL_DATADIR STREQUAL "${${APP_NAME_UC}_DATA_DIR}")
296 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")
297 endif()
298 set(CMAKE_INSTALL_PREFIX "${${APP_NAME_UC}_PREFIX}" CACHE PATH "${APP_NAME} install prefix" FORCE)
299 set(CMAKE_INSTALL_LIBDIR "${${APP_NAME_UC}_LIB_DIR}" CACHE PATH "${APP_NAME} install libdir" FORCE)
300 set(CMAKE_INSTALL_DATADIR "${${APP_NAME_UC}_DATA_DIR}" CACHE PATH "${APP_NAME} install datadir" FORCE)
301 else()
302 if(NOT CMAKE_INSTALL_LIBDIR)
303 set(CMAKE_INSTALL_LIBDIR "${CMAKE_INSTALL_PREFIX}/lib/${APP_NAME_LC}")
304 endif()
305 if(NOT CMAKE_INSTALL_DATADIR)
306 set(CMAKE_INSTALL_DATADIR "${CMAKE_INSTALL_PREFIX}/share/${APP_NAME_LC}")
307 endif()
308 endif()
309 else()
310 set(CMAKE_INSTALL_LIBDIR "lib/${APP_NAME_LC}")
311 set(CMAKE_INSTALL_DATADIR "share/${APP_NAME_LC}")
312 endif()
313 if(${prefix}_SOURCES)
314 install(TARGETS ${target} DESTINATION ${CMAKE_INSTALL_LIBDIR}/addons/${target})
315 endif()
316 if (${prefix}_CUSTOM_BINARY)
317 install(FILES ${LIBRARY_LOCATION} DESTINATION ${CMAKE_INSTALL_LIBDIR}/addons/${target} RENAME ${LIBRARY_FILENAME})
318 endif()
319 install(DIRECTORY ${target} DESTINATION ${CMAKE_INSTALL_DATADIR}/addons PATTERN "xml.in" EXCLUDE)
320 if(${prefix}_CUSTOM_DATA)
321 install(DIRECTORY ${${prefix}_CUSTOM_DATA} DESTINATION ${CMAKE_INSTALL_DATADIR}/addons/${target}/resources)
322 endif()
323 endif()
324 if(${APP_NAME_UC}_BUILD_DIR)
325 file(GLOB_RECURSE files ${CMAKE_CURRENT_SOURCE_DIR}/${target}/*)
326 if(${prefix}_CUSTOM_DATA)
327 add_custom_command(TARGET ${target} POST_BUILD
328 COMMAND ${CMAKE_COMMAND} -E copy_directory
329 ${${prefix}_CUSTOM_DATA}
330 ${${APP_NAME_UC}_BUILD_DIR}/addons/${target}/resources)
331 endif()
332 foreach(file ${files})
333 string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/${target}/" "" name "${file}")
334 # A good way to deal with () in filenames
335 if(NOT ${file} MATCHES xml.in)
336 configure_file(${file} ${${APP_NAME_UC}_BUILD_DIR}/addons/${target}/${name} COPYONLY)
337 endif()
338 endforeach()
339 add_custom_command(TARGET ${target} POST_BUILD
340 COMMAND ${CMAKE_COMMAND} -E copy
341 ${LIBRARY_LOCATION}
342 ${${APP_NAME_UC}_BUILD_DIR}/addons/${target}/${LIBRARY_FILENAME})
343 endif()
344endmacro()
345
346# finds a path to a given file (recursive)
347function (kodi_find_path var_name filename search_path strip_file)
348 file(GLOB_RECURSE PATH_TO_FILE ${search_path} ${filename})
349 if(strip_file)
350 string(REPLACE ${filename} "" PATH_TO_FILE ${PATH_TO_FILE})
351 endif()
352 set (${var_name} ${PATH_TO_FILE} PARENT_SCOPE)
353endfunction()
354
355# Cmake build options
356include(AddOptions)
357include(TestCXXAcceptsFlag)
358option(PACKAGE_ZIP "Package Zip file?" OFF)
359option(PACKAGE_TGZ "Package TGZ file?" OFF)
360option(BUILD_SHARED_LIBS "Build shared libs?" ON)
361
362# LTO support?
363CHECK_CXX_ACCEPTS_FLAG("-flto" HAVE_LTO)
364if(HAVE_LTO)
365 option(USE_LTO "use link time optimization" OFF)
366 if(USE_LTO)
367 add_options(ALL_LANGUAGES ALL_BUILDS "-flto")
368 endif()
369endif()
370
371# set this to try linking dependencies as static as possible
372if(ADDONS_PREFER_STATIC_LIBS)
373 set(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
374endif()
375
376if(${APP_NAME_UC}_BUILD_DIR)
377 list(APPEND CMAKE_PREFIX_PATH ${${APP_NAME_UC}_BUILD_DIR}/build)
378endif()
diff --git a/cmake/scripts/common/ArchSetup.cmake b/cmake/scripts/common/ArchSetup.cmake
new file mode 100644
index 0000000..8d5dba8
--- /dev/null
+++ b/cmake/scripts/common/ArchSetup.cmake
@@ -0,0 +1,159 @@
1# This script configures the build for a given architecture.
2# Flags and stringified arch is set up.
3# General compiler tests belongs here.
4#
5# On return, the following variables are set:
6# CMAKE_SYSTEM_NAME - a lowercased system name
7# CPU - the CPU on the target
8# ARCH - the system architecture
9# ARCH_DEFINES - list of compiler definitions for this architecture
10# SYSTEM_DEFINES - list of compiler definitions for this system
11# DEP_DEFINES - compiler definitions for system dependencies (e.g. LIRC)
12# + the results of compiler tests etc.
13
14include(CheckCXXSourceCompiles)
15include(CheckSymbolExists)
16include(CheckFunctionExists)
17include(CheckIncludeFile)
18
19# Macro to check if a given type exists in a given header
20# Arguments:
21# header the header to check
22# type the type to check for existence
23# var the compiler definition to set if type exists
24# On return:
25# If type was found, the definition is added to SYSTEM_DEFINES
26macro(check_type header type var)
27 check_cxx_source_compiles("#include <${header}>
28 int main()
29 {
30 ${type} s;
31 }" ${var})
32 if(${var})
33 list(APPEND SYSTEM_DEFINES -D${var}=1)
34 endif()
35endmacro()
36
37# Macro to check if a given builtin function exists
38# Arguments:
39# func the function to check
40# var the compiler definition to set if type exists
41# On return:
42# If type was found, the definition is added to SYSTEM_DEFINES
43macro(check_builtin func var)
44 check_cxx_source_compiles("
45 int main()
46 {
47 ${func};
48 }" ${var})
49 if(${var})
50 list(APPEND SYSTEM_DEFINES -D${var}=1)
51 endif()
52endmacro()
53
54
55# -------- Main script ---------
56message(STATUS "System type: ${CMAKE_SYSTEM_NAME}")
57if(NOT CORE_SYSTEM_NAME)
58 string(TOLOWER ${CMAKE_SYSTEM_NAME} CORE_SYSTEM_NAME)
59endif()
60
61if(WITH_CPU)
62 set(CPU ${WITH_CPU})
63elseif(NOT KODI_DEPENDSBUILD)
64 set(CPU ${CMAKE_SYSTEM_PROCESSOR})
65endif()
66
67if(CMAKE_TOOLCHAIN_FILE)
68 if(NOT EXISTS "${CMAKE_TOOLCHAIN_FILE}")
69 message(FATAL_ERROR "Toolchain file ${CMAKE_TOOLCHAIN_FILE} does not exist.")
70 elseif(KODI_DEPENDSBUILD AND (NOT DEPENDS_PATH OR NOT NATIVEPREFIX))
71 message(FATAL_ERROR "Toolchain did not define DEPENDS_PATH or NATIVEPREFIX. Possibly outdated depends.")
72 endif()
73endif()
74
75# While CMAKE_CROSSCOMPILING is set unconditionally if there's a toolchain file,
76# this variable is set if we can execute build artefacts on the host system (for example unit tests).
77if(CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL CMAKE_SYSTEM_PROCESSOR AND
78 CMAKE_HOST_SYSTEM_NAME STREQUAL CMAKE_SYSTEM_NAME)
79 set(CORE_HOST_IS_TARGET TRUE)
80else()
81 set(CORE_HOST_IS_TARGET FALSE)
82endif()
83
84# Main cpp
85set(CORE_MAIN_SOURCE ${CMAKE_SOURCE_DIR}/xbmc/platform/posix/main.cpp)
86
87# system specific arch setup
88if(NOT EXISTS ${CMAKE_SOURCE_DIR}/cmake/scripts/${CORE_SYSTEM_NAME}/ArchSetup.cmake)
89 message(FATAL_ERROR "Couldn't find configuration for '${CORE_SYSTEM_NAME}' "
90 "Either the platform is not (yet) supported "
91 "or a toolchain file has to be specified. "
92 "Consult ${CMAKE_SOURCE_DIR}/cmake/README.md for instructions. "
93 "Note: Specifying a toolchain requires a clean build directory!")
94endif()
95include(${CMAKE_SOURCE_DIR}/cmake/scripts/${CORE_SYSTEM_NAME}/ArchSetup.cmake)
96
97message(STATUS "Core system type: ${CORE_SYSTEM_NAME}")
98message(STATUS "Platform: ${PLATFORM}")
99message(STATUS "CPU: ${CPU}, ARCH: ${ARCH}")
100message(STATUS "Cross-Compiling: ${CMAKE_CROSSCOMPILING}")
101message(STATUS "Execute build artefacts on host: ${CORE_HOST_IS_TARGET}")
102message(STATUS "Depends based build: ${KODI_DEPENDSBUILD}")
103
104check_type(string std::u16string HAVE_STD__U16_STRING)
105check_type(string std::u32string HAVE_STD__U32_STRING)
106check_type(string char16_t HAVE_CHAR16_T)
107check_type(string char32_t HAVE_CHAR32_T)
108check_type(stdint.h uint_least16_t HAVE_STDINT_H)
109check_symbol_exists(posix_fadvise fcntl.h HAVE_POSIX_FADVISE)
110check_symbol_exists(PRIdMAX inttypes.h HAVE_INTTYPES_H)
111check_builtin("long* temp=0; long ret=__sync_add_and_fetch(temp, 1)" HAS_BUILTIN_SYNC_ADD_AND_FETCH)
112check_builtin("long* temp=0; long ret=__sync_sub_and_fetch(temp, 1)" HAS_BUILTIN_SYNC_SUB_AND_FETCH)
113check_builtin("long* temp=0; long ret=__sync_val_compare_and_swap(temp, 1, 1)" HAS_BUILTIN_SYNC_VAL_COMPARE_AND_SWAP)
114check_include_file(sys/inotify.h HAVE_INOTIFY)
115if(HAVE_INOTIFY)
116 list(APPEND SYSTEM_DEFINES -DHAVE_INOTIFY=1)
117endif()
118if(HAVE_POSIX_FADVISE)
119 list(APPEND SYSTEM_DEFINES -DHAVE_POSIX_FADVISE=1)
120endif()
121check_function_exists(localtime_r HAVE_LOCALTIME_R)
122if(HAVE_LOCALTIME_R)
123 list(APPEND SYSTEM_DEFINES -DHAVE_LOCALTIME_R=1)
124endif()
125if(HAVE_INTTYPES_H)
126 list(APPEND SYSTEM_DEFINES -DHAVE_INTTYPES_H=1)
127endif()
128
129find_package(SSE)
130foreach(_sse SSE SSE2 SSE3 SSSE3 SSE4_1 SSE4_2 AVX AVX2)
131 if(${${_sse}_FOUND})
132 # enable SSE versions up to 4.1 by default, if available
133 if(NOT ${_sse} MATCHES "AVX" AND NOT ${_sse} STREQUAL "SSE4_2")
134 option(ENABLE_${_sse} "Enable ${_sse}" ON)
135 else()
136 option(ENABLE_${_sse} "Enable ${_sse}" OFF)
137 endif()
138 endif()
139 if(ENABLE_${_sse})
140 set(HAVE_${_sse} TRUE CACHE STRING "${_sse} enabled")
141 list(APPEND ARCH_DEFINES -DHAVE_${_sse}=1)
142 endif()
143endforeach()
144
145if(NOT DEFINED NEON OR NEON)
146 option(ENABLE_NEON "Enable NEON optimization" ${NEON})
147 if(ENABLE_NEON)
148 message(STATUS "NEON optimization enabled")
149 add_definitions(-DHAS_NEON)
150 if(NEON_FLAGS)
151 add_options(ALL_LANGUAGES ALL_BUILDS ${NEON_FLAGS})
152 endif()
153 endif()
154endif()
155
156if(CMAKE_BUILD_TYPE STREQUAL "Debug")
157 add_options (ALL_LANGUAGES DEBUG "-g" "-D_DEBUG" "-Wall")
158endif()
159
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 @@
1# This file contains functions that support the debugging of the CMake files.
2
3# This file shouldn't be included per default in any CMake file. It should be
4# included and used only on demand. All functions are prefixed with "debug_".
5#
6# Usage:
7# include(scripts/common/CMakeHelpers.cmake)
8# debug_print_variables()
9
10# Print all CMake variables.
11macro(debug_print_variables)
12 get_cmake_property(_variableNames VARIABLES)
13 foreach(_variableName ${_variableNames})
14 message(STATUS "${_variableName} = ${${_variableName}}")
15 endforeach()
16endmacro()
17
18# Get all properties that CMake supports and convert them to a list.
19function(debug_get_properties VAR)
20 execute_process(COMMAND cmake --help-property-list
21 OUTPUT_VARIABLE _properties)
22 string(REGEX REPLACE ";" "\\\\;" _properties "${_properties}")
23 string(REGEX REPLACE "\n" ";" _properties "${_properties}")
24 list(REMOVE_DUPLICATES _properties)
25 list(REMOVE_ITEM _properties LOCATION)
26 set(${VAR} ${_properties} PARENT_SCOPE)
27endfunction()
28
29# List all properties.
30function(debug_list_properties)
31 debug_get_properties(_properties)
32 message("CMake properties = ${_properties}")
33endfunction()
34
35# Print all set properties of a specified target.
36function(debug_print_target_properties target)
37 if(NOT TARGET ${target})
38 message(FATAL_ERROR "There is no target named '${target}'")
39 endif()
40
41 debug_get_properties(_properties)
42
43 # Reading LOCATION property is deprecated and triggers a fatal error.
44 string(REGEX REPLACE ";LOCATION;|LOCATION" "" _properties "${_properties}")
45 string(REGEX REPLACE "<CONFIG>" "${CMAKE_BUILD_TYPE}" _properties
46 "${_properties}")
47 foreach(_property ${_properties})
48 get_property(_value TARGET ${target} PROPERTY ${_property} SET)
49 if(_value)
50 get_target_property(_value ${target} ${_property})
51 message("${target} ${_property} = ${_value}")
52 endif()
53 endforeach()
54endfunction()
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 @@
1find_package(Git REQUIRED)
2
3macro(sanity_check message)
4 if(status_code)
5 message(FATAL_ERROR "${message}")
6 endif()
7endmacro()
8
9# Check that there are no changes in working-tree
10execute_process(COMMAND ${GIT_EXECUTABLE} diff --quiet
11 RESULT_VARIABLE status_code)
12sanity_check("Cannot run with working tree changes. Commit, stash or drop them.")
13
14# Setup base of tests
15set(check_base $ENV{CHECK_BASE})
16if(NOT check_base)
17 set(check_base origin/master)
18endif()
19
20# Setup end of tests
21set(check_head $ENV{CHECK_HEAD})
22if(NOT check_head)
23 set(check_head HEAD)
24endif()
25
26# Setup target to build
27set(check_target $ENV{CHECK_TARGET})
28if(NOT check_target)
29 set(check_target check)
30endif()
31
32# Build threads
33set(build_threads $ENV{CHECK_THREADS})
34if(NOT build_threads)
35 if(UNIX)
36 execute_process(COMMAND nproc
37 OUTPUT_VARIABLE build_threads)
38 string(REGEX REPLACE "(\r?\n)+$" "" build_threads "${build_threads}")
39 endif()
40endif()
41
42# Record current HEAD
43execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD
44 OUTPUT_VARIABLE current_branch)
45
46string(REGEX REPLACE "(\r?\n)+$" "" current_branch "${current_branch}")
47
48# Grab revision list
49execute_process(COMMAND ${GIT_EXECUTABLE} rev-list ${check_base}..${check_head} --reverse
50 OUTPUT_VARIABLE rev_list)
51
52string(REPLACE "\n" ";" rev_list ${rev_list})
53foreach(rev ${rev_list})
54 # Checkout
55 message("Testing revision ${rev}")
56 execute_process(COMMAND ${GIT_EXECUTABLE} checkout ${rev}
57 RESULT_VARIABLE status_code)
58 sanity_check("Failed to checkout ${rev}")
59
60 # Build
61 if(build_threads GREATER 2)
62 execute_process(COMMAND ${CMAKE_COMMAND} "--build" "${CMAKE_BINARY_DIR}" "--target" "${check_target}" "--use-stderr" "--" "-j${build_threads}"
63 RESULT_VARIABLE status_code)
64 else()
65 execute_process(COMMAND ${CMAKE_COMMAND} "--build" "${CMAKE_BINARY_DIR}" "--target" "${check_target}" "--use-stderr"
66 RESULT_VARIABLE status_code)
67 endif()
68 if(status_code)
69 execute_process(COMMAND ${GIT_EXECUTABLE} checkout ${current_branch})
70 endif()
71 sanity_check("Failed to build target for revision ${rev}")
72endforeach()
73
74message("Everything checks out fine")
75execute_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..82ee668
--- /dev/null
+++ b/cmake/scripts/common/CheckTargetPlatform.cmake
@@ -0,0 +1,67 @@
1# handle target platforms
2function(check_target_platform dir target_platform build)
3 # param[in] dir path/directory of the addon/dependency
4 # param[in] target_platform target platform of the build
5 # param[out] build Result whether the addon/dependency should be built for the specified target platform
6
7 set(${build} FALSE)
8 # check if the given directory exists and contains a platforms.txt
9 if(EXISTS ${dir} AND EXISTS ${dir}/platforms.txt)
10 # get all the specified platforms
11 file(STRINGS ${dir}/platforms.txt platforms)
12
13 list( LENGTH platforms listlen )
14 if(${listlen} EQUAL 1)
15 string(REPLACE " " ";" platforms ${platforms})
16 endif()
17
18 # check if the addon/dependency should be built for the current platform
19 foreach(platform ${platforms})
20 if(${platform} STREQUAL "all" OR ${platform} STREQUAL ${target_platform})
21 set(${build} TRUE)
22 else()
23 # check if the platform is defined as "!<platform>"
24 string(SUBSTRING ${platform} 0 1 platform_first)
25 if(${platform_first} STREQUAL "!")
26 # extract the platform
27 string(LENGTH ${platform} platform_length)
28 math(EXPR platform_length "${platform_length} - 1")
29 string(SUBSTRING ${platform} 1 ${platform_length} platform)
30
31 # check if the current platform does not match the extracted platform
32 if(NOT ${platform} STREQUAL ${target_platform})
33 set(${build} TRUE)
34 endif()
35 endif()
36 endif()
37 endforeach()
38 else()
39 set(${build} TRUE)
40 endif()
41
42 # make the ${build} variable available to the calling script
43 set(${build} "${${build}}" PARENT_SCOPE)
44endfunction()
45
46function(check_install_permissions install_dir have_perms)
47 # param[in] install_dir directory to check for write permissions
48 # param[out] have_perms wether we have permissions to install to install_dir
49
50 set(testfile_lib ${install_dir}/lib/kodi/.cmake-inst-test)
51 set(testfile_share ${install_dir}/share/kodi/.cmake-inst-test)
52 get_filename_component(testdir_lib ${testfile_lib} DIRECTORY)
53 get_filename_component(testdir_share ${testfile_share} DIRECTORY)
54
55 execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${testdir_lib})
56 execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${testdir_share})
57 execute_process(COMMAND ${CMAKE_COMMAND} -E touch ${testfile_lib})
58 execute_process(COMMAND ${CMAKE_COMMAND} -E touch ${testfile_share})
59
60 if(EXISTS ${testfile_lib} AND EXISTS ${testfile_share})
61 set(${have_perms} True PARENT_SCOPE)
62 else()
63 message(STATUS "check_install_permissions ${install_dir}: failed to create files")
64 set(${have_perms} False PARENT_SCOPE)
65 endif()
66 file(REMOVE ${testfile_lib} ${testfile_share})
67endfunction()
diff --git a/cmake/scripts/common/GenerateVersionedFiles.cmake b/cmake/scripts/common/GenerateVersionedFiles.cmake
new file mode 100644
index 0000000..90b2173
--- /dev/null
+++ b/cmake/scripts/common/GenerateVersionedFiles.cmake
@@ -0,0 +1,38 @@
1include(${CORE_SOURCE_DIR}/cmake/scripts/common/Macros.cmake)
2
3core_find_versions()
4
5# configure_file without dependency tracking
6# configure_file would register additional file dependencies that interfere
7# with the ones from add_custom_command (and the generation would happen twice)
8function(generate_versioned_file _SRC _DEST)
9 file(READ ${CORE_SOURCE_DIR}/${_SRC} file_content)
10 string(CONFIGURE "${file_content}" file_content @ONLY)
11 file(WRITE ${CMAKE_BINARY_DIR}/${_DEST} "${file_content}")
12endfunction()
13
14# add-on xml's
15file(GLOB ADDON_XML_IN_FILE ${CORE_SOURCE_DIR}/addons/*/addon.xml.in)
16foreach(loop_var ${ADDON_XML_IN_FILE})
17 # prevent 'xbmc.json'; will be obtained from 'xbmc/interfaces/json-rpc/schema/CMakeLists.txt'.
18 if(loop_var MATCHES "xbmc.json")
19 continue()
20 endif()
21
22 list(GET loop_var 0 xml_name)
23
24 string(REPLACE "/addon.xml.in" "" source_dir ${xml_name})
25 string(REPLACE ${CORE_SOURCE_DIR} ${CMAKE_BINARY_DIR} dest_dir ${source_dir})
26 file(MAKE_DIRECTORY ${dest_dir})
27
28 # copy everything except addon.xml.in to build folder
29 file(COPY "${source_dir}" DESTINATION "${CMAKE_BINARY_DIR}/addons" REGEX ".xml.in" EXCLUDE)
30
31 configure_file(${source_dir}/addon.xml.in ${dest_dir}/addon.xml @ONLY)
32
33 unset(source_dir)
34 unset(dest_dir)
35 unset(xml_name)
36endforeach()
37
38generate_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 @@
1# Configure single-/multiconfiguration generators and variables
2#
3# CORE_BUILD_CONFIG that is set to
4# - CMAKE_BUILD_TYPE for single configuration generators such as make, nmake
5# - a variable that expands on build time to the current configuration for
6# multi configuration generators such as VS or Xcode
7if(CMAKE_CONFIGURATION_TYPES)
8 if(CMAKE_BUILD_TYPE)
9 message(FATAL_ERROR "CMAKE_BUILD_TYPE must not be defined for multi-configuration generators")
10 endif()
11 set(CORE_BUILD_CONFIG ${CMAKE_CFG_INTDIR})
12 message(STATUS "Generator: Multi-configuration (${CMAKE_GENERATOR})")
13else()
14 if(CMAKE_BUILD_TYPE)
15 set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE}
16 CACHE STRING "Choose build type (${CMAKE_BUILD_TYPES})" FORCE)
17 else()
18 # Set default
19 set(CMAKE_BUILD_TYPE Release
20 CACHE STRING "Choose build type (${CMAKE_BUILD_TYPES})" FORCE)
21 endif()
22 set(CORE_BUILD_CONFIG ${CMAKE_BUILD_TYPE})
23 message(STATUS "Generator: Single-configuration: ${CMAKE_BUILD_TYPE} (${CMAKE_GENERATOR})")
24endif()
25
26# Print CMake version
27message(STATUS "CMake Version: ${CMAKE_VERSION}")
28
29# Deal with CMake special cases
30if(CMAKE_VERSION VERSION_EQUAL 3.5.1)
31 message(WARNING "CMake 3.5.1 introduced a crash during configuration. "
32 "Please consider upgrading to 3.5.2 (cmake.org/Bug/view.php?id=16044)")
33endif()
34
35# Darwin needs CMake 3.4
36if(APPLE AND CMAKE_VERSION VERSION_LESS 3.4)
37 message(WARNING "Build on Darwin requires CMake 3.4 or later (tdb library support) "
38 "or the usage of the patched version in depends.")
39endif()
40
41# Windows needs CMake 3.6 (VS_STARTUP_PROJECT)
42if(WIN32 AND CMAKE_VERSION VERSION_LESS 3.6)
43 message(FATAL_ERROR "Build on Windows needs CMake 3.6 or later")
44endif()
45
46# Ninja needs CMake 3.2 due to ExternalProject BUILD_BYPRODUCTS usage
47if(CMAKE_GENERATOR STREQUAL Ninja AND CMAKE_VERSION VERSION_LESS 3.2)
48 message(FATAL_ERROR "Generator: Ninja requires CMake 3.2 or later")
49endif()
diff --git a/cmake/scripts/common/HandleDepends.cmake b/cmake/scripts/common/HandleDepends.cmake
new file mode 100644
index 0000000..85d2cf4
--- /dev/null
+++ b/cmake/scripts/common/HandleDepends.cmake
@@ -0,0 +1,252 @@
1include(${CORE_SOURCE_DIR}/cmake/scripts/common/CheckTargetPlatform.cmake)
2
3# handle addon depends
4function(add_addon_depends addon searchpath)
5 # input: string addon string searchpath
6
7 set(OUTPUT_DIR ${ADDON_DEPENDS_PATH})
8 # look for platform-specific dependencies
9 file(GLOB_RECURSE cmake_input_files ${searchpath}/${CORE_SYSTEM_NAME}/*.txt)
10 file(GLOB_RECURSE cmake_input_files2 ${searchpath}/common/*.txt)
11 list(APPEND cmake_input_files ${cmake_input_files2})
12
13 foreach(file ${cmake_input_files})
14 set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${file})
15 if(NOT (file MATCHES CMakeLists.txt OR
16 file MATCHES install.txt OR
17 file MATCHES noinstall.txt OR
18 file MATCHES flags.txt OR
19 file MATCHES deps.txt OR
20 file MATCHES "[a-z]+-deps[.]txt" OR
21 file MATCHES platforms.txt))
22 message(STATUS "Processing ${file}")
23 file(STRINGS ${file} def)
24 string(REPLACE " " ";" def ${def})
25 list(LENGTH def deflength)
26 get_filename_component(dir ${file} DIRECTORY)
27
28 # get the id of the dependency
29 if(NOT "${def}" STREQUAL "")
30 # read the id from the file
31 list(GET def 0 id)
32 else()
33 # read the id from the filename
34 get_filename_component(id ${file} NAME_WE)
35 endif()
36
37 # check if the dependency has a platforms.txt
38 set(platform_found FALSE)
39 check_target_platform(${dir} ${CORE_SYSTEM_NAME} platform_found)
40
41 if(${platform_found} AND NOT TARGET ${id})
42 # determine the download URL of the dependency
43 set(url "")
44 if(deflength GREATER 1)
45 list(GET def 1 url)
46 message(STATUS "${id} url: ${url}")
47 endif()
48
49 # check if there are any library specific flags that need to be passed on
50 if(EXISTS ${dir}/flags.txt)
51 set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${dir}/flags.txt)
52 file(STRINGS ${dir}/flags.txt extraflags)
53
54 # replace some custom placeholders
55 string(REPLACE "@MINGW_TOOLCHAIN_FILE@" "${OUTPUT_DIR}/Toolchain_mingw32.cmake" extraflags "${extraflags}")
56 string(REPLACE " " ";" extraflags ${extraflags})
57
58 message(STATUS "${id} extraflags: ${extraflags}")
59 endif()
60
61 set(BUILD_ARGS -DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}
62 -DOUTPUT_DIR=${OUTPUT_DIR}
63 -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
64 -DCMAKE_USER_MAKE_RULES_OVERRIDE=${CMAKE_USER_MAKE_RULES_OVERRIDE}
65 -DCMAKE_USER_MAKE_RULES_OVERRIDE_CXX=${CMAKE_USER_MAKE_RULES_OVERRIDE_CXX}
66 -DCMAKE_INSTALL_PREFIX=${OUTPUT_DIR}
67 -DCORE_SYSTEM_NAME=${CORE_SYSTEM_NAME}
68 -DENABLE_STATIC=1
69 -DBUILD_SHARED_LIBS=0)
70 # if there are no make rules override files available take care of manually passing on ARCH_DEFINES
71 if(NOT CMAKE_USER_MAKE_RULES_OVERRIDE AND NOT CMAKE_USER_MAKE_RULES_OVERRIDE_CXX)
72 # make sure we create strings, not lists
73 set(TMP_C_FLAGS "${CMAKE_C_FLAGS} ${ARCH_DEFINES}")
74 set(TMP_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ARCH_DEFINES}")
75 list(APPEND BUILD_ARGS -DCMAKE_C_FLAGS=${TMP_C_FLAGS}
76 -DCMAKE_CXX_FLAGS=${TMP_CXX_FLAGS})
77 endif()
78
79 if(CMAKE_TOOLCHAIN_FILE)
80 list(APPEND BUILD_ARGS -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE})
81 message("toolchain specified")
82 message(${BUILD_ARGS})
83 endif()
84
85 # prepare patchfile. ensure we have a clean file after reconfiguring
86 set(PATCH_FILE ${BUILD_DIR}/${id}/tmp/patch.cmake)
87 file(REMOVE ${PATCH_FILE})
88
89 # if there's a CMakeLists.txt use it to prepare the build
90 if(EXISTS ${dir}/CMakeLists.txt)
91 set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${dir}/CMakeLists.txt)
92 file(APPEND ${PATCH_FILE}
93 "file(COPY ${dir}/CMakeLists.txt
94 DESTINATION ${BUILD_DIR}/${id}/src/${id})\n")
95 endif()
96
97 # check if we have patches to apply
98 file(GLOB patches ${dir}/*.patch)
99 list(SORT patches)
100 foreach(patch ${patches})
101 if(NOT PATCH_PROGRAM OR "${PATCH_PROGRAM}" STREQUAL "")
102 if(NOT PATCH_EXECUTABLE)
103 # find the path to the patch executable
104 find_program(PATCH_EXECUTABLE NAMES patch)
105
106 if(NOT PATCH_EXECUTABLE)
107 message(FATAL_ERROR "Missing patch command (we looked in ${CMAKE_PREFIX_PATH})")
108 endif()
109 endif()
110
111 set(PATCH_PROGRAM ${PATCH_EXECUTABLE})
112
113 # On Windows "patch.exe" can only handle CR-LF line-endings.
114 # Our patches have LF-only line endings - except when they
115 # have been checked out as part of a dependency hosted on Git
116 # and core.autocrlf=true.
117 if(WIN32)
118 file(READ ${patch} patch_content_hex HEX)
119 # Force handle LF-only line endings
120 if(NOT patch_content_hex MATCHES "0d0a")
121 set(PATCH_PROGRAM "\"${PATCH_PROGRAM}\" --binary")
122 endif()
123 endif()
124 endif()
125
126 set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${patch})
127 file(APPEND ${PATCH_FILE}
128 "execute_process(COMMAND ${PATCH_PROGRAM} -p1 -i \"${patch}\")\n")
129 endforeach()
130
131
132 # if there's an install.txt use it to properly install the built files
133 set(INSTALL_COMMAND "")
134 if(EXISTS ${dir}/install.txt)
135 set(INSTALL_COMMAND INSTALL_COMMAND ${CMAKE_COMMAND}
136 -DINPUTDIR=${BUILD_DIR}/${id}/src/${id}-build/
137 -DINPUTFILE=${dir}/install.txt
138 -DDESTDIR=${OUTPUT_DIR}
139 -DENABLE_STATIC=1
140 "${extraflags}"
141 -P ${PROJECT_SOURCE_DIR}/install.cmake)
142 elseif(EXISTS ${dir}/noinstall.txt)
143 set(INSTALL_COMMAND INSTALL_COMMAND "")
144 endif()
145
146 # check if there's a platform-specific or generic deps.txt containing dependencies on other libraries
147 if(EXISTS ${dir}/${CORE_SYSTEM_NAME}-deps.txt)
148 file(STRINGS ${dir}/${CORE_SYSTEM_NAME}-deps.txt deps)
149 message(STATUS "${id} depends: ${deps}")
150 elseif(EXISTS ${dir}/deps.txt)
151 set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${dir}/deps.txt)
152 file(STRINGS ${dir}/deps.txt deps)
153 message(STATUS "${id} depends: ${deps}")
154 else()
155 set(deps)
156 endif()
157
158 if(CROSS_AUTOCONF AND AUTOCONF_FILES)
159 foreach(afile ${AUTOCONF_FILES})
160 set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${afile})
161 file(APPEND ${PATCH_FILE}
162 "message(STATUS \"AUTOCONF: copying ${afile} to ${BUILD_DIR}/${id}/src/${id}\")\n
163 file(COPY ${afile} DESTINATION ${BUILD_DIR}/${id}/src/${id})\n")
164 endforeach()
165 endif()
166
167 # if the patch file exists we need to set the PATCH_COMMAND
168 set(PATCH_COMMAND "")
169 if(EXISTS ${PATCH_FILE})
170 set(PATCH_COMMAND ${CMAKE_COMMAND} -P ${PATCH_FILE})
171 endif()
172
173 # prepare the setup of the call to externalproject_add()
174 set(EXTERNALPROJECT_SETUP PREFIX ${BUILD_DIR}/${id}
175 CMAKE_ARGS ${extraflags} ${BUILD_ARGS}
176 PATCH_COMMAND ${PATCH_COMMAND}
177 "${INSTALL_COMMAND}")
178
179 if(CMAKE_VERSION VERSION_GREATER 3.5.9)
180 list(APPEND EXTERNALPROJECT_SETUP GIT_SHALLOW 1)
181 endif()
182
183 # if there's an url defined we need to pass that to externalproject_add()
184 if(DEFINED url AND NOT "${url}" STREQUAL "")
185 # check if there's a third parameter in the file
186 if(deflength GREATER 2)
187 # the third parameter is considered as a revision of a git repository
188 list(GET def 2 revision)
189
190 externalproject_add(${id}
191 GIT_REPOSITORY ${url}
192 GIT_TAG ${revision}
193 "${EXTERNALPROJECT_SETUP}")
194
195 # For patchfiles to work, disable (users globally set) autocrlf=true
196 if(CMAKE_MINIMUM_REQUIRED_VERSION VERSION_GREATER 3.7)
197 message(AUTHOR_WARNING "Make use of GIT_CONFIG")
198 endif()
199 if(WIN32 AND patches)
200 externalproject_add_step(${id} gitconfig
201 COMMAND git config core.autocrlf false
202 COMMAND git rm -rf --cached .
203 COMMAND git reset --hard HEAD
204 COMMENT "Performing gitconfig step: Disabling autocrlf to enable patching for '${id}'"
205 DEPENDERS patch
206 WORKING_DIRECTORY <SOURCE_DIR>)
207 endif()
208 else()
209 set(CONFIGURE_COMMAND "")
210 if(NOT WIN32)
211 # manually specify the configure command to be able to pass in the custom PKG_CONFIG_PATH
212 set(CONFIGURE_COMMAND PKG_CONFIG_PATH=${OUTPUT_DIR}/lib/pkgconfig
213 ${CMAKE_COMMAND} -DCMAKE_LIBRARY_PATH=${OUTPUT_DIR}/lib ${extraflags} ${BUILD_ARGS}
214 ${BUILD_DIR}/${id}/src/${id}
215 -DPACKAGE_CONFIG_PATH=${OUTPUT_DIR}/lib/pkgconfig
216 -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
217 -DOUTPUT_DIR=${OUTPUT_DIR}
218 -DCMAKE_PREFIX_PATH=${OUTPUT_DIR}
219 -DCMAKE_INSTALL_PREFIX=${OUTPUT_DIR}
220 -DCMAKE_EXE_LINKER_FLAGS=-L${OUTPUT_DIR}/lib
221 -DCMAKE_INCLUDE_PATH=${OUTPUT_DIR}/include)
222 endif()
223
224 externalproject_add(${id}
225 URL ${url}
226 DOWNLOAD_DIR ${BUILD_DIR}/download
227 CONFIGURE_COMMAND ${CONFIGURE_COMMAND}
228 "${EXTERNALPROJECT_SETUP}")
229 endif()
230 else()
231 externalproject_add(${id}
232 SOURCE_DIR ${dir}
233 "${EXTERNALPROJECT_SETUP}")
234 endif()
235
236 if(deps)
237 add_dependencies(${id} ${deps})
238 endif()
239 endif()
240
241 # if the dependency is available for the target platform add it to the list of the addon's dependencies
242 # (even if the target already exists as it still has to be built before the addon)
243 if(${platform_found})
244 list(APPEND ${addon}_DEPS ${id})
245 endif()
246 endif()
247 endforeach()
248
249 # make the ${addon}_DEPS variable available to the calling script
250 set(${addon}_DEPS "${${addon}_DEPS}" PARENT_SCOPE)
251endfunction()
252
diff --git a/cmake/scripts/common/Macros.cmake b/cmake/scripts/common/Macros.cmake
new file mode 100644
index 0000000..4b6f890
--- /dev/null
+++ b/cmake/scripts/common/Macros.cmake
@@ -0,0 +1,722 @@
1# This script holds the main functions used to construct the build system
2
3# Include system specific macros but only if this file is included from
4# kodi main project. It's not needed for kodi-addons project
5# If CORE_SOURCE_DIR is set, it was called from kodi-addons project
6# TODO: drop check if we ever integrate kodi-addons into kodi project
7if(NOT CORE_SOURCE_DIR)
8 include(${CMAKE_SOURCE_DIR}/cmake/scripts/${CORE_SYSTEM_NAME}/Macros.cmake)
9endif()
10
11# IDEs: Group source files in target in folders (file system hierarchy)
12# Source: http://blog.audio-tk.com/2015/09/01/sorting-source-files-and-projects-in-folders-with-cmake-and-visual-studioxcode/
13# Arguments:
14# target The target that shall be grouped by folders.
15# Optional Arguments:
16# RELATIVE allows to specify a different reference folder.
17function(source_group_by_folder target)
18 if(NOT TARGET ${target})
19 message(FATAL_ERROR "There is no target named '${target}'")
20 endif()
21
22 set(SOURCE_GROUP_DELIMITER "/")
23
24 cmake_parse_arguments(arg "" "RELATIVE" "" ${ARGN})
25 if(arg_RELATIVE)
26 set(relative_dir ${arg_RELATIVE})
27 else()
28 set(relative_dir ${CMAKE_CURRENT_SOURCE_DIR})
29 endif()
30
31 get_property(files TARGET ${target} PROPERTY SOURCES)
32 if(files)
33 list(SORT files)
34
35 if(CMAKE_GENERATOR STREQUAL Xcode)
36 set_target_properties(${target} PROPERTIES SOURCES "${files}")
37 endif()
38 endif()
39 foreach(file ${files})
40 if(NOT IS_ABSOLUTE ${file})
41 set(file ${CMAKE_CURRENT_SOURCE_DIR}/${file})
42 endif()
43 file(RELATIVE_PATH relative_file ${relative_dir} ${file})
44 get_filename_component(dir "${relative_file}" DIRECTORY)
45 if(NOT dir STREQUAL "${last_dir}")
46 if(files)
47 source_group("${last_dir}" FILES ${files})
48 endif()
49 set(files "")
50 endif()
51 set(files ${files} ${file})
52 set(last_dir "${dir}")
53 endforeach(file)
54 if(files)
55 source_group("${last_dir}" FILES ${files})
56 endif()
57endfunction()
58
59# Add sources to main application
60# Arguments:
61# name name of the library to add
62# Implicit arguments:
63# ENABLE_STATIC_LIBS Build static libraries per directory
64# SOURCES the sources of the library
65# HEADERS the headers of the library (only for IDE support)
66# OTHERS other library related files (only for IDE support)
67# On return:
68# Library will be built, optionally added to ${core_DEPENDS}
69# Sets CORE_LIBRARY for calls for setting target specific options
70function(core_add_library name)
71 if(ENABLE_STATIC_LIBS)
72 add_library(${name} STATIC ${SOURCES} ${HEADERS} ${OTHERS})
73 set_target_properties(${name} PROPERTIES PREFIX "")
74 set(core_DEPENDS ${name} ${core_DEPENDS} CACHE STRING "" FORCE)
75 add_dependencies(${name} libcpluff ffmpeg dvdnav crossguid)
76 set(CORE_LIBRARY ${name} PARENT_SCOPE)
77
78 # Add precompiled headers to Kodi main libraries
79 if(CORE_SYSTEM_NAME STREQUAL windows)
80 add_precompiled_header(${name} pch.h ${CMAKE_SOURCE_DIR}/xbmc/platform/win32/pch.cpp PCH_TARGET kodi)
81 set_language_cxx(${name})
82 target_link_libraries(${name} PUBLIC effects11)
83 endif()
84 else()
85 foreach(src IN LISTS SOURCES HEADERS OTHERS)
86 get_filename_component(src_path "${src}" ABSOLUTE)
87 list(APPEND FILES ${src_path})
88 endforeach()
89 target_sources(lib${APP_NAME_LC} PRIVATE ${FILES})
90 set(CORE_LIBRARY lib${APP_NAME_LC} PARENT_SCOPE)
91 endif()
92endfunction()
93
94# Add a test library, and add sources to list for gtest integration macros
95function(core_add_test_library name)
96 if(ENABLE_STATIC_LIBS)
97 add_library(${name} STATIC ${SOURCES} ${SUPPORTED_SOURCES} ${HEADERS} ${OTHERS})
98 set_target_properties(${name} PROPERTIES PREFIX ""
99 EXCLUDE_FROM_ALL 1
100 FOLDER "Build Utilities/tests")
101 add_dependencies(${name} libcpluff ffmpeg dvdnav crossguid)
102 set(test_archives ${test_archives} ${name} CACHE STRING "" FORCE)
103 endif()
104 foreach(src IN LISTS SOURCES SUPPORTED_SOURCES HEADERS OTHERS)
105 get_filename_component(src_path "${src}" ABSOLUTE)
106 set(test_sources "${src_path}" ${test_sources} CACHE STRING "" FORCE)
107 endforeach()
108endfunction()
109
110# Add an addon callback library
111# Arguments:
112# name name of the library to add
113# Implicit arguments:
114# SOURCES the sources of the library
115# HEADERS the headers of the library (only for IDE support)
116# OTHERS other library related files (only for IDE support)
117# On return:
118# Library target is defined and added to LIBRARY_FILES
119function(core_add_addon_library name)
120 get_filename_component(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} NAME)
121 list(APPEND SOURCES lib${name}.cpp)
122 core_add_shared_library(${name} OUTPUT_DIRECTORY addons/${DIRECTORY})
123 set_target_properties(${name} PROPERTIES FOLDER addons)
124 target_include_directories(${name} PRIVATE
125 ${CMAKE_CURRENT_SOURCE_DIR}
126 ${CMAKE_SOURCE_DIR}/xbmc/addons/kodi-addon-dev-kit/include/kodi
127 ${CMAKE_SOURCE_DIR}/xbmc)
128endfunction()
129
130# Add an dl-loaded shared library
131# Arguments:
132# name name of the library to add
133# Optional arguments:
134# WRAPPED wrap this library on POSIX platforms to add VFS support for
135# libraries that would otherwise not support it.
136# OUTPUT_DIRECTORY where to create the library in the build dir
137# (default: system)
138# Implicit arguments:
139# SOURCES the sources of the library
140# HEADERS the headers of the library (only for IDE support)
141# OTHERS other library related files (only for IDE support)
142# On return:
143# Library target is defined and added to LIBRARY_FILES
144function(core_add_shared_library name)
145 cmake_parse_arguments(arg "WRAPPED" "OUTPUT_DIRECTORY" "" ${ARGN})
146 if(arg_OUTPUT_DIRECTORY)
147 set(OUTPUT_DIRECTORY ${arg_OUTPUT_DIRECTORY})
148 else()
149 if(NOT CORE_SYSTEM_NAME STREQUAL windows)
150 set(OUTPUT_DIRECTORY system)
151 endif()
152 endif()
153 if(CORE_SYSTEM_NAME STREQUAL windows)
154 set(OUTPUT_NAME lib${name})
155 else()
156 set(OUTPUT_NAME lib${name}-${ARCH})
157 endif()
158
159 if(NOT arg_WRAPPED OR CORE_SYSTEM_NAME STREQUAL windows)
160 add_library(${name} SHARED ${SOURCES} ${HEADERS} ${OTHERS})
161 set_target_properties(${name} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${OUTPUT_DIRECTORY}
162 RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${OUTPUT_DIRECTORY}
163 OUTPUT_NAME ${OUTPUT_NAME} PREFIX "")
164 foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES})
165 string(TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG)
166 set_target_properties(${name} PROPERTIES LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_BINARY_DIR}/${OUTPUT_DIRECTORY}
167 RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_BINARY_DIR}/${OUTPUT_DIRECTORY})
168 endforeach()
169
170 set(LIBRARY_FILES ${LIBRARY_FILES} ${CMAKE_BINARY_DIR}/${OUTPUT_DIRECTORY}/${OUTPUT_NAME}${CMAKE_SHARED_LIBRARY_SUFFIX} CACHE STRING "" FORCE)
171 add_dependencies(${APP_NAME_LC}-libraries ${name})
172 else()
173 add_library(${name} STATIC ${SOURCES} ${HEADERS} ${OTHERS})
174 set_target_properties(${name} PROPERTIES POSITION_INDEPENDENT_CODE 1)
175 core_link_library(${name} ${OUTPUT_DIRECTORY}/lib${name})
176 endif()
177endfunction()
178
179# Sets the compile language for all C source files in a target to CXX.
180# Needs to be called from the CMakeLists.txt that defines the target.
181# Arguments:
182# target target
183function(set_language_cxx target)
184 get_property(sources TARGET ${target} PROPERTY SOURCES)
185 foreach(file IN LISTS sources)
186 if(file MATCHES "\.c$")
187 set_source_files_properties(${file} PROPERTIES LANGUAGE CXX)
188 endif()
189 endforeach()
190endfunction()
191
192# Add a data file to installation list with a mirror in build tree
193# Mirroring files in the buildtree allows to execute the app from there.
194# Arguments:
195# file full path to file to mirror
196# Optional Arguments:
197# NO_INSTALL: exclude file from installation target (only mirror)
198# DIRECTORY: directory where the file should be mirrored to
199# (default: preserve tree structure relative to CMAKE_SOURCE_DIR)
200# KEEP_DIR_STRUCTURE: preserve tree structure even when DIRECTORY is set
201# On return:
202# Files is mirrored to the build tree and added to ${install_data}
203# (if NO_INSTALL is not given).
204function(copy_file_to_buildtree file)
205 cmake_parse_arguments(arg "NO_INSTALL" "DIRECTORY;KEEP_DIR_STRUCTURE" "" ${ARGN})
206 if(arg_DIRECTORY)
207 set(outdir ${arg_DIRECTORY})
208 if(arg_KEEP_DIR_STRUCTURE)
209 get_filename_component(srcdir ${arg_KEEP_DIR_STRUCTURE} DIRECTORY)
210 string(REPLACE "${CMAKE_SOURCE_DIR}/${srcdir}/" "" outfile ${file})
211 if(NOT IS_DIRECTORY ${file})
212 set(outdir ${outdir}/${outfile})
213 endif()
214 else()
215 get_filename_component(outfile ${file} NAME)
216 set(outfile ${outdir}/${outfile})
217 endif()
218 else()
219 string(REPLACE "${CMAKE_SOURCE_DIR}/" "" outfile ${file})
220 get_filename_component(outdir ${outfile} DIRECTORY)
221 endif()
222
223 if(NOT TARGET export-files)
224 file(REMOVE ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/ExportFiles.cmake)
225 add_custom_target(export-files ALL COMMENT "Copying files into build tree"
226 COMMAND ${CMAKE_COMMAND} -P ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/ExportFiles.cmake)
227 set_target_properties(export-files PROPERTIES FOLDER "Build Utilities")
228 file(APPEND ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/ExportFiles.cmake "# Export files to build tree\n")
229 endif()
230
231 # Exclude autotools build artefacts and other blacklisted files in source tree.
232 if(file MATCHES "(Makefile|\.in|\.xbt|\.so|\.dylib|\.gitignore)$")
233 if(VERBOSE)
234 message(STATUS "copy_file_to_buildtree - ignoring file: ${file}")
235 endif()
236 return()
237 endif()
238
239 if(NOT file STREQUAL ${CMAKE_BINARY_DIR}/${outfile})
240 if(VERBOSE)
241 message(STATUS "copy_file_to_buildtree - copying file: ${file} -> ${CMAKE_BINARY_DIR}/${outfile}")
242 endif()
243 file(APPEND ${CMAKE_BINARY_DIR}/${CORE_BUILD_DIR}/ExportFiles.cmake
244 "file(COPY \"${file}\" DESTINATION \"${CMAKE_BINARY_DIR}/${outdir}\")\n")
245 endif()
246
247 if(NOT arg_NO_INSTALL)
248 list(APPEND install_data ${outfile})
249 set(install_data ${install_data} PARENT_SCOPE)
250 endif()
251endfunction()
252
253# Add data files to installation list with a mirror in build tree.
254# reads list of files to install from a given list of text files.
255# Arguments:
256# pattern globbing pattern for text files to read
257# Optional Arguments:
258# NO_INSTALL: exclude files from installation target
259# Implicit arguments:
260# CMAKE_SOURCE_DIR - root of source tree
261# On return:
262# Files are mirrored to the build tree and added to ${install_data}
263# (if NO_INSTALL is not given).
264function(copy_files_from_filelist_to_buildtree pattern)
265 # copies files listed in text files to the buildtree
266 # Input: [glob pattern: filepattern]
267 cmake_parse_arguments(arg "NO_INSTALL" "" "" ${ARGN})
268 list(APPEND pattern ${ARGN})
269 list(SORT pattern)
270 if(VERBOSE)
271 message(STATUS "copy_files_from_filelist_to_buildtree - got pattern: ${pattern}")
272 endif()
273 foreach(pat ${pattern})
274 file(GLOB filenames ${pat})
275 foreach(filename ${filenames})
276 string(STRIP ${filename} filename)
277 core_file_read_filtered(fstrings ${filename})
278 foreach(dir ${fstrings})
279 string(CONFIGURE ${dir} dir)
280 string(REPLACE " " ";" dir ${dir})
281 list(GET dir 0 src)
282 list(LENGTH dir len)
283 if(len EQUAL 1)
284 set(dest)
285 elseif(len EQUAL 3)
286 list(GET dir 1 opt)
287 if(opt STREQUAL "KEEP_DIR_STRUCTURE")
288 set(DIR_OPTION ${opt} ${src})
289 if(VERBOSE)
290 message(STATUS "copy_files_from_filelist_to_buildtree - DIR_OPTION: ${DIR_OPTION}")
291 endif()
292 endif()
293 list(GET dir -1 dest)
294 else()
295 list(GET dir -1 dest)
296 endif()
297
298 # If the full path to an existing file is specified then add that single file.
299 # Don't recursively add all files with the given name.
300 if(EXISTS ${CMAKE_SOURCE_DIR}/${src} AND (NOT IS_DIRECTORY ${CMAKE_SOURCE_DIR}/${src} OR DIR_OPTION))
301 set(files ${src})
302 else()
303 file(GLOB_RECURSE files RELATIVE ${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/${src})
304 endif()
305
306 foreach(file ${files})
307 if(arg_NO_INSTALL)
308 copy_file_to_buildtree(${CMAKE_SOURCE_DIR}/${file} DIRECTORY ${dest} NO_INSTALL ${DIR_OPTION})
309 else()
310 copy_file_to_buildtree(${CMAKE_SOURCE_DIR}/${file} DIRECTORY ${dest} ${DIR_OPTION})
311 endif()
312 endforeach()
313 endforeach()
314 endforeach()
315 endforeach()
316 set(install_data ${install_data} PARENT_SCOPE)
317endfunction()
318
319# helper macro to set modified variables in parent scope
320macro(export_dep)
321 set(SYSTEM_INCLUDES ${SYSTEM_INCLUDES} PARENT_SCOPE)
322 set(DEPLIBS ${DEPLIBS} PARENT_SCOPE)
323 set(DEP_DEFINES ${DEP_DEFINES} PARENT_SCOPE)
324 set(${depup}_FOUND ${${depup}_FOUND} PARENT_SCOPE)
325 mark_as_advanced(${depup}_LIBRARIES)
326endmacro()
327
328# add a required dependency of main application
329# Arguments:
330# dep_list name of find rule for dependency, used uppercased for variable prefix
331# also accepts a list of multiple dependencies
332# On return:
333# dependency added to ${SYSTEM_INCLUDES}, ${DEPLIBS} and ${DEP_DEFINES}
334function(core_require_dep)
335 foreach(dep ${ARGN})
336 find_package(${dep} REQUIRED)
337 string(TOUPPER ${dep} depup)
338 list(APPEND SYSTEM_INCLUDES ${${depup}_INCLUDE_DIRS})
339 list(APPEND DEPLIBS ${${depup}_LIBRARIES})
340 list(APPEND DEP_DEFINES ${${depup}_DEFINITIONS})
341 export_dep()
342 endforeach()
343endfunction()
344
345# add a required dyloaded dependency of main application
346# Arguments:
347# dep_list name of find rule for dependency, used uppercased for variable prefix
348# also accepts a list of multiple dependencies
349# On return:
350# dependency added to ${SYSTEM_INCLUDES}, ${dep}_SONAME is set up
351function(core_require_dyload_dep)
352 foreach(dep ${ARGN})
353 find_package(${dep} REQUIRED)
354 string(TOUPPER ${dep} depup)
355 list(APPEND SYSTEM_INCLUDES ${${depup}_INCLUDE_DIRS})
356 list(APPEND DEP_DEFINES ${${depup}_DEFINITIONS})
357 find_soname(${depup} REQUIRED)
358 export_dep()
359 set(${depup}_SONAME ${${depup}_SONAME} PARENT_SCOPE)
360 endforeach()
361endfunction()
362
363# helper macro for optional deps
364macro(setup_enable_switch)
365 string(TOUPPER ${dep} depup)
366 if(${ARGV1})
367 set(enable_switch ${ARGV1})
368 else()
369 set(enable_switch ENABLE_${depup})
370 endif()
371 # normal options are boolean, so we override set our ENABLE_FOO var to allow "auto" handling
372 set(${enable_switch} "AUTO" CACHE STRING "Enable ${depup} support?")
373endmacro()
374
375# add an optional dependency of main application
376# Arguments:
377# dep_list name of find rule for dependency, used uppercased for variable prefix
378# also accepts a list of multiple dependencies
379# On return:
380# dependency optionally added to ${SYSTEM_INCLUDES}, ${DEPLIBS} and ${DEP_DEFINES}
381function(core_optional_dep)
382 foreach(dep ${ARGN})
383 set(_required False)
384 setup_enable_switch()
385 if(${enable_switch} STREQUAL AUTO)
386 find_package(${dep})
387 elseif(${${enable_switch}})
388 find_package(${dep} REQUIRED)
389 set(_required True)
390 endif()
391
392 if(${depup}_FOUND)
393 list(APPEND SYSTEM_INCLUDES ${${depup}_INCLUDE_DIRS})
394 list(APPEND DEPLIBS ${${depup}_LIBRARIES})
395 list(APPEND DEP_DEFINES ${${depup}_DEFINITIONS})
396 set(final_message ${final_message} "${depup} enabled: Yes")
397 export_dep()
398 elseif(_required)
399 message(FATAL_ERROR "${depup} enabled but not found")
400 else()
401 set(final_message ${final_message} "${depup} enabled: No")
402 endif()
403 endforeach()
404 set(final_message ${final_message} PARENT_SCOPE)
405endfunction()
406
407# add an optional dyloaded dependency of main application
408# Arguments:
409# dep_list name of find rule for dependency, used uppercased for variable prefix
410# also accepts a list of multiple dependencies
411# On return:
412# dependency optionally added to ${SYSTEM_INCLUDES}, ${DEP_DEFINES}, ${dep}_SONAME is set up
413function(core_optional_dyload_dep)
414 foreach(dep ${ARGN})
415 set(_required False)
416 setup_enable_switch()
417 if(${enable_switch} STREQUAL AUTO)
418 find_package(${dep})
419 elseif(${${enable_switch}})
420 find_package(${dep} REQUIRED)
421 set(_required True)
422 endif()
423
424 if(${depup}_FOUND)
425 list(APPEND SYSTEM_INCLUDES ${${depup}_INCLUDE_DIRS})
426 find_soname(${depup} REQUIRED)
427 list(APPEND DEP_DEFINES ${${depup}_DEFINITIONS})
428 set(final_message ${final_message} "${depup} enabled: Yes" PARENT_SCOPE)
429 export_dep()
430 set(${depup}_SONAME ${${depup}_SONAME} PARENT_SCOPE)
431 elseif(_required)
432 message(FATAL_ERROR "${depup} enabled but not found")
433 else()
434 set(final_message ${final_message} "${depup} enabled: No" PARENT_SCOPE)
435 endif()
436 endforeach()
437endfunction()
438
439function(core_file_read_filtered result filepattern)
440 # Reads STRINGS from text files
441 # with comments filtered out
442 # Result: [list: result]
443 # Input: [glob pattern: filepattern]
444 file(GLOB filenames ${filepattern})
445 list(SORT filenames)
446 foreach(filename ${filenames})
447 if(VERBOSE)
448 message(STATUS "core_file_read_filtered - filename: ${filename}")
449 endif()
450 set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${filename})
451 file(STRINGS ${filename} fstrings REGEX "^[^#//]")
452 foreach(fstring ${fstrings})
453 string(REGEX REPLACE "^(.*)#(.*)" "\\1" fstring ${fstring})
454 string(REGEX REPLACE "[ \n\r\t]//.*" "" fstring ${fstring})
455 string(STRIP ${fstring} fstring)
456 list(APPEND filename_strings ${fstring})
457 endforeach()
458 endforeach()
459 set(${result} ${filename_strings} PARENT_SCOPE)
460endfunction()
461
462function(core_add_subdirs_from_filelist files)
463 # Adds subdirectories from a sorted list of files
464 # Input: [list: filenames] [bool: sort]
465 foreach(arg ${ARGN})
466 list(APPEND files ${arg})
467 endforeach()
468 list(SORT files)
469 if(VERBOSE)
470 message(STATUS "core_add_subdirs_from_filelist - got pattern: ${files}")
471 endif()
472 foreach(filename ${files})
473 string(STRIP ${filename} filename)
474 core_file_read_filtered(fstrings ${filename})
475 foreach(subdir ${fstrings})
476 string(REPLACE " " ";" subdir ${subdir})
477 list(GET subdir 0 subdir_src)
478 list(GET subdir -1 subdir_dest)
479 if(VERBOSE)
480 message(STATUS " core_add_subdirs_from_filelist - adding subdir: ${CMAKE_SOURCE_DIR}/${subdir_src} -> ${CORE_BUILD_DIR}/${subdir_dest}")
481 endif()
482 add_subdirectory(${CMAKE_SOURCE_DIR}/${subdir_src} ${CORE_BUILD_DIR}/${subdir_dest})
483 endforeach()
484 endforeach()
485endfunction()
486
487macro(core_add_optional_subdirs_from_filelist pattern)
488 # Adds subdirectories from text files
489 # if the option(s) in the 3rd field are enabled
490 # Input: [glob pattern: filepattern]
491 foreach(arg ${ARGN})
492 list(APPEND pattern ${arg})
493 endforeach()
494 foreach(elem ${pattern})
495 string(STRIP ${elem} elem)
496 list(APPEND filepattern ${elem})
497 endforeach()
498
499 file(GLOB filenames ${filepattern})
500 list(SORT filenames)
501 if(VERBOSE)
502 message(STATUS "core_add_optional_subdirs_from_filelist - got pattern: ${filenames}")
503 endif()
504
505 foreach(filename ${filenames})
506 if(VERBOSE)
507 message(STATUS "core_add_optional_subdirs_from_filelist - reading file: ${filename}")
508 endif()
509 set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${filename})
510 file(STRINGS ${filename} fstrings REGEX "^[^#//]")
511 foreach(line ${fstrings})
512 string(REPLACE " " ";" line "${line}")
513 list(GET line 0 subdir_src)
514 list(GET line 1 subdir_dest)
515 list(GET line 3 opts)
516 foreach(opt ${opts})
517 if(ENABLE_${opt})
518 if(VERBOSE)
519 message(STATUS " core_add_optional_subdirs_from_filelist - adding subdir: ${CMAKE_SOURCE_DIR}/${subdir_src} -> ${CORE_BUILD_DIR}/${subdir_dest}")
520 endif()
521 add_subdirectory(${CMAKE_SOURCE_DIR}/${subdir_src} ${CORE_BUILD_DIR}/${subdir_dest})
522 else()
523 if(VERBOSE)
524 message(STATUS " core_add_optional_subdirs_from_filelist: OPTION ${opt} not enabled for ${subdir_src}, skipping subdir")
525 endif()
526 endif()
527 endforeach()
528 endforeach()
529 endforeach()
530endmacro()
531
532# Generates an RFC2822 timestamp
533#
534# The following variable is set:
535# RFC2822_TIMESTAMP
536function(rfc2822stamp)
537 execute_process(COMMAND date -R
538 OUTPUT_VARIABLE RESULT)
539 set(RFC2822_TIMESTAMP ${RESULT} PARENT_SCOPE)
540endfunction()
541
542# Generates an user stamp from git config info
543#
544# The following variable is set:
545# PACKAGE_MAINTAINER - user stamp in the form of "username <username@example.com>"
546# if no git tree is found, value is set to "nobody <nobody@example.com>"
547function(userstamp)
548 find_package(Git)
549 if(GIT_FOUND AND EXISTS ${CMAKE_SOURCE_DIR}/.git)
550 execute_process(COMMAND ${GIT_EXECUTABLE} config user.name
551 OUTPUT_VARIABLE username
552 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
553 OUTPUT_STRIP_TRAILING_WHITESPACE)
554 execute_process(COMMAND ${GIT_EXECUTABLE} config user.email
555 OUTPUT_VARIABLE useremail
556 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
557 OUTPUT_STRIP_TRAILING_WHITESPACE)
558 set(PACKAGE_MAINTAINER "${username} <${useremail}>" PARENT_SCOPE)
559 else()
560 set(PACKAGE_MAINTAINER "nobody <nobody@example.com>" PARENT_SCOPE)
561 endif()
562endfunction()
563
564# Parses git info and sets variables used to identify the build
565# Arguments:
566# stamp variable name to return
567# Optional Arguments:
568# FULL: generate git HEAD commit in the form of 'YYYYMMDD-hash'
569# if git tree is dirty, value is set in the form of 'YYYYMMDD-hash-dirty'
570# if no git tree is found, value is set in the form of 'YYYYMMDD-nogitfound'
571# if FULL is not given, stamp is generated following the same process as above
572# but without 'YYYYMMDD'
573# On return:
574# Variable is set with generated stamp to PARENT_SCOPE
575function(core_find_git_rev stamp)
576 # allow manual setting GIT_VERSION
577 if(GIT_VERSION)
578 set(${stamp} ${GIT_VERSION} PARENT_SCOPE)
579 else()
580 find_package(Git)
581 if(GIT_FOUND AND EXISTS ${CMAKE_SOURCE_DIR}/.git)
582 execute_process(COMMAND ${GIT_EXECUTABLE} update-index --ignore-submodules --refresh -q)
583 execute_process(COMMAND ${GIT_EXECUTABLE} diff-files --ignore-submodules --quiet --
584 RESULT_VARIABLE status_code
585 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
586 if(NOT status_code)
587 execute_process(COMMAND ${GIT_EXECUTABLE} diff-index --ignore-submodules --quiet HEAD --
588 RESULT_VARIABLE status_code
589 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
590 endif()
591 if(status_code)
592 execute_process(COMMAND ${GIT_EXECUTABLE} log -n 1 --pretty=format:"%h-dirty" HEAD
593 OUTPUT_VARIABLE HASH
594 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
595 string(SUBSTRING ${HASH} 1 13 HASH)
596 else()
597 execute_process(COMMAND ${GIT_EXECUTABLE} log -n 1 --pretty=format:"%h" HEAD
598 OUTPUT_VARIABLE HASH
599 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
600 string(SUBSTRING ${HASH} 1 7 HASH)
601 endif()
602 execute_process(COMMAND ${GIT_EXECUTABLE} log -1 --pretty=format:"%cd" --date=short HEAD
603 OUTPUT_VARIABLE DATE
604 WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
605 string(SUBSTRING ${DATE} 1 10 DATE)
606 string(REPLACE "-" "" DATE ${DATE})
607 else()
608 string(TIMESTAMP DATE "%Y%m%d" UTC)
609 set(HASH "nogitfound")
610 endif()
611 cmake_parse_arguments(arg "FULL" "" "" ${ARGN})
612 if(arg_FULL)
613 set(${stamp} ${DATE}-${HASH} PARENT_SCOPE)
614 else()
615 set(${stamp} ${HASH} PARENT_SCOPE)
616 endif()
617 endif()
618endfunction()
619
620# Parses version.txt and versions.h and sets variables
621# used to construct dirs structure, file naming, API version, etc.
622#
623# The following variables are set from version.txt:
624# APP_NAME - app name
625# APP_NAME_LC - lowercased app name
626# APP_NAME_UC - uppercased app name
627# APP_PACKAGE - Android full package name
628# COMPANY_NAME - company name
629# APP_VERSION_MAJOR - the app version major
630# APP_VERSION_MINOR - the app version minor
631# APP_VERSION_TAG - the app version tag
632# APP_VERSION_TAG_LC - lowercased app version tag
633# APP_VERSION - the app version (${APP_VERSION_MAJOR}.${APP_VERSION_MINOR}-${APP_VERSION_TAG})
634# APP_ADDON_API - the addon API version in the form of 16.9.702
635# FILE_VERSION - file version in the form of 16,9,702,0 - Windows only
636#
637# Set various variables defined in "versions.h"
638macro(core_find_versions)
639 # kodi-addons project also calls this macro and uses CORE_SOURCE_DIR
640 # to point to core base dir
641 # Set CORE_SOURCE_DIR here, otherwise kodi main project fails
642 # TODO: drop this code block and refactor the rest to use CMAKE_SOURCE_DIR
643 # if we ever integrate kodi-addons into kodi project
644 if(NOT CORE_SOURCE_DIR)
645 set(CORE_SOURCE_DIR ${CMAKE_SOURCE_DIR})
646 endif()
647
648 include(CMakeParseArguments)
649 core_file_read_filtered(version_list ${CORE_SOURCE_DIR}/version.txt)
650 string(REPLACE " " ";" version_list "${version_list}")
651 cmake_parse_arguments(APP "" "APP_NAME;COMPANY_NAME;WEBSITE;VERSION_MAJOR;VERSION_MINOR;VERSION_TAG;VERSION_CODE;ADDON_API;APP_PACKAGE" "" ${version_list})
652
653 set(APP_NAME ${APP_APP_NAME}) # inconsistency but APP_APP_NAME looks weird
654 string(TOLOWER ${APP_APP_NAME} APP_NAME_LC)
655 string(TOUPPER ${APP_APP_NAME} APP_NAME_UC)
656 set(COMPANY_NAME ${APP_COMPANY_NAME})
657 set(APP_VERSION ${APP_VERSION_MAJOR}.${APP_VERSION_MINOR})
658 set(APP_PACKAGE ${APP_APP_PACKAGE})
659 if(APP_VERSION_TAG)
660 set(APP_VERSION ${APP_VERSION}-${APP_VERSION_TAG})
661 string(TOLOWER ${APP_VERSION_TAG} APP_VERSION_TAG_LC)
662 endif()
663 string(REPLACE "." "," FILE_VERSION ${APP_ADDON_API}.0)
664
665 # Set defines used in addon.xml.in and read from versions.h to set add-on
666 # version parts automatically
667 # This part is nearly identical to "AddonHelpers.cmake", except location of versions.h
668 file(STRINGS ${CORE_SOURCE_DIR}/xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h BIN_ADDON_PARTS)
669 foreach(loop_var ${BIN_ADDON_PARTS})
670 string(FIND "${loop_var}" "#define ADDON_" matchres)
671 if("${matchres}" EQUAL 0)
672 string(REGEX MATCHALL "[A-Z0-9._]+|[A-Z0-9._]+$" loop_var "${loop_var}")
673 list(GET loop_var 0 include_name)
674 list(GET loop_var 1 include_version)
675 string(REGEX REPLACE ".*\"(.*)\"" "\\1" ${include_name} ${include_version})
676 endif()
677 endforeach(loop_var)
678
679 # unset variables not used anywhere else
680 unset(version_list)
681 unset(APP_APP_NAME)
682 unset(BIN_ADDON_PARTS)
683
684 # bail if we can't parse version.txt
685 if(NOT DEFINED APP_VERSION_MAJOR OR NOT DEFINED APP_VERSION_MINOR)
686 message(FATAL_ERROR "Could not determine app version! Make sure that ${CORE_SOURCE_DIR}/version.txt exists")
687 endif()
688endmacro()
689
690# add-on xml's
691# find all folders containing addon.xml.in and used to define
692# ADDON_XML_OUTPUTS, ADDON_XML_DEPENDS and ADDON_INSTALL_DATA
693macro(find_addon_xml_in_files)
694 file(GLOB ADDON_XML_IN_FILE ${CMAKE_SOURCE_DIR}/addons/*/addon.xml.in)
695 foreach(loop_var ${ADDON_XML_IN_FILE})
696 list(GET loop_var 0 xml_name)
697
698 string(REPLACE "/addon.xml.in" "" xml_name ${xml_name})
699 string(REPLACE "${CORE_SOURCE_DIR}/" "" xml_name ${xml_name})
700
701 list(APPEND ADDON_XML_DEPENDS "${CORE_SOURCE_DIR}/${xml_name}/addon.xml.in")
702 list(APPEND ADDON_XML_OUTPUTS "${CMAKE_BINARY_DIR}/${xml_name}/addon.xml")
703
704 # Read content of add-on folder to have on install
705 file(GLOB ADDON_FILES "${CORE_SOURCE_DIR}/${xml_name}/*")
706 foreach(loop_var ${ADDON_FILES})
707 if(loop_var MATCHES "addon.xml.in")
708 string(REPLACE "addon.xml.in" "addon.xml" loop_var ${loop_var})
709 endif()
710
711 list(GET loop_var 0 file_name)
712 string(REPLACE "${CORE_SOURCE_DIR}/" "" file_name ${file_name})
713 list(APPEND ADDON_INSTALL_DATA "${file_name}")
714
715 unset(file_name)
716 endforeach()
717 unset(xml_name)
718 endforeach()
719
720 # Append also versions.h to depends
721 list(APPEND ADDON_XML_DEPENDS "${CORE_SOURCE_DIR}/xbmc/addons/kodi-addon-dev-kit/include/kodi/versions.h")
722endmacro()
diff --git a/cmake/scripts/common/PrepareEnv.cmake b/cmake/scripts/common/PrepareEnv.cmake
new file mode 100644
index 0000000..4dc8698
--- /dev/null
+++ b/cmake/scripts/common/PrepareEnv.cmake
@@ -0,0 +1,65 @@
1# parse version.txt and versions.h to get the version and API info
2include(${CORE_SOURCE_DIR}/cmake/scripts/common/Macros.cmake)
3core_find_versions()
4
5# in case we need to download something, set KODI_MIRROR to the default if not already set
6if(NOT DEFINED KODI_MIRROR)
7 set(KODI_MIRROR "http://mirrors.kodi.tv")
8endif()
9
10### copy all the addon binding header files to include/kodi
11# make sure include/kodi exists and is empty
12set(APP_LIB_DIR ${ADDON_DEPENDS_PATH}/lib/${APP_NAME_LC})
13if(NOT EXISTS "${APP_LIB_DIR}/")
14 file(MAKE_DIRECTORY ${APP_LIB_DIR})
15endif()
16
17set(APP_DATA_DIR ${ADDON_DEPENDS_PATH}/share/${APP_NAME_LC})
18if(NOT EXISTS "${APP_DATA_DIR}/")
19 file(MAKE_DIRECTORY ${APP_DATA_DIR})
20endif()
21
22set(APP_INCLUDE_DIR ${ADDON_DEPENDS_PATH}/include/${APP_NAME_LC})
23if(NOT EXISTS "${APP_INCLUDE_DIR}/")
24 file(MAKE_DIRECTORY ${APP_INCLUDE_DIR})
25endif()
26
27# make sure C++11 is always set
28if(NOT WIN32)
29 string(REGEX MATCH "-std=(gnu|c)\\+\\+11" cxx11flag "${CMAKE_CXX_FLAGS}")
30 if(NOT cxx11flag)
31 set(CXX11_SWITCH "-std=c++11")
32 endif()
33endif()
34
35# generate the proper KodiConfig.cmake file
36configure_file(${CORE_SOURCE_DIR}/cmake/KodiConfig.cmake.in ${APP_LIB_DIR}/KodiConfig.cmake @ONLY)
37
38# copy cmake helpers to lib/kodi
39file(COPY ${CORE_SOURCE_DIR}/cmake/scripts/common/AddonHelpers.cmake
40 ${CORE_SOURCE_DIR}/cmake/scripts/common/AddOptions.cmake
41 DESTINATION ${APP_LIB_DIR})
42
43# copy standard add-on include files
44file(COPY ${CORE_SOURCE_DIR}/xbmc/addons/kodi-addon-dev-kit/include/kodi/
45 DESTINATION ${APP_INCLUDE_DIR})
46
47### copy all the addon binding header files to include/kodi
48# parse addon-bindings.mk to get the list of header files to copy
49core_file_read_filtered(bindings ${CORE_SOURCE_DIR}/xbmc/addons/addon-bindings.mk)
50foreach(header ${bindings})
51 # copy the header file to include/kodi
52 configure_file(${CORE_SOURCE_DIR}/${header} ${APP_INCLUDE_DIR} COPYONLY)
53endforeach()
54
55### processing additional tools required by the platform
56if(EXISTS ${CORE_SOURCE_DIR}/cmake/scripts/${CORE_SYSTEM_NAME}/tools/)
57 file(GLOB platform_tools ${CORE_SOURCE_DIR}/cmake/scripts/${CORE_SYSTEM_NAME}/tools/*.cmake)
58 foreach(platform_tool ${platform_tools})
59 get_filename_component(platform_tool_name ${platform_tool} NAME_WE)
60 message(STATUS "Processing ${CORE_SYSTEM_NAME} specific tool: ${platform_tool_name}")
61
62 # include the file
63 include(${platform_tool})
64 endforeach()
65endif()
diff --git a/cmake/scripts/common/ProjectMacros.cmake b/cmake/scripts/common/ProjectMacros.cmake
new file mode 100644
index 0000000..89ecca4
--- /dev/null
+++ b/cmake/scripts/common/ProjectMacros.cmake
@@ -0,0 +1,89 @@
1# This script holds macros which are project specific
2
3# Pack a skin xbt file
4# Arguments:
5# input input directory to pack
6# output ouput xbt file
7# On return:
8# xbt is added to ${XBT_FILES}
9function(pack_xbt input output)
10 file(GLOB_RECURSE MEDIA_FILES ${input}/*)
11 get_filename_component(dir ${output} DIRECTORY)
12 add_custom_command(OUTPUT ${output}
13 COMMAND ${CMAKE_COMMAND} -E make_directory ${dir}
14 COMMAND TexturePacker::TexturePacker
15 ARGS -input ${input}
16 -output ${output}
17 -dupecheck
18 DEPENDS ${MEDIA_FILES})
19 list(APPEND XBT_FILES ${output})
20 set(XBT_FILES ${XBT_FILES} PARENT_SCOPE)
21endfunction()
22
23# Add a skin to installation list, mirroring it in build tree, packing textures
24# Arguments:
25# skin skin directory
26# On return:
27# xbt is added to ${XBT_FILES}, data added to ${install_data}, mirror in build tree
28function(copy_skin_to_buildtree skin)
29 file(GLOB_RECURSE FILES ${skin}/*)
30 file(GLOB_RECURSE MEDIA_FILES ${skin}/media/*)
31 list(REMOVE_ITEM FILES ${MEDIA_FILES})
32 foreach(file ${FILES})
33 copy_file_to_buildtree(${file})
34 endforeach()
35 file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/${dest}/media)
36 string(REPLACE "${CMAKE_SOURCE_DIR}/" "" dest ${skin})
37 pack_xbt(${skin}/media ${CMAKE_BINARY_DIR}/${dest}/media/Textures.xbt)
38
39 file(GLOB THEMES RELATIVE ${skin}/themes ${skin}/themes/*)
40 foreach(theme ${THEMES})
41 pack_xbt(${skin}/themes/${theme} ${CMAKE_BINARY_DIR}/${dest}/media/${theme}.xbt)
42 endforeach()
43
44 set(XBT_FILES ${XBT_FILES} PARENT_SCOPE)
45 set(install_data ${install_data} PARENT_SCOPE)
46endfunction()
47
48# Get GTest tests as CMake tests.
49# Copied from FindGTest.cmake
50# Thanks to Daniel Blezek <blezek@gmail.com> for the GTEST_ADD_TESTS code
51function(GTEST_ADD_TESTS executable extra_args)
52 if(NOT ARGN)
53 message(FATAL_ERROR "Missing ARGN: Read the documentation for GTEST_ADD_TESTS")
54 endif()
55 foreach(source ${ARGN})
56 # This assumes that every source file passed in exists. Consider using
57 # SUPPORT_SOURCES for source files which do not contain tests and might
58 # have to be generated.
59 file(READ "${source}" contents)
60 string(REGEX MATCHALL "TEST_?[F]?\\(([A-Za-z_0-9 ,]+)\\)" found_tests ${contents})
61 foreach(hit ${found_tests})
62 string(REGEX REPLACE ".*\\( *([A-Za-z_0-9]+), *([A-Za-z_0-9]+) *\\).*" "\\1.\\2" test_name ${hit})
63 add_test(${test_name} ${executable} --gtest_filter=${test_name} ${extra_args})
64 endforeach()
65 # Groups parametrized tests under a single ctest entry
66 string(REGEX MATCHALL "INSTANTIATE_TEST_CASE_P\\(([^,]+), *([^,]+)" found_tests2 ${contents})
67 foreach(hit ${found_tests2})
68 string(SUBSTRING ${hit} 24 -1 test_name)
69 string(REPLACE "," ";" test_name "${test_name}")
70 list(GET test_name 0 filter_name)
71 list(GET test_name 1 test_prefix)
72 string(STRIP ${test_prefix} test_prefix)
73 add_test(${test_prefix}.${filter_name} ${executable} --gtest_filter=${filter_name}* ${extra_args})
74 endforeach()
75 endforeach()
76endfunction()
77
78function(whole_archive output)
79 if(CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang)
80 set(${output} -Wl,--whole-archive ${ARGN} -Wl,--no-whole-archive PARENT_SCOPE)
81 elseif(CMAKE_CXX_COMPILER_ID STREQUAL AppleClang)
82 foreach(library ${ARGN})
83 list(APPEND ${output} -Wl,-force_load ${library})
84 set(${output} ${${output}} PARENT_SCOPE)
85 endforeach()
86 else()
87 set(${output} ${ARGN} PARENT_SCOPE)
88 endif()
89endfunction()
diff --git a/cmake/scripts/common/Uninstall.cmake b/cmake/scripts/common/Uninstall.cmake
new file mode 100644
index 0000000..5660e19
--- /dev/null
+++ b/cmake/scripts/common/Uninstall.cmake
@@ -0,0 +1,22 @@
1# Uninstall target
2set(MANIFEST ${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt)
3if(EXISTS ${MANIFEST})
4 file(STRINGS ${MANIFEST} files)
5 foreach(file IN LISTS files)
6 if(EXISTS $ENV{DESTDIR}${file})
7 message(STATUS "Uninstalling: ${file}")
8 execute_process(
9 COMMAND ${CMAKE_COMMAND} -E remove $ENV{DESTDIR}${file}
10 OUTPUT_VARIABLE rm_out
11 RESULT_VARIABLE rm_retval
12 )
13 if(NOT "${rm_retval}" STREQUAL 0)
14 message(FATAL_ERROR "Failed to remove file: $ENV{DESTDIR}${file}")
15 endif()
16 else()
17 message(STATUS "File does not exist: $ENV{DESTDIR}${file}")
18 endif()
19 endforeach(file)
20else()
21 message(STATUS "Cannot find install manifest: '${MANIFEST}'")
22endif()