# 5. Créer une distribution compilée

Une « distribution compilée » vous fait surement penser à un « paquet binaire » ou à un « installateur » (tout dépend de votre environnement). Ce n’est cependant pas forcément un binaire, il peut ne contenir que des sources Python et / ou du byte-code ; et nous n’appelons pas ça un package parce que ce mot est déjà utilisée dans Python (et « installateur » est un terme spécifique au monde des systèmes de bureau).

Une distribution compilée est une manière de rendre la vie plus facile à ceux qui installent votre module : pour les utilisateurs de système Linux basé sur RPM, ce sera des binaire RPM ; pour les utilisateurs de Windows, c’est un installateur exécutable ; pour les utilisateurs de Linux basé sur Debian, c’est un paquet Debian ; et ainsi de suite. Évidemment, personne n’est capable de créer une distribution compilée pour toute les plateformes existantes, donc Distutils est fait pour permettre aux développeurs de se concentrer sur leurs spécialités — écrire du code et créer des distribution source — pendant que d’autres, appelés packagers s’occupent de transformer les sources en paquets pour chaque plateforme.

Of course, the module developer could be their own packager; or the packager could be a volunteer « out there » somewhere who has access to a platform which the original developer does not; or it could be software periodically grabbing new source distributions and turning them into built distributions for as many platforms as the software has access to. Regardless of who they are, a packager uses the setup script and the bdist command family to generate built distributions.

Pour prendre un exemple simple, si je lance la commande suivante dans les sources de Distutils :

    python setup.py bdist

alors Distutils construit ma distribution du module (Distutils lui même dans ce cas), fait une « fausse » installation (aussi dans le dossier `build`) et crée le type de distribution compilée par défaut pour ma plateforme. Le format par défaut est un « bête » fichier tar pour Unix et un simple installateur exécutable pour Windows (ce fichier tar est considéré comme « bête » car il doit être décompressé à un endroit précis pour fonctionner).

Par conséquent, la commande si dessus crée le fichier `Distutils-1.0.plat.tar.gz` sur les systèmes Unix ; décompresser cette archive tar au bon endroit installe Distutils exactement comme si vous aviez téléchargé la distribution source et lancé `python setup.py install` (le « bon endroit » est soit la racine du système de fichier, ou le dossier de Python `prefix`, tout dépend des options données à la commande bdist_dumb ; la valeur par défaut est de créer une distribution « bête » relative à `prefix`).

Évidemment, pour une distribution en Python pur, ce n’est pas aussi simple que de simplement lancer `python setup.py install`—mais pour une distribution non-pure qui inclut des extensions qui devraient être compilées, ça peut faire la différence entre quelqu’un qui sera capable d’utiliser votre extension, ou non. De plus créer une distribution compilée « intelligente » tel qu’un paquet RPM ou un installateur exécutable Windows, est bien plus pratique pour les utilisateurs, même si votre module n’inclut aucune extension.

The bdist command has a `--formats` option, similar to the sdist command, which you can use to select the types of built distribution to generate: for example,

    python setup.py bdist --format=zip

serait, lors d’une exécution sur un système Unix, crée `Distutils-1.0.plat.zip`—à nouveau, cette archive devra être décompressé depuis la racine pour installer Distutils.

Les formats disponible pour les distributions compilées sont :

Format | Description | Notes
--- | --- | ---
`gztar` | Fichier tar gzippé (`.tar.gz`) | (1), (3)
`ztar` | Fichier tar compressé par compress (`.tar.Z`) | (3)
`tar` | fichier tar (`.tar`) | (3)
`zip` | Fichier zip (`.zip`) | (2),(4)
`rpm` | RPM | (5)
`pkgtool` | Solaris pkgtool |
`sdux` | HP-UX swinstall |
`wininst` | Fichier zip auto-extracteur Windows | (4)
`msi` | Installateur Microsoft. |

Notes :

1. Par défaut sur Unix
2. Par défaut sur Windows
3. requires external utilities: tar and possibly one of gzip, bzip2, or compress
4. nécessite soit un utilitaire zip extérieur ou le module `zipfile` (inclut dans la bibliothèque standard depuis Python 1.6)
5. Nécessite un programme externe rpm, version 3.0.4 ou mieux (utilisez `rpm --version` pour connaître quelle version vous avez)

You don’t have to use the bdist command with the `--formats` option; you can also use the command that directly implements the format you’re interested in. Some of these bdist « sub-commands » actually generate several similar formats; for instance, the bdist_dumb command generates all the « dumb » archive formats (`tar`, `ztar`, `gztar`, and `zip`), and bdist_rpm generates both binary and source RPMs. The bdist sub-commands, and the formats generated by each, are:

Commande | Formats
--- | ---
bdist_dumb | tar, ztar, gztar, zip
bdist_rpm | rpm, srpm
bdist_wininst | wininst
bdist_msi | msi

Le chapitre suivant donne des détails individuel sur les commandes bdist_*.

## 5.1. Creating dumb built distributions

## 5.2. Créer un paquet RPM

Le format RPM est utilisé par beaucoup de distributions Linux populaires, incluant Red Hat, SuSE et Mandrake. Si l’une d’entre elle (ou n’importe quelle autre distribution basé sur RPM) est votre environnement habituel, créer un paquet pour les autres utilisateur de ces distributions est trivial. Cela dépend de la complexité de votre module et des différences entre les distributions Linux, vous pourrez aussi créer des RPM qui fonctionneront sur des distributions RPM différentes.

La manière habituelle de créer un RPM de votre module est d’utiliser la commande bdist_rpm :

    python setup.py bdist_rpm

or the bdist command with the `--format` option:

    python setup.py bdist --formats=rpm

La première vous permet de spécifier des options spécifique à RPM ; la dernière vous permet de spécifier plusieurs format d’un seul coup. Si vous avez besoin d’utiliser les deux, vous pouvez explicitement spécifier plusieurs commande bdist_* et leurs options :

    python setup.py bdist_rpm --packager="John Doe <jdoe@example.org>" \
                    bdist_wininst --target-version="2.0"

La création de Package RPM est configurée par une fichier `.spec`, un peu comme Distutils est configuré par script setup.py. Pour vous faciliter la tâche, la commande bdist_rpm crée normalement un fichier `.spec` basé sur les informations que vous fournissez dans setup.py, dans les options de la ligne de commande et dans la configuration de Distutils. Beaucoup d’options du fichier `.spec` sont dérivées des options du script de préparation suivant :

Option de fichier RPM `.spec` | Options du script de préparation Distutils
--- | ---
Nom | `name`
Summary (dans le préambule) | `description`
Version | `version`
vendor | `author` et `author_email`, ou — & `maintainer` et `maintainer_email`
Copyright | `license`
Url | `url`
%description (section) | `long_description`

De plus, il y a beaucoup d’options dans le fichier `.spec` qui n’ont aucun équivalent dans le script de préparation. La plupart de celles ci sont gérées par les options de la commande bdist_rpm suivant :

Option de fichier RPM `.spec` | Option de bdist_rpm | Valeur par défaut
--- | --- | ---
Version | `release` | « 1 »
Group | `group` | « Développement/Bibliothèques »
vendor | `vendor` | (voir au-dessus)
Packager | `packager` | (none)
Provides | `provides` | (none)
Requires | `requires` | (none)
Conflicts | `conflicts` | (none)
Obsoletes | `obsoletes` | (none)
Distribution | `distribution_name` | (none)
BuildRequires | `build_requires` | (none)
Icon | `icon` | (none)

Obviously, supplying even a few of these options on the command-line would be tedious and error-prone, so it’s usually best to put them in the setup configuration file, `setup.cfg`—see section Writing the Setup Configuration File. If you distribute or package many Python module distributions, you might want to put options that apply to all of them in your personal Distutils configuration file (`~/.pydistutils.cfg`). If you want to temporarily disable this file, you can pass the –no-user-cfg option to setup.py.

La création de binaire RPM se fait en trois étapes, chacune gérée automatiquement par Distutils :

1. Créer un fichier `.spec` qui décrira le paquet (comme le script de préparation Distutils, en réalité la plupart des informations du script de préparation se retrouve dans le fichier `.spec`)
2. crée un RPM source
3. Créer le RPM « binaire » (qui peut ou non contenir des binaires, tout dépend de si votre module contiens des extensions)

Normalement, RPM réunit les deux dernières étapes ensemble ; quand vous utilisez Distutils, les trois étapes sont regroupées.

If you wish, you can separate these three steps. You can use the `--spec-only` option to make bdist_rpm just create the `.spec` file and exit; in this case, the `.spec` file will be written to the « distribution directory »—normally `dist/`, but customizable with the `--dist-dir` option. (Normally, the `.spec` file winds up deep in the « build tree, » in a temporary directory created by bdist_rpm.)

## 5.3. Créer un installateur Windows

Les installateurs exécutable sont le format naturel pour les distributions sur Windows. Ils affichent une jolie interface graphique, montrent quelques informations à propos du module qui va être installé, tiré des métadonnées dans le script de préparation, laisse l’utilisateur choisir quelques options et démarrer ou annuler l’installation.

Étant donné que les métadonnées sont tirées du script de préparation, créer un installateur Windows est généralement facile, il suffit de lancer :

    python setup.py bdist_wininst

or the bdist command with the `--formats` option:

    python setup.py bdist --formats=wininst

Si vous avez un module pur (contenant seulement des modules et des packages en Python pur), l’installateur final ne sera lié a aucune version de Python et aura un nom du type `foo-1.0.win32.exe`. Ces installateurs peuvent même être créés sur les plateformes Unix ou Mac OS X.

Si vous avez une distribution « non-pure », l’extension peut être créée uniquement pour les plateformes Windows et sera lié à une version de Python. Le nom de l’installateur reflétera ça et sera de format `foo-1.0.win32-py2.0.exe`. Vous devrez créer un installateur pour chaque version de Python que vous voulez supporter.

The installer will try to compile pure modules into bytecode after installation on the target system in normal and optimizing mode. If you don’t want this to happen for some reason, you can run the bdist_wininst command with the `--no-target-compile` and/or the `--no-target-optimize` option.

By default the installer will display the cool « Python Powered » logo when it is run, but you can also supply your own 152x261 bitmap which must be a Windows `.bmp` file with the `--bitmap` option.

The installer will also display a large title on the desktop background window when it is run, which is constructed from the name of your distribution and the version number. This can be changed to another text by using the `--title` option.

The installer file will be written to the « distribution directory » — normally `dist/`, but customizable with the `--dist-dir` option.

## 5.4. Compiler pour toute les plateformes Windows

Depuis Python 2.6, distutils est capable de compiler pour toute les plateformes de Windows. En pratique, cela signifie qu’avec les bons outils installés, vous pouvez utiliser une version 32 bits de Windows pour créer une extension 64 bits et vice-versa.

To build for an alternate platform, specify the `--plat-name` option to the build command. Valid values are currently “win32”, “win-amd64” and “win-ia64”. For example, on a 32bit version of Windows, you could execute:

    python setup.py build --plat-name=win-amd64

Pour construire une version 64 bits de votre module. L’installateur Windows supporte aussi cette option, donc la commande :

    python setup.py build --plat-name=win-amd64 bdist_wininst

créera un installateur exécutable 64 bits depuis votre version 32 bits de Windows.

Pour compiler pour toute les versions de Windows, vous devez télécharger le code source de Python et de le compiler pour la plateforme choisie - il est impossible de le faire depuis une installation de Python (vu que les fichiers .lib pour les autres plateformes ne sont pas inclut). En pratique, cela veut dire qu’un utilisateur de systeme 32 bits devra utiliser Visual Studio 2008 pour ouvrir la solution `PCBuild/PCbuild.sln` dans l’arborescence des sources de Python et construire la version « x64 » du projet « pythoncore » avant de pouvoir compiler son extension.

Remarquez que par défaut Visual Studio 2008 n’installe pas les outils et compilateur 64 bits. Vous devrez peut être réexécuter le processus d’installation et sélectionner ces outils (utiliser le Panneau de Contrôle -> [Ajouter/Supprimer] est un bon moyen de vérifier ou modifier votre installation existante.)

### 5.4.1. Le script de post-installation

Starting with Python 2.3, a postinstallation script can be specified with the `--install-script` option. The basename of the script must be specified, and the script filename must also be listed in the scripts argument to the setup function.

This script will be run at installation time on the target system after all the files have been copied, with `argv[1]` set to `-install`, and again at uninstallation time before the files are removed with `argv[1]` set to `-remove`.

Le script d’installation s’exécute intégré à la fenêtre d’installation, chaque sortie (`sys.stdout`, `sys.stderr`) est redirigé dans le tampon et sera affiché dans le GUI après que les scripts soient finis.

certaines fonctions spécialement utiles dans ce contexte sont disponibles comme fonctions intégrées additionnelles dans le script d’installation.

`directory_created`(path)
`file_created`(path)

  Ces fonctions peuvent être appelées lorsqu’un répertoire ou un fichier est crée par le script de post installation au moment de l’installation. Cela va enregistrer le chemin avec le des-installeur, de sorte qu’il soit retiré lors de la des-installation de la distribution. pour être sûr, les répertoires sont uniquement retirés s’ils sont vides.

`get_special_folder_path`(csidl_string)

  Cette fonction peut être utilisée pour extraire des localisations de fichiers spéciaux sous Windows comme un menu démarrer ou le Bureau. Cela renvoie le chemin complet pour le fichier. csidl_string doit être unes des chaines suivantes :

      "CSIDL_APPDATA"

      "CSIDL_COMMON_STARTMENU"
      "CSIDL_STARTMENU"

      "CSIDL_COMMON_DESKTOPDIRECTORY"
      "CSIDL_DESKTOPDIRECTORY"

      "CSIDL_COMMON_STARTUP"
      "CSIDL_STARTUP"

      "CSIDL_COMMON_PROGRAMS"
      "CSIDL_PROGRAMS"

      "CSIDL_FONTS"

  Si le fichier ne peut être extrait, `OSError` est obtenu..

  Quel dossier est disponible dépend de la version exacte de Windows, et probablement aussi de la configuration. pour des détails se référer à la documentation Microsoft de la fonction `SHGetSpecialFolderPath()`.

`create_shortcut`(target, description, filename[, arguments[, workdir[, iconpath[, iconindex]]]])

  Cette fonction crée un raccourci. cible est le chemin au programme auquel mène le raccourci. description est la description du raccourci. nomfichier est le titre du raccourci que verra l’utilisateur. arguments spécifie les arguments de la ligne de commande, si existant. cheminRep est le répertoire de travail pour le programme. cheminIcone est le fichier contenant l’icône pour le raccourci, et IndexIcone est l’index pour l’icône dans le fichier cheminIcone. Encore, pour les détails consulter la documentation Microsoft pour l’interface `ILienShell`.

## 5.5. Contrôle d’accès utilisateur Vista (UAC)

Starting with Python 2.6, bdist_wininst supports a `--user-access-control` option. The default is “none” (meaning no UAC handling is done), and other valid values are “auto” (meaning prompt for UAC elevation if Python was installed for all users) and “force” (meaning always prompt for elevation).