Improve cross-compile support (#634)

* Update minimum CMake version requirement to get rid of warning.
* Include CMake compile commands for easier diagnostics.
* More improvements to arm toolchain selection while cross-compiling third-party dependencies.
* Use x-tools provided cmake toolchains
* Add a script to download and extract deb dependencies for crosscompile.
* Link against libstdc++ statically when cross-compiling to ARM to improve portability.
* Update GeneratePackage.cmake to generate better filenames.
* Ensure symbols are stripped properly when cross-compiling
* Remove old scripts that are no longer required
* Add script to install x-tools
* Add some docs that describe how to setup a crosscompile environment.
* Add docs for building standlone on Linux
* Update CHANGELOG
* Update version hash.
This commit is contained in:
casey langen 2023-09-07 22:05:43 -07:00 committed by GitHub
parent e422c4a928
commit 4f44829cda
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 725 additions and 224 deletions

View File

@ -4,6 +4,7 @@ macro(find_vendor_library target_var library_name)
endmacro(find_vendor_library)
macro(find_header header_name)
set(TEMP "")
find_path(TEMP ${header_name} HINTS ${PROJECT_INCLUDE_DIRECTORIES} REQUIRED NO_CACHE)
if (${TEMP} MATCHES "TEMP-NOTFOUND")
message(STATUS "[dependency-detection] ${BoldRed}'${header_name}' COULD NOT BE FOUND!${ColorReset}")

View File

@ -57,12 +57,14 @@ if (${GENERATE_DEB} MATCHES "true" AND CMAKE_SYSTEM_NAME MATCHES "Linux")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "casey langen")
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE ${PACKAGE_ARCHITECTURE})
set(CPACK_DEBIAN_FILE_NAME "musikcube_${musikcube_VERSION_MAJOR}.${musikcube_VERSION_MINOR}.${musikcube_VERSION_PATCH}_${FRIENDLY_ARCHITECTURE_NAME}.deb")
set(CPACK_RPM_PACKAGE_LICENSE "BSD-3-Clause")
set(CPACK_RPM_PACKAGE_URL "https://www.musikcube.com")
set(CPACK_RPM_PACKAGE_VERSION "${musikcube_VERSION_MAJOR}.${musikcube_VERSION_MINOR}.${musikcube_VERSION_PATCH}")
set(CPACK_RPM_REQUIRES_EXCLUDE_FROM "^/.*$")
if (${PACKAGE_ARCHITECTURE} MATCHES "amd64")
set(CPACK_RPM_FILE_NAME "musikcube_${musikcube_VERSION_MAJOR}.${musikcube_VERSION_MINOR}.${musikcube_VERSION_PATCH}_${FRIENDLY_ARCHITECTURE_NAME}.rpm")
if (${PACKAGE_ARCHITECTURE} MATCHES "amd64")
# debs use `amd64`, but rpm uses `x86_64`. both seem to agree on other architecture values.
message(STATUS "[GeneratePackage] ${BoldYellow}set RPM architecture to x86_64${ColorReset}")
set(CPACK_RPM_PACKAGE_ARCHITECTURE "x86_64")

View File

@ -0,0 +1,4 @@
include("/build/x-tools/armv6-rpi-linux-gnueabihf/armv6-rpi-linux-gnueabihf.toolchain.cmake")
set(CROSS_COMPILE_SYSROOT /build/x-tools/armv6-rpi-linux-gnueabihf/armv6-rpi-linux-gnueabihf/sysroot)
set(CROSS_COMPILE_PKG_CONFIG_PATH "${CROSS_COMPILE_SYSROOT}/usr/lib/arm-linux-gnueabi/pkgconfig")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libstdc++")

View File

@ -0,0 +1,4 @@
include("/build/x-tools/armv8-rpi3-linux-gnueabihf/armv8-rpi3-linux-gnueabihf.toolchain.cmake")
set(CROSS_COMPILE_SYSROOT /build/x-tools/armv8-rpi3-linux-gnueabihf/armv8-rpi3-linux-gnueabihf/sysroot)
set(CROSS_COMPILE_PKG_CONFIG_PATH "${CROSS_COMPILE_SYSROOT}/usr/lib/arm-linux-gnueabi/pkgconfig")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libstdc++")

View File

@ -1,15 +0,0 @@
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(CROSS_COMPILE_SYSROOT /build/rpi/sysroot)
set(CROSS_COMPILE_PKG_CONFIG_PATH "${CROSS_COMPILE_SYSROOT}/usr/lib/arm-linux-gnueabihf/pkgconfig")
set(CMAKE_SYSROOT ${CROSS_COMPILE_SYSROOT})
set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)

1
.gitignore vendored
View File

@ -20,6 +20,7 @@ dist
bin
bin32
bin64
compile_commands.json
ipch
build
local-circle-ci.yml

View File

@ -9,6 +9,11 @@
* fixed 64-bit RPM architecture value (was `amd64`, but should be `x86_64`)
* updated musikdroid to latest version of Android Studio and external
dependencies (anecdotally improving Opus playback reliability)
* updated to openssl@3.1.2, libcurl@8.2.1, libmicrohttpd@0.9.77 and
libopenmpt@0.7.1 on unix platforms
* re-wrote raspberry-pi/arm cross-compiling functionality to be more generic and
use more well-maintained toolkits.
* added `armv6` builds for Raspberry Pi Zero (and other similar devices)
--------------------------------------------------------------------------------

View File

@ -3,7 +3,7 @@
#cmake -DGENERATE_DEB=true -DPACKAGE_ARCHITECTURE=i386|amd64|armhf -DDEB_PLATFORM=ubuntu -DDEB_DISTRO=eoan -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release .
#cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_STANDALONE=true .
cmake_minimum_required(VERSION 3.0)
cmake_minimum_required(VERSION 3.5)
project(musikcube)
set (musikcube_VERSION_MAJOR 3)
@ -48,10 +48,6 @@ else()
message(STATUS "[cross-compile] not enabled!")
endif()
message(STATUS "[vendor-link-directories] ${VENDOR_LINK_DIRECTORIES}")
message(STATUS "[vendor-include-directories] ${VENDOR_INCLUDE_DIRECTORIES}")
message(STATUS "[os-system-libs] ${DEFAULT_OS_SYSTEM_LIBS}")
list(
APPEND
PROJECT_INCLUDE_DIRECTORIES
@ -66,6 +62,11 @@ include_directories(${PROJECT_INCLUDE_DIRECTORIES})
link_directories("${musikcube_SOURCE_DIR}/bin/plugins")
message(STATUS "[vendor-link-directories] ${VENDOR_LINK_DIRECTORIES}")
message(STATUS "[vendor-include-directories] ${VENDOR_INCLUDE_DIRECTORIES}")
message(STATUS "[os-system-libs] ${DEFAULT_OS_SYSTEM_LIBS}")
message(STATUS "[project-include-directories] ${PROJECT_INCLUDE_DIRECTORIES}")
# these are used to (1) disable the standalone ASIO from trying to use
# boost, and (2) instruct websocketpp to use standalone (not boost) ASIO
add_definitions(

View File

@ -0,0 +1,69 @@
# Overview
By default when you build `musikcube` it's almost exclusively tied to your Linux distribution and version. If you try to copy the binaries compiled from `Ubuntu` to `Fedora`, for example, they probably won't work.
It turns out that building a single C++ app once that works across many Linux distributions and versions can be very challenging, especially when there are external dependencies involved. The difficulties have been documented and discussed countless times and include, but are not limited to:
1. Incompatible `GLIBC`/`GLIBCXX` versions
3. Incompatible versions of required dependencies
4. Incompatible locations of required dependencies (e.g. `/lib` vs `/usr/lib` vs `/usr/local/lib`)
5. Incompatible filenames for required depdencies (eg `libfoo.so.3` vs `libfoo.so`)
6. General unavailability of required dependencies (i.e. "dependency `foo` doesn't exist in `Ubuntu`'s `apt`")
In an ideal world we wouldn't have to worry about these problems, and `musikcube` would be available via all major Linux distribution package management systems. In practice, however, it's not. It can take tremendous time and effort to get packages accepted upstream by maintainers. For example, see the [DebianMentorsFaq](https://wiki.debian.org/DebianMentorsFaq).
So, for now, we've developed a process that allows us to compile "generic" binaries once per CPU architecture that should generally work across most modern Linux distributions without hassle. In short, we do the following:
1. Compile using an operating system with versions of `GLIBC` and `GLIBCXX` that should work on any Linux distribution from 2018 to now. We currently use `Debian Buster`.
2. Include modern versions of fundamental dependencies (`openssl`, `curl`, `ffmpeg` and others), compiled from source, ommitting any unused/extraneous functionality.
3. Ensure the app is "relocatable" on the filesystem; all libraries are loaded via relative paths so you can put the `musikcube` directory wherever you want and it'll still run. This is done by manually rewriting `rpath` values for shared libraries and executables where necessary.
The rest of this document will describe how we produce these builds, which are what we distribute on our [Github project page](https://github.com/clangen/musikcube/releases) for all releases.
Regular build instructions can be found on the [Github project page, here](https://github.com/clangen/musikcube/wiki/building), and have fewer weird prerequisites.
# Instructions
## Install `Debian Buster`
It's probably easiest to just install a `docker` image and use that, but an install straight to physical hardware (or a virtual machine) will work just fine.
## Install dependencies
### From `apt-get`:
- `sudo apt update`
- `sudo apt dist-upgrade`
- `sudo apt install build-essential g++ gcc git libasound2-dev libev-dev libncurses-dev libopus-dev libopus-dev libopus0 libpulse-dev libsndio-dev libssl-dev libsystemd-dev libvorbis-dev libvorbis-dev libvorbis0a libvorbisenc2 portaudio19-dev rpm wget zlib1g-dev`
### Compile from source:
Install the following from source, as the distro-provided packages are too old:
- `cmake` v3.27.4+
- `pipewire` v0.3.x (optional -- only if you want to use `pipewire`)
## Provision your build directory
A couple build steps assume that you'll be building from the `/build` directory. This can either be a physical directory or a symlink to elsewhere. This is currently a hard-requirement, but may not be in the future. Sorry.
- `cd /build`
- `git clone https://github.com/clangen/musikcube.git --recursive`
## Compile third-party dependencies
As mentioned above, a number of larger third-party dependencies are compiled from source, stripping unused functionality to ensure they are as small and efficient as possible. Doing this manually is really annoying, so it's all been automated behind a script.
- `cd /build`
- `./musikcube/script/build-vendor-libraries.sh`
This process may take a while, but when it completes you'll be left with a `/build/vendor-${arch}` directory that will contain all build artifacts. The `musikcube` app compile will reference this directory during its build process.
## Compile `musikcube`
Now that we have all required dependencies available it's time to compile the app itself. As mentioned above we want the resulting binary to be relocatable on the filesystem, so some special pre- and post-processing must happen. Specifically: we need to gather copies of all dependencies and rewrite their `rpaths` if necessary. We also need to collect and include resource files like themes and localization files, then create `.deb`, `.rpm`, and `.tar.bz2` archives for distribution. As in the previous step all of this complexity has been hidden behind a script.
- `cd /build/musikcube`
- `./script/archive-standalone-nix.sh x.y.z`
- `x.y.z` is the version of `musikcube` we'd like to appear in the filename. You can use anything you want, e.g. `0.0.0`
- The build process will automatically discover and use the `/build/vendor-${arch}` directory created in the previous step.
After the script has completed you should have a set of "relocatable" binaries in `/build/musikcube/dist/x.y.z/` that will work on most Linux distributions released in 2018 or later.

48
doc/crosscompile-rpi.md Normal file
View File

@ -0,0 +1,48 @@
# Prerequisites
Cross compiling depends on:
- A working "standalone" build environment ([see here](build-standalone-unix.md))
- A working Raspberry Pi `Buster` environment, either via `chroot` ([see here](rpi-buster-chroot.md)) or on a physical device
# Gather dependencies from a Raspbian install
The cross-compile toolchain ships with a minimal system "image" that does not include all of the third-party dependencies we need to compile musikcube.
To obtain these dependencies we need to boot into the chroot environment and execute a script to download and collect the latest versions of the headers and libraries so we can add them to the cross-compile toolchain.
1. Enter the `chroot` environment (or boot your device)
2. `apt-get update`
3. `sudo apt-get dist-upgrade`
4. `cd /build/sysroot`
5. `node /build/musikcube/script/create-crosscompile-sysroot.js`
After this process completes you will be left with a file called `sysroot.tar`.
# Install the cross-compile toolchain
The cross-compile toochains that ship with Debian and Ubuntu generally do not fully support `armv6`, which means we cannot use them to generate builds for older Raspberry Pi devices.
Instead, we'll install a better maintained toolchain from the following github project: https://github.com/tttapa/docker-arm-cross-toolchain
1. `cd /build`
2. `cp /path/to/generated/sysroot/sysroot.tar .`
3. `node /build/musikcube/script/install-crosscompile-tools.js`
This will download the cross-compile tools to the current directory, extract them, then use the `sysroot.tar` to populate the tools' environments.
# Use cross-compile toolchain to compile dependencies
In order to facilite easy, efficient distribution of musikcube binaries, we compile various dependencies ourselves, omitting unused features and ensuring the entire package is "relocatable," meaning users can run them from anywhere (i.e. they don't need to be installed to `/usr/` or `/usr/local/` to work properly).
1. `cd /build`
2. `CROSSCOMPILE=rpi-armv6 ./musikcube/script/build-vendor-libraries.sh`
When this has finished, you'll be left with a `vendor-rpi-armv6` directory that the main app compile will reference.
# Build the main app
Now that we have all of our dependencies available it's time to compile the main app.
1. `cd /build/musikcube`
2. `CROSSCOMPILE=rpi-armv6 ./script/archive-standalone-nix.sh 3.0.2`

71
doc/rpi-buster-chroot.md Normal file
View File

@ -0,0 +1,71 @@
# Forward
- stolen from here: https://medium.com/@crmoratelli/architectural-chroot-for-faster-compilation-and-deployment-on-raspberry-pi-76224327659d
# Install dependencies
- `sudo apt install qemu-kvm qemu-user-static binfmt-support qemu-user-static qemu-utils kpartx e2fsprogs`
# Create a new directory
- `mkdir rpi-buster-chroot`
# Download image
- `wget https://downloads.raspberrypi.org/raspios_oldstable_lite_armhf/images/raspios_oldstable_lite_armhf-2023-05-03/2023-05-03-raspios-buster-armhf-lite.img.xz`
# Extract image
- `xz -d -v 2023-05-03-raspios-buster-armhf-lite.img.xz`
# Expand the image
- `qemu-img resize -f raw 2023-05-03-raspios-buster-armhf-lite.img 16G`
# Expand the partition within the image
- `fdisk 2023-05-03-raspios-buster-armhf-lite.img`
- `Command: p` [prints the partition table. note partition #2's "Start" value.]
- `Command: d` [delete a partition]
- `Command: 2` [delete the Linux partition, which should be #2]
- `Command: n` [add new partition]
- `Command: p` [primary partition]
- `Command: 2` [partition number]
- `Command: ` [enter start value from first step]
- `Command: ` [press enter to accept default value]
- `Command: N` [to *NOT* remove the ext4 signature]
- `Command: w` [write table to file]
# Create a mount point
- `mkdir os-mount`
# Mount both disk imagen partitions via loopback
- `sudo kpartx -a -v 2023-05-03-raspios-buster-armhf-lite.img`
output, note device names:
```
add map loop4p1 (253:0): 0 524288 linear 7:4 8192
add map loop4p2 (253:1): 0 33021952 linear 7:4 532480 <== THIS IS OUR ACTUAL OS
```
# Mount the second partition to the filesystem
- `sudo mount /dev/mapper/loop4p2 ./os-mount`
# Resize the ext filesystem
- `sudo /sbin/resize2fs /dev/mapper/loop4p2`
# Inject qemu and setup special mount points
- `sudo cp /usr/bin/qemu-arm-static ./os-mount/usr/bin`
- `sudo mount -o bind /dev ./os-mount/dev`
- `sudo mount -o bind /proc ./os-mount/proc`
- `sudo mount -o bind /sys ./os-mount/sys`
# Magic: register `qemu-arm-static` as the arm interpreter in the kernel
> Must be root, no `sudo`
- `su`
- `echo ':arm:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-arm-static:' > /proc/sys/fs/binfmt_misc/register`
- `exit`
# Enter the chroot
- `sudo chroot ./os-mount`
# Shutdown
- `sudo umount ./os-mount/dev`
- `sudo umount ./os-mount/proc`
- `sudo umount ./os-mount/sys`
- `sudo umount ./os-mount`
- `sudo kpartx -d -v 2023-05-03-raspios-buster-armhf-lite.img`

View File

@ -19,19 +19,26 @@ if [[ $OS == "Darwin" ]]; then
JOBS="-j$(sysctl -n hw.ncpu)"
fi
ARCH=$(uname -m)
DEB_ARCH=$ARCH
VENDOR=$ARCH
if [[ -n $CROSSCOMPILE ]]; then
FRIENDLY_OS_NAME="linux_${CROSSCOMPILE}"
STRIP="strip"
FRIENDLY_ARCH_NAME=$(uname -m)
DEB_ARCH=$FRIENDLY_ARCH_NAME
VENDOR=$FRIENDLY_ARCH_NAME
if [[ $CROSSCOMPILE == rpi-* ]]; then
FRIENDLY_OS_NAME="linux_rpi"
XTOOLS_NAME="armv8-rpi3-linux-gnueabihf"
VENDOR=${CROSSCOMPILE}
ARCH="armhf"
FRIENDLY_ARCH_NAME="armv8"
DEB_ARCH="armhf"
elif [[ $ARCH == "x86_64" ]]; then
if [[ $CROSSCOMPILE == "rpi-armv6" ]]; then
XTOOLS_NAME="armv6-rpi-linux-gnueabihf"
FRIENDLY_ARCH_NAME="armv6"
fi
STRIP="/build/x-tools/${XTOOLS_NAME}/${XTOOLS_NAME}/bin/strip"
elif [[ $FRIENDLY_ARCH_NAME == "x86_64" ]]; then
DEB_ARCH="amd64"
fi
OS_ARCH="${FRIENDLY_OS_NAME}_${ARCH}"
OS_ARCH="${FRIENDLY_OS_NAME}_${FRIENDLY_ARCH_NAME}"
OUTNAME="musikcube_${OS_ARCH}_$VERSION"
OUTDIR="dist/$VERSION/$OUTNAME"
SCRIPTDIR=`dirname "$0"`
@ -44,15 +51,17 @@ fi
OS_SPECIFIC_BUILD_FLAGS=""
if [[ $OS == "Linux" ]]; then
OS_SPECIFIC_BUILD_FLAGS="-DGENERATE_DEB=true -DPACKAGE_ARCHITECTURE=${DEB_ARCH} -DCMAKE_INSTALL_PREFIX=/usr"
if [[ $CROSSCOMPILE == "rpi" ]]; then
OS_SPECIFIC_BUILD_FLAGS="-DGENERATE_DEB=true -DPACKAGE_ARCHITECTURE=${DEB_ARCH} -DFRIENDLY_ARCHITECTURE_NAME=${OS_ARCH} -DCMAKE_INSTALL_PREFIX=/usr"
if [[ $CROSSCOMPILE == rpi-* ]]; then
# for now we don't support pipewire when cross compiling...
OS_SPECIFIC_BUILD_FLAGS="$OS_SPECIFIC_BUILD_FLAGS -DENABLE_PIPEWIRE=false"
fi
fi
if [[ $CROSSCOMPILE == "rpi" ]]; then
CMAKE_TOOLCHAIN="-DCMAKE_TOOLCHAIN_FILE=.cmake/RaspberryPiToolchain.cmake"
if [[ $CROSSCOMPILE == "rpi-armv8" ]]; then
CMAKE_TOOLCHAIN="-DCMAKE_TOOLCHAIN_FILE=.cmake/RaspberryPiToolchain-armv8.cmake"
elif [[ $CROSSCOMPILE == "rpi-armv6" ]]; then
CMAKE_TOOLCHAIN="-DCMAKE_TOOLCHAIN_FILE=.cmake/RaspberryPiToolchain-armv6.cmake"
fi
rm vendor
@ -72,20 +81,27 @@ else
${SCRIPTDIR}/clean-nix.sh
rm -rf bin/ 2> /dev/null
./script/stage-vendor-libraries.sh || exit $?
cmake ${CMAKE_TOOLCHAIN} -DCMAKE_BUILD_TYPE=Release -DBUILD_STANDALONE=true -DENABLE_PCH=true ${OS_SPECIFIC_BUILD_FLAGS} . || exit $?
cmake ${CMAKE_TOOLCHAIN} -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DBUILD_STANDALONE=true -DENABLE_PCH=true ${OS_SPECIFIC_BUILD_FLAGS} . || exit $?
make ${JOBS} || exit $?
fi
./script/patch-rpath.sh $(pwd) || exit $?
rm -rf dist/$VERSION/*${OS_ARCH}_$VERSION* 2> /dev/null
printf "stripping binaries..."
$STRIP bin/musikcube
$STRIP bin/musikcubed
$STRIP bin/libmusikcore.${DLL_EXT}
$STRIP bin/lib/*
$STRIP bin/libmusikcore.${DLL_EXT}
$STRIP bin/plugins/*.${DLL_EXT}
printf "staging binaries..."
rm -rf dist/$VERSION/*${OS_ARCH}_$VERSION* 2> /dev/null
mkdir -p $OUTDIR/lib
mkdir -p $OUTDIR/plugins
mkdir -p $OUTDIR/locales
mkdir -p $OUTDIR/themes
mkdir -p $OUTDIR/share/terminfo
cp bin/musikcube $OUTDIR
cp bin/musikcubed $OUTDIR
cp bin/libmusikcore.${DLL_EXT} $OUTDIR
@ -95,7 +111,7 @@ cp bin/locales/*.json $OUTDIR/locales
cp bin/themes/*.json $OUTDIR/themes
cp -rfp bin/share/terminfo/* $OUTDIR/share/terminfo/
if [[ $CROSSCOMPILE == "rpi" ]]; then
if [[ $CROSSCOMPILE == rpi-* ]]; then
printf "\n\n\n ***** CROSSCOMPILE DETECTED, **NOT** SCANNING DEPENDENCIES! *****\n\n\n"
sleep 1
else
@ -104,13 +120,6 @@ else
node ./script/scan-standalone dist/$VERSION/$OUTNAME || exit $?
fi
strip $OUTDIR/musikcube
strip $OUTDIR/musikcubed
strip $OUTDIR/libmusikcore.${DLL_EXT}
strip $OUTDIR/lib/*
strip $OUTDIR/libmusikcore.${DLL_EXT}
strip $OUTDIR/plugins/*.${DLL_EXT}
cd dist/$VERSION/
tar cvf $OUTNAME.tar $OUTNAME
bzip2 $OUTNAME.tar

View File

@ -27,12 +27,12 @@ RPATH="@rpath"
OS=$(uname)
ARCH=$(uname -m)
SCRIPTDIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
OPENSSL_VERSION="3.1.0"
CURL_VERSION="8.0.1"
LIBMICROHTTPD_VERSION="0.9.76"
OPENSSL_VERSION="3.1.2"
CURL_VERSION="8.2.1"
LIBMICROHTTPD_VERSION="0.9.77"
FFMPEG_VERSION="6.0"
LAME_VERSION="3.100"
LIBOPENMPT_VERSION="0.6.9"
LIBOPENMPT_VERSION="0.7.1"
TAGLIB_VERSION="1.13"
GME_VERSION="0.6.3"
OUTDIR="$(pwd)/vendor/bin"
@ -48,29 +48,81 @@ if [[ $OS == "Darwin" ]]; then
OPENSSL_TYPE="darwin64-${ARCH}-cc"
fi
# update cross-compile vars, if specified.
if [[ $CROSSCOMPILE == "rpi" ]]; then
OPENSSL_VERSION="1.1.1n"
ARM_ROOT="/build/rpi/sysroot"
export CPPFLAGS="-I${ARM_ROOT}/usr/include"
export CXXFLAGS="$CXXFLAGS -I${ARM_ROOT}/usr/include"
export LDFLAGS="$LDFLAGS --sysroot=${ARM_ROOT} -L${ARM_ROOT}/lib/arm-linux-gnueabihf/"
OPENSSL_TYPE="linux-generic32"
OPENSSL_CROSSCOMPILE_PREFIX="--cross-compile-prefix=arm-linux-gnueabihf-"
GENERIC_CONFIGURE_FLAGS="--build=x86_64-pc-linux-gnu --host=arm-linux-gnueabihf --with-sysroot=${ARM_ROOT}"
FFMPEG_CONFIGURE_FLAGS="--arch=${ARCH} --target-os=linux --cross-prefix=arm-linux-gnueabihf-"
CMAKE_COMPILER_TOOLCHAIN="-DCMAKE_TOOLCHAIN_FILE=/build/musikcube/.cmake/RaspberryPiToolchain.cmake"
PKG_CONFIG_PATH="${LIBDIR}/pkgconfig/:${ARM_ROOT}/usr/lib/arm-linux-gnueabihf/pkgconfig/"
printf "\n\ndetected CROSSCOMPILE=${CROSSCOMPILE}\n"
printf " CFLAGS=${CFLAGS}\n CXXFLAGS=${CXXFLAGS}\n LDFLAGS=${LDFLAGS}\n GENERIC_CONFIGURE_FLAGS=${GENERIC_CONFIGURE_FLAGS}\n"
printf " OPENSSL_TYPE=${OPENSSL_TYPE}\n OPENSSL_CROSSCOMPILE_PREFIX=${OPENSSL_CROSSCOMPILE_PREFIX}\n"
printf " FFMPEG_CONFIGURE_FLAGS=${FFMPEG_CONFIGURE_FLAGS}\n PKG_CONFIG_PATH=${PKG_CONFIG_PATH}\n\n"
sleep 3
fi
BUILD_ROOT="/build"
function clean() {
rm -rf vendor
mkdir vendor
function set_makefile_env_vars() {
if [[ -n $CROSSCOMPILE ]]; then
printf "updating AR, CC, CXX, LD for Makefile cross-compile\n"
OLD_AR=$AR
OLD_CC=$CC
OLD_CXX=$CXX
OLD_LD=$LD
export AR="${XTOOLS_TOOLCHAIN_NAME}-ar"
export CC="${XTOOLS_TOOLCHAIN_NAME}-gcc"
export CXX="${XTOOLS_TOOLCHAIN_NAME}-g++"
export LD="${XTOOLS_TOOLCHAIN_NAME}-ld"
fi
}
function unset_makefile_env_vars() {
if [[ -n $CROSSCOMPILE ]]; then
printf "restoring AR, CC, CXX, LDD for autotools/cmake cross-compile\n"
AR=$OLD_AR
CC=$OLD_CC
CXX=$OLD_CXX
LD=$OLD_LD
fi
}
function configure_crosscompile_if_necessary() {
# update cross-compile vars, if specified.
if [[ $CROSSCOMPILE == rpi-* ]]; then
# cross-compile toolchains found here: https://github.com/tttapa/docker-arm-cross-toolchain. note
# that the toolchain uses a newer version of libstdc++ than supported by our oldest platform,
# so we link with "-static-libstdc++".
# see: https://github.com/tttapa/docker-arm-cross-toolchain/issues/5#issuecomment-1665744288
OPENSSL_TYPE="linux-generic32"
XTOOLS_TOOLCHAIN_NAME="armv8-rpi3-linux-gnueabihf"
CMAKE_COMPILER_TOOLCHAIN="--toolchain ${BUILD_ROOT}/musikcube/.cmake/RaspberryPiToolchain-armv8.cmake"
if [[ $CROSSCOMPILE == "rpi-armv6" ]]; then
XTOOLS_TOOLCHAIN_NAME="armv6-rpi-linux-gnueabihf"
CMAKE_COMPILER_TOOLCHAIN="--toolchain ${BUILD_ROOT}/musikcube/.cmake/RaspberryPiToolchain-armv6.cmake"
fi
XTOOLS_SYSROOT="${BUILD_ROOT}/x-tools/${XTOOLS_TOOLCHAIN_NAME}/${XTOOLS_TOOLCHAIN_NAME}/sysroot/"
XTOOLS_LDFLAGS="--sysroot=${XTOOLS_SYSROOT}"
XTOOLS_BIN_PATH="${BUILD_ROOT}/x-tools/${XTOOLS_TOOLCHAIN_NAME}/bin"
XTOOLS_PKG_CONFIG_PATH="${XTOOLS_SYSROOT}/usr/lib/arm-linux-gnueabihf/pkgconfig/"
VENDOR_PKG_CONFIG_PATH="${LIBDIR}/pkgconfig/"
# in general these are all we need for autotools
export PATH="${XTOOLS_BIN_PATH}:$PATH"
export LDFLAGS="$LDFLAGS ${XTOOLS_LDFLAGS}"
export CXXFLAGS="$CXXFLAGS -static-libstdc++"
export PKG_CONFIG_PATH="${VENDOR_PKG_CONFIG_PATH}:${XTOOLS_PKG_CONFIG_PATH}"
OPENSSL_CROSSCOMPILE_PREFIX="--cross-compile-prefix=${XTOOLS_TOOLCHAIN_NAME}-"
GENERIC_CONFIGURE_FLAGS="--build=x86_64-pc-linux-gnu --host=${XTOOLS_TOOLCHAIN_NAME} --with-sysroot=${XTOOLS_SYSROOT}"
FFMPEG_CONFIGURE_FLAGS="--arch=${ARCH} --target-os=linux --enable-cross-compile --sysroot=${XTOOLS_SYSROOT} --cross-prefix=${XTOOLS_TOOLCHAIN_NAME}-"
fi
}
function print_build_configuration() {
show_banner "build configuration"
printf " - XTOOLS_TOOLCHAIN_NAME=${XTOOLS_TOOLCHAIN_NAME}\n"
printf " - CMAKE_COMPILER_TOOLCHAIN=${CMAKE_COMPILER_TOOLCHAIN}\n"
printf " - CFLAGS=${CFLAGS}\n"
printf " - CXXFLAGS=${CXXFLAGS}\n"
printf " - LDFLAGS=${LDFLAGS}\n"
printf " - GENERIC_CONFIGURE_FLAGS=${GENERIC_CONFIGURE_FLAGS}\n"
printf " - OPENSSL_TYPE=${OPENSSL_TYPE}\n"
printf " - OPENSSL_CROSSCOMPILE_PREFIX=${OPENSSL_CROSSCOMPILE_PREFIX}\n"
printf " - FFMPEG_CONFIGURE_FLAGS=${FFMPEG_CONFIGURE_FLAGS}\n"
printf " - PKG_CONFIG_PATH=${PKG_CONFIG_PATH}\n"
sleep 3
}
#
@ -97,17 +149,27 @@ function fetch_packages() {
copy_or_download https://ftp.gnu.org/gnu/libmicrohttpd libmicrohttpd-${LIBMICROHTTPD_VERSION}.tar.gz
copy_or_download https://ffmpeg.org/releases ffmpeg-${FFMPEG_VERSION}.tar.bz2
copy_or_download https://downloads.sourceforge.net/project/lame/lame/${LAME_VERSION} lame-${LAME_VERSION}.tar.gz
copy_or_download https://lib.openmpt.org/files/libopenmpt/src libopenmpt-${LIBOPENMPT_VERSION}+release.makefile.tar.gz
copy_or_download https://lib.openmpt.org/files/libopenmpt/src libopenmpt-${LIBOPENMPT_VERSION}+release.autotools.tar.gz
copy_or_download https://github.com/taglib/taglib/releases/download/v${TAGLIB_VERSION} taglib-${TAGLIB_VERSION}.tar.gz
copy_or_download https://bitbucket.org/mpyne/game-music-emu/downloads game-music-emu-${GME_VERSION}.tar.gz
}
function show_banner {
printf "\n\n********************************************************************************\n"
printf "*\n"
printf "* $1\n"
printf "*\n"
printf "********************************************************************************\n\n"
}
#
# openssl
#
function build_openssl() {
tar xvfz openssl-${OPENSSL_VERSION}.tar.gz
show_banner "building openssl..."
tar xvfz openssl-${OPENSSL_VERSION}.tar.gz > /dev/null
cd openssl-${OPENSSL_VERSION}
perl ./Configure --prefix=${OUTDIR} no-ssl3 no-ssl3-method no-zlib ${OPENSSL_TYPE} ${OPENSSL_CROSSCOMPILE_PREFIX} || exit $?
make -j8
@ -131,8 +193,9 @@ function build_openssl() {
#
function build_curl() {
show_banner "building libcurl..."
rm -rf curl-${CURL_VERSION}
tar xvfz curl-${CURL_VERSION}.tar.gz
tar xvfz curl-${CURL_VERSION}.tar.gz > /dev/null
cd curl-${CURL_VERSION}
./configure --enable-shared \
--with-pic \
@ -175,8 +238,9 @@ function build_curl() {
#
function build_libmicrohttpd() {
show_banner "building libmicrohttpd..."
rm -rf libmicrohttpd-${LIBMICROHTTPD_VERSION}
tar xvfz libmicrohttpd-${LIBMICROHTTPD_VERSION}.tar.gz
tar xvfz libmicrohttpd-${LIBMICROHTTPD_VERSION}.tar.gz > /dev/null
cd libmicrohttpd-${LIBMICROHTTPD_VERSION}
./configure --enable-shared --with-pic --enable-https=no --disable-curl --prefix=${OUTDIR} ${GENERIC_CONFIGURE_FLAGS}
make -j8 || exit $?
@ -189,9 +253,16 @@ function build_libmicrohttpd() {
#
function build_ffmpeg() {
show_banner "building ffmpeg..."
# fix for cross-compile: https://github.com/NixOS/nixpkgs/pull/76915/files
rm -rf ffmpeg-${FFMPEG_VERSION}
tar xvfj ffmpeg-${FFMPEG_VERSION}.tar.bz2
tar xvfj ffmpeg-${FFMPEG_VERSION}.tar.bz2 > /dev/null
OLD_LDFLAGS=$LDFLAGS
OLD_CFLAGS=$CFLAGS
export LDFLAGS="$LDFLAGS -lm"
export CFLAGS="$CFLAGS -I${XTOOLS_SYSROOT}/usr/include/opus"
cd ffmpeg-${FFMPEG_VERSION}
./configure \
--prefix=${OUTDIR} \
@ -370,6 +441,10 @@ function build_ffmpeg() {
--build-suffix=-musikcube || exit $?
make ${JOBS} || exit $?
make install
export LDFLAGS=$OLD_LDFLAGS
export CFLAGS=$OLD_CFLAGS
cd ..
}
@ -378,8 +453,9 @@ function build_ffmpeg() {
#
function build_lame() {
show_banner "building lame..."
rm -rf lame-${LAME_VERSION}
tar xvfz lame-${LAME_VERSION}.tar.gz
tar xvfz lame-${LAME_VERSION}.tar.gz > /dev/null
cd lame-${LAME_VERSION}
# https://sourceforge.net/p/lame/mailman/message/36081038/
perl -i.bak -0pe "s|lame_init_old\n||" include/libmp3lame.sym
@ -394,30 +470,45 @@ function build_lame() {
#
function build_libopenmpt() {
rm -rf libopenmpt-${LIBOPENMPT_VERSION}+release.autotools
tar xvfz libopenmpt-${LIBOPENMPT_VERSION}+release.autotools.tar.gz
cd libopenmpt-${LIBOPENMPT_VERSION}+release.autotools
./configure \
--disable-dependency-tracking \
--enable-shared \
--disable-openmpt123 \
--disable-examples \
--disable-tests \
--disable-doxygen-doc \
--disable-doxygen-html \
--without-mpg123 \
--without-ogg \
--without-vorbis \
--without-vorbisfile \
--without-portaudio \
--without-portaudiocpp \
--without-sndfile \
--without-flac \
${GENERIC_CONFIGURE_FLAGS} \
--prefix=${OUTDIR} || exit $?
make ${JOBS} || exit $?
make install
cd ..
show_banner "building libopenmpt..."
# macOS needs to use the autotools version, but Linux uses the Makefile
# version for cross-compile support.
if [[ $OS == "Darwin" ]]; then
rm -rf libopenmpt-${LIBOPENMPT_VERSION}+release.autotools
tar xvfz libopenmpt-${LIBOPENMPT_VERSION}+release.autotools.tar.gz > /dev/null
cd libopenmpt-${LIBOPENMPT_VERSION}+release.autotools
./configure \
--disable-dependency-tracking \
--enable-shared \
--disable-openmpt123 \
--disable-examples \
--disable-tests \
--disable-doxygen-doc \
--disable-doxygen-html \
--without-mpg123 \
--without-ogg \
--without-vorbis \
--without-vorbisfile \
--without-portaudio \
--without-portaudiocpp \
--without-sndfile \
--without-flac \
${GENERIC_CONFIGURE_FLAGS} \
--prefix=${OUTDIR} || exit $?
make ${JOBS} || exit $?
make install
cd ..
else
set_makefile_env_vars
rm -rf libopenmpt-0.7.0+release/
tar xvfz libopenmpt-${LIBOPENMPT_VERSION}+release.makefile.tar.gz > /dev/null
cd libopenmpt-${LIBOPENMPT_VERSION}+release
OPENMPT_OPTIONS="EXAMPLES=0 NO_FLAC=1 NO_MINIMP3=1 NO_MINIZ=1 NO_MPG123=1 NO_OGG=1 NO_PORTAUDIO=1 NO_PORTAUDIOCPP=1 NO_PULSEAUDIO=1 NO_SDL2=1 NO_SNDFILE=1 NO_STBVORBIS=1 NO_VORBIS=1 NO_VORBISFILE=1 OPENMPT123=0 SHARED_LIB=1 STATIC_LIB=0 TEST=0 PREFIX=${OUTDIR}"
make ${OPENMPT_OPTIONS} ${JOBS} VERBOSE=1 || exit $?
make ${OPENMPT_OPTIONS} install
unset_makefile_env_vars
cd ..
fi
}
#
@ -425,12 +516,14 @@ function build_libopenmpt() {
#
function build_gme() {
show_banner "building gme (game-music-emu)..."
rm -rf game-music-emu-${GME_VERSION}
tar xvfz game-music-emu-${GME_VERSION}.tar.gz
tar xvfz game-music-emu-${GME_VERSION}.tar.gz > /dev/null
cd game-music-emu-${GME_VERSION}
cmake \
-DCMAKE_INSTALL_PREFIX=${OUTDIR} \
${CMAKE_COMPILER_TOOLCHAIN} \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
-DCMAKE_INSTALL_PREFIX=${OUTDIR} \
-DENABLE_UBSAN=OFF \
-DBUILD_SHARED_LIBS=1 \
. || exit $?
@ -444,12 +537,14 @@ function build_gme() {
#
function build_taglib() {
show_banner "building taglib..."
rm -rf taglib-${TAGLIB_VERSION}
tar xvfz taglib-${TAGLIB_VERSION}.tar.gz
tar xvfz taglib-${TAGLIB_VERSION}.tar.gz > /dev/null
cd taglib-${TAGLIB_VERSION}
cmake \
-DCMAKE_INSTALL_PREFIX=${OUTDIR} \
${CMAKE_COMPILER_TOOLCHAIN} \
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
-DCMAKE_INSTALL_PREFIX=${OUTDIR} \
-DBUILD_SHARED_LIBS=1 \
. || exit $?
make ${JOBS} || exit $?
@ -502,28 +597,39 @@ function delete_unused_libraries() {
cd ../../
}
clean
mkdir vendor
cd vendor
function main() {
rm -rf vendor
mkdir vendor
cd vendor
touch ".config-${ARCH}-${CROSSCOMPILE}"
stage_prebuilt_libraries
fetch_packages
build_openssl
build_curl
build_libmicrohttpd
build_ffmpeg
build_lame
build_libopenmpt
build_gme
build_taglib
delete_unused_libraries
relink_dynamic_libraries
configure_crosscompile_if_necessary
print_build_configuration
cd ..
if [[ $CROSSCOMPILE == "rpi" ]]; then
mv vendor vendor-${CROSSCOMPILE}
else
mv vendor vendor-$(uname -m)
fi
stage_prebuilt_libraries
fetch_packages
build_ffmpeg
build_openssl
build_curl
build_libopenmpt
build_libmicrohttpd
build_lame
build_gme
build_taglib
delete_unused_libraries
relink_dynamic_libraries
cd ..
if [[ $CROSSCOMPILE == rpi-* ]]; then
mv vendor vendor-${CROSSCOMPILE}
else
mv vendor vendor-$(uname -m)
fi
}
main
printf "\n\ndone!\n\n"

View File

@ -0,0 +1,196 @@
const { promisify } = require('util');
const exec = promisify(require('child_process').exec);
const fs = require('fs');
const path = require('path');
/**
* This script will download and extract all transitive dependencies
* for the packages specified by PACKAGE_NAMES. This is used to populate
* a cross-compile sysroot with the libraries required to compile the
* app itself.
*/
const PACKAGE_NAMES = [
'libasound2-dev',
'libev-dev',
'libncurses-dev',
'libopus-dev',
'libpulse-dev',
'libsndio-dev',
'libsystemd-dev',
'libvorbis-dev',
'portaudio19-dev',
'zlib1g-dev',
];
/**
* These are packages that are either provided by the cross-compiler
* tools, or otherwise introduce conflicts while building and linking.
* If any of the packages depend on these, we explicitly ignore them.
*/
const EXCLUDE = [
'debconf',
'dpkg',
'gcc-10-base',
'gcc-13-base',
'gcc-8-base',
'install-info',
'libc-dev-bin',
'libc6-dev',
'libc6',
'libcrypt1',
'libdebian-installer4',
'libdpkg-perl',
'libgcc-s1',
'libgcc1',
'libselinux1-dev',
'libselinux1',
'libstdc++6',
'linux-libc-dev',
];
/**
* A list of files known to be provided by deb archives that we don't
* want or need; we'll delete these after we're done downloading and
* extracting files.
*/
const CLEANUP_FILES = [
'control.tar.gz',
'control.tar.bz2',
'control.tar.xz',
'control.tar.zst',
'data.tar.gz',
'data.tar.bz2',
'data.tar.xz',
'data.tar.zst',
'debian-binary',
];
/**
* Uses `apt-cache` to resolve a list of package dependencies for
* the specified package.
*/
const getPackageDependencies = async (packageName) => {
const rawOutput = (
await exec(
`apt-cache depends --recurse --no-recommends --no-suggests --no-conflicts --no-breaks --no-replaces --no-enhances ${packageName}`
)
).stdout.split('\n');
const packages = rawOutput
.filter((e) => e.indexOf('Depends:') >= 0)
.map((e) => e.replace('Depends:', '').trim())
.filter(
(e) => !(e.startsWith('Pre ') || e.startsWith('<') || e.startsWith('|'))
);
return packages;
};
/**
* Uses `apt download` to get a list of download URLs from
* the specified list of packages.
*/
const getPackageDownloadUrls = async (packages) => {
const rawOutput = (
await exec(`apt download --print-uris ${packages.join(' ')}`)
).stdout.split('\n');
const downloadUrls = rawOutput
.filter((e) => e.trim().length > 0)
.map((e) => e.split(' ')[0].trim().replace(/'/g, ''));
return downloadUrls;
};
/**
* Downloads and extracts a list of deb URLs
*/
const downloadAndExtract = async (downloadUrls) => {
for (let i = 0; i < downloadUrls.length; i++) {
const fn = decodeURIComponent(downloadUrls[i].split('/').pop());
console.log(
`processing [${i + 1}/${downloadUrls.length}]`,
downloadUrls[i]
);
await exec(`wget ${downloadUrls[i]}`);
await exec(`ar x ./${fn}`);
if (fs.existsSync('data.tar.zst')) {
await exec(`tar --use-compress-program=unzstd -xvf data.tar.zst`);
} else if (fs.existsSync('data.tar.xz')) {
await exec(`tar -xvf data.tar.xz`);
} else if (fs.existsSync('data.tar.gz')) {
await exec(`tar xvfz data.tar.gz`);
} else if (fs.existsSync('data.tar.bz2')) {
await exec(`tar xvfj data.tar.bz2`);
} else {
console.error('unknown file type');
process.exit(-1);
}
for (let j = 0; j < CLEANUP_FILES.length; j++) {
if (fs.existsSync(CLEANUP_FILES[j])) {
await exec(`rm ${CLEANUP_FILES[j]}`);
}
}
}
};
/**
* Finds all symlinks with absolute paths in our generated
* sysroot, and converts them to relative paths. This ensures
* the sysroot is "relocatable" and can be used with
* crosscompile toolchains.
*/
const convertAbsoluteToRelativeSymlinks = async () => {
const root = process.cwd();
const symlinks = (await exec('find . -type l')).stdout
.split('\n')
.filter((e) => e.length > 0);
for (let i = 0; i < symlinks.length; i++) {
const dest = fs.readlinkSync(symlinks[i]);
if (dest[0] === '/') {
const absoluteTo = path.join(root, dest);
const absoluteFrom = path.join(root, symlinks[i]);
const relative = path.relative(path.dirname(absoluteFrom), absoluteTo);
console.log(
`relinking\n * fn: ${absoluteFrom}\n * from: ${absoluteTo}\n * to: ${relative}`
);
fs.unlinkSync(symlinks[i]);
fs.symlinkSync(relative, symlinks[i]);
}
}
};
/**
* Delete any debs we downloaded
*/
const rmDebs = async () => {
try {
console.log('cleaning up downloads');
await exec('rm *.deb');
} catch (e) {
/* nothing */
}
};
const main = async () => {
await rmDebs();
let dependencies = [];
for (let i = 0; i < PACKAGE_NAMES.length; i++) {
console.log(
`scanning [${i + 1}/${PACKAGE_NAMES.length}]`,
PACKAGE_NAMES[i]
);
dependencies = [
...dependencies,
...(await getPackageDependencies(PACKAGE_NAMES[i])),
];
}
const deduped = new Set([...PACKAGE_NAMES, ...dependencies]);
for (let i = 0; i < EXCLUDE.length; i++) {
deduped.delete(EXCLUDE[i]);
}
console.log(`resolved ${deduped.size} transitive dependencies`);
const downloadUrls = await getPackageDownloadUrls(Array.from(deduped));
await downloadAndExtract(downloadUrls);
await convertAbsoluteToRelativeSymlinks();
await rmDebs();
await exec('tar cvf sysroot.tar .', { maxBuffer: 1024 * 1024 * 8 }); /* 8mb */
};
main();

View File

@ -0,0 +1,43 @@
const { promisify } = require('util');
const exec = promisify(require('child_process').exec);
const fs = require('fs');
const TOOLCHAINS = ['armv6-rpi-linux-gnueabihf', 'armv8-rpi3-linux-gnueabihf'];
const run = async (command) => {
console.log(' > ', command);
await exec(command, { maxBuffer: 1024 * 1024 * 8 }); /* 8mb */
};
const install = async (toolchain) => {
const archiveFn = `x-tools-${toolchain}.tar.xz`;
const toolsRootDir = `x-tools/${toolchain}`;
const sysrootDir = `${toolsRootDir}/${toolchain}/sysroot`;
const downloadUrl = `https://github.com/tttapa/docker-arm-cross-toolchain/releases/download/0.1.2/${archiveFn}`;
console.log(' * downloading...');
await run(`wget ${downloadUrl}`);
console.log(' * extracting...');
await run(`tar xvf ${archiveFn}`);
console.log(' * updating permissions...');
await run(`chmod u+w ${sysrootDir} -R`);
console.log(' * installing sysroot...');
await run(`tar xvf sysroot.tar --directory=${sysrootDir}`);
console.log(' * cleaning up...');
await run(`rm ${archiveFn} 2> /dev/null`);
};
main = async () => {
for (let i = 0; i < TOOLCHAINS.length; i++) {
console.log(`installing [${i + 1}/${TOOLCHAINS.length}] ${TOOLCHAINS[i]}`);
await install(TOOLCHAINS[i]);
}
};
if (!fs.existsSync('./sysroot.tar')) {
console.error(
'[ERROR]: sysroot.tar not found in the current directory, process will not continue'
);
process.exit(1);
}
main();

View File

@ -10,53 +10,54 @@ const filetype = mac ? '.dylib' : '.so';
const ignoredLibraries = mac
? new Set([])
: new Set([
'libalsaout.so',
'libmpris.so',
'libpipewireout.so',
'libpulseout.so',
'libsndioout.so',
]);
'libalsaout.so',
'libmpris.so',
'libpipewireout.so',
'libpulseout.so',
'libsndioout.so',
]);
/* we assume these dependencies will always be available on the user's
target machine. */
const validLibraries = mac
? new Set([
'/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit',
'/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices',
'/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox',
'/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon',
'/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio',
'/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation',
'/System/Library/Frameworks/CoreGraphics.framework/Versions/A/CoreGraphics',
'/System/Library/Frameworks/CoreMedia.framework/Versions/A/CoreMedia',
'/System/Library/Frameworks/CoreVideo.framework/Versions/A/CoreVideo',
'/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation',
'/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration',
'/usr/lib/libc++.1.dylib',
'/usr/lib/libobjc.A.dylib',
'/usr/lib/libSystem.B.dylib',
'/usr/lib/libz.1.dylib',
'/opt/homebrew/opt/portaudio/lib/libportaudio.2.dylib',
'/usr/local/opt/portaudio/lib/libportaudio.2.dylib',
])
'/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit',
'/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices',
'/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox',
'/System/Library/Frameworks/Carbon.framework/Versions/A/Carbon',
'/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio',
'/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation',
'/System/Library/Frameworks/CoreGraphics.framework/Versions/A/CoreGraphics',
'/System/Library/Frameworks/CoreMedia.framework/Versions/A/CoreMedia',
'/System/Library/Frameworks/CoreVideo.framework/Versions/A/CoreVideo',
'/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation',
'/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration',
'/usr/lib/libc++.1.dylib',
'/usr/lib/libobjc.A.dylib',
'/usr/lib/libSystem.B.dylib',
'/usr/lib/libz.1.dylib',
'/opt/homebrew/opt/portaudio/lib/libportaudio.2.dylib',
'/usr/local/opt/portaudio/lib/libportaudio.2.dylib',
])
: new Set([
'/lib/ld-linux-armhf.so.3',
'/lib64/ld-linux-x86-64.so.2',
'/usr/lib/arm-linux-gnueabihf/libarmmem-${PLATFORM}.so',
'libc.so.6',
'libdl.so.2',
'libgcc_s.so.1',
'libm.so.6',
'libpthread.so.0',
'librt.so.1',
'libstdc++.so.6',
'libz.so.1',
'linux-vdso.so.1',
'libportaudio.so.2',
'libasound.so.2',
'libjack.so.0',
'libdb-5.3.so',
]);
'/lib/ld-linux-armhf.so.3',
'/lib64/ld-linux-x86-64.so.2',
'/usr/lib/arm-linux-gnueabihf/libarmmem-${PLATFORM}.so',
'/usr/lib/arm-linux-gnueabi/libarmmem-${PLATFORM}.so',
'libc.so.6',
'libdl.so.2',
'libgcc_s.so.1',
'libm.so.6',
'libpthread.so.0',
'librt.so.1',
'libstdc++.so.6',
'libz.so.1',
'linux-vdso.so.1',
'libportaudio.so.2',
'libasound.so.2',
'libjack.so.0',
'libdb-5.3.so',
]);
let errors = 0;

View File

@ -22,7 +22,7 @@ if [[ "$PLATFORM" == 'Darwin' ]]; then
cp vendor/bin/lib/libcurl.4.dylib ./bin/lib
cp vendor/bin/lib/libmicrohttpd.12.dylib ./bin/lib
cp vendor/bin/lib/libmp3lame.0.dylib ./bin/lib
cp vendor/bin/lib/libopenmpt.0.dylib ./bin/lib
cp vendor/bin/lib/libopenmpt.4.dylib ./bin/lib
cp vendor/bin/lib/libgme.0.6.3.dylib ./bin/lib
cp vendor/bin/lib/libtag.1.19.0.dylib ./bin/lib
@ -36,19 +36,25 @@ elif [[ "$PLATFORM" == 'Linux' ]]; then
cp vendor/bin/lib/libavformat-musikcube.so.60 ./bin/lib
cp vendor/bin/lib/libavutil-musikcube.so.58 ./bin/lib
cp vendor/bin/lib/libswresample-musikcube.so.4 ./bin/lib
cp vendor/bin/lib/libcrypto.so.3 ./bin/lib
cp vendor/bin/lib/libssl.so.3 ./bin/lib
cp vendor/bin/lib/libcrypto.so.3 ./bin/lib 2> /dev/null
cp vendor/bin/lib/libssl.so.3 ./bin/lib 2> /dev/null
cp vendor/bin/lib/libcrypto.so.1.1 ./bin/lib 2> /dev/null
cp vendor/bin/lib/libssl.so.1.1 ./bin/lib 2> /dev/null
cp vendor/bin/lib/libcurl.so.4 ./bin/lib
cp vendor/bin/lib/libmp3lame.so.0 ./bin/lib
cp vendor/bin/lib/libmicrohttpd.so.12 ./bin/lib
cp vendor/bin/lib/libopenmpt.so.0 ./bin/lib
cp vendor/bin/lib/libopenmpt.so.4 ./bin/lib
cp vendor/bin/lib/libgme.so.0 ./bin/lib
cp vendor/bin/lib/libtag.so.1 ./bin/lib
SYSTEM_ROOT=""
SYSTEM_TYPE="x86_64-linux-gnu"
if [[ $CROSSCOMPILE == "rpi" ]]; then
SYSTEM_ROOT="/build/rpi/sysroot"
if [[ $CROSSCOMPILE == rpi-* ]]; then
XTOOLS_ARCH="armv8-rpi3-linux-gnueabihf"
if [[ $CROSSCOMPILE == "rpi-armv6" ]]; then
XTOOLS_ARCH="armv6-rpi-linux-gnueabihf"
fi
SYSTEM_ROOT="/build/x-tools/${XTOOLS_ARCH}/${XTOOLS_ARCH}/sysroot"
SYSTEM_TYPE="arm-linux-gnueabihf"
fi

View File

@ -1,20 +0,0 @@
#!/bin/bash
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
HOST=$1
if [[ -z $HOST ]]; then
printf "usage: sync-pi-sysroot.sh <pi_hostname>"
exit 1
fi
# https://mechatronicsblog.com/cross-compile-and-deploy-qt-5-12-for-raspberry-pi/
mkdir -p sysroot/usr
mkdir -p sysroot/opt
rsync -avz pi@$HOST:/lib sysroot
rsync -avz pi@$HOST:/usr/include sysroot/usr
rsync -avz pi@$HOST:/usr/lib sysroot/usr
rsync -avz pi@$HOST:/opt/vc sysroot/opt
# https://raw.githubusercontent.com/riscv/riscv-poky/master/scripts/sysroot-relativelinks.py
$SCRIPT_DIR/update-pi-sysroot-symlinks.py ./sysroot

View File

@ -1,31 +0,0 @@
#!/usr/bin/env python
import sys
import os
# Take a sysroot directory and turn all the absolute symlinks into
# relative ones such that the sysroot is usable within another system.
if len(sys.argv) != 2:
print("Usage is " + sys.argv[0] + "<directory>")
sys.exit(1)
topdir = sys.argv[1]
topdir = os.path.abspath(topdir)
def handlelink(filep, subdir):
link = os.readlink(filep)
if link[0] != "/":
return
if link.startswith(topdir):
return
#print("Replacing %s with %s for %s" % (link, topdir+link, filep))
print("Replacing %s with %s for %s" % (link, os.path.relpath(topdir+link, subdir), filep))
os.unlink(filep)
os.symlink(os.path.relpath(topdir+link, subdir), filep)
for subdir, dirs, files in os.walk(topdir):
for f in files:
filep = os.path.join(subdir, f)
if os.path.islink(filep):
#print("Considering %s" % filep)
handlelink(filep, subdir)

View File

@ -40,8 +40,8 @@
#define MUSIKCUBE_VERSION_MINOR 0
#define MUSIKCUBE_VERSION_PATCH 2
#define MUSIKCUBE_VERSION "3.0.2"
#define MUSIKCUBE_VERSION_COMMIT_HASH "#3dad0594"
#define MUSIKCUBE_VERSION_WITH_COMMIT_HASH "3.0.2-#3dad0594"
#define MUSIKCUBE_VERSION_COMMIT_HASH "#7191e5ad"
#define MUSIKCUBE_VERSION_WITH_COMMIT_HASH "3.0.2-#7191e5ad"
namespace musik {
namespace cube {