104 votes

Création d'un pack d'applications OSX

Supposons que j'ai créé une application osX sans utiliser Xcode. Après avoir compilé avec GCC, j'obtiens un exécutable qui est lié à plusieurs autres bibliothèques. Certaines de ces bibliothèques peuvent être liées dynamiquement à d'autres bibliothèques système non standard.

Existe-t-il un outil qui crée un paquet d'applications OSX en créant d'abord les structures de répertoires nécessaires, puis en copiant/vérifiant/fixant récursivement les liens pour s'assurer que toutes les dépendances dynamiques sont également dans le paquet d'applications ?

Je suppose que je peux essayer d'écrire quelque chose comme ça, mais je me demandais si quelque chose comme ça existe déjà.

4 votes

Je ne peux pas utiliser Xcode pour plusieurs raisons. L'une d'entre elles est que j'utilise un gcc personnalisé. Xcode ne me permet pas de spécifier une gcc différente. J'utilise cmake pour construire mes makefiles.

0 votes

>> Certaines de ces bibliothèques pourraient à nouveau être liées dynamiquement à d'autres bibliothèques système non standard << La réponse sélectionnée ne permet pas de résoudre ce cas. Comment l'avez-vous résolu ?

164voto

hyperlogic Points 2343

Il y a deux façons de créer un paquet d'applications sous MacOSX, la plus simple et la moins agréable.

Le moyen le plus simple est d'utiliser XCode. C'est fait.

Le problème est que parfois vous ne pouvez pas.

Dans mon cas, je crée une application qui crée d'autres applications. Je ne peux pas supposer que l'utilisateur a installé XCode. J'utilise également MacPorts pour construire les bibliothèques dont dépend mon application. Je dois m'assurer que ces dylibs sont incluses dans l'application avant de la distribuer.

Avis de non-responsabilité : Je ne suis absolument pas qualifié pour écrire cet article. a été glané dans les docs d'Apple, en décortiquant des applications existantes et par essais et erreurs. Cela fonctionne pour moi, mais c'est très probablement faux. S'il vous plaît envoyez-moi un courriel si vous avez des corrections.

La première chose que vous devez savoir est qu'un paquet d'applications est juste un répertoire.
Examinons la structure d'un hypothétique foo.app.

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

Info.plist est un fichier XML simple. Vous pouvez le modifier avec un éditeur de texte ou l'application Property List Editor fournie avec XCode. (Elle se trouve dans le répertoire /Developer/Applications/Utilities/).

Les éléments clés que vous devez inclure sont les suivants :

CFBundleName - Le nom de l'application.

CFBundleIcon - Un fichier d'icône supposé se trouver dans le répertoire Contents/Resources. Utilisez l'application Icon Composer pour créer l'icône. (Elle se trouve également dans le répertoire /Developer/Applications/Utilities/). Vous pouvez simplement faire glisser et déposer un png sur sa fenêtre et il générera automatiquement les mip-levels pour vous.

CFBundleExecutable - Nom du fichier exécutable supposé se trouver dans le sous-dossier Contents/MacOS/.

Il existe beaucoup d'autres options, celles énumérées ci-dessus ne sont que le strict minimum. Voici de la documentation Apple sur le Info.plist et Structure du paquet d'applications .

Aussi, voici un exemple de 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>

Dans un monde parfait, vous pourriez simplement déposer votre exécutable dans le répertoire Contents/MacOS/ et c'est tout. Cependant, si votre application a des dépendances dylib non standard, cela ne fonctionnera pas. Comme Windows, MacOS est livré avec son propre type de L'enfer des DLL .

Si vous utilisez MacPorts pour construire des bibliothèques que vous liez, l'emplacement des dylibs sera codé en dur dans votre exécutable. Si vous exécutez l'application sur une machine qui a les dylibs exactement au même endroit, elle fonctionnera bien. Cependant, la plupart des utilisateurs n'auront pas installé les dylibs ; lorsqu'ils double-cliqueront sur votre application, celle-ci se plantera.

Avant de distribuer votre exécutable, vous devrez collecter tous les dylibs qu'il charge et les copier dans le bundle de l'application. Vous devrez également modifier l'exécutable pour qu'il recherche les dylibs au bon endroit, c'est-à-dire là où vous les avez copiés.

Modifier manuellement un exécutable peut sembler dangereux, n'est-ce pas ? Heureusement, il existe des outils en ligne de commande pour vous aider.

otool -L executable\_name

Cette commande va lister toutes les dylibs dont dépend votre application. Si vous en voyez qui ne sont PAS dans le dossier System/Library ou usr/lib, ce sont ceux que vous devez copier dans le paquet d'applications. Copiez-les dans le dossier /Contents/MacOS/. Ensuite, vous devrez modifier l'exécutable pour utiliser les nouvelles dylibs.

Tout d'abord, vous devez vous assurer que vous utilisez l'option -headerpad_max_install_names. Cela permet de s'assurer que si le nouveau chemin de la dylib est plus long que le précédent, il y aura de la place pour lui.

Ensuite, utilisez l'outil install_name_tool pour modifier chaque chemin dylib.

install\_name\_tool -change existing\_path\_to\_dylib @executable\_path/blah.dylib executable\_name

A titre d'exemple pratique, disons que votre application utilise libSDL et otool indique que son emplacement est "/opt/local/lib/libSDL-1.2.0.dylib".

Copiez-le d'abord dans le paquet d'applications.

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

Puis modifiez l'exécutable pour utiliser le nouvel emplacement (NOTE : assurez-vous que vous l'avez construit avec l'option -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

Ouf, on a presque fini. Maintenant, il y a un petit problème avec le répertoire de travail actuel.

Lorsque vous démarrez votre application, le répertoire courant sera le répertoire supérieur où se trouve l'application. Par exemple : Si vous placez foo.app dans le dossier /Applcations, le répertoire courant lorsque vous lancez l'application sera le dossier /Applications. Et non pas le dossier /Applications/foo.app/Contents/MacOS/ comme vous pourriez vous y attendre.

Vous pouvez modifier votre application pour tenir compte de cela, ou vous pouvez utiliser ce petit lanceur magique script qui changera le répertoire courant et lancera votre application.

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

Assurez-vous d'ajuster le fichier Info.plist de façon à ce que CFBundleExecutable pointe vers le script de lancement et non vers l'exécutable précédent.

Ok, tout est fait maintenant. Heureusement, une fois que vous connaissez tous ces trucs, vous les enterrez dans un build script.

7 votes

+1. Cependant, le chien zombie me fait peur. Pourriez-vous utiliser une image moins marquante pour illustrer l'enfer des DLL ? (Sans compter que le terme "enfer des DLL" ne s'applique pas. La méthode préférée pour distribuer les bibliothèques dynamiques est via des frameworks qui évitent la plupart des problèmes. Néanmoins, l'approche .dylib est utile pour les bibliothèques de style UNIX).

1 votes

Comment corriger les doubles dépendances ? Par exemple, une dylib fait référence à une autre dylib ?

0 votes

N'y a-t-il aucun moyen de compiler l'exécutable avec les emplacements corrects pour ne pas avoir à le modifier ?

23voto

Chris Points 764

J'ai trouvé un outil très pratique qui mérite un certain crédit ... NON - je ne l'ai pas développé ;)

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

Il résoudra toutes les dépendances et "réparera" votre exécutable ainsi que vos fichiers dylib pour qu'ils fonctionnent sans problème dans votre paquet d'applications.

... il vérifiera également les dépendances de vos librairies dynamiques dépendantes :D

0 votes

C'est un outil très utile ! Merci de le partager et de le développer.

0 votes

Il manque ici les dépendances des dépendances. Correction ?

10voto

subatomic Points 1

J'utilise ceci dans mon Makefile... Il crée un paquet d'applications. Lisez-le et comprenez-le, parce que vous aurez besoin d'un fichier d'icône en png dans un dossier macosx/ avec les fichiers PkgInfo et Info.plist que j'inclus ici...

"ça marche sur mon ordinateur"... Je l'utilise pour plusieurs applications sur 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>

PkgInfo

APPLMyAp

0 votes

Vous pourriez faire en sorte que le fichier Info.plist contienne des caractères de remplacement, puis utiliser quelque chose comme sed ou awk pour créer le fichier Info.plist final avec les bons champs. Ou peut-être même utiliser plutil pour créer le fichier plist.

8voto

F'x Points 6557

La solution la plus simple est la suivante : créez une fois un projet Xcode sans rien changer (c'est-à-dire gardez la simple application à une fenêtre que Xcode crée pour vous), construisez-le, et copiez le bundle qu'il a créé pour vous. Ensuite, modifiez les fichiers (notamment le fichier Info.plist) en fonction de votre contenu, et mettez votre propre binaire dans le répertoire Contents/MacOS/.

4 votes

La question demande explicitement comment le faire sans xcode. Je suis dans le même bateau et j'aimerais avoir une vraie réponse.

5 votes

Avec cela, vous n'aurez à utiliser XCode qu'une seule fois dans votre vie :) ou à demander à quelqu'un de le faire pour vous.

0 votes

@F'x Pouvez-vous simplement publier ce .app généré comme exemple quelque part ?

5voto

Wil Shipley Points 5327

Il n'y a vraiment rien de magique dans le bundle - il suffit de lire la documentation d'Apple à ce sujet, et de l'imiter. A la base, vous avez besoin d'un Info.plist, du Contents/MacOS/binary, et d'une icône.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X