489 lines
26 KiB
CMake
489 lines
26 KiB
CMake
#
|
|
# Singe 3
|
|
# Copyright (C) 2006-2026 Scott Duensing <scott@kangaroopunch.com>
|
|
#
|
|
# This program is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public Licens
|
|
# as published by the Free Software Foundation; either version 3
|
|
# of the License, or (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
# 02110-1301, USA.
|
|
#
|
|
|
|
# Superbuild: builds every vendored library into BUILD_DIR, then Singe against them.
|
|
# Entered from CMakeLists.txt when SINGE_SUPERBUILD is ON (the presets set it). Each
|
|
# library is an ExternalProject with its own configure, build and install steps, so a
|
|
# change to one rebuilds only it and what depends on it:
|
|
# cmake --build --preset linux-x86_64 --target rebuild-ffmpeg
|
|
# The toolchain environment (PATH, SYSROOT, osxcross variables) comes from
|
|
# ../toolchains/toolchains.sh; build-all.sh sources it before calling cmake.
|
|
|
|
include(ExternalProject)
|
|
include(ProcessorCount)
|
|
|
|
ProcessorCount(SB_JOBS)
|
|
if(SB_JOBS EQUAL 0)
|
|
set(SB_JOBS 4)
|
|
endif()
|
|
|
|
# Target description: the presets pass these; a plain cmake invocation can take them from
|
|
# the environment toolchains.sh exports.
|
|
foreach(pair "SINGE_TRIPLE;TRIPLE" "SINGE_CROSS_OS;CROSS_OS" "SINGE_SUFFIX;SUFFIX")
|
|
list(GET pair 0 var)
|
|
list(GET pair 1 env)
|
|
if(NOT DEFINED ${var})
|
|
set(${var} "$ENV{${env}}")
|
|
endif()
|
|
endforeach()
|
|
if(NOT SINGE_TRIPLE OR NOT SINGE_CROSS_OS)
|
|
message(FATAL_ERROR "SINGE_TRIPLE and SINGE_CROSS_OS must be set (use a preset or source toolchains.sh).")
|
|
endif()
|
|
|
|
set(SB_PREFIX ${BUILD_DIR})
|
|
set(SB_THIRDPARTY ${CMAKE_SOURCE_DIR}/thirdparty)
|
|
file(MAKE_DIRECTORY ${SB_PREFIX}/include ${SB_PREFIX}/lib)
|
|
|
|
# Compilers as the toolchain resolved them; the configure based libraries get them by name.
|
|
set(SB_CC "${CMAKE_C_COMPILER}")
|
|
if(CMAKE_CXX_COMPILER)
|
|
set(SB_CXX "${CMAKE_CXX_COMPILER}")
|
|
elseif(DEFINED ENV{CXX})
|
|
set(SB_CXX "$ENV{CXX}")
|
|
else()
|
|
string(REGEX REPLACE "gcc$" "g++" SB_CXX "${SB_CC}")
|
|
string(REGEX REPLACE "clang$" "clang++" SB_CXX "${SB_CXX}")
|
|
endif()
|
|
if(CMAKE_RANLIB)
|
|
set(SB_RANLIB "${CMAKE_RANLIB}")
|
|
elseif(DEFINED ENV{RANLIB})
|
|
set(SB_RANLIB "$ENV{RANLIB}")
|
|
else()
|
|
set(SB_RANLIB ranlib)
|
|
endif()
|
|
|
|
# The flags build-all.sh exported for every library: our install tree first, then the
|
|
# platform's. The Pi sysroot and the osxcross linker come from the toolchain.
|
|
set(SB_CFLAGS_BASE "$ENV{CFLAGS}")
|
|
set(SB_LDFLAGS "-L${SB_PREFIX}/lib $ENV{LDFLAGS}")
|
|
if(CMAKE_SYSROOT)
|
|
set(SB_CFLAGS_BASE "--sysroot=${CMAKE_SYSROOT} ${SB_CFLAGS_BASE}")
|
|
endif()
|
|
set(SB_CFLAGS "-I${SB_PREFIX}/include ${SB_CFLAGS_BASE}")
|
|
set(SB_PKG_CONFIG_LIBDIR "${SB_PREFIX}/lib/pkgconfig")
|
|
# A cross build looks inside its sysroot; a build for this machine looks at this machine. The
|
|
# sysroot is what tells them apart, not the platform's name.
|
|
if(SINGE_SYSROOT)
|
|
set(SB_PKG_CONFIG_LIBDIR "${SB_PKG_CONFIG_LIBDIR}:${SINGE_SYSROOT}/usr/lib/${SINGE_TRIPLE}/pkgconfig:${SINGE_SYSROOT}/usr/lib/pkgconfig:${SINGE_SYSROOT}/usr/share/pkgconfig")
|
|
elseif(KANGAROO_OS STREQUAL "linux")
|
|
set(SB_PKG_CONFIG_LIBDIR "${SB_PKG_CONFIG_LIBDIR}:/usr/lib/${SINGE_TRIPLE}/pkgconfig:/usr/lib/pkgconfig:/usr/share/pkgconfig")
|
|
elseif(DEFINED ENV{PKG_CONFIG_LIBDIR})
|
|
set(SB_PKG_CONFIG_LIBDIR "${SB_PKG_CONFIG_LIBDIR}:$ENV{PKG_CONFIG_LIBDIR}")
|
|
endif()
|
|
|
|
# Environment every step runs under. CFLAGS is a parameter because SDL3_image's vendored
|
|
# libpng must not see the zlib headers under the install prefix.
|
|
function(singeStepEnv outVar cflags)
|
|
set(env ${CMAKE_COMMAND} -E env
|
|
"CC=${SB_CC}"
|
|
"CXX=${SB_CXX}"
|
|
"RANLIB=${SB_RANLIB}"
|
|
"CFLAGS=${cflags}"
|
|
"CXXFLAGS=${cflags}"
|
|
"LDFLAGS=${SB_LDFLAGS}"
|
|
"LD_LIBRARY_PATH=${SB_PREFIX}/lib"
|
|
"PKG_CONFIG_LIBDIR=${SB_PKG_CONFIG_LIBDIR}"
|
|
"MAKEFLAGS=-j${SB_JOBS}"
|
|
)
|
|
if(CMAKE_AR)
|
|
list(APPEND env "AR=${CMAKE_AR}")
|
|
endif()
|
|
if(SINGE_SYSROOT)
|
|
list(APPEND env "PKG_CONFIG_SYSROOT_DIR=${SINGE_SYSROOT}")
|
|
endif()
|
|
set(${outVar} ${env} PARENT_SCOPE)
|
|
endfunction()
|
|
|
|
singeStepEnv(SB_ENV "${SB_CFLAGS}")
|
|
singeStepEnv(SB_ENV_NO_PREFIX_INCLUDE "${SB_CFLAGS_BASE}")
|
|
|
|
set(SB_CMAKE_ARGS
|
|
-DCMAKE_BUILD_TYPE=Release
|
|
-DCMAKE_INSTALL_PREFIX=${SB_PREFIX}
|
|
-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}
|
|
)
|
|
|
|
# A vendored CMake project: name, source directory, its dependencies, extra cache arguments,
|
|
# and the step environment to use.
|
|
function(singeCmakeProject name source deps args env)
|
|
set(binary ${SB_PREFIX}/build/${name})
|
|
ExternalProject_Add(${name}
|
|
SOURCE_DIR ${source}
|
|
BINARY_DIR ${binary}
|
|
DEPENDS ${deps}
|
|
CONFIGURE_COMMAND ${env} ${CMAKE_COMMAND} -S ${source} -B ${binary} ${SB_CMAKE_ARGS} ${args}
|
|
BUILD_COMMAND ${env} ${CMAKE_COMMAND} --build ${binary} --parallel ${SB_JOBS}
|
|
INSTALL_COMMAND ${env} ${CMAKE_COMMAND} --build ${binary} --target install
|
|
LOG_CONFIGURE ON LOG_BUILD ON LOG_INSTALL ON LOG_OUTPUT_ON_FAILURE ON
|
|
)
|
|
singeRebuildTarget(${name})
|
|
endfunction()
|
|
|
|
# rebuild-<name> forgets the stamps and the build directory and builds the library again, then whatever depends on it
|
|
# is rebuilt by the normal build.
|
|
function(singeRebuildTarget name)
|
|
ExternalProject_Get_Property(${name} STAMP_DIR BINARY_DIR)
|
|
add_custom_target(rebuild-${name}
|
|
COMMAND ${CMAKE_COMMAND} -E rm -rf ${STAMP_DIR} ${BINARY_DIR}
|
|
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target ${name}
|
|
COMMENT "Rebuilding ${name}"
|
|
)
|
|
endfunction()
|
|
|
|
|
|
# ===== zlib (configure script; the generated zconf.h lives in the build directory) =====
|
|
|
|
set(zlibBinary ${SB_PREFIX}/build/zlib)
|
|
ExternalProject_Add(zlib
|
|
SOURCE_DIR ${SB_THIRDPARTY}/zlib
|
|
BINARY_DIR ${zlibBinary}
|
|
CONFIGURE_COMMAND ${CMAKE_COMMAND} -E env "CC=${SB_CC}" "AR=${CMAKE_AR}" "RANLIB=${SB_RANLIB}" "CFLAGS=-I${zlibBinary} ${SB_CFLAGS_BASE}" ${SB_THIRDPARTY}/zlib/configure --prefix=${SB_PREFIX} --static
|
|
BUILD_COMMAND ${SB_ENV} make
|
|
INSTALL_COMMAND ${SB_ENV} make install
|
|
LOG_CONFIGURE ON LOG_BUILD ON LOG_INSTALL ON LOG_OUTPUT_ON_FAILURE ON
|
|
)
|
|
singeRebuildTarget(zlib)
|
|
|
|
|
|
# ===== zstd =====
|
|
|
|
singeCmakeProject(zstd ${SB_THIRDPARTY}/zstd/build/cmake "" "-DZSTD_BUILD_SHARED=off;-DZSTD_BUILD_STATIC=on;-DZSTD_BUILD_PROGRAMS=off" "${SB_ENV}")
|
|
|
|
|
|
# ===== SDL3 and its satellites =====
|
|
|
|
singeCmakeProject(SDL3 ${SB_THIRDPARTY}/SDL3 "" "-DSDL_SHARED=off;-DSDL_STATIC=on;-DSDL_TESTS=off;-DSDL_EXAMPLES=off" "${SB_ENV}")
|
|
|
|
# ===== Host tools: the shader compiler (see cmake/hostTools.cmake) =====
|
|
include(${CMAKE_CURRENT_LIST_DIR}/hostTools.cmake)
|
|
|
|
# ===== Jolt Physics (C++; static, single precision, no tests or samples) =====
|
|
# The x86 baseline is SSE4.1/4.2 so a shipped binary runs on anything from 2008 on; AVX and the
|
|
# bit-count instructions would silently raise it. No link-time optimisation through the cross
|
|
# compiler, no warnings-as-errors with a clang Jolt has not met, nothing but the library; the GPU
|
|
# compute paths (hair and soft bodies on DX12, Vulkan, Metal or a CPU fallback) would need a shader
|
|
# compiler at build time and are not used.
|
|
set(joltOptions
|
|
-DTARGET_UNIT_TESTS=OFF -DTARGET_HELLO_WORLD=OFF -DTARGET_PERFORMANCE_TEST=OFF -DTARGET_SAMPLES=OFF -DTARGET_VIEWER=OFF
|
|
-DJPH_BUILD_SHARED_LIBS=OFF -DDOUBLE_PRECISION=OFF -DCROSS_PLATFORM_DETERMINISTIC=OFF
|
|
-DUSE_SSE4_1=ON -DUSE_SSE4_2=ON -DUSE_AVX=OFF -DUSE_AVX2=OFF -DUSE_AVX512=OFF -DUSE_F16C=OFF -DUSE_FMADD=OFF -DUSE_LZCNT=OFF -DUSE_TZCNT=OFF
|
|
-DINTERPROCEDURAL_OPTIMIZATION=OFF -DENABLE_ALL_WARNINGS=OFF -DGENERATE_DEBUG_SYMBOLS=OFF
|
|
-DDEBUG_RENDERER_IN_DEBUG_AND_RELEASE=OFF -DDEBUG_RENDERER_IN_DISTRIBUTION=ON -DFLOATING_POINT_EXCEPTIONS_ENABLED=OFF -DCPP_EXCEPTIONS_ENABLED=OFF -DCPP_RTTI_ENABLED=OFF
|
|
-DJPH_USE_DX12=OFF -DJPH_USE_VK=OFF -DJPH_USE_MTL=OFF -DJPH_USE_CPU_COMPUTE=OFF
|
|
)
|
|
singeCmakeProject(Jolt ${SB_THIRDPARTY}/JoltPhysics/Build "" "${joltOptions}" "${SB_ENV}")
|
|
|
|
# ===== Recast Navigation (C++; static, the libraries only) =====
|
|
singeCmakeProject(recastnavigation ${SB_THIRDPARTY}/recastnavigation ""
|
|
"-DRECASTNAVIGATION_DEMO=OFF;-DRECASTNAVIGATION_TESTS=OFF;-DRECASTNAVIGATION_EXAMPLES=OFF;-DBUILD_SHARED_LIBS=OFF"
|
|
"${SB_ENV}")
|
|
|
|
set(sdl3Dir -DSDL3_DIR=${SB_PREFIX}/lib/cmake/SDL3)
|
|
|
|
# Brotli, for the WOFF2 web fonts FreeType reads only when it is present. It is built before
|
|
# SDL3_image and SDL3_ttf so that it is in the prefix when FreeType looks for it.
|
|
#
|
|
# libjxl vendors brotli as well, and its install writes libbrotlidec.a and libbrotlicommon.a over
|
|
# the ones built here. That is harmless and is left alone: it is the same upstream library, the
|
|
# two FreeType links come from libjxl's tree as a matched pair, and only the decoder is ever linked
|
|
# -- libbrotlienc.a is the one file of this project's own build that survives, and nothing asks for
|
|
# it. Telling libjxl to use the copy already installed (JPEGXL_FORCE_SYSTEM_BROTLI) does work, but
|
|
# SDL3_image then tries to install brotli targets that no longer exist, and patching its install
|
|
# list is a worse trade than one duplicated build.
|
|
singeCmakeProject(brotli ${SB_THIRDPARTY}/brotli "" "-DBUILD_SHARED_LIBS=off;-DBROTLI_BUILD_TOOLS=off;-DBROTLI_DISABLE_TESTS=on" "${SB_ENV}")
|
|
|
|
singeCmakeProject(SDL3_image ${SB_THIRDPARTY}/SDL3_image "SDL3;zlib;brotli"
|
|
"-DBUILD_SHARED_LIBS=off;-DSDLIMAGE_DEPS_SHARED=off;-DSDLIMAGE_SAMPLES=off;-DSDLIMAGE_TESTS=off;-DSDLIMAGE_VENDORED=on;-DSDLIMAGE_BACKEND_STB=off;-DSDLIMAGE_AVIF=off;-DSDLIMAGE_JXL=on;-DSDLIMAGE_JXL_SHARED=off;-DBUILD_TESTING=OFF;-DSDLIMAGE_TIF=off;-DSDLIMAGE_WEBP=on;${sdl3Dir};-DWEBP_BUILD_ANIM_UTILS=off;-DWEBP_BUILD_CWEBP=off;-DWEBP_BUILD_DWEBP=off;-DWEBP_BUILD_GIF2WEBP=off;-DWEBP_BUILD_IMG2WEBP=off;-DWEBP_BUILD_VWEBP=off;-DWEBP_BUILD_WEBPINFO=off;-DWEBP_BUILD_WEBPMUX=off;-DWEBP_BUILD_EXTRAS=off"
|
|
"${SB_ENV_NO_PREFIX_INCLUDE}")
|
|
|
|
# SDL3_image builds libpng and installs the archive but not its headers, and FreeType needs both
|
|
# before it will read a font's colour bitmap glyphs. pnglibconf.h is generated, so it comes from
|
|
# the build tree rather than the source one.
|
|
ExternalProject_Add_Step(SDL3_image pngHeaders
|
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${SB_THIRDPARTY}/SDL3_image/external/libpng/png.h ${SB_THIRDPARTY}/SDL3_image/external/libpng/pngconf.h ${SB_PREFIX}/build/SDL3_image/external/libpng-build/pnglibconf.h ${SB_PREFIX}/include
|
|
DEPENDEES install
|
|
COMMENT "Installing the libpng headers"
|
|
)
|
|
|
|
singeCmakeProject(SDL3_mixer ${SB_THIRDPARTY}/SDL3_mixer "SDL3"
|
|
"-DBUILD_SHARED_LIBS=off;-DSDLMIXER_DEPS_SHARED=off;-DSDLMIXER_VENDORED=on;-DSDLMIXER_EXAMPLES=off;-DSDLMIXER_TESTS=off;-DSDLMIXER_FLAC_LIBFLAC=off;-DSDLMIXER_MP3_MPG123=off;-DSDLMIXER_VORBIS_STB=on;-DSDLMIXER_VORBIS_VORBISFILE=off;-DSDLMIXER_VORBIS_TREMOR=off;-DSDLMIXER_GME=on;-DSDLMIXER_GME_SHARED=off;-DGME_BUILD_EXAMPLES=off;-DGME_BUILD_TESTING=off;-DGME_YM2612_EMU=MAME;-DSDLMIXER_MIDI_FLUIDSYNTH=off;${sdl3Dir};-DWAVPACK_ENABLE_ASM=no"
|
|
"${SB_ENV}")
|
|
|
|
singeCmakeProject(SDL3_ttf ${SB_THIRDPARTY}/SDL3_ttf "SDL3;zlib;brotli;SDL3_image"
|
|
"-DBUILD_SHARED_LIBS=off;-DSDLTTF_VENDORED=on;-DSDLTTF_HARFBUZZ=on;-DSDLTTF_PLUTOSVG=on;-DHB_HAVE_CORETEXT=off;-DSDLTTF_SAMPLES=off;-DFT_DISABLE_ZLIB=off;-DFT_DISABLE_BROTLI=off;-DZLIB_INCLUDE_DIR=${SB_PREFIX}/include;-DZLIB_LIBRARY=${SB_PREFIX}/lib/libz.a;-DBROTLIDEC_INCLUDE_DIRS=${SB_PREFIX}/include;-DBROTLIDEC_LIBRARIES=${SB_PREFIX}/lib/libbrotlidec.a;-DFT_DISABLE_PNG=off;-DPNG_PNG_INCLUDE_DIR=${SB_PREFIX}/include;-DPNG_LIBRARY=${SB_PREFIX}/lib/libpng16.a;${sdl3Dir}"
|
|
"${SB_ENV}")
|
|
# SDL3_ttf builds its vendored FreeType but does not install it, and Singe links it directly.
|
|
ExternalProject_Add_Step(SDL3_ttf freetype
|
|
COMMAND ${CMAKE_COMMAND} -E copy ${SB_PREFIX}/build/SDL3_ttf/external/freetype/libfreetype.a ${SB_PREFIX}/lib/libfreetype.a
|
|
DEPENDEES install
|
|
COMMENT "Installing libfreetype.a"
|
|
)
|
|
|
|
# ===== RmlUi (C++; static, the core, the Lua plugin and the debugger; no samples) =====
|
|
# FreeType is the copy SDL3_ttf builds (installed as libfreetype.a below, headers from its tree);
|
|
# Lua is the engine's own, handed over as a header-only target by cmake/rmluiLua.cmake.
|
|
set(rmluiOptions
|
|
-DBUILD_SHARED_LIBS=OFF -DRMLUI_SAMPLES=OFF -DRMLUI_PRECOMPILED_HEADERS=OFF
|
|
-DRMLUI_FONT_ENGINE=freetype -DRMLUI_LUA_BINDINGS=ON -DRMLUI_LUA_BINDINGS_LIBRARY=lua
|
|
-DFREETYPE_LIBRARY=${SB_PREFIX}/lib/libfreetype.a
|
|
-DFREETYPE_INCLUDE_DIR_ft2build=${SB_THIRDPARTY}/SDL3_ttf/external/freetype/include
|
|
-DFREETYPE_INCLUDE_DIR_freetype2=${SB_THIRDPARTY}/SDL3_ttf/external/freetype/include
|
|
-DSINGE_LUA_INCLUDE=${SB_THIRDPARTY}/lua/src
|
|
-DCMAKE_PROJECT_RmlUi_INCLUDE=${CMAKE_CURRENT_LIST_DIR}/rmluiLua.cmake
|
|
)
|
|
singeCmakeProject(RmlUi ${SB_THIRDPARTY}/RmlUi "SDL3_ttf" "${rmluiOptions}" "${SB_ENV}")
|
|
|
|
|
|
# ===== OpenSSL (its own Configure; the target name follows the platform) =====
|
|
|
|
if(KANGAROO_OS STREQUAL "windows")
|
|
if(KANGAROO_ARCH STREQUAL "x86")
|
|
set(opensslTarget mingw)
|
|
else()
|
|
set(opensslTarget mingw64)
|
|
endif()
|
|
elseif(KANGAROO_OS STREQUAL "linux")
|
|
if(KANGAROO_ARCH STREQUAL "aarch64")
|
|
set(opensslTarget linux-aarch64)
|
|
elseif(KANGAROO_ARCH STREQUAL "armhf")
|
|
set(opensslTarget linux-armv4)
|
|
elseif(SINGE_ZIG_TARGET)
|
|
set(opensslTarget linux-x86_64)
|
|
else()
|
|
set(opensslTarget "")
|
|
endif()
|
|
elseif(KANGAROO_OS STREQUAL "macos")
|
|
if(KANGAROO_ARCH STREQUAL "aarch64")
|
|
set(opensslTarget darwin64-arm64)
|
|
else()
|
|
set(opensslTarget darwin64-x86_64)
|
|
endif()
|
|
elseif(SINGE_ZIG_TARGET)
|
|
set(opensslTarget linux-x86_64)
|
|
else()
|
|
set(opensslTarget "")
|
|
endif()
|
|
# OpenSSL's generated assembly uses GNU as directives clang's assembler rejects; under zig the
|
|
# portable C paths serve, which is all LuaSec's traffic needs.
|
|
if(SINGE_ZIG_TARGET)
|
|
set(opensslAsm no-asm)
|
|
else()
|
|
set(opensslAsm "")
|
|
endif()
|
|
# OpenSSL's Configure derives the source tree from the build directory's position and only
|
|
# copes with a build directory nested inside its own tree, so this one lives there, one per target
|
|
# so that switching presets never links another architecture's objects.
|
|
set(opensslBinary ${SB_THIRDPARTY}/openssl/.builddir/${KANGAROO_OS}-${KANGAROO_ARCH})
|
|
ExternalProject_Add(openssl
|
|
SOURCE_DIR ${SB_THIRDPARTY}/openssl
|
|
BINARY_DIR ${opensslBinary}
|
|
DEPENDS zlib zstd
|
|
CONFIGURE_COMMAND ${SB_ENV} perl ../../Configure ${opensslTarget} --prefix=${SB_PREFIX} --libdir=lib --with-zlib-include=${SB_PREFIX}/include --with-zlib-lib=${SB_PREFIX}/lib --with-zstd-include=${SB_PREFIX}/include --with-zstd-lib=${SB_PREFIX}/lib ${opensslAsm} no-apps no-docs no-dso no-dynamic-engine no-module no-shared no-tests zlib enable-zstd
|
|
BUILD_COMMAND ${SB_ENV} make build_sw
|
|
INSTALL_COMMAND ${SB_ENV} make install_sw
|
|
LOG_CONFIGURE ON LOG_BUILD ON LOG_INSTALL ON LOG_OUTPUT_ON_FAILURE ON
|
|
)
|
|
singeRebuildTarget(openssl)
|
|
|
|
|
|
# ===== FFmpeg (hardware decoding per platform; CMakeLists.txt reads its .pc files back) =====
|
|
|
|
# ===== Rockchip Media Process Platform (the vendor decode library for Rockchip SoCs) =====
|
|
|
|
# Rockchip's decoders are aarch64 only. Because the library links statically it costs nothing on a
|
|
# board that is not a Rockchip, so it is built for the aarch64 targets rather than needing one of
|
|
# its own; set SINGE_ROCKCHIP_MPP to override either way.
|
|
if(NOT DEFINED SINGE_ROCKCHIP_MPP)
|
|
if((KANGAROO_OS STREQUAL "linux") AND (KANGAROO_ARCH STREQUAL "aarch64"))
|
|
set(SINGE_ROCKCHIP_MPP ON)
|
|
else()
|
|
set(SINGE_ROCKCHIP_MPP OFF)
|
|
endif()
|
|
endif()
|
|
|
|
# MPP is packaged by no distribution, so it is vendored and built here like everything else. Only
|
|
# the static library is kept: linked statically the Singe binary carries no runtime dependency on
|
|
# it, so one ARM build runs on a Rockchip board and on anything else, where the decoder simply fails
|
|
# to open a device and the player falls back. A shared build would put librockchip_mpp.so in the
|
|
# binary's DT_NEEDED and stop it starting anywhere the library is absent.
|
|
set(rkmppFlag "")
|
|
set(rkmppDep "")
|
|
if(SINGE_ROCKCHIP_MPP)
|
|
# MPP strips its merged archive with ${CMAKE_STRIP}, and no cross strip here understands an ar
|
|
# archive: zig's objcopy is ELF only. The step only drops debug symbols from an intermediate
|
|
# library, so it is skipped; the release binary is stripped at its own link.
|
|
singeCmakeProject(rockchipMpp ${SB_THIRDPARTY}/rockchip-mpp "" "-DBUILD_SHARED_LIBS=OFF;-DBUILD_TEST=OFF;-DHAVE_DRM=ON;-DCMAKE_STRIP=/bin/true" "${SB_ENV}")
|
|
# Its install puts both the archive and the shared object down; the shared one is removed so
|
|
# that -lrockchip_mpp can only resolve to the archive.
|
|
ExternalProject_Add_Step(rockchipMpp staticOnly
|
|
COMMAND ${CMAKE_COMMAND} -E rm -f ${SB_PREFIX}/lib/librockchip_mpp.so ${SB_PREFIX}/lib/librockchip_mpp.so.0 ${SB_PREFIX}/lib/librockchip_mpp.so.1 ${SB_PREFIX}/lib/librockchip_vpu.so ${SB_PREFIX}/lib/librockchip_vpu.so.0 ${SB_PREFIX}/lib/librockchip_vpu.so.1
|
|
DEPENDEES install
|
|
COMMENT "Keeping only the static Rockchip MPP library"
|
|
)
|
|
set(rkmppFlag --enable-rkmpp)
|
|
set(rkmppDep rockchipMpp)
|
|
message(STATUS "Rockchip MPP will be built and linked statically; the rkmpp decoders are enabled")
|
|
endif()
|
|
|
|
# ===== dav1d, the AV1 decoder =====
|
|
|
|
# FFmpeg's own AV1 decoder needs hardware behind it: with no hwaccel it says "Your platform doesn't
|
|
# support hardware accelerated AV1 decoding" and decodes nothing, so an AV1 video does not play at
|
|
# all on a machine without an AV1 capable GPU. dav1d is the software decoder, and it brings AVIF
|
|
# stills with it, an AVIF being an AV1 picture in a HEIF box. It is the one vendored library whose
|
|
# own build system is Meson rather than CMake or a configure script.
|
|
set(dav1dBinary ${SB_PREFIX}/build/dav1d)
|
|
set(dav1dCross "")
|
|
if(SINGE_ZIG_TARGET)
|
|
# Meson learns a cross build from a file rather than from the environment, and names both the
|
|
# system and some architectures its own way. The system name is not cosmetic: Meson picks
|
|
# nasm's output format from it, and calling Windows "mingw32" -- which is what FFmpeg calls it
|
|
# -- leaves nasm emitting ELF objects that the Windows linker will not read.
|
|
if(KANGAROO_OS STREQUAL "windows")
|
|
set(dav1dSystem windows)
|
|
elseif(KANGAROO_OS STREQUAL "macos")
|
|
set(dav1dSystem darwin)
|
|
else()
|
|
set(dav1dSystem linux)
|
|
endif()
|
|
if(KANGAROO_ARCH STREQUAL "armhf")
|
|
set(dav1dCpuFamily arm)
|
|
else()
|
|
set(dav1dCpuFamily ${KANGAROO_ARCH})
|
|
endif()
|
|
set(dav1dCrossFile ${SB_PREFIX}/build/dav1dCross.txt)
|
|
file(WRITE ${dav1dCrossFile}
|
|
"[binaries]\nc = '${SB_CC}'\ncpp = '${SB_CXX}'\nar = '${CMAKE_AR}'\nranlib = '${SB_RANLIB}'\nstrip = 'true'\npkg-config = 'pkg-config'\nnasm = 'nasm'\n\n[host_machine]\nsystem = '${dav1dSystem}'\ncpu_family = '${dav1dCpuFamily}'\ncpu = '${KANGAROO_ARCH}'\nendian = 'little'\n")
|
|
set(dav1dCross --cross-file ${dav1dCrossFile})
|
|
endif()
|
|
ExternalProject_Add(dav1d
|
|
SOURCE_DIR ${SB_THIRDPARTY}/dav1d
|
|
BINARY_DIR ${dav1dBinary}
|
|
CONFIGURE_COMMAND ${SB_ENV} meson setup --wipe --prefix=${SB_PREFIX} --libdir=lib --buildtype=release --default-library=static -Denable_tools=false -Denable_tests=false ${dav1dCross} ${dav1dBinary} ${SB_THIRDPARTY}/dav1d
|
|
BUILD_COMMAND ${SB_ENV} ninja -C ${dav1dBinary}
|
|
INSTALL_COMMAND ${SB_ENV} ninja -C ${dav1dBinary} install
|
|
LOG_CONFIGURE ON LOG_BUILD ON LOG_INSTALL ON LOG_OUTPUT_ON_FAILURE ON
|
|
)
|
|
singeRebuildTarget(dav1d)
|
|
|
|
|
|
if(KANGAROO_OS STREQUAL "linux")
|
|
# ARM boards decode through a V4L2 memory-to-memory device; desktops have VAAPI or VDPAU.
|
|
if(KANGAROO_ARCH MATCHES "^(aarch64|armhf)$")
|
|
set(hwaccel --enable-v4l2-m2m --enable-libdrm ${rkmppFlag})
|
|
else()
|
|
set(hwaccel --enable-vaapi --enable-vdpau --enable-libdrm ${rkmppFlag})
|
|
endif()
|
|
elseif(KANGAROO_OS STREQUAL "macos")
|
|
set(hwaccel --enable-videotoolbox)
|
|
elseif(KANGAROO_OS STREQUAL "windows")
|
|
set(hwaccel --enable-d3d11va --enable-dxva2)
|
|
else()
|
|
set(hwaccel "")
|
|
endif()
|
|
# With a classic cross toolchain every tool is <triple>-<tool>; with zig each is named outright.
|
|
if(SINGE_ZIG_TARGET)
|
|
set(ffmpegTools --enable-cross-compile --cc=${SB_CC} --cxx=${SB_CXX} --ar=${CMAKE_AR} --ranlib=${SB_RANLIB} --windres=${CMAKE_RC_COMPILER})
|
|
# FFmpeg only uses nm to learn the symbol prefix. The host's binutils nm reads x86 ELF and PE
|
|
# objects but not aarch64 or Mach-O ones; the prefix is empty on Linux either way, and on macOS
|
|
# (where it is an underscore) llvm-nm from Debian's llvm package reads Mach-O.
|
|
if(KANGAROO_OS STREQUAL "macos")
|
|
find_program(SINGE_LLVM_NM NAMES llvm-nm llvm-nm-21 llvm-nm-20 llvm-nm-19 llvm-nm-18 llvm-nm-17 llvm-nm-16 llvm-nm-15)
|
|
if(NOT SINGE_LLVM_NM)
|
|
message(FATAL_ERROR "llvm-nm is needed for the macOS FFmpeg build (apt-get install llvm).")
|
|
endif()
|
|
list(APPEND ffmpegTools --nm=${SINGE_LLVM_NM})
|
|
elseif(KANGAROO_ARCH STREQUAL "x86_64")
|
|
list(APPEND ffmpegTools --nm=nm)
|
|
endif()
|
|
else()
|
|
set(ffmpegTools --cross-prefix=${SINGE_TRIPLE}- --cc=${SB_CC} --cxx=${SB_CXX} --ranlib=${SB_RANLIB})
|
|
endif()
|
|
# FFmpeg's configure sees sys/sysctl.h in the Pi sysroot and in zig's glibc header set, then its
|
|
# build cannot include it; an empty stand-in satisfies both (Linux uses sysconf, not sysctl).
|
|
if((KANGAROO_OS STREQUAL "linux") AND SINGE_ZIG_TARGET)
|
|
file(WRITE ${SB_PREFIX}/include/sys/sysctl.h "/* File no longer used */\n")
|
|
endif()
|
|
set(ffmpegBinary ${SB_PREFIX}/build/ffmpeg)
|
|
ExternalProject_Add(ffmpeg
|
|
SOURCE_DIR ${SB_THIRDPARTY}/ffmpeg
|
|
BINARY_DIR ${ffmpegBinary}
|
|
DEPENDS dav1d ${rkmppDep}
|
|
CONFIGURE_COMMAND ${SB_ENV} ${SB_THIRDPARTY}/ffmpeg/configure --enable-static --disable-shared --disable-debug --disable-muxers ${hwaccel} --disable-encoders --disable-filters --enable-filter=bwdif --enable-filter=yadif --enable-filter=buffer --enable-filter=buffersink --enable-filter=format --disable-network --disable-devices --disable-vulkan --disable-d3d12va --disable-bzlib --disable-lzma --disable-doc --disable-programs --enable-libdav1d --enable-gpl --enable-version3 --extra-ldflags=-L${SB_PREFIX}/lib --prefix=${SB_PREFIX} --arch=${KANGAROO_ARCH} --target-os=${SINGE_CROSS_OS} ${ffmpegTools}
|
|
BUILD_COMMAND ${SB_ENV} make
|
|
INSTALL_COMMAND ${SB_ENV} make install
|
|
LOG_CONFIGURE ON LOG_BUILD ON LOG_INSTALL ON LOG_OUTPUT_ON_FAILURE ON
|
|
)
|
|
singeRebuildTarget(ffmpeg)
|
|
|
|
|
|
# ===== Singe itself, against everything above =====
|
|
|
|
string(SUBSTRING ${KANGAROO_OS} 0 1 osInitial)
|
|
string(SUBSTRING ${KANGAROO_OS} 1 -1 osRest)
|
|
string(TOUPPER ${osInitial} osInitial)
|
|
# The built file carries the platform's executable suffix; the copy in .builddir/ carries the
|
|
# preset's, which is the same thing for Windows and lets an experimental build live beside another.
|
|
set(singeBinaryBase "Singe-v${PROJECT_VERSION}-${osInitial}${osRest}-${KANGAROO_ARCH}")
|
|
set(singeBinaryName "${singeBinaryBase}${SINGE_SUFFIX}")
|
|
set(singeBinary ${SB_PREFIX}/singe)
|
|
ExternalProject_Add(singe
|
|
SOURCE_DIR ${CMAKE_SOURCE_DIR}
|
|
BINARY_DIR ${singeBinary}
|
|
DEPENDS zlib zstd SDL3 SDL3_image SDL3_mixer SDL3_ttf openssl ffmpeg Jolt recastnavigation RmlUi shadercross
|
|
CONFIGURE_COMMAND ${SB_ENV} ${CMAKE_COMMAND} -S ${CMAKE_SOURCE_DIR} -B ${singeBinary} ${SB_CMAKE_ARGS} -DSINGE_SHADERCROSS=${SINGE_SHADERCROSS} -DSINGE_SUPERBUILD=OFF -DKANGAROO_OS=${KANGAROO_OS} -DKANGAROO_ARCH=${KANGAROO_ARCH} -DSINGE_TREE=${SINGE_TREE}
|
|
BUILD_COMMAND ${SB_ENV} ${CMAKE_COMMAND} --build ${singeBinary} --parallel ${SB_JOBS}
|
|
INSTALL_COMMAND ${CMAKE_COMMAND} -E copy ${singeBinary}/${singeBinaryBase}${CMAKE_EXECUTABLE_SUFFIX} ${CMAKE_SOURCE_DIR}/.builddir/${singeBinaryName}
|
|
BUILD_ALWAYS ON
|
|
)
|
|
|
|
# Forge, packed into .builddir beside the binary so it can be copied out and tested. It is NOT
|
|
# part of the engine and nothing of it is embedded; this only puts the distributable where the
|
|
# binaries already are. Only a build that produces a runnable binary can pack it, since packing is
|
|
# the engine's own --pack, so cross builds skip it and the host build does the work. The manual,
|
|
# rendered by the engine's own build into .builddir, goes in beside the scripts: Forge copies it
|
|
# out to its data directory on its first run.
|
|
if((KANGAROO_OS STREQUAL "linux") AND (CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux"))
|
|
# Everything under assets/Forge -- the scripts, the kit, the tutorials -- and re-globbed on
|
|
# every build, so a file added or changed anywhere in it repacks Forge.game without anyone
|
|
# having to remember.
|
|
file(GLOB_RECURSE forgeSources CONFIGURE_DEPENDS ${CMAKE_SOURCE_DIR}/assets/Forge/*)
|
|
set(forgePack ${CMAKE_SOURCE_DIR}/.builddir/Forge.game)
|
|
set(forgeManual ${CMAKE_SOURCE_DIR}/.builddir/Forge.pdf)
|
|
set(forgeStage ${SB_PREFIX}/forgepack)
|
|
add_custom_command(
|
|
OUTPUT ${forgePack}
|
|
# Packing refuses to overwrite, and a stale pack is worse than none.
|
|
COMMAND ${CMAKE_COMMAND} -E rm -rf ${forgePack} ${forgeStage}
|
|
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/assets/Forge ${forgeStage}/Forge
|
|
COMMAND ${CMAKE_COMMAND} -E copy ${forgeManual} ${forgeStage}/Forge/Forge.pdf
|
|
# The samples that need no art beyond what the engine ships, so the chooser has something to
|
|
# open on a fresh install. They come from the test set, which is the one copy of them.
|
|
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/testScripts/author/platformer.game ${CMAKE_SOURCE_DIR}/testScripts/author/breakout.game ${CMAKE_SOURCE_DIR}/testScripts/author/qte.game ${CMAKE_SOURCE_DIR}/testScripts/author/fmv.game ${forgeStage}/Forge/
|
|
# Run it somewhere harmless: the engine writes Singe/ and data/ into the working directory.
|
|
COMMAND ${CMAKE_COMMAND} -E chdir ${forgeStage} ${CMAKE_SOURCE_DIR}/.builddir/${singeBinaryName} --pack ${forgeStage}/Forge ${forgePack}
|
|
DEPENDS singe ${forgeSources} ${forgeManual} ${CMAKE_SOURCE_DIR}/testScripts/author/platformer.game ${CMAKE_SOURCE_DIR}/testScripts/author/breakout.game ${CMAKE_SOURCE_DIR}/testScripts/author/qte.game ${CMAKE_SOURCE_DIR}/testScripts/author/fmv.game
|
|
COMMENT "Packing Forge into .builddir/Forge.game"
|
|
VERBATIM
|
|
)
|
|
add_custom_target(forge ALL DEPENDS ${forgePack})
|
|
endif()
|
|
|
|
message(STATUS "Superbuild for ${KANGAROO_OS}/${KANGAROO_ARCH}: libraries into ${SB_PREFIX}, binary ${singeBinaryName}")
|