1# 2# Copyright OpenEmbedded Contributors 3# 4# SPDX-License-Identifier: MIT 5# 6 7# Path to the CMake file to process. 8OECMAKE_SOURCEPATH ??= "${S}" 9 10DEPENDS:prepend = "cmake-native " 11B = "${WORKDIR}/build" 12 13# What CMake generator to use. 14# The supported options are "Unix Makefiles" or "Ninja". 15OECMAKE_GENERATOR ?= "Ninja" 16 17python() { 18 generator = d.getVar("OECMAKE_GENERATOR") 19 if "Unix Makefiles" in generator: 20 args = "-G '" + generator + "' -DCMAKE_MAKE_PROGRAM=" + d.getVar("MAKE") 21 d.setVar("OECMAKE_GENERATOR_ARGS", args) 22 d.setVarFlag("do_compile", "progress", "percent") 23 elif "Ninja" in generator: 24 args = "-G '" + generator + "' -DCMAKE_MAKE_PROGRAM=ninja" 25 d.appendVar("DEPENDS", " ninja-native") 26 d.setVar("OECMAKE_GENERATOR_ARGS", args) 27 d.setVarFlag("do_compile", "progress", r"outof:^\[(\d+)/(\d+)\]\s+") 28 else: 29 bb.fatal("Unknown CMake Generator %s" % generator) 30} 31OECMAKE_AR ?= "${AR}" 32 33# Compiler flags 34OECMAKE_C_FLAGS ?= "${HOST_CC_ARCH} ${TOOLCHAIN_OPTIONS} ${CFLAGS}" 35OECMAKE_CXX_FLAGS ?= "${HOST_CC_ARCH} ${TOOLCHAIN_OPTIONS} ${CXXFLAGS}" 36OECMAKE_C_FLAGS_RELEASE ?= "-DNDEBUG" 37OECMAKE_CXX_FLAGS_RELEASE ?= "-DNDEBUG" 38OECMAKE_C_LINK_FLAGS ?= "${HOST_CC_ARCH} ${TOOLCHAIN_OPTIONS} ${CPPFLAGS} ${LDFLAGS}" 39OECMAKE_CXX_LINK_FLAGS ?= "${HOST_CC_ARCH} ${TOOLCHAIN_OPTIONS} ${CXXFLAGS} ${LDFLAGS}" 40 41def oecmake_map_compiler(compiler, d): 42 args = d.getVar(compiler).split() 43 if args[0] == "ccache": 44 return args[1], args[0] 45 return args[0], "" 46 47# C/C++ Compiler (without cpu arch/tune arguments) 48OECMAKE_C_COMPILER ?= "${@oecmake_map_compiler('CC', d)[0]}" 49OECMAKE_C_COMPILER_LAUNCHER ?= "${@oecmake_map_compiler('CC', d)[1]}" 50OECMAKE_CXX_COMPILER ?= "${@oecmake_map_compiler('CXX', d)[0]}" 51OECMAKE_CXX_COMPILER_LAUNCHER ?= "${@oecmake_map_compiler('CXX', d)[1]}" 52 53# clear compiler vars for allarch to avoid sig hash difference 54OECMAKE_C_COMPILER:allarch = "" 55OECMAKE_C_COMPILER_LAUNCHER:allarch = "" 56OECMAKE_CXX_COMPILER:allarch = "" 57OECMAKE_CXX_COMPILER_LAUNCHER:allarch = "" 58 59OECMAKE_RPATH ?= "" 60OECMAKE_PERLNATIVE_DIR ??= "" 61OECMAKE_EXTRA_ROOT_PATH ?= "" 62 63OECMAKE_FIND_ROOT_PATH_MODE_PROGRAM = "ONLY" 64 65EXTRA_OECMAKE:append = " ${PACKAGECONFIG_CONFARGS}" 66 67export CMAKE_BUILD_PARALLEL_LEVEL 68CMAKE_BUILD_PARALLEL_LEVEL:task-compile = "${@oe.utils.parallel_make(d, False)}" 69CMAKE_BUILD_PARALLEL_LEVEL:task-install = "${@oe.utils.parallel_make(d, True)}" 70 71OECMAKE_TARGET_COMPILE ?= "all" 72OECMAKE_TARGET_INSTALL ?= "install" 73 74def map_host_os_to_system_name(host_os): 75 if host_os.startswith('darwin'): 76 return 'Darwin' 77 if host_os.startswith('mingw'): 78 return 'Windows' 79 if host_os.startswith('linux'): 80 return 'Linux' 81 return host_os 82 83# CMake expects target architectures in the format of uname(2), 84# which do not always match TARGET_ARCH, so all the necessary 85# conversions should happen here. 86def map_host_arch_to_uname_arch(host_arch): 87 if host_arch == "powerpc": 88 return "ppc" 89 if host_arch == "powerpc64le": 90 return "ppc64le" 91 if host_arch == "powerpc64": 92 return "ppc64" 93 return host_arch 94 95 96cmake_do_generate_toolchain_file() { 97 if [ "${BUILD_SYS}" = "${HOST_SYS}" ]; then 98 cmake_crosscompiling="set( CMAKE_CROSSCOMPILING FALSE )" 99 else 100 cmake_sysroot="set( CMAKE_SYSROOT \"${RECIPE_SYSROOT}\" )" 101 fi 102 103 cat > ${WORKDIR}/toolchain.cmake <<EOF 104# CMake system name must be something like "Linux". 105# This is important for cross-compiling. 106$cmake_crosscompiling 107set( CMAKE_SYSTEM_NAME ${@map_host_os_to_system_name(d.getVar('HOST_OS'))} ) 108set( CMAKE_SYSTEM_PROCESSOR ${@map_host_arch_to_uname_arch(d.getVar('HOST_ARCH'))} ) 109set( CMAKE_C_COMPILER ${OECMAKE_C_COMPILER} ) 110set( CMAKE_CXX_COMPILER ${OECMAKE_CXX_COMPILER} ) 111set( CMAKE_C_COMPILER_LAUNCHER ${OECMAKE_C_COMPILER_LAUNCHER} ) 112set( CMAKE_CXX_COMPILER_LAUNCHER ${OECMAKE_CXX_COMPILER_LAUNCHER} ) 113set( CMAKE_ASM_COMPILER ${OECMAKE_C_COMPILER} ) 114find_program( CMAKE_AR ${OECMAKE_AR} DOC "Archiver" REQUIRED ) 115 116set( CMAKE_C_FLAGS "${OECMAKE_C_FLAGS}" CACHE STRING "CFLAGS" ) 117set( CMAKE_CXX_FLAGS "${OECMAKE_CXX_FLAGS}" CACHE STRING "CXXFLAGS" ) 118set( CMAKE_ASM_FLAGS "${OECMAKE_C_FLAGS}" CACHE STRING "ASM FLAGS" ) 119set( CMAKE_C_FLAGS_RELEASE "${OECMAKE_C_FLAGS_RELEASE}" CACHE STRING "Additional CFLAGS for release" ) 120set( CMAKE_CXX_FLAGS_RELEASE "${OECMAKE_CXX_FLAGS_RELEASE}" CACHE STRING "Additional CXXFLAGS for release" ) 121set( CMAKE_ASM_FLAGS_RELEASE "${OECMAKE_C_FLAGS_RELEASE}" CACHE STRING "Additional ASM FLAGS for release" ) 122set( CMAKE_C_LINK_FLAGS "${OECMAKE_C_LINK_FLAGS}" CACHE STRING "LDFLAGS" ) 123set( CMAKE_CXX_LINK_FLAGS "${OECMAKE_CXX_LINK_FLAGS}" CACHE STRING "LDFLAGS" ) 124 125# only search in the paths provided so cmake doesnt pick 126# up libraries and tools from the native build machine 127set( CMAKE_FIND_ROOT_PATH ${STAGING_DIR_HOST} ${STAGING_DIR_NATIVE} ${CROSS_DIR} ${OECMAKE_PERLNATIVE_DIR} ${OECMAKE_EXTRA_ROOT_PATH} ${EXTERNAL_TOOLCHAIN} ${HOSTTOOLS_DIR}) 128set( CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY ) 129set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ${OECMAKE_FIND_ROOT_PATH_MODE_PROGRAM} ) 130set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY ) 131set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY ) 132set( CMAKE_PROGRAM_PATH "/" ) 133 134$cmake_sysroot 135 136# Use qt.conf settings 137set( ENV{QT_CONF_PATH} ${WORKDIR}/qt.conf ) 138 139# We need to set the rpath to the correct directory as cmake does not provide any 140# directory as rpath by default 141set( CMAKE_INSTALL_RPATH ${OECMAKE_RPATH} ) 142 143# Use RPATHs relative to build directory for reproducibility 144set( CMAKE_BUILD_RPATH_USE_ORIGIN ON ) 145 146# Use our cmake modules 147list(APPEND CMAKE_MODULE_PATH "${STAGING_DATADIR}/cmake/Modules/") 148 149# add for non /usr/lib libdir, e.g. /usr/lib64 150set( CMAKE_LIBRARY_PATH ${libdir} ${base_libdir}) 151 152# add include dir to implicit includes in case it differs from /usr/include 153list(APPEND CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES ${includedir}) 154list(APPEND CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES ${includedir}) 155 156EOF 157} 158 159addtask generate_toolchain_file after do_patch before do_configure 160 161CONFIGURE_FILES = "CMakeLists.txt *.cmake" 162 163do_configure[cleandirs] = "${@d.getVar('B') if d.getVar('S') != d.getVar('B') else ''}" 164 165OECMAKE_ARGS = "\ 166 -DCMAKE_INSTALL_PREFIX:PATH=${prefix} \ 167 -DCMAKE_INSTALL_BINDIR:PATH=${@os.path.relpath(d.getVar('bindir'), d.getVar('prefix') + '/')} \ 168 -DCMAKE_INSTALL_SBINDIR:PATH=${@os.path.relpath(d.getVar('sbindir'), d.getVar('prefix') + '/')} \ 169 -DCMAKE_INSTALL_LIBEXECDIR:PATH=${@os.path.relpath(d.getVar('libexecdir'), d.getVar('prefix') + '/')} \ 170 -DCMAKE_INSTALL_SYSCONFDIR:PATH=${sysconfdir} \ 171 -DCMAKE_INSTALL_SHAREDSTATEDIR:PATH=${@os.path.relpath(d.getVar('sharedstatedir'), d. getVar('prefix') + '/')} \ 172 -DCMAKE_INSTALL_LOCALSTATEDIR:PATH=${localstatedir} \ 173 -DCMAKE_INSTALL_LIBDIR:PATH=${@os.path.relpath(d.getVar('libdir'), d.getVar('prefix') + '/')} \ 174 -DCMAKE_INSTALL_INCLUDEDIR:PATH=${@os.path.relpath(d.getVar('includedir'), d.getVar('prefix') + '/')} \ 175 -DCMAKE_INSTALL_DATAROOTDIR:PATH=${@os.path.relpath(d.getVar('datadir'), d.getVar('prefix') + '/')} \ 176 -DPYTHON_EXECUTABLE:PATH=${PYTHON} \ 177 -DPython_EXECUTABLE:PATH=${PYTHON} \ 178 -DPython3_EXECUTABLE:PATH=${PYTHON} \ 179 -DLIB_SUFFIX=${@d.getVar('baselib').replace('lib', '')} \ 180 -DCMAKE_INSTALL_SO_NO_EXE=0 \ 181 -DCMAKE_TOOLCHAIN_FILE:FILEPATH=${WORKDIR}/toolchain.cmake \ 182 -DCMAKE_NO_SYSTEM_FROM_IMPORTED=1 \ 183 -DCMAKE_EXPORT_NO_PACKAGE_REGISTRY=ON \ 184 -DFETCHCONTENT_FULLY_DISCONNECTED=ON \ 185 -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=ON \ 186" 187 188cmake_do_configure() { 189 if [ "${OECMAKE_BUILDPATH}" ]; then 190 bbnote "cmake.bbclass no longer uses OECMAKE_BUILDPATH. The default behaviour is now out-of-tree builds with B=WORKDIR/build." 191 fi 192 193 if [ "${S}" = "${B}" ]; then 194 find ${B} -name CMakeFiles -or -name Makefile -or -name cmake_install.cmake -or -name CMakeCache.txt -delete 195 fi 196 197 # Just like autotools cmake can use a site file to cache result that need generated binaries to run 198 if [ -e ${WORKDIR}/site-file.cmake ] ; then 199 oecmake_sitefile="-C ${WORKDIR}/site-file.cmake" 200 else 201 oecmake_sitefile= 202 fi 203 204 cmake \ 205 ${OECMAKE_GENERATOR_ARGS} \ 206 $oecmake_sitefile \ 207 ${OECMAKE_SOURCEPATH} \ 208 ${OECMAKE_ARGS} \ 209 ${EXTRA_OECMAKE} \ 210 -Wno-dev 211} 212 213# To disable verbose cmake logs for a given recipe or globally config metadata e.g. local.conf 214# add following 215# 216# CMAKE_VERBOSE = "" 217# 218 219CMAKE_VERBOSE ??= "VERBOSE=1" 220 221# Then run do_compile again 222cmake_runcmake_build() { 223 bbnote ${DESTDIR:+DESTDIR=${DESTDIR} }${CMAKE_VERBOSE} cmake --build '${B}' "$@" -- ${EXTRA_OECMAKE_BUILD} 224 eval ${DESTDIR:+DESTDIR=${DESTDIR} }${CMAKE_VERBOSE} cmake --build '${B}' "$@" -- ${EXTRA_OECMAKE_BUILD} 225} 226 227# Install an already-generated project binary tree. Not checking the compile 228# dependencies again is particularly important for SDK use cases. 229cmake_runcmake_install() { 230 bbnote ${DESTDIR:+DESTDIR=${DESTDIR} }${CMAKE_VERBOSE} cmake --install '${B}' 231 eval ${DESTDIR:+DESTDIR=${DESTDIR} }${CMAKE_VERBOSE} cmake --install '${B}' 232} 233 234cmake_do_compile() { 235 cmake_runcmake_build --target ${OECMAKE_TARGET_COMPILE} 236} 237 238cmake_do_install() { 239 if [ "${OECMAKE_TARGET_INSTALL}" = "install" ]; then 240 DESTDIR='${D}' cmake_runcmake_install 241 else 242 # Legacy path which supports also custom install targets 243 DESTDIR='${D}' cmake_runcmake_build --target ${OECMAKE_TARGET_INSTALL} 244 fi 245} 246 247EXPORT_FUNCTIONS do_configure do_compile do_install do_generate_toolchain_file 248