support for fully independent .app build on Mac
The resulting Mac wX .app build is now completely independent and redistributable, only needs to be codesigned. Necessary dylibs are bundled and linked in a POST_BUILD step using third_party_libs_tool (included) for which I created a separate repo here as well: http://github.com/rkitover/mac-third-party-libs-tool Turn off Cairo on Mac because it does not work for now. Set RPATH on the executable to @loader_path/../Frameworks, the bundling tool also does this. Update .gitignore for Finder .DS_Store files. TOOD: * write a ./quickbuild for Mac and other platforms such as msys2 and linux
This commit is contained in:
parent
2d9ec99c11
commit
d18afb982f
|
@ -8,3 +8,6 @@ build/
|
||||||
|
|
||||||
# vim swap files
|
# vim swap files
|
||||||
*.sw?
|
*.sw?
|
||||||
|
|
||||||
|
# mac finder crap
|
||||||
|
*.DS_Store
|
||||||
|
|
|
@ -1,8 +1,17 @@
|
||||||
#Do not use this file directly. Always use the top level CMakeLists.txt file
|
#Do not use this file directly. Always use the top level CMakeLists.txt file
|
||||||
# This build is much easier if we just do it here.
|
# This build is much easier if we just do it here.
|
||||||
SET( CMAKE_CXX_FLAGS -std=gnu++11 )
|
SET( CMAKE_CXX_FLAGS -std=gnu++11 )
|
||||||
|
|
||||||
# not yet implemented
|
# not yet implemented
|
||||||
option( ENABLE_CAIRO "Enable Cairo rendering for the wxWidgets port" ON )
|
IF(APPLE)
|
||||||
|
# does not work, no reason to link to it
|
||||||
|
SET(CAIRO_DEFAULT OFF)
|
||||||
|
ELSE(APPLE)
|
||||||
|
SET(CAIRO_DEFAULT ON)
|
||||||
|
ENDIF(APPLE)
|
||||||
|
|
||||||
|
option(ENABLE_CAIRO "Enable Cairo rendering for the wxWidgets port" ${CAIRO_DEFAULT})
|
||||||
|
|
||||||
if( WIN32 )
|
if( WIN32 )
|
||||||
# not yet implemented
|
# not yet implemented
|
||||||
option( ENABLE_DIRECT3D "Enable Direct3D rendering for the wxWidgets port" ON )
|
option( ENABLE_DIRECT3D "Enable Direct3D rendering for the wxWidgets port" ON )
|
||||||
|
@ -201,6 +210,11 @@ SET(VBAM_ICON vbam.icns)
|
||||||
|
|
||||||
SET(VBAM_ICON_PATH ${CMAKE_CURRENT_SOURCE_DIR}/icons/${VBAM_ICON})
|
SET(VBAM_ICON_PATH ${CMAKE_CURRENT_SOURCE_DIR}/icons/${VBAM_ICON})
|
||||||
|
|
||||||
|
IF(APPLE)
|
||||||
|
SET(CMAKE_BUILD_WITH_INSTALL_RPATH ON)
|
||||||
|
SET(CMAKE_INSTALL_RPATH "@loader_path/../Frameworks")
|
||||||
|
ENDIF(APPLE)
|
||||||
|
|
||||||
ADD_EXECUTABLE (
|
ADD_EXECUTABLE (
|
||||||
visualboyadvance-m
|
visualboyadvance-m
|
||||||
WIN32
|
WIN32
|
||||||
|
@ -232,6 +246,9 @@ if(APPLE)
|
||||||
SET_PROPERTY(TARGET visualboyadvance-m APPEND PROPERTY MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/wxplist.in)
|
SET_PROPERTY(TARGET visualboyadvance-m APPEND PROPERTY MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/wxplist.in)
|
||||||
SET(MACOSX_BUNDLE_ICON_FILE ${VBAM_ICON})
|
SET(MACOSX_BUNDLE_ICON_FILE ${VBAM_ICON})
|
||||||
SET_SOURCE_FILES_PROPERTIES(${VBAM_ICON_PATH} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
SET_SOURCE_FILES_PROPERTIES(${VBAM_ICON_PATH} PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
||||||
|
|
||||||
|
ADD_CUSTOM_COMMAND(TARGET visualboyadvance-m POST_BUILD
|
||||||
|
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/tools/osx/third_party_libs_tool "$<TARGET_FILE_DIR:visualboyadvance-m>/../..")
|
||||||
endif(APPLE)
|
endif(APPLE)
|
||||||
|
|
||||||
SET(WX_EXE_NAME visualboyadvance-m-wx${CMAKE_EXECUTABLE_SUFFIX})
|
SET(WX_EXE_NAME visualboyadvance-m-wx${CMAKE_EXECUTABLE_SUFFIX})
|
||||||
|
|
|
@ -0,0 +1,262 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
version=0.1
|
||||||
|
|
||||||
|
main() {
|
||||||
|
# parse options
|
||||||
|
list=
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
-h|--help|--usage)
|
||||||
|
usage
|
||||||
|
quit 0
|
||||||
|
;;
|
||||||
|
-v|--version)
|
||||||
|
echo "third_party_libs_tool $version"
|
||||||
|
quit 0
|
||||||
|
;;
|
||||||
|
-l|--list)
|
||||||
|
list=1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ $# -ne 1 ]; then
|
||||||
|
usage
|
||||||
|
quit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
mktmp
|
||||||
|
|
||||||
|
app_bundle=$(echo "$1" | fully_resolve_links | sed 's,/*$,,')
|
||||||
|
|
||||||
|
case "$app_bundle" in
|
||||||
|
*.app|*.APP)
|
||||||
|
if [ ! -d "$app_bundle" ]; then
|
||||||
|
usage
|
||||||
|
quit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
usage
|
||||||
|
quit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
set --
|
||||||
|
|
||||||
|
OLDIFS=$IFS
|
||||||
|
IFS='
|
||||||
|
'
|
||||||
|
for file in $(find "$app_bundle/Contents/MacOS" -type f); do
|
||||||
|
case "$file" in
|
||||||
|
*.dylib)
|
||||||
|
set -- "$@" "$file"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
[ -x "$file" ] && set -- "$@" "$file"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
IFS=$OLDIFS
|
||||||
|
|
||||||
|
frameworks="$app_bundle/Contents/Frameworks"
|
||||||
|
|
||||||
|
mkdir -p "$frameworks" 2>/dev/null
|
||||||
|
|
||||||
|
lib_scan "$@" | fully_resolve_links | sort -u | \
|
||||||
|
while read lib; do
|
||||||
|
if [ -n "$list" ]; then
|
||||||
|
echo "$lib"
|
||||||
|
else
|
||||||
|
cp -f "$lib" "$frameworks" 2>/dev/null
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# fix dynamic link info in executables and just copied libs
|
||||||
|
[ -z "$list" ] && relink_all "$@"
|
||||||
|
|
||||||
|
quit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Usage: [32mthird_party_libs_tool [1;34m[[1;35mOPTION[1;34m][0m [1;35mBUNDLE.app[0m
|
||||||
|
Bundle third party dylibs into [1;35mBUNDLE.app[0m and fix up linkages.
|
||||||
|
|
||||||
|
Binaries are searched for in [1;35mBUNDLE.app[0m/Contents/MacOS .
|
||||||
|
|
||||||
|
The dylibs are copied into [1;35mBUNDLE.app[0m/Contents/Frameworks .
|
||||||
|
|
||||||
|
[1m-h, --help, --usage[0m Show this help screen and exit.
|
||||||
|
[1m-v, --version[0m Show version information and exit.
|
||||||
|
[1m-l, --list[0m Only list dylibs used by binaries, do not copy or link.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
[32mthird_party_libs_tool [1;35m./MyApp.app[0m # bundle and link [1;35m./MyApp.app[0m
|
||||||
|
[32mthird_party_libs_tool [1m--list[0m [1;35m./MyApp.app[0m # list third party libs used by [1;35m./MyApp.app[0m
|
||||||
|
|
||||||
|
Project homepage and documentation: <[1;34mhttp://github.com/rkitover/mac-third-party-libs-tool[0m>
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
mktmp() {
|
||||||
|
tmp="/tmp/third_party_libs_tool_$$"
|
||||||
|
mkdir "$tmp" || quit 1
|
||||||
|
chmod 700 "$tmp" 2>/dev/null
|
||||||
|
trap "quit 1" PIPE HUP INT QUIT ILL TRAP KILL BUS TERM
|
||||||
|
}
|
||||||
|
|
||||||
|
quit() {
|
||||||
|
[ -n "$tmp" ] && rm -rf "$tmp" 2>/dev/null
|
||||||
|
exit ${1:-0}
|
||||||
|
}
|
||||||
|
|
||||||
|
lib_scan() {
|
||||||
|
for bin in "$@"; do
|
||||||
|
case "$bin" in
|
||||||
|
*.dylib)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
[ ! -x "$bin" ] && continue
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
set --
|
||||||
|
|
||||||
|
OLDIFS=$IFS
|
||||||
|
IFS='
|
||||||
|
'
|
||||||
|
for lib in $(otool -L "$bin" 2>/dev/null | sed -n 's/^ \([^ ]*\).*/\1/p' | grep -v '^/System/' | grep -v '^/usr/lib/'); do
|
||||||
|
[ "$lib" = "$bin" ] && continue
|
||||||
|
|
||||||
|
echo "$lib"
|
||||||
|
set -- "$@" "$lib"
|
||||||
|
done
|
||||||
|
IFS=$OLDIFS
|
||||||
|
|
||||||
|
# recurse
|
||||||
|
[ $# -ne 0 ] && lib_scan "$@"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
fully_resolve_links() {
|
||||||
|
while read -r file; do
|
||||||
|
OLDIFS=$IFS
|
||||||
|
IFS='
|
||||||
|
'
|
||||||
|
path=
|
||||||
|
for part in $(echo "$file" | sed 's,^/*,,; s,/*$,,; s,//*,\
|
||||||
|
,g'); do
|
||||||
|
path=$(resolve_link "$path/$part")
|
||||||
|
done
|
||||||
|
IFS=$OLDIFS
|
||||||
|
|
||||||
|
# remove '..' path parts
|
||||||
|
while :; do
|
||||||
|
case "$path" in
|
||||||
|
*/../*|*/..)
|
||||||
|
path=$(echo "$path" | sed 's,//*[^/][^/]*//*\.\./*,/,g')
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "$path"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve_link() {
|
||||||
|
file="$1"
|
||||||
|
|
||||||
|
while [ -h "$file" ]; do
|
||||||
|
ls0=`ls -l "$file"`
|
||||||
|
new_link=`expr "$ls0" : '.* -> \(.*\)$'`
|
||||||
|
if expr "$new_link" : '/.*' > /dev/null; then
|
||||||
|
file="$new_link"
|
||||||
|
else
|
||||||
|
file="${file%/*}"/"$new_link"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "$file"
|
||||||
|
}
|
||||||
|
|
||||||
|
relink_all() {
|
||||||
|
for exe in "$@"; do
|
||||||
|
# dylib search path for executable
|
||||||
|
install_name_tool -add_rpath '@loader_path/../Frameworks' "$exe"
|
||||||
|
|
||||||
|
OLDIFS=$IFS
|
||||||
|
IFS='
|
||||||
|
'
|
||||||
|
set --
|
||||||
|
for lib in $(find "$app_bundle/Contents/Frameworks" -name '*.dylib'); do
|
||||||
|
set -- "$@" "$lib"
|
||||||
|
done
|
||||||
|
IFS=$OLDIFS
|
||||||
|
|
||||||
|
for lib in "$@"; do
|
||||||
|
# make lib writable
|
||||||
|
chmod u+w "$lib"
|
||||||
|
|
||||||
|
# change id of lib
|
||||||
|
install_name_tool -id "@rpath/${lib##*/}" "$lib"
|
||||||
|
|
||||||
|
# set search path of lib
|
||||||
|
install_name_tool -add_rpath '@loader_path/../Frameworks' "$lib"
|
||||||
|
|
||||||
|
# relink executable and all other libs to this lib
|
||||||
|
for target in "$exe" "$@"; do
|
||||||
|
relink "$lib" "$target"
|
||||||
|
done
|
||||||
|
done
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
relink() {
|
||||||
|
lib=$1
|
||||||
|
target=$2
|
||||||
|
|
||||||
|
lib_basename=${lib##*/}
|
||||||
|
lib_basename_unversioned_re=$(echo "$lib_basename" | sed 's/[0-9.-]*\.dylib$//; s/\./\\./g')
|
||||||
|
|
||||||
|
# remove full path and version of lib in executable
|
||||||
|
lib_link_path=$(
|
||||||
|
otool -l "$target" 2>/dev/null | \
|
||||||
|
sed -n 's,^ *name \(/.*/*'"$lib_basename_unversioned_re"'[0-9.-]*\.dylib\) (offset .*,\1,p' | \
|
||||||
|
head -1
|
||||||
|
)
|
||||||
|
|
||||||
|
if [ -n "$lib_link_path" ]; then
|
||||||
|
install_name_tool -change "$lib_link_path" "@rpath/$lib_basename" "$target"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# try with sudo in case it fails,
|
||||||
|
# also suppress duplicate path errors
|
||||||
|
install_name_tool() {
|
||||||
|
out_file="$tmp/install_name_tool.out"
|
||||||
|
|
||||||
|
if ! command install_name_tool "$@" >"$out_file" 2>&1; then
|
||||||
|
if grep -Eq -i 'permission denied|bad file descriptor' "$out_file"; then
|
||||||
|
if ! command sudo install_name_tool "$@" >"$out_file" 2>&1; then
|
||||||
|
cat "$out_file" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
elif ! grep -Eq -i 'would duplicate path' "$out_file"; then
|
||||||
|
cat "$out_file" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
Loading…
Reference in New Issue