summaryrefslogtreecommitdiffstats
path: root/cmake/addons/CMakeLists.txt
diff options
context:
space:
mode:
Diffstat (limited to 'cmake/addons/CMakeLists.txt')
-rw-r--r--cmake/addons/CMakeLists.txt439
1 files changed, 439 insertions, 0 deletions
diff --git a/cmake/addons/CMakeLists.txt b/cmake/addons/CMakeLists.txt
new file mode 100644
index 0000000..a6ea149
--- /dev/null
+++ b/cmake/addons/CMakeLists.txt
@@ -0,0 +1,439 @@
1cmake_minimum_required(VERSION 3.1)
2project(kodi-addons)
3
4list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR})
5
6option(ADDON_TARBALL_CACHING "Cache downloaded addon source tarballs?" ON)
7if(ADDON_TARBALL_CACHING)
8 message(STATUS "Addon source tarball caching is enabled")
9else()
10 message(STATUS "Addon source tarball caching is disabled")
11endif()
12
13if(NOT CMAKE_BUILD_TYPE)
14 set(CMAKE_BUILD_TYPE Release)
15endif()
16
17if(NOT CORE_SYSTEM_NAME)
18 if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
19 set(CORE_SYSTEM_NAME "osx")
20 else()
21 string(TOLOWER ${CMAKE_SYSTEM_NAME} CORE_SYSTEM_NAME)
22 endif()
23endif()
24
25include(ExternalProject)
26
27### setup all the necessary paths
28if(APP_ROOT)
29 set(CORE_SOURCE_DIR ${APP_ROOT})
30 unset(APP_ROOT)
31 message(WARNING "APP_ROOT is deprecated. Please use CORE_SOURCE_DIR instead.")
32endif()
33if(NOT CORE_SOURCE_DIR)
34 set(CORE_SOURCE_DIR ${PROJECT_SOURCE_DIR}/../..)
35else()
36 file(TO_CMAKE_PATH "${CORE_SOURCE_DIR}" CORE_SOURCE_DIR)
37endif()
38get_filename_component(CORE_SOURCE_DIR "${CORE_SOURCE_DIR}" ABSOLUTE)
39
40if(NOT BUILD_DIR)
41 set(BUILD_DIR "${CMAKE_BINARY_DIR}/build")
42else()
43 file(TO_CMAKE_PATH "${BUILD_DIR}" BUILD_DIR)
44endif()
45get_filename_component(BUILD_DIR "${BUILD_DIR}" ABSOLUTE)
46
47if(NOT ADDON_DEPENDS_PATH)
48 set(ADDON_DEPENDS_PATH "${BUILD_DIR}/depends")
49else()
50 file(TO_CMAKE_PATH "${ADDON_DEPENDS_PATH}" ADDON_DEPENDS_PATH)
51endif()
52get_filename_component(ADDON_DEPENDS_PATH "${ADDON_DEPENDS_PATH}" ABSOLUTE)
53
54if(NOT PLATFORM_DIR)
55 set(PLATFORM_DIR ${CORE_SOURCE_DIR}/cmake/platform/${CORE_SYSTEM_NAME})
56 file(TO_CMAKE_PATH "${PLATFORM_DIR}" PLATFORM_DIR)
57endif()
58
59# make sure CMAKE_PREFIX_PATH is set
60if(NOT CMAKE_PREFIX_PATH)
61 set(CMAKE_PREFIX_PATH "${ADDON_DEPENDS_PATH}")
62else()
63 file(TO_CMAKE_PATH "${CMAKE_PREFIX_PATH}" CMAKE_PREFIX_PATH)
64 list(APPEND CMAKE_PREFIX_PATH "${ADDON_DEPENDS_PATH}")
65endif()
66
67# check for autoconf stuff to pass on
68if(AUTOCONF_FILES)
69 string(REPLACE " " ";" AUTOCONF_FILES ${AUTOCONF_FILES})
70 set(CROSS_AUTOCONF "yes")
71endif()
72
73if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT OR NOT CMAKE_INSTALL_PREFIX)
74 set(CMAKE_INSTALL_PREFIX "${PROJECT_SOURCE_DIR}/output/addons")
75endif()
76list(APPEND CMAKE_PREFIX_PATH ${CMAKE_INSTALL_PREFIX})
77
78set(BUILD_ARGS -DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}
79 -DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
80 -DPACKAGE_CONFIG_PATH=${ADDON_DEPENDS_PATH}/lib/pkgconfig
81 -DADDON_DEPENDS_PATH=${ADDON_DEPENDS_PATH}
82 -DOVERRIDE_PATHS=${OVERRIDE_PATHS}
83 -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
84 -DCMAKE_USER_MAKE_RULES_OVERRIDE=${CMAKE_USER_MAKE_RULES_OVERRIDE}
85 -DCMAKE_USER_MAKE_RULES_OVERRIDE_CXX=${CMAKE_USER_MAKE_RULES_OVERRIDE_CXX}
86 -DCORE_SYSTEM_NAME=${CORE_SYSTEM_NAME}
87 -DBUILD_SHARED_LIBS=1
88 -DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}
89 -DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS})
90
91if(MSVC)
92 # move cmake specific targets to a CMakePredefinedTargets folder in Visual Studio
93 set_property(GLOBAL PROPERTY USE_FOLDERS ON)
94endif()
95
96option(PACKAGE_ZIP "Prepare built addons for packaging" OFF)
97if(PACKAGE_ZIP)
98 # needed for project installing
99 list(APPEND BUILD_ARGS -DPACKAGE_ZIP=ON)
100
101 # figure out where to store the packaged ZIP archives
102 if(NOT PACKAGE_DIR)
103 set(PACKAGE_DIR "${BUILD_DIR}/zips")
104 else()
105 file(TO_CMAKE_PATH "${PACKAGE_DIR}" PACKAGE_DIR)
106 endif()
107 list(APPEND BUILD_ARGS -DPACKAGE_DIR=${PACKAGE_DIR})
108
109 message(STATUS "ZIP packaging enabled (destination: ${PACKAGE_DIR})")
110endif()
111
112if(CMAKE_TOOLCHAIN_FILE)
113 list(APPEND BUILD_ARGS -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE})
114 message(STATUS "Toolchain specified")
115 message(STATUS ${BUILD_ARGS})
116endif()
117
118if(NOT ADDONS_TO_BUILD)
119 set(ADDONS_TO_BUILD "all")
120else()
121 string(STRIP "${ADDONS_TO_BUILD}" ADDONS_TO_BUILD)
122 message(STATUS "Building following addons: ${ADDONS_TO_BUILD}")
123 string(REPLACE " " ";" ADDONS_TO_BUILD ${ADDONS_TO_BUILD})
124endif()
125
126if(NOT ADDONS_DEFINITION_DIR)
127 set(ADDONS_DEFINITION_DIR ${PROJECT_SOURCE_DIR}/addons)
128else()
129 file(TO_CMAKE_PATH "${ADDONS_DEFINITION_DIR}" ADDONS_DEFINITION_DIR)
130endif()
131get_filename_component(ADDONS_DEFINITION_DIR "${ADDONS_DEFINITION_DIR}" ABSOLUTE)
132
133if(ADDON_SRC_PREFIX)
134 if(NOT IS_ABSOLUTE ${ADDON_SRC_PREFIX})
135 get_filename_component(ADDON_SRC_PREFIX "${CMAKE_BINARY_DIR}/${ADDON_SRC_PREFIX}" ABSOLUTE)
136 endif()
137 message(STATUS "Overriding addon source directory prefix: ${ADDON_SRC_PREFIX}")
138endif()
139
140if(NOT APP_LIB_DIR)
141 set(APP_LIB_DIR "${ADDON_DEPENDS_PATH}/lib/kodi")
142else()
143 file(TO_CMAKE_PATH "${APP_LIB_DIR}" APP_LIB_DIR)
144endif()
145
146set(APP_PREFIX "${CMAKE_INSTALL_PREFIX}")
147
148# check for platform specific stuff
149if(EXISTS ${PLATFORM_DIR}/defines.txt)
150 file(STRINGS ${PLATFORM_DIR}/defines.txt platformdefines)
151
152 if(NOT ARCH_DEFINES AND platformdefines)
153 set(ARCH_DEFINES ${platformdefines})
154 endif()
155endif()
156
157# include check_target_platform() function
158include(${CORE_SOURCE_DIR}/cmake/scripts/common/CheckTargetPlatform.cmake)
159
160set(ADDON_INSTALL_DIR ${CMAKE_INSTALL_PREFIX})
161if(NOT WIN32)
162 # check install permissions
163 check_install_permissions(${CMAKE_INSTALL_PREFIX} can_write)
164 if(NOT ${can_write} AND CMAKE_SYSTEM_NAME STREQUAL "Linux")
165 set(NEED_SUDO TRUE)
166 set(ADDON_INSTALL_DIR ${CMAKE_BINARY_DIR}/.install)
167 list(APPEND BUILD_ARGS -DOVERRIDE_PATHS=ON)
168 message(STATUS "NEED_SUDO: ${NEED_SUDO} (no write permission for ${CMAKE_INSTALL_PREFIX})")
169 endif()
170endif()
171
172### prepare the build environment for the binary addons
173# copy the PrepareEnv.cmake script to the depends path so that we can include it
174file(COPY ${CORE_SOURCE_DIR}/cmake/scripts/common/PrepareEnv.cmake DESTINATION ${APP_LIB_DIR})
175
176# add the location of PrepareEnv.cmake to CMAKE_MODULE_PATH so that it is found
177list(APPEND CMAKE_MODULE_PATH ${APP_LIB_DIR})
178
179# include PrepareEnv.cmake which contains the logic to install the addon header bindings etc
180include(PrepareEnv)
181
182### add the depends subdirectory for any general dependencies
183message(STATUS "\n-- ---- Preparing general dependencies ----")
184add_subdirectory(depends)
185
186# add a custom target "package-addons" which will package and install all addons
187add_custom_target(package-addons)
188
189### get and build all the binary addons
190# look for all the addons to be built
191file(GLOB_RECURSE addons ${ADDONS_DEFINITION_DIR}/*.txt)
192
193#if there are no addons assume that bootstrapping hasn't happened yet
194if(NOT addons)
195 message(STATUS "Bootstrapping all default repositories as no addons were found...")
196 set(BOOTSTRAP_BUILD_DIR "${BUILD_DIR}/bootstrap")
197
198 # make sure that the bootstraps build addon exists
199 if(NOT EXISTS ${BOOTSTRAP_BUILD_DIR})
200 file(MAKE_DIRECTORY ${BOOTSTRAP_BUILD_DIR})
201 endif()
202
203 string(REPLACE ";" " " ADDONS_TO_BUILD_STR "${ADDONS_TO_BUILD}")
204 # generate the bootstrap buildsystem
205 execute_process(COMMAND ${CMAKE_COMMAND} ${PROJECT_SOURCE_DIR}/bootstrap
206 -DCMAKE_INSTALL_PREFIX:PATH=${ADDONS_DEFINITION_DIR}
207 -DBUILD_DIR:PATH=${BOOTSTRAP_BUILD_DIR}
208 -DADDONS_TO_BUILD:STRING=${ADDONS_TO_BUILD_STR}
209 -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}
210 WORKING_DIRECTORY ${BOOTSTRAP_BUILD_DIR})
211
212 # execute the generated bootstrap buildsystem
213 execute_process(COMMAND ${CMAKE_COMMAND} --build ${BOOTSTRAP_BUILD_DIR}
214 WORKING_DIRECTORY ${BOOTSTRAP_BUILD_DIR})
215
216 # now look for all the addons to be built again
217 file(GLOB_RECURSE addons ${ADDONS_DEFINITION_DIR}/*.txt)
218
219 if(NOT addons)
220 message(FATAL_ERROR "No addons available to be built")
221 endif()
222endif()
223
224# Track if at least one addon has been found. Everything else is likely an
225# error either in ADDONS_TO_BUILD or in the directory configuration.
226set(SUPPORTED_ADDON_FOUND FALSE)
227
228foreach(addon ${addons})
229 if(NOT (addon MATCHES platforms.txt))
230 file(STRINGS ${addon} def)
231 string(REPLACE " " ";" def ${def})
232 list(GET def 0 id)
233
234 set(ADDON_FOUND FALSE)
235 # try to find a perfect match
236 list(FIND ADDONS_TO_BUILD ${id} idx)
237 if(idx GREATER -1 OR "${ADDONS_TO_BUILD}" STREQUAL "all")
238 set(ADDON_FOUND TRUE)
239 # Maybe we have a regex
240 elseif(id MATCHES "${ADDONS_TO_BUILD}")
241 message(STATUS "Pattern ${ADDONS_TO_BUILD} matches ${id}, building addon")
242 set(ADDON_FOUND TRUE)
243 endif()
244
245 if(ADDON_FOUND)
246 message(STATUS "\n-- ---- Configuring addon ${addon} ----")
247 set(SUPPORTED_ADDON_FOUND TRUE)
248
249 get_filename_component(dir ${addon} DIRECTORY)
250
251 # check if the addon has a platforms.txt
252 set(platform_found FALSE)
253 check_target_platform(${dir} ${CORE_SYSTEM_NAME} platform_found)
254
255 if(${platform_found})
256 # make sure the output directory is clean
257 file(REMOVE_RECURSE "${CMAKE_INSTALL_PREFIX}/${id}/")
258
259 # get the URL and revision of the addon
260 list(LENGTH def deflength)
261 list(GET def 1 url)
262
263 set(archive_name ${id})
264 if(ADDON_SRC_PREFIX)
265 set(SOURCE_DIR ${ADDON_SRC_PREFIX}/${id})
266 set(archive_name "")
267 else()
268 set(SOURCE_DIR "")
269 endif()
270
271 # if there is a 3rd parameter in the file, we consider it a git revision
272 if(deflength GREATER 2 AND "${SOURCE_DIR}" STREQUAL "")
273 list(GET def 2 revision)
274
275 # we need access to a git executable
276 find_package(Git REQUIRED)
277
278 # resolve revision to git hash
279 execute_process(COMMAND ${GIT_EXECUTABLE} ls-remote ${url} ${revision} OUTPUT_VARIABLE revision_hash)
280 # git ls-remote only works on branches and tag names but not on revisions
281 if(NOT "${revision_hash}" STREQUAL "")
282 string(REPLACE "\t" ";" revision_list ${revision_hash})
283 list(GET revision_list 0 revision_hash)
284 message(STATUS "${id}: git branch/tag ${revision} resolved to hash: ${revision_hash}")
285 set(revision ${revision_hash})
286 endif()
287
288 # Note: downloading specific revisions via http in the format below is probably github specific
289 # if we ever use other repositories, this might need adapting
290 set(url ${url}/archive/${revision}.tar.gz)
291 set(archive_name ${archive_name}-${revision})
292 elseif("${SOURCE_DIR}" STREQUAL "")
293 # check if the URL starts with file://
294 string(REGEX MATCH "^file://.*$" local_url "${url}")
295
296 #if not we assume this to be a local directory
297 if(local_url)
298 # this is not an archive
299 set(archive_name "")
300
301 # remove the file:// protocol from the URL
302 string(REPLACE "file://" "" SOURCE_DIR "${url}")
303
304 # on win32 we may have to remove another leading /
305 if(WIN32)
306 # check if the path is a local path
307 string(REGEX MATCH "^/.*$" local_path "${SOURCE_DIR}")
308 if(local_path)
309 string(SUBSTRING "${SOURCE_DIR}" 1 -1 SOURCE_DIR)
310 endif()
311 endif()
312 endif()
313 endif()
314
315 # download the addon if necessary
316 if(NOT "${archive_name}" STREQUAL "")
317 # download and extract the addon
318 if(NOT ADDON_TARBALL_CACHING OR NOT EXISTS ${BUILD_DIR}/download/${archive_name}.tar.gz)
319 # cleanup any of the previously downloaded archives of this addon
320 file(GLOB archives "${BUILD_DIR}/download/${id}*.tar.gz")
321 if(archives)
322 message(STATUS "Removing old archives of ${id}: ${archives}")
323 file(REMOVE ${archives})
324 endif()
325
326 # download the addon
327 file(DOWNLOAD "${url}" "${BUILD_DIR}/download/${archive_name}.tar.gz" STATUS dlstatus LOG dllog SHOW_PROGRESS)
328 list(GET dlstatus 0 retcode)
329 if(NOT ${retcode} EQUAL 0)
330 file(REMOVE ${BUILD_DIR}/download/${archive_name}.tar.gz)
331 message(STATUS "ERROR downloading ${url} - status: ${dlstatus} log: ${dllog}")
332 # add a dummy target for addons to get it in addons failure file
333 list(APPEND ALL_ADDONS_BUILDING ${id})
334 add_custom_target(${id} COMMAND ${CMAKE_COMMAND} -E echo "IGNORED ${id} - download failed" COMMAND exit 1)
335 continue()
336 endif()
337 endif()
338
339 # remove any previously extracted version of the addon
340 file(REMOVE_RECURSE "${BUILD_DIR}/${id}")
341
342 # extract the addon from the archive
343 execute_process(COMMAND ${CMAKE_COMMAND} -E tar xzvf ${BUILD_DIR}/download/${archive_name}.tar.gz
344 WORKING_DIRECTORY ${BUILD_DIR})
345 file(GLOB extract_dir "${BUILD_DIR}/${archive_name}*")
346 if(extract_dir STREQUAL "")
347 message(FATAL_ERROR "${id}: error extracting ${BUILD_DIR}/download/${archive_name}.tar.gz")
348 else()
349 file(RENAME "${extract_dir}" "${BUILD_DIR}/${id}")
350 endif()
351
352 set(SOURCE_DIR ${BUILD_DIR}/${id})
353 endif()
354
355 if(NOT "${SOURCE_DIR}" STREQUAL "" AND EXISTS ${SOURCE_DIR})
356 # create a list of addons we are building
357 list(APPEND ALL_ADDONS_BUILDING ${id})
358
359 # setup the buildsystem for the addon
360 externalproject_add(${id}
361 SOURCE_DIR ${SOURCE_DIR}
362 INSTALL_DIR ${ADDON_INSTALL_DIR}
363 CMAKE_ARGS ${BUILD_ARGS})
364
365 # add a custom step to the external project between the configure and the build step which will always
366 # be executed and therefore forces a re-build of all changed files
367 externalproject_add_step(${id} forcebuild
368 COMMAND ${CMAKE_COMMAND} -E echo "Force build of ${id}"
369 DEPENDEES configure
370 DEPENDERS build
371 ALWAYS 1)
372
373 # add "kodi-platform" as a dependency to every addon
374 add_dependencies(${id} kodi-platform)
375
376 set(${id}_DEPENDS_DIR ${SOURCE_DIR}/depends)
377
378 if(EXISTS ${${id}_DEPENDS_DIR})
379 include(${CORE_SOURCE_DIR}/cmake/scripts/common/HandleDepends.cmake)
380 add_addon_depends(${id} ${${id}_DEPENDS_DIR})
381 if(${id}_DEPS AND NOT "${${id}_DEPS}" STREQUAL "")
382 message(STATUS "${id} DEPENDENCIES: ${${id}_DEPS}")
383 add_dependencies(${id} ${${id}_DEPS})
384 endif()
385 endif()
386
387 if(CROSS_AUTOCONF AND AUTOCONF_FILES)
388 if(EXISTS ${SOURCE_DIR}/bootstrap/autoreconf.txt)
389 file(STRINGS ${SOURCE_DIR}/bootstrap/autoreconf.txt conf_dirs)
390 foreach(conf_dir ${conf_dirs})
391 foreach(afile ${AUTOCONF_FILES})
392 message(STATUS "copying ${afile} to ${SOURCE_DIR}/${conf_dir}")
393 file(COPY ${afile} DESTINATION ${SOURCE_DIR}/${conf_dir})
394 endforeach()
395 endforeach()
396 endif()
397 endif()
398
399 # create a forwarding target to the addon-package target
400 add_custom_target(package-${id}
401 COMMAND ${CMAKE_COMMAND} --build ${id}-prefix/src/${id}-build --target addon-package
402 DEPENDS ${id})
403 add_dependencies(package-addons package-${id})
404
405 else()
406 message(FATAL_ERROR "${id}: invalid or missing addon source directory at ${SOURCE_DIR}")
407 endif()
408 else()
409 # add a dummy target for addons that are unsupported on this platform
410 add_custom_target(${id} COMMAND ${CMAKE_COMMAND} -E echo "IGNORED ${id} - not supported on ${CORE_SYSTEM_NAME}\n")
411 endif()
412 endif()
413 endif()
414endforeach()
415message(STATUS "")
416
417if(NEED_SUDO)
418 add_custom_target(sudo-install
419 COMMAND ${CMAKE_COMMAND} -E echo "sudo rights needed to install to ${CMAKE_INSTALL_PREFIX}\n"
420 COMMAND sudo ${CMAKE_COMMAND} -E copy_directory ${ADDON_INSTALL_DIR}/ ${CMAKE_INSTALL_PREFIX}/
421 COMMAND sudo -k)
422
423 foreach(_id ${ALL_ADDONS_BUILDING})
424 add_dependencies(sudo-install ${_id})
425 endforeach()
426 message(WARNING "sudo rights needed to install to ${CMAKE_INSTALL_PREFIX}")
427 message(STATUS "\nplease type \"make sudo-install\"\n\n")
428endif()
429
430if(NOT SUPPORTED_ADDON_FOUND)
431 message(FATAL_ERROR "${ADDONS_TO_BUILD} did not match any of the supported addons. \
432 A list of supported addons can be viewed by building the 'supported_addons' target. \
433 Addon definitions are loaded from ADDONS_DEFINITION_DIR (${ADDONS_DEFINITION_DIR}).")
434endif()
435
436# add custom target "supported_addons" that returns all addons that are supported on this platform
437string(REPLACE ";" " " ALL_ADDONS_BUILDING "${ALL_ADDONS_BUILDING}")
438add_custom_target(supported_addons COMMAND ${CMAKE_COMMAND} -E echo "ALL_ADDONS_BUILDING: ${ALL_ADDONS_BUILDING}" VERBATIM)
439add_custom_target(need-sudo COMMAND ${CMAKE_COMMAND} -E echo ${NEED_SUDO} VERBATIM)