假设我制作了一个OSX应用程序,但没有使用Xcode。在使用GCC编译后,我得到了一个链接到其他几个库的可执行文件。其中一些库可能再次动态链接到其他非标准系统库。
是否存在任何工具,可以首先创建所需的目录结构,然后递归地复制/检查/修复链接,以确保所有动态依赖项也在应用程序包中?
我想我可以尝试编写类似的东西,但我想知道是否已经存在这样的工具。
假设我制作了一个OSX应用程序,但没有使用Xcode。在使用GCC编译后,我得到了一个链接到其他几个库的可执行文件。其中一些库可能再次动态链接到其他非标准系统库。
是否存在任何工具,可以首先创建所需的目录结构,然后递归地复制/检查/修复链接,以确保所有动态依赖项也在应用程序包中?
我想我可以尝试编写类似的东西,但我想知道是否已经存在这样的工具。
iconutil
来代替它:https://dev59.com/Smct5IYBdhLWcg3wKqQd#20703594 - rsethc我实际上找到了一款非常方便的工具,值得一提......NO - 我没开发出这款工具 ;)
https://github.com/auriamg/macdylibbundler/
它将解决所有依赖关系,并“修复”您的可执行文件以及dylib文件,使它们在应用程序包中平稳运行。
... 还会检查您的相关动态库的依赖关系:D
我在Makefile中使用这个...它创建了一个应用程序包。仔细阅读并理解它,因为你需要一个png图标文件放在macosx/文件夹中,以及我在这里包含的PkgInfo和Info.plist文件...
"它在我的电脑上工作"......我在Mavericks上为多个应用程序使用它...
APPNAME=MyApp
APPBUNDLE=$(APPNAME).app
APPBUNDLECONTENTS=$(APPBUNDLE)/Contents
APPBUNDLEEXE=$(APPBUNDLECONTENTS)/MacOS
APPBUNDLERESOURCES=$(APPBUNDLECONTENTS)/Resources
APPBUNDLEICON=$(APPBUNDLECONTENTS)/Resources
appbundle: macosx/$(APPNAME).icns
rm -rf $(APPBUNDLE)
mkdir $(APPBUNDLE)
mkdir $(APPBUNDLE)/Contents
mkdir $(APPBUNDLE)/Contents/MacOS
mkdir $(APPBUNDLE)/Contents/Resources
cp macosx/Info.plist $(APPBUNDLECONTENTS)/
cp macosx/PkgInfo $(APPBUNDLECONTENTS)/
cp macosx/$(APPNAME).icns $(APPBUNDLEICON)/
cp $(OUTFILE) $(APPBUNDLEEXE)/$(APPNAME)
macosx/$(APPNAME).icns: macosx/$(APPNAME)Icon.png
rm -rf macosx/$(APPNAME).iconset
mkdir macosx/$(APPNAME).iconset
sips -z 16 16 macosx/$(APPNAME)Icon.png --out macosx/$(APPNAME).iconset/icon_16x16.png
sips -z 32 32 macosx/$(APPNAME)Icon.png --out macosx/$(APPNAME).iconset/icon_16x16@2x.png
sips -z 32 32 macosx/$(APPNAME)Icon.png --out macosx/$(APPNAME).iconset/icon_32x32.png
sips -z 64 64 macosx/$(APPNAME)Icon.png --out macosx/$(APPNAME).iconset/icon_32x32@2x.png
sips -z 128 128 macosx/$(APPNAME)Icon.png --out macosx/$(APPNAME).iconset/icon_128x128.png
sips -z 256 256 macosx/$(APPNAME)Icon.png --out macosx/$(APPNAME).iconset/icon_128x128@2x.png
sips -z 256 256 macosx/$(APPNAME)Icon.png --out macosx/$(APPNAME).iconset/icon_256x256.png
sips -z 512 512 macosx/$(APPNAME)Icon.png --out macosx/$(APPNAME).iconset/icon_256x256@2x.png
sips -z 512 512 macosx/$(APPNAME)Icon.png --out macosx/$(APPNAME).iconset/icon_512x512.png
cp macosx/$(APPNAME)Icon.png macosx/$(APPNAME).iconset/icon_512x512@2x.png
iconutil -c icns -o macosx/$(APPNAME).icns macosx/$(APPNAME).iconset
rm -r macosx/$(APPNAME).iconset
Info.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>MyApp</string>
<key>CFBundleGetInfoString</key>
<string>0.48.2, Copyright 2013 my company</string>
<key>CFBundleIconFile</key>
<string>MyApp.icns</string>
<key>CFBundleIdentifier</key>
<string>com.mycompany.MyApp</string>
<key>CFBundleDocumentTypes</key>
<array>
</array>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>0.48.2</string>
<key>CFBundleSignature</key>
<string>MyAp</string>
<key>CFBundleVersion</key>
<string>0.48.2</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright 2013 my company.</string>
<key>LSMinimumSystemVersion</key>
<string>10.3</string>
</dict>
</plist>
PkgInfoAPPLMyAp
有一些开源工具可以帮助构建应用程序包,并针对特定环境使用相关的库,例如基于Python的应用程序可以使用py2app工具。如果你没有找到更通用的工具,也许可以根据自己的需求进行适当的调整。
希望我早些时候找到这篇文章...
这是我解决问题的简略方法,使用一个“运行脚本”阶段,在每次构建我的应用程序的“发布”版本时调用:
# this is an array of my dependencies' libraries paths
# which will be iterated in order to find those dependencies using otool -L
libpaths=("$NDNRTC_LIB_PATH" "$BOOST_LIB_PATH" "$NDNCHAT_LIB_PATH" "$NDNCPP_LIB_PATH" "/opt/local/lib")
frameworksDir=$BUILT_PRODUCTS_DIR/$FRAMEWORKS_FOLDER_PATH
executable=$BUILT_PRODUCTS_DIR/$EXECUTABLE_PATH
#echo "libpaths $libpaths"
bRecursion=0
lRecursion=0
# this function iterates through libpaths array
# and checks binary with "otool -L" command for containment
# of dependency which has "libpath" path
# if such dependency has been found, it will be copied to Frameworks
# folder and binary will be fixed with "install_name_tool -change" command
# to point to Frameworks/<dependency> library
# then, dependency is checked recursively with resolveDependencies function
function resolveDependencies()
{
local binfile=$1
local prefix=$2
local binname=$(basename $binfile)
local offset=$((lRecursion*20))
printf "%s :\t%s\n" $prefix "resolving $binname..."
for path in ${libpaths[@]}; do
local temp=$path
#echo "check lib path $path"
local pattern="$path/([A-z0-9.-]+\.dylib)"
while [[ "$(otool -L ${binfile})" =~ $pattern ]]; do
local libname=${BASH_REMATCH[1]}
otool -L ${binfile}
#echo "found match $libname"
printf "%s :\t%s\n" $prefix "fixing $libname..."
local libpath="${path}/$libname"
#echo "cp $libpath $frameworksDir"
${SRCROOT}/sudocp.sh $libpath $frameworksDir/$libname $(whoami)
local installLibPath="@rpath/$libname"
#echo "install_name_tool -change $libpath $installLibPath $binfile"
if [ "$libname" == "$binname" ]; then
install_name_tool -id "@rpath/$libname" $binfile
printf "%s :\t%s\n" $prefix "fixed id for $libname."
else
install_name_tool -change $libpath $installLibPath $binfile
printf "%s :\t%s\n" $prefix "$libname dependency resolved."
let lRecursion++
resolveDependencies "$frameworksDir/$libname" "$prefix>$libname"
resolveBoostDependencies "$frameworksDir/$libname" "$prefix>$libname"
let lRecursion--
fi
path=$temp
done # while
done # for
printf "%s :\t%s\n" $prefix "$(basename $binfile) resolved."
} # resolveDependencies
# for some reason, unlike other dependencies which maintain full path
# in "otool -L" output, boost libraries do not - they just appear
# as "libboost_xxxx.dylib" entries, without fully qualified path
# thus, resolveDependencies can't be used and a designated function is needed
# this function works pretty much in a similar way to resolveDependencies
# but targets only dependencies starting with "libboost_", copies them
# to the Frameworks folder and resolves them recursively
function resolveBoostDependencies()
{
local binfile=$1
local prefix=$2
local binname=$(basename $binfile)
local offset=$(((bRecursion+lRecursion)*20))
printf "%s :\t%s\n" $prefix "resolving Boost for $(basename $binfile)..."
local pattern="[[:space:]]libboost_([A-z0-9.-]+\.dylib)"
while [[ "$(otool -L ${binfile})" =~ $pattern ]]; do
local libname="libboost_${BASH_REMATCH[1]}"
#echo "found match $libname"
local libpath="${BOOST_LIB_PATH}/$libname"
#echo "cp $libpath $frameworksDir"
${SRCROOT}/sudocp.sh $libpath $frameworksDir/$libname $(whoami)
installLibPath="@rpath/$libname"
#echo "install_name_tool -change $libname $installLibPath $binfile"
if [ "$libname" == "$binname" ]; then
install_name_tool -id "@rpath/$libname" $binfile
printf "%s :\t%s\n" $prefix "fixed id for $libname."
else
install_name_tool -change $libname $installLibPath $binfile
printf "%s :\t%s\n" $prefix "$libname Boost dependency resolved."
let bRecursion++
resolveBoostDependencies "$frameworksDir/$libname" "$prefix>$libname"
let bRecursion--
fi
done # while
printf "%s :\t%s\n" $prefix "$(basename $binfile) resolved."
}
resolveDependencies $executable $(basename $executable)
resolveBoostDependencies $executable $(basename $executable)
在 Mac 上使用 wxWidget 代码使菜单正常工作的解决方法是:
我同意在 Mac 上构建程序的正确方式是使用 app bundle。这只是一个简单的解决方法,可帮助调试。
编辑:这是在 Mac Catalina 上,使用 wxWidgets 3.1.4 和 g++ 4.2.1(2020 年 11 月)。