tools sierra not mac installing high found for downloads developer apple macos gcc otool

macos - sierra - Desarrollar paquete de aplicaciones OSX



mac install xcode select (7)

Supongamos que he creado una aplicación osX sin usar Xcode. Después de compilar con GCC, obtengo un ejecutable que está vinculado a varias otras bibliotecas. Algunas de esas bibliotecas podrían vincularse dinámicamente a otras bibliotecas de sistemas no estándar

¿Existe alguna herramienta que cree un conjunto de aplicaciones OSX creando primero las estructuras de directorios requeridas y luego copiando / revisando / arreglando recursivamente los enlaces para asegurarse de que todas las dependencias dinámicas también estén en el paquete de la aplicación?

Creo que puedo intentar escribir algo como esto, pero me preguntaba si ya existe algo como esto.


De hecho, encontré una herramienta muy útil que merece un poco de crédito ... NO, no desarrollé esto;)

https://github.com/auriamg/macdylibbundler/

Resolverá todas las dependencias y "arreglará" tu ejecutable, así como tus archivos dylib para que funcionen sin problemas en tu paquete de aplicaciones.

... también comprobará las dependencias de sus libs dinámicas dependientes: D


Desearía haber encontrado esta publicación antes ...

Aquí está mi manera esquemática de resolver este problema usando una fase de Run script que se invoca cada vez que construyo una versión de Release de mi aplicación:

# 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)

Espero que esto pueda ser útil para alguien.


Existen algunas herramientas de código abierto para ayudar a crear paquetes de aplicaciones con bibliotecas dependientes para entornos específicos, por ejemplo, py2app para aplicaciones basadas en Python. Si no encuentra uno más general, quizás pueda adaptarlo a sus necesidades.


Hay dos formas de crear un paquete de aplicaciones en MacOSX, el Easy y el Ugly.

La manera más sencilla es usar XCode. Hecho.

El problema es que a veces no puedes.

En mi caso, estoy construyendo una aplicación que crea otras aplicaciones. No puedo suponer que el usuario tenga XCode instalado. También estoy usando MacPorts para construir las bibliotecas de las que depende mi aplicación. Necesito asegurarme de que estos dylibs se incluyan con la aplicación antes de distribuirla.

Descargo de responsabilidad: no estoy totalmente calificado para escribir esta publicación, todo en es ha brillado en los documentos de Apple, seleccionando las aplicaciones existentes y prueba y error. Funciona para mí, pero lo más probable es que esté mal. Por favor envíeme un correo electrónico si tiene alguna corrección.

Lo primero que debes saber es que un paquete de aplicaciones es solo un directorio.
Examinemos la estructura de un foo.app hipotético.

foo.app/ Contents/ Info.plist MacOS/ foo Resources/ foo.icns

Info.plist es un archivo XML sin formato. Puede editarlo con un editor de texto o la aplicación Editor de lista de propiedades que viene incluida con XCode. (Está en / Developer / Applications / Utilities / directory).

Las cosas clave que debe incluir son:

CFBundleName : el nombre de la aplicación.

CFBundleIcon : se supone que un archivo de ícono está en el directorio Contenido / Recursos. Usa la aplicación Icon Composer para crear el ícono. (También está en el directorio / Developer / Applications / Utilities /). Solo puede arrastrar y soltar un png en su ventana y generar automáticamente los niveles de mip para usted.

CFBundleExecutable : nombre del archivo ejecutable que se supone que está en Contents / MacOS / sub-folder.

Hay muchas más opciones, las enumeradas anteriormente son solo las mínimas. Aquí hay algunos documentos de Apple sobre el archivo Info.plist y la estructura del paquete de la aplicación .

Además, aquí hay una muestra 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>CFBundleGetInfoString</key> <string>Foo</string> <key>CFBundleExecutable</key> <string>foo</string> <key>CFBundleIdentifier</key> <string>com.your-company-name.www</string> <key>CFBundleName</key> <string>foo</string> <key>CFBundleIconFile</key> <string>foo.icns</string> <key>CFBundleShortVersionString</key> <string>0.01</string> <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string> <key>CFBundlePackageType</key> <string>APPL</string> <key>IFMajorVersion</key> <integer>0</integer> <key>IFMinorVersion</key> <integer>1</integer> </dict> </plist>

En un mundo perfecto podrías simplemente dejar caer tu ejecutable en el contenido / MacOS / dir y listo. Sin embargo, si su aplicación tiene dependencias no estándar de dylib, no funcionará. Al igual que Windows, MacOS viene con su propio tipo especial de DLL Hell .

Si está utilizando MacPorts para compilar bibliotecas con las que establece un vínculo, las ubicaciones de los dylibs estarán codificadas en su ejecutable. Si ejecuta la aplicación en una máquina que tiene los dylibs en la misma ubicación, funcionará correctamente. Sin embargo, la mayoría de los usuarios no los tendrán instalados; cuando hagan doble clic en tu aplicación, se bloqueará.

Antes de distribuir el archivo ejecutable, deberá recopilar todos los archivos DLL que carga y copiarlos en el paquete de la aplicación. También necesitará editar el ejecutable para que busque los dylibs en el lugar correcto. es decir, donde los copiaste.

La edición manual de un ejecutable suena peligrosa ¿no? Afortunadamente, hay herramientas de línea de comandos para ayudar.

otool -L executable_name

Este comando listará todos los dylibs de los que depende su aplicación. Si ve alguno que NO se encuentre en la carpeta System / Library o usr / lib, esos serán los que deberá copiar en el paquete de la aplicación. Cópialos en la carpeta / Contents / MacOS /. A continuación, deberá editar el ejecutable para usar los nuevos dylibs.

En primer lugar, debe asegurarse de vincular mediante el indicador -headerpad_max_install_names. Esto solo asegura que si la nueva ruta dylib es más larga que la anterior, habrá espacio para ello.

En segundo lugar, use la herramienta install_name_tool para cambiar cada ruta de dylib.

install_name_tool -change existing_path_to_dylib @executable_path/blah.dylib executable_name

Como ejemplo práctico, digamos que su aplicación usa libSDL , y otool enumera su ubicación como "/opt/local/lib/libSDL-1.2.0.dylib".

Primero cópielo en el paquete de la aplicación.

cp /opt/local/lib/libSDL-1.2.0.dylib foo.app/Contents/MacOS/

Luego edite el ejecutable para usar la nueva ubicación (NOTA: asegúrese de construirlo con el indicador -headerpad_max_install_names)

install_name_tool -change /opt/local/lib/libSDL-1.2.0.dylib @executable_path/libSDL-1.2.0.dylib foo.app/Contents/MacOS/foo

Menos mal, casi hemos terminado. Ahora hay un pequeño problema con el directorio de trabajo actual.

Cuando inicie su aplicación, el directorio actual será el directorio arriba donde se encuentra la aplicación. Por ejemplo: si coloca el foo.app en la carpeta / Applcations, entonces el directorio actual cuando inicie la aplicación será la carpeta / Aplicaciones. No es el / Application / foo.app / Content / MacOS / como es de esperar.

Puede modificar su aplicación para que cuente con esto, o puede usar este script pequeño y mágico que cambiará el directorio actual y ejecutará su aplicación.

#!/bin/bash cd "${0%/*}" ./foo

Asegúrese de ajustar el archivo Info.plist para que CFBundleExecutable apunte al script de inicio y no al archivo ejecutable anterior.

Ok, todo hecho ahora. Afortunadamente, una vez que sabes todo esto lo entierras en un guión de compilación.


La solución más simple es: crea una vez un proyecto de Xcode sin cambiar nada (es decir, conserva la aplicación de ventana única que Xcode crea para ti), compila y copia el paquete creado para ti. A continuación, edite los archivos (especialmente Info.plist) para adaptarlos a su contenido y coloque su propio binario en el directorio Contents / MacOS /.


No hay nada de mágico en el paquete: solo lea la documentación de Apple y móntelo. En la base, necesita Info.plist, Contents / MacOS / binary y un ícono.


Utilizo esto en mi Makefile ... Crea un paquete de aplicaciones. Léelo y entiéndelo, porque necesitarás un archivo de icono png en una carpeta macosx / junto con los archivos PkgInfo e Info.plist que incluyo aquí ...

"funciona en mi computadora" ... Lo uso para múltiples aplicaciones en 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/[email protected] 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/[email protected] 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/[email protected] 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/[email protected] sips -z 512 512 macosx/$(APPNAME)Icon.png --out macosx/$(APPNAME).iconset/icon_512x512.png cp macosx/$(APPNAME)Icon.png macosx/$(APPNAME).iconset/[email protected] 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>

PkgInfo

APPLMyAp