From 3bea0b247553aedb607fb03f3c40951eeffeed22 Mon Sep 17 00:00:00 2001 From: Pau RE Date: Sun, 12 Jan 2025 21:17:39 +0100 Subject: [PATCH] Bundle r2 on macOS --- .github/workflows/ci.yml | 22 +++++----- .gitignore | 8 +++- dist/macos/Makefile | 27 +++++++++++++ dist/macos/scripts/command.sh | 16 ++++++++ dist/macos/scripts/embed-radare2.sh | 63 +++++++++++++++++++++++++++++ src/Iaito.pro | 8 ++-- src/IaitoApplication.cpp | 37 +++++++++-------- src/core/Iaito.cpp | 4 +- 8 files changed, 152 insertions(+), 33 deletions(-) create mode 100644 dist/macos/Makefile create mode 100755 dist/macos/scripts/command.sh create mode 100755 dist/macos/scripts/embed-radare2.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index feb539b1..d0e58ea3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -81,20 +81,20 @@ jobs: echo $(brew --prefix qt@5)/bin >> $GITHUB_PATH pip3 install meson ninja - name: install r2 + working-directory: dist/macos run: | - wget -q https://github.com/radareorg/radare2/releases/download/${{env.R2V}}/radare2-x64-${{env.R2V}}.pkg - sudo installer -pkg *.pkg -target / + curl -Lo radare2.pkg "https://github.com/radareorg/radare2/releases/download/${{env.R2V}}/radare2-x64-${{env.R2V}}.pkg" + sudo installer -pkg radare2.pkg -target / - name: build iaito run: | ./configure - make -j4 + make -j4 QMAKE_FLAGS=IAITO_BUNDLE_R2_APPBUNDLE=true - name: packaging - working-directory: build - run: macdeployqt iaito.app -dmg -verbose=2 + run: make -C dist/macos - uses: actions/upload-artifact@v4 with: name: iaito-x64.dmg - path: build/iaito.dmg + path: dist/macos/iaito.dmg acr-macos-arm64: runs-on: macos-latest steps: @@ -113,20 +113,20 @@ jobs: echo $(brew --prefix qt@5)/bin >> $GITHUB_PATH pip3 install meson ninja - name: install r2 + working-directory: dist/macos run: | - wget -q https://github.com/radareorg/radare2/releases/download/${{env.R2V}}/radare2-m1-${{env.R2V}}.pkg - sudo installer -pkg *.pkg -target / + curl -Lo radare2.pkg "https://github.com/radareorg/radare2/releases/download/${{env.R2V}}/radare2-m1-${{env.R2V}}.pkg" + sudo installer -pkg radare2.pkg -target / - name: build iaito run: | ./configure make -j4 - name: packaging - working-directory: build - run: macdeployqt iaito.app -dmg -verbose=2 + run: make -C dist/macos - uses: actions/upload-artifact@v4 with: name: iaito-arm64.dmg - path: build/iaito.dmg + path: dist/macos/iaito.dmg meson: runs-on: ${{ matrix.os }} strategy: diff --git a/.gitignore b/.gitignore index ce31bea5..9df0c7b6 100644 --- a/.gitignore +++ b/.gitignore @@ -91,4 +91,10 @@ src/out *.orig # Translations -src/translations \ No newline at end of file +src/translations + +# macOS package +/dist/macos/radare2.pkg +/dist/macos/radare2-unpkg +/dist/macos/disk +/dist/macos/*.dmg diff --git a/dist/macos/Makefile b/dist/macos/Makefile new file mode 100644 index 00000000..54951f68 --- /dev/null +++ b/dist/macos/Makefile @@ -0,0 +1,27 @@ +.PHONY: all app clean mrproper + +all: app + +app: ../../build/iaito.app radare2-unpkg + mkdir disk + cp -a ../../build/iaito.app disk/ + scripts/embed-radare2.sh radare2-unpkg disk/iaito.app + cd disk && macdeployqt iaito.app -dmg -verbose=2 + mv disk/*.dmg . + +radare2-unpkg: radare2.pkg + pkgutil --expand-full $< $@ + +radare2.pkg: + echo "Download first radare2.pkg from https://github.com/radareorg/radare2/releases" + @false + +../../build/iaito.app: + echo "Building iaito..." + $(MAKE) -C ../.. QMAKE_FLAGS=IAITO_BUNDLE_R2_APPBUNDLE=true + +clean: + rm -rf disk radare2-unpkg + +mrproper: clean + rm -f radare2.pkg diff --git a/dist/macos/scripts/command.sh b/dist/macos/scripts/command.sh new file mode 100755 index 00000000..5f6d3f2b --- /dev/null +++ b/dist/macos/scripts/command.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +CMD=$(basename "$0") +APPDIR=$(cd "$(dirname "$0")/../../../.."; pwd) + +R2_BINDIR="${APPDIR}/Contents/Helpers" +R2_LIBDIR="${APPDIR}/Contents/Frameworks" +R2_LIBR_PLUGINS="${APPDIR}/Contents/PlugIns/radare2" +R2_PREFIX="${APPDIR}/Contents/Resources/radare2" + +export R2_BINDIR +export R2_LIBDIR +export R2_LIBR_PLUGINS +export R2_PREFIX + +exec "${R2_BINDIR}/${CMD}" "$@" diff --git a/dist/macos/scripts/embed-radare2.sh b/dist/macos/scripts/embed-radare2.sh new file mode 100755 index 00000000..d70abeb7 --- /dev/null +++ b/dist/macos/scripts/embed-radare2.sh @@ -0,0 +1,63 @@ +#!/bin/sh -e + +R2PKGDIR="$1" +APPDIR="$2" + +SCRIPTS="$(dirname "$0")" +R2DIR="${R2PKGDIR}/Payload/usr/local" +R2V=$(readlink "${R2DIR}/lib/radare2/last") + +fix_binary() { + echo "Change library paths for \"$1\"..." + ARGS=$(otool -L "$1" | awk '/\/usr\/local\/lib\/libr_/{dst=$1; sub(/\/usr\/local\/lib/,"@executable_path/../Frameworks", dst); print "-change "$1" "dst}') + [ -n "$ARGS" ] && install_name_tool $ARGS "$1" +} + +mkdir -p \ + "${APPDIR}/Contents/Helpers" \ + "${APPDIR}/Contents/Frameworks" \ + "${APPDIR}/Contents/PlugIns/radare2" \ + "${APPDIR}/Contents/Resources/radare2/bin" \ + "${APPDIR}/Contents/Resources/radare2/lib/radare2" + +cp -a "${R2DIR}/bin/"* "${APPDIR}/Contents/Helpers/" +cp -a "${R2DIR}/lib/radare2/${R2V}/"* "${APPDIR}/Contents/PlugIns/radare2/" +cp -a "${R2DIR}/lib/"*.dylib "${APPDIR}/Contents/Frameworks/" +cp -a "${R2DIR}/include" "${APPDIR}/Contents/Resources/radare2/" +cp -a "${R2DIR}/share" "${APPDIR}/Contents/Resources/radare2/" +#cp -a "${R2DIR}/lib/pkgconfig" "${APPDIR}/Contents/Resources/radare2/lib/" +cp -p "${SCRIPTS}/command.sh" "${APPDIR}/Contents/Resources/radare2/bin/radare2" +cp -a "${R2DIR}/lib/radare2/last" "${APPDIR}/Contents/Resources/radare2/lib/radare2/" +ln -s "../../../../PlugIns/radare2" "${APPDIR}/Contents/Resources/radare2/lib/radare2/${R2V}" + +( + cd "${APPDIR}/Contents/MacOS" + fix_binary "iaito" +) + +( + cd "${APPDIR}/Contents/Helpers" + for c in *; do + [ -L "$c" ] || fix_binary "$c" + [ "$c" != "radare2" ] && ln -s radare2 "../Resources/radare2/bin/$c" + done +) + +( + LIBS=$(cd "${R2DIR}/lib"; ls *.dylib) + cd "${APPDIR}/Contents/Frameworks" + for c in $LIBS; do + [ -L "$c" ] || fix_binary "$c" + c2=$c # Resolve upto 2 link levels + [ -L "$c2" ] && c2=$(readlink "$c2") + [ -L "$c2" ] && c2=$(readlink "$c2") + ln -s "../../../Frameworks/$c2" "../Resources/radare2/lib/$c" + done +) + +( + cd "${APPDIR}/Contents/PlugIns/radare2" + for c in *; do + [ -L "$c" ] || fix_binary "$c" + done +) diff --git a/src/Iaito.pro b/src/Iaito.pro index 92f8e9b9..e13b9ad6 100644 --- a/src/Iaito.pro +++ b/src/Iaito.pro @@ -12,9 +12,11 @@ CONFIG+=app_bundle CONFIG += sdk_no_version_check -unix:QMAKE_RPATHDIR += /usr/local/lib -unix:QMAKE_LFLAGS_RPATH= -unix:QMAKE_LFLAGS += "-Wl,-rpath,/usr/local/lib" +unix:!macx|macx:!IAITO_BUNDLE_R2_APPBUNDLE { + QMAKE_RPATHDIR += /usr/local/lib + QMAKE_LFLAGS_RPATH= + QMAKE_LFLAGS += "-Wl,-rpath,/usr/local/lib" +} QMAKE_CXXFLAGS += $$(CXXFLAGS) QMAKE_CFLAGS += $$(CFLAGS) diff --git a/src/IaitoApplication.cpp b/src/IaitoApplication.cpp index 59e74d90..172a5a7f 100644 --- a/src/IaitoApplication.cpp +++ b/src/IaitoApplication.cpp @@ -142,6 +142,27 @@ IaitoApplication::IaitoApplication(int &argc, char **argv) qputenv("R_ALT_SRC_DIR", "1"); #endif +#ifdef MACOS_R2_BUNDLED + { + auto appdir = QDir(QCoreApplication::applicationDirPath()); // Contents/MacOS + appdir.cdUp(); // Contents + + auto r2prefix = appdir; // Contents + r2prefix.cd("Resources/radare2"); // Contents/Resources/radare2 + qputenv("R2_PREFIX", r2prefix.absolutePath().toLocal8Bit()); + + auto r2bin = appdir; // Contents + r2bin.cd("Helpers"); // Contents/Helpers + auto paths = QStringList(QString::fromLocal8Bit(qgetenv("PATH"))); + paths.prepend(r2bin.absolutePath()); + qputenv("PATH", paths.join(QLatin1Char(':')).toLocal8Bit()); + + // auto sleighHome = appdir; // Contents + // sleighHome.cd("PlugIns/radare2/r2ghidra_sleigh"); // Contents/PlugIns/radare2/r2ghidra_sleigh + // qputenv("SLEIGHHOME", sleighHome.absolutePath().toLocal8Bit()); + } +#endif + Core()->initialize(clOptions.enableR2Plugins); Core()->setSettings(); Config()->loadInitial(); @@ -219,22 +240,6 @@ IaitoApplication::IaitoApplication(int &argc, char **argv) } #endif -#ifdef Q_OS_MACOS - { - auto r2prefix = QDir(QCoreApplication::applicationDirPath()); // Contents/MacOS - r2prefix.cdUp(); // Contents - r2prefix.cd("Resources/r2"); // Contents/Resources/r2 - - auto sleighHome = r2prefix; - sleighHome.cd("share/radare2/plugins/r2ghidra_sleigh"); // Contents/Resources/r2/share/radare2/plugins/r2ghidra_sleigh - Core()->setConfig("r2ghidra.sleighhome", sleighHome.absolutePath()); - - auto r2decHome = r2prefix; - r2decHome.cd("share/radare2/plugins/r2dec-js"); // Contents/Resources/r2/share/radare2/plugins/r2dec-js - qputenv("R2DEC_HOME", r2decHome.absolutePath().toLocal8Bit()); - } -#endif - #ifdef IAITO_APPVEYOR_R2DEC qputenv("R2DEC_HOME", "lib\\plugins\\r2dec-js"); #endif diff --git a/src/core/Iaito.cpp b/src/core/Iaito.cpp index a6ddb2f4..c6660d34 100644 --- a/src/core/Iaito.cpp +++ b/src/core/Iaito.cpp @@ -218,10 +218,10 @@ void IaitoCore::initialize(bool loadPlugins) prefix.cdUp(); qInfo() << "Setting r2 prefix =" << prefix.absolutePath() << " for AppImage."; #else // MACOS_R2_BUNDLED \ - // Executable is in Contents/MacOS, prefix is Contents/Resources/r2 + // Executable is in Contents/MacOS, prefix is Contents/Resources/radare2 prefix.cdUp(); prefix.cd("Resources"); - prefix.cd("r2"); + prefix.cd("radare2"); qInfo() << "Setting r2 prefix =" << prefix.absolutePath() << " for macOS Application Bundle."; #endif setConfig("dir.prefix", prefix.absolutePath());