Extracted dylib relinking into a separate script that's more dymamic, less error prone, and easier to use.

This commit is contained in:
casey langen 2022-02-20 21:00:43 -08:00
parent 79f1fa940a
commit 11404b837a
3 changed files with 162 additions and 133 deletions

View File

@ -26,6 +26,7 @@ RPATH="@rpath"
OS=$(uname)
ARCH=$(uname -m)
SCRIPTDIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
BOOST_VERSION_URL_PATH="1.76.0"
BOOST_VERSION="1_76_0"
OPENSSL_VERSION="1.1.1m"
@ -438,154 +439,44 @@ function build_libopenmpt() {
# macOS dylib rpaths
#
function stage_opus_ogg_vorbis() {
function stage_prebuilt_libraries() {
if [[ $OS == "Darwin" ]]; then
# instead of building opus, ogg and vorbis from source we snag them
# from brew, update their dylib ids with @rpath, re-sign them, then create
# new pkg-config files to point towards this directory. that way ffmpeg
# will pick them up automatically.
mkdir -p bin/lib/
cd bin/lib/
export PKG_CONFIG_PATH=$(pwd)
BREW=$(brew --prefix)
# create pkg-config files to point towards this dir
cp $BREW/opt/opus/lib/pkgconfig/opus.pc .
cp $BREW/opt/libogg/lib/pkgconfig/ogg.pc .
cp $BREW/opt/libvorbis/lib/pkgconfig/vorbis.pc .
cp $BREW/opt/libvorbis/lib/pkgconfig/vorbisenc.pc .
chmod 644 *.pc
perl -i.bak -0pe "s|libdir.*\n|libdir=$(pwd)\n|" opus.pc
perl -i.bak -0pe "s|libdir.*\n|libdir=$(pwd)\n|" ogg.pc
perl -i.bak -0pe "s|libdir.*\n|libdir=$(pwd)\n|" vorbis.pc
perl -i.bak -0pe "s|libdir.*\n|libdir=$(pwd)\n|" vorbisenc.pc
rm *.bak
# copy libs, update their ids, then resign
LIBOPUS="$BREW/opt/opus/lib/libopus.0.dylib"
LIBOGG="$BREW/opt/libogg/lib/libogg.0.dylib"
LIBVORBIS="$BREW/opt/libvorbis/lib/libvorbis.0.dylib"
LIBVORBISENC="$BREW/opt/libvorbis/lib/libvorbisenc.2.dylib"
cp ${LIBOPUS} ${LIBOGG} ${LIBVORBIS} ${LIBVORBISENC} .
chmod 755 *.dylib
install_name_tool -id "$RPATH/libopus.0.dylib" ./libopus.0.dylib
codesign --remove-signature ./libopus.0.dylib
codesign --sign=- ./libopus.0.dylib
ln -s libopus.0.dylib libopus.dylib
install_name_tool -id "$RPATH/libogg.0.dylib" ./libogg.0.dylib
codesign --remove-signature ./libogg.0.dylib
codesign --sign=- ./libogg.0.dylib
ln -s libogg.0.dylib libogg.dylib
install_name_tool -id "$RPATH/libvorbis.0.dylib" ./libvorbis.0.dylib
install_name_tool -change "${LIBOGG}" "$RPATH/libogg.0.dylib" ./libvorbis.0.dylib
ln -s libvorbis.0.dylib libvorbis.dylib
install_name_tool -id "$RPATH/libvorbisenc.2.dylib" ./libvorbisenc.2.dylib
install_name_tool -change "${LIBOGG}" "$RPATH/libogg.0.dylib" ./libvorbisenc.2.dylib
install_name_tool -change "${LIBVORBIS}" "$RPATH/libvorbis.0.dylib" ./libvorbisenc.2.dylib
# odd man out... not sure why this is this way...
LIBVORBIS_CELLAR="$BREW/Cellar/libvorbis/1.3.7/lib/libvorbis.0.dylib"
install_name_tool -change "${LIBVORBIS_CELLAR}" "$RPATH/libvorbis.0.dylib" ./libvorbisenc.2.dylib
#end weird hack
ln -s libvorbisenc.2.dylib libvorbisenc.dylib
codesign --remove-signature ./libvorbis.0.dylib
codesign --remove-signature ./libvorbisenc.2.dylib
codesign --sign=- ./libvorbis.0.dylib
codesign --sign=- ./libvorbisenc.2.dylib
cd ../..
mkdir -p bin/lib/
cp ${LIBOPUS} ${LIBOGG} ${LIBVORBIS} ${LIBVORBISENC} bin/lib/
chmod 755 bin/lib/*.dylib
fi
}
function patch_dylib_rpaths() {
if [[ $OS == "Darwin" ]]; then
cd bin/lib
install_name_tool -id "$RPATH/libavutil-musikcube.57.dylib" libavutil-musikcube.57.dylib
rm libavutil-musikcube.dylib
ln -s libavutil-musikcube.57.dylib libavutil-musikcube.dylib
# ffmpeg
install_name_tool -id "$RPATH/libavformat-musikcube.59.dylib" libavformat-musikcube.59.dylib
install_name_tool -change "$LIBDIR/libswresample-musikcube.4.dylib" "$RPATH/libswresample-musikcube.4.dylib" libavformat-musikcube.59.dylib
install_name_tool -change "$LIBDIR/libavcodec-musikcube.59.dylib" "$RPATH/libavcodec-musikcube.59.dylib" libavformat-musikcube.59.dylib
install_name_tool -change "$LIBDIR/libavutil-musikcube.57.dylib" "$RPATH/libavutil-musikcube.57.dylib" libavformat-musikcube.59.dylib
install_name_tool -change "${LIBOPUS}" "$RPATH/libopus.0.dylib" libavformat-musikcube.59.dylib
install_name_tool -change "${LIBOGG}" "$RPATH/libogg.0.dylib" libavformat-musikcube.59.dylib
install_name_tool -change "${LIBVORBIS}" "$RPATH/libvorbis.0.dylib" libavformat-musikcube.59.dylib
install_name_tool -change "${LIBVORBISENC}" "$RPATH/libvorbisenc.2.dylib" libavformat-musikcube.59.dylib
rm libavformat-musikcube.dylib
ln -s libavformat-musikcube.59.dylib libavformat-musikcube.dylib
install_name_tool -id "$RPATH/libavcodec-musikcube.59.dylib" libavcodec-musikcube.59.dylib
install_name_tool -change "$LIBDIR/libswresample-musikcube.4.dylib" "$RPATH/libswresample-musikcube.4.dylib" libavcodec-musikcube.59.dylib
install_name_tool -change "$LIBDIR/libavcodec-musikcube.59.dylib" "$RPATH/libavcodec-musikcube.59.dylib" libavcodec-musikcube.59.dylib
install_name_tool -change "$LIBDIR/libavutil-musikcube.57.dylib" "$RPATH/libavutil-musikcube.57.dylib" libavcodec-musikcube.59.dylib
install_name_tool -change "${LIBOPUS}" "$RPATH/libopus.0.dylib" libavcodec-musikcube.59.dylib
install_name_tool -change "${LIBOGG}" "$RPATH/libogg.0.dylib" libavcodec-musikcube.59.dylib
install_name_tool -change "${LIBVORBIS}" "$RPATH/libvorbis.0.dylib" libavcodec-musikcube.59.dylib
install_name_tool -change "${LIBVORBISENC}" "$RPATH/libvorbisenc.2.dylib" libavcodec-musikcube.59.dylib
rm libavcodec-musikcube.dylib
ln -s libavcodec-musikcube.59.dylib libavcodec-musikcube.dylib
install_name_tool -id "$RPATH/libswresample-musikcube.4.dylib" libswresample-musikcube.4.dylib
install_name_tool -change "$LIBDIR/libavutil-musikcube.57.dylib" "$RPATH/libavutil-musikcube.57.dylib" libswresample-musikcube.4.dylib
rm libswresample-musikcube.dylib
ln -s libswresample-musikcube.4.dylib libswresample-musikcube.dylib
# openssl
install_name_tool -id "$RPATH/libcrypto.1.1.dylib" libcrypto.1.1.dylib
rm libcrypto.dylib
ln -s libcrypto.1.1.dylib libcrypto.dylib
install_name_tool -id "$RPATH/libssl.1.1.dylib" libssl.1.1.dylib
install_name_tool -change "${LIBDIR}/libcrypto.1.1.dylib" "$RPATH/libcrypto.1.1.dylib" libssl.1.1.dylib
rm libssl.dylib
ln -s libssl.1.1.dylib libssl.dylib
# curl
install_name_tool -id "$RPATH/libcurl.4.dylib" libcurl.4.dylib
install_name_tool -change "${LIBDIR}/libcrypto.1.1.dylib" "$RPATH/libcrypto.1.1.dylib" libcurl.4.dylib
install_name_tool -change "${LIBDIR}/libssl.1.1.dylib" "$RPATH/libssl.1.1.dylib" libcurl.4.dylib
rm libcurl.dylib
ln -s libcurl.4.dylib libcurl.dylib
# libmicrohttpd
install_name_tool -id "$RPATH/libmicrohttpd.12.dylib" libmicrohttpd.12.dylib
rm libmicrohttpd.dylib
ln -s libmicrohttpd.12.dylib libmicrohttpd.dylib
# lame
install_name_tool -id "$RPATH/libmp3lame.0.dylib" libmp3lame.0.dylib
rm libmp3lame.dylib
ln -s libmp3lame.0.dylib libmp3lame.dylib
# libopenmpt
install_name_tool -id "$RPATH/libopenmpt.0.dylib" libopenmpt.0.dylib
rm libopenmpt.dylib
ln -s libopenmpt.0.dylib libopenmpt.dylib
cd ../../
fi
function relink_dynamic_libraries() {
node ${SCRIPTDIR}/relink-dynamic-libraries.js bin/lib
}
clean
mkdir vendor
cd vendor
stage_prebuilt_libraries
fetch_packages
build_boost
build_openssl
build_curl
build_libmicrohttpd
stage_opus_ogg_vorbis
build_ffmpeg
build_lame
build_libopenmpt
patch_dylib_rpaths
relink_dynamic_libraries
cd ..
if [[ $CROSSCOMPILE == "rpi" ]]; then
mv vendor vendor-${CROSSCOMPILE}
else
mv vendor vendor-$(uname -m)
fi
printf "\n\ndone!\n\n"

View File

@ -0,0 +1,137 @@
/* this script is used to update all macOS dynamic libraries so they can discover
each other in the app's sandboxed directory; it removes absolute paths and replaces
them with @rpaths. it also ensures symlinks are setup properly. whenever we add
a new third-party dependency we need to update the `libraries` and `symlinks`
mapping so the script knows to process them.
the result of the script will be later validated by the `scan-standalone.js` script
during app build-time. */
const { promisify } = require('util');
const exec = promisify(require('child_process').exec);
const fs = require('fs');
const rm = promisify(fs.rm);
const symlink = promisify(fs.symlink);
const mac = process.platform === 'darwin';
if (!mac) {
console.log(`\n\n no need to relink libraries on '${process.platform}\n\n`);
process.exit(0);
}
/* these are the libraries we'll scan, and update linked libraries from
absolute paths to "@rpath/filename" */
const libraries = [
'libavcodec-musikcube.59.18.100.dylib',
'libavcodec-musikcube.59.dylib',
'libavformat-musikcube.59.16.100.dylib',
'libavformat-musikcube.59.dylib',
'libavutil-musikcube.57.17.100.dylib',
'libavutil-musikcube.57.dylib',
'libswresample-musikcube.4.3.100.dylib',
'libswresample-musikcube.4.dylib',
'libcrypto.1.1.dylib',
'libssl.1.1.dylib',
'libcurl.4.dylib',
'libmicrohttpd.12.dylib',
'libmp3lame.0.dylib',
'libogg.0.dylib',
'libvorbis.0.dylib',
'libvorbisenc.2.dylib',
'libopus.0.dylib',
'libopenmpt.0.dylib',
];
/* after updating libraries, re-establish symlinks */
const symlinks = [
['libavcodec-musikcube.59.18.100.dylib', 'libavcodec-musikcube.59.dylib'],
['libavcodec-musikcube.59.dylib', 'libavcodec-musikcube.dylib'],
['libavformat-musikcube.59.16.100.dylib', 'libavformat-musikcube.59.dylib'],
['libavformat-musikcube.59.dylib', 'libavformat-musikcube.dylib'],
['libavutil-musikcube.57.17.100.dylib', 'libavutil-musikcube.57.dylib'],
['libavutil-musikcube.57.dylib', 'libavutil-musikcube.dylib'],
['libswresample-musikcube.4.3.100.dylib', 'libswresample-musikcube.4.dylib'],
['libswresample-musikcube.4.dylib', 'libswresample-musikcube.dylib'],
['libcrypto.1.1.dylib', 'libcrypto.dylib'],
['libssl.1.1.dylib', 'libssl.dylib'],
['libcurl.4.dylib', 'libcurl.dylib'],
['libmicrohttpd.12.dylib', 'libmicrohttpd.dylib'],
['libmp3lame.0.dylib', 'libmp3lame.dylib'],
['libogg.0.dylib', 'libogg.dylib'],
['libvorbis.0.dylib', 'libvorbis.dylib'],
['libvorbisenc.2.dylib', 'libvorbisenc.dylib'],
['libopus.0.dylib', 'libopus.dylib'],
['libopenmpt.0.dylib', 'libopenmpt.dylib'],
];
const path = process.argv[2];
if (!path) {
console.log('\n\nusage: node relink-dynamic-libraries.js <path>\n\n');
process.exit(1);
}
const run = async (cmd) => {
console.log(cmd);
return await exec(cmd);
};
/* scans the specified dylib using `otool`, builds a list of dependencies
that need their absolute paths updated with relative paths, then uses
`install_name_tool` to update the paths */
const relink = async (fn) => {
const output = await exec(`otool -L ${path}/${fn}`);
const relink = output.stdout
.split('\n')
.map((line) => line.trim())
.filter((line) => !!line)
/* the first line of output is the path to the library; ignore. */
.slice()
/* libraries are formatted as "<name> (compatibility ...)", so split
and take the name */
.map((line) => line.split(' (compatibility')[0].trim())
/* grab the filename from the path, and see if it's one we want to
re-link relatively */
.filter((line) => libraries.indexOf(line.split('/').pop()) !== -1);
await run(`install_name_tool -id "@rpath/${fn}" ${path}/${fn}`);
for (let i = 0; i < relink.length; i++) {
const entry = relink[i];
const leaf = entry.split('/').pop();
await run(
`install_name_tool -change "${entry}" "@rpath/${leaf}" ${path}/${fn}`
);
}
/* changing the id and updating entries sometimes invalidates the code
signature. remove the old one, and re-sign */
await run(`codesign --remove-signature ${path}/${fn}`);
await run(`codesign --sign=- ${path}/${fn}`);
return relink;
};
const rebuildSymlinks = async () => {
for (let i = 0; i < symlinks.length; i++) {
const [src, dst] = symlinks[i];
if (fs.existsSync(`${path}/${dst}`)) {
console.log('removing symlink:', `${path}/${dst}`);
await rm(`${path}/${dst}`);
}
console.log('creating symlink:', src, dst);
await symlink(src, `${path}/${dst}`);
}
};
const main = async () => {
try {
await Promise.allSettled(libraries.map((library) => relink(library)));
await rebuildSymlinks();
} catch (e) {
console.log(`\n\n failed to relink dynamic libraries!\n\n`);
console.log(e, '\n\n');
process.exit(1);
}
console.log(`\n\n finished relinking dynamic libraries!\n\n`);
process.exit(0);
};
main();

View File

@ -10,13 +10,14 @@ ln -s ../lib/
popd
PLATFORM=$(uname)
if [[ "$PLATFORM" == 'Darwin' ]]; then
echo "[stage-static-vendor-libraries] staging macOS .dylib files..."
cp vendor/bin/lib/libavcodec-musikcube.59.dylib ./bin/lib
cp vendor/bin/lib/libavformat-musikcube.59.dylib ./bin/lib
cp vendor/bin/lib/libavutil-musikcube.57.dylib ./bin/lib
cp vendor/bin/lib/libswresample-musikcube.4.dylib ./bin/lib
cp vendor/bin/lib/libavcodec-musikcube*.dylib ./bin/lib
cp vendor/bin/lib/libavformat-musikcube*.dylib ./bin/lib
cp vendor/bin/lib/libavutil-musikcube*.dylib ./bin/lib
cp vendor/bin/lib/libswresample-musikcube*.dylib ./bin/lib
cp vendor/bin/lib/libopus.0.dylib ./bin/lib
cp vendor/bin/lib/libogg.0.dylib ./bin/lib
cp vendor/bin/lib/libvorbis.0.dylib ./bin/lib