Created
October 17, 2025 15:05
-
-
Save chrismacke/c123a6c25c211932099628d0504e5808 to your computer and use it in GitHub Desktop.
Build macOS Universal LibRaw dylib
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| set -euo pipefail | |
| LIBRAW_VERSION="${LIBRAW_VERSION:-0.21.1}" | |
| LCMS2_VERSION="${LCMS2_VERSION:-2.15}" | |
| DEPLOY_TARGET="${MACOSX_DEPLOYMENT_TARGET:-11.0}" | |
| ARCHS=(arm64 x86_64) | |
| ROOT_DIR="$(pwd)" | |
| BUILD_DIR="$ROOT_DIR/build" | |
| PREFIX_DIR="$ROOT_DIR/prefix" | |
| UNIVERSAL_DIR="$ROOT_DIR/libraw_universal" | |
| SRC_LIBRAW="$ROOT_DIR/libraw_src" | |
| SRC_LCMS="$ROOT_DIR/lcms2_src" | |
| DL_TAR_LIBRAW="$ROOT_DIR/libraw.tar.gz" | |
| DL_TAR_LCMS="$ROOT_DIR/lcms2.tar.gz" | |
| rm -rf "$BUILD_DIR" "$PREFIX_DIR" "$UNIVERSAL_DIR" "$SRC_LIBRAW" "$SRC_LCMS" "$DL_TAR_LIBRAW" "$DL_TAR_LCMS" | |
| mkdir -p "$BUILD_DIR" "$PREFIX_DIR" "$UNIVERSAL_DIR/lib" "$UNIVERSAL_DIR/include" | |
| refresh_gnu_config() { | |
| local dir="$1" | |
| find "$dir" -type f \( -name config.guess -o -name config.sub \) | while read -r f; do | |
| curl -sL "https://git.savannah.gnu.org/cgit/config.git/plain/$(basename "$f")" -o "$f" | |
| chmod +x "$f" | |
| done | |
| } | |
| # ====== Fetch and extract sources ====== | |
| echo "==> Fetching LibRaw $LIBRAW_VERSION" | |
| curl -L -o "$DL_TAR_LIBRAW" "https://www.libraw.org/data/LibRaw-$LIBRAW_VERSION.tar.gz" | |
| mkdir -p "$SRC_LIBRAW" | |
| tar -xzf "$DL_TAR_LIBRAW" -C "$SRC_LIBRAW" --strip-components=1 | |
| refresh_gnu_config "$SRC_LIBRAW" | |
| echo "==> Fetching Little CMS $LCMS2_VERSION" | |
| curl -L -o "$DL_TAR_LCMS" "https://downloads.sourceforge.net/project/lcms/lcms/$LCMS2_VERSION/lcms2-$LCMS2_VERSION.tar.gz" | |
| mkdir -p "$SRC_LCMS" | |
| tar -xzf "$DL_TAR_LCMS" -C "$SRC_LCMS" --strip-components=1 | |
| refresh_gnu_config "$SRC_LCMS" | |
| SDKROOT="$(xcrun --sdk macosx --show-sdk-path)" | |
| # ====== Build LCMS2 normally (for both archs) ====== | |
| for ARCH in "${ARCHS[@]}"; do | |
| echo "==> Building LCMS2 for $ARCH" | |
| BUILD_LCMS="$BUILD_DIR/lcms2_$ARCH" | |
| mkdir -p "$BUILD_LCMS" | |
| cp -r "$SRC_LCMS/" "$BUILD_LCMS/" | |
| pushd "$BUILD_LCMS" >/dev/null | |
| export CC=clang | |
| export CXX=clang++ | |
| export CFLAGS="-arch $ARCH -g -fPIC -O2 -mmacosx-version-min=$DEPLOY_TARGET -isysroot $SDKROOT" | |
| export CXXFLAGS="$CFLAGS" | |
| export LDFLAGS="-arch $ARCH -mmacosx-version-min=$DEPLOY_TARGET -isysroot $SDKROOT" | |
| export CPPFLAGS="-isysroot $SDKROOT" | |
| ARCH_PREFIX="$PREFIX_DIR/$ARCH" | |
| ./configure --disable-static --enable-shared --enable-debug --host="${ARCH}-apple-darwin" --prefix="$ARCH_PREFIX" | |
| make -j"$(sysctl -n hw.logicalcpu)" | |
| make install | |
| # Rename for consistency | |
| mv "$ARCH_PREFIX/lib/"liblcms2.*.dylib "$ARCH_PREFIX/lib/liblcms2.dylib" | |
| install_name_tool -id "@rpath/liblcms2.dylib" "$ARCH_PREFIX/lib/liblcms2.dylib" | |
| popd >/dev/null | |
| done | |
| # ====== Build LibRaw statically for both archs ====== | |
| for ARCH in "${ARCHS[@]}"; do | |
| echo "==> Building LibRaw for $ARCH (static only)" | |
| BUILD_RAW="$BUILD_DIR/libraw_$ARCH" | |
| mkdir -p "$BUILD_RAW" | |
| cp -r "$SRC_LIBRAW/" "$BUILD_RAW/" | |
| pushd "$BUILD_RAW" >/dev/null | |
| export CC=clang | |
| export CXX=clang++ | |
| export CFLAGS="-arch $ARCH -g -fPIC -O2 -mmacosx-version-min=$DEPLOY_TARGET -isysroot $SDKROOT" | |
| export CXXFLAGS="$CFLAGS" | |
| export LDFLAGS="-arch $ARCH -mmacosx-version-min=$DEPLOY_TARGET -isysroot $SDKROOT" | |
| export CPPFLAGS="-isysroot $SDKROOT" | |
| ARCH_PREFIX="$PREFIX_DIR/$ARCH" | |
| ./configure --disable-shared --enable-static --disable-examples --disable-silent-rules --prefix="$ARCH_PREFIX" --host="${ARCH}-apple-darwin" | |
| make -j"$(sysctl -n hw.logicalcpu)" | |
| cp lib/.libs/libraw.a "$ARCH_PREFIX/lib/libraw.a" | |
| popd >/dev/null | |
| done | |
| # ====== Create dylibs manually using clang++ and -all_load ====== | |
| for ARCH in "${ARCHS[@]}"; do | |
| echo "==> Creating libraw.dylib for $ARCH with -all_load" | |
| OUT_DYLIB="$BUILD_DIR/libraw_${ARCH}.dylib" | |
| LIBRAW_A="$PREFIX_DIR/$ARCH/lib/libraw.a" | |
| LIBLCMS2_DYLIB="$PREFIX_DIR/$ARCH/lib/liblcms2.dylib" | |
| clang++ -dynamiclib \ | |
| -arch $ARCH \ | |
| -Wl,-all_load \ | |
| -Wl,-install_name,@rpath/libraw.dylib \ | |
| "$LIBRAW_A" -o "$OUT_DYLIB" \ | |
| -L"$PREFIX_DIR/$ARCH/lib" -llcms2 -lz \ | |
| -isysroot "$SDKROOT" \ | |
| -mmacosx-version-min=$DEPLOY_TARGET \ | |
| -g | |
| # Optional: copy LCMS2 for later merging | |
| cp "$LIBLCMS2_DYLIB" "$BUILD_DIR/liblcms2_${ARCH}.dylib" | |
| done | |
| # ====== lipo to create universal dylibs ====== | |
| echo "==> Creating universal dylibs with lipo" | |
| lipo -create \ | |
| "$BUILD_DIR/libraw_x86_64.dylib" \ | |
| "$BUILD_DIR/libraw_arm64.dylib" \ | |
| -output "$UNIVERSAL_DIR/lib/libraw.dylib" | |
| install_name_tool -id "@rpath/libraw.dylib" "$UNIVERSAL_DIR/lib/libraw.dylib" | |
| lipo -create \ | |
| "$BUILD_DIR/liblcms2_x86_64.dylib" \ | |
| "$BUILD_DIR/liblcms2_arm64.dylib" \ | |
| -output "$UNIVERSAL_DIR/lib/liblcms2.dylib" | |
| install_name_tool -id "@rpath/liblcms2.dylib" "$UNIVERSAL_DIR/lib/liblcms2.dylib" | |
| # ====== Generate dSYM files ====== | |
| dsymutil "$UNIVERSAL_DIR/lib/libraw.dylib" -o "$UNIVERSAL_DIR/lib/libraw.dylib.dSYM" || echo "⚠️ No debug symbols found in libraw.dylib" | |
| dsymutil "$UNIVERSAL_DIR/lib/liblcms2.dylib" -o "$UNIVERSAL_DIR/lib/liblcms2.dylib.dSYM" || echo "⚠️ No debug symbols found in liblcms2.dylib" | |
| # ====== Headers ====== | |
| rsync -a "$PREFIX_DIR/arm64/include/" "$UNIVERSAL_DIR/include/" | |
| # ====== Summary ====== | |
| echo "" | |
| echo "✅ Done: universal dylibs with full symbol export" | |
| echo "📦 libraw.dylib: $UNIVERSAL_DIR/lib/libraw.dylib" | |
| echo "📦 liblcms2.dylib: $UNIVERSAL_DIR/lib/liblcms2.dylib" | |
| echo "📂 Headers: $UNIVERSAL_DIR/include" | |
| echo "" | |
| echo "🔍 Symbol count:" | |
| nm -gU "$UNIVERSAL_DIR/lib/libraw.dylib" | wc -l | |
| echo "" | |
| echo "🔎 lipo info:" | |
| lipo -info "$UNIVERSAL_DIR/lib/libraw.dylib" | |
| lipo -info "$UNIVERSAL_DIR/lib/liblcms2.dylib" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment