% Homebrew et alternatives

# Question

homebrew peut casser occasionnellement certains logiciels installés qui auparavant fonctionnaient (je pense notamment à ffmpeg qui peut être en conflit quand on le compile manuellement)

Cependant, ne pas le mettre à jour pose d'autres soucis.

Existe-t-il une solution qui permettrait d'isoler les unes des autres des "sets" d'installation pour permettre d'éviter que des outils tombent en panne tout en conservant une version à jour des autres outils ? 

## Réponse


Le problème que vous décrivez est inhérent à la conception de **Homebrew** : c'est un gestionnaire de paquets de type "rolling release" qui s'appuie sur des liens symboliques vers une structure de bibliothèques partagées unique (`/opt/homebrew/lib` ou `/usr/local/lib`). Lorsqu'une bibliothèque est mise à jour pour un outil A, elle peut briser l'outil B qui dépendait de l'ancienne version.

Voici les solutions techniques pour isoler des environnements et éviter ces ruptures.

---

## 1. Nix (La solution la plus rigoureuse)
Nix est un gestionnaire de paquets purement fonctionnel. Contrairement à Homebrew, il n'installe pas les fichiers dans des dossiers standards. Chaque paquet et chaque version sont stockés dans un répertoire unique basé sur un hash de toutes ses dépendances (ex: `/nix/store/v24...-ffmpeg-6.0`).

* **Avantage :** Isolation totale. Deux versions d'un même logiciel ou de ses dépendances peuvent coexister sans jamais interférer.
* **Fonctionnement :** Vous pouvez créer un fichier `shell.nix` par projet ou par "set" d'outils. En entrant dans ce shell, seules les versions spécifiées sont accessibles.

## 2. Conteneurisation (Docker / Podman)
Pour des outils complexes comme `ffmpeg` qui dépendent de nombreuses bibliothèques système ou de compilations manuelles, le conteneur est la méthode d'isolation la plus étanche.

* **Avantage :** Vous figez non seulement l'outil, mais tout l'OS de base et les bibliothèques (`glibc`, etc.).
* **Usage :** Créer un alias dans votre shell : `alias ffmpeg='docker run --rm -v $(pwd):$(pwd) -w $(pwd) jrottenberg/ffmpeg'`. Cela rend l'outil "portable" et indépendant des mises à jour de macOS ou de Homebrew.



## 3. Mise / Asdf (Gestionnaires de versions)
`mise` (ou son prédécesseur `asdf`) permet d'installer plusieurs versions d'un même outil et de basculer entre elles selon le répertoire où vous vous trouvez.

* **Avantage :** Plus léger que Docker, mieux intégré au shell que Nix pour un débutant.
* **Usage :** Très efficace pour les langages (Node, Python, Rust) et certains outils CLI. Cependant, il ne gère pas toujours parfaitement les dépendances système partagées (comme les bibliothèques `.dylib` dont `ffmpeg` a besoin).

## 4. Homebrew : Le "Pinning" (Solution palliative)
Si vous souhaitez rester sur Homebrew, vous pouvez "épingler" une version pour empêcher sa mise à jour lors d'un `brew upgrade`.

* **Commande :** `brew pin ffmpeg`
* **Faille :** C'est une solution fragile. Si une autre application que vous mettez à jour nécessite une version plus récente d'une dépendance commune à `ffmpeg`, Homebrew pourrait soit casser l'installation, soit refuser la mise à jour de l'autre application.

---

### Tableau comparatif

| Solution | Niveau d'isolation | Complexité | Recommandation |
| :--- | :--- | :--- | :--- |
| **Nix** | Maximale | Élevée | Pour une gestion scientifique et reproductible. |
| **Docker** | Maximale | Moyenne | Pour les outils avec des dépendances "lourdes" (`ffmpeg`). |
| **Mise/Asdf** | Partielle | Faible | Pour les outils de développement (langages). |
| **Brew Pin** | Nulle | Très faible | À éviter pour le long terme. |

### Critique de votre approche actuelle
Vouloir gérer des compilations manuelles au milieu d'un environnement géré par Homebrew est une erreur structurelle. Homebrew ne suit pas les fichiers que vous installez manuellement, ce qui provoque des conflits de liens lors des phases de `link` ou de `cleanup`. 

**Ma recommandation :** Utilisez **Nix** pour vos besoins de rigueur scientifique et d'isolation, ou basculez vos outils critiques (ceux que vous compilez manuellement) dans des images **Docker** dédiées pour supprimer toute interaction avec les bibliothèques du système hôte.

# Performance

En matière de performance, la distinction entre Nix et Homebrew se joue sur trois tableaux : l'exécution binaire, le coût de l'isolation (chargement) et l'efficience de la gestion système (construction/disque).

---

## 1. Performance d'exécution (Runtime)
Sur le plan du pur calcul CPU ou de la gestion mémoire, les performances sont **sensiblement identiques**. Les deux gestionnaires installent des binaires compilés (souvent avec les mêmes flags de compilation via LLVM/Clang sur macOS).

Cependant, une nuance technique existe au niveau du **Dynamic Linking** (liage dynamique) :
* **Homebrew :** Utilise les chemins standards de recherche de bibliothèques du système ou des chemins relatifs (`@rpath`). Le "loader" de l'OS doit parfois résoudre ces liens au lancement.
* **Nix :** Utilise des chemins absolus vers le `/nix/store` inscrits directement dans le header du binaire via `RPATH`. 
* **Impact :** La différence est négligeable (microsecondes), mais l'approche de Nix est plus déterministe. Le binaire Nix ne "cherche" jamais ses dépendances ; il sait exactement où elles sont sur le disque.

## 2. Performance de construction et d'installation
C'est ici que Homebrew est généralement perçu comme "plus rapide" pour l'utilisateur lambda, bien que Nix soit techniquement plus robuste.

* **Évaluation des paquets :** Homebrew utilise des scripts Ruby relativement simples. Nix doit évaluer un langage de programmation fonctionnel complet pour calculer le "graphe de dérivation" (le plan de construction). Pour des environnements complexes, cette phase d'évaluation peut prendre plusieurs secondes.
* **Mises à jour :** `brew update` met à jour un index global. Nix doit souvent réévaluer les expressions pour vérifier si l'état actuel correspond à l'état désiré.
* **Binaires (Caches) :** Les deux disposent de binaires pré-compilés (Bottles pour Brew, Substitutes pour Nix). Si un binaire manque, Nix lancera une compilation locale isolée (sandbox), ce qui est plus coûteux en ressources mais garantit la reproductibilité.



## 3. Empreinte disque et I/O
Nix est nettement plus gourmand en ressources disque que Homebrew.

* **Duplication :** Là où Homebrew écrase l'ancienne version par la nouvelle (sauf si on intervient manuellement), Nix conserve chaque version de chaque dépendance tant qu'elles ne sont pas explicitement supprimées et collectées par le "Garbage Collector" (`nix-collect-garbage`).
* **Dédoublonnement :** Nix utilise des liens physiques (hard links) pour optimiser l'espace si deux versions partagent des fichiers identiques, mais l'empreinte globale reste supérieure à Homebrew.
* **Vitesse du Shell :** L'utilisation de `nix-shell` ou `nix develop` introduit un délai au démarrage du terminal (le temps de configurer les variables d'environnement `$PATH` spécifiques), contrairement à Homebrew qui injecte tout de manière permanente dans `/opt/homebrew/bin`.

---

### Synthèse technique

| Métrique | Homebrew | Nix | Analyse critique |
| :--- | :--- | :--- | :--- |
| **Vitesse d'exécution** | Native | Native | Équivalence quasi-totale. |
| **Lancement d'outil** | Instantané | Léger délai (si via shell) | Avantage Homebrew pour l'usage interactif simple. |
| **Installation** | Rapide (Bottles) | Variable (Évaluation Nix) | Nix est plus lent à cause de sa rigueur logique. |
| **Espace Disque** | Optimisé | Élevé (Immutabilité) | Nix sacrifie le disque pour la fiabilité. |

**Verdict :** Si vous cherchez la **performance de flux de travail** (ne jamais avoir un outil qui casse), Nix gagne car il élimine le temps perdu à réparer les dépendances brisées. Si vous cherchez la **performance système pure** (vitesse d'installation et économie d'espace), Homebrew est supérieur, au prix d'une fragilité structurelle importante.




# Cohabitation



Oui, faire cohabiter **Homebrew** et **Nix** est tout à fait possible et même assez courant chez les utilisateurs avancés. Ils utilisent des racines de fichiers distinctes (`/opt/homebrew` ou `/usr/local` pour Brew, et `/nix` pour Nix), ce qui empêche les collisions de fichiers bruts.

Cependant, la cohabitation entre Homebrew et des **outils compilés manuellement** est beaucoup plus risquée si elle n'est pas strictement encadrée.

---

## 1. Cohabitation Nix / Homebrew
C'est la solution la plus stable.
* **Mécanisme :** Nix n'ajoute rien à votre `$PATH` global de manière permanente (sauf si vous le configurez ainsi). Vous pouvez utiliser Homebrew pour vos applications graphiques ou outils quotidiens, et Nix via un `nix-shell` pour vos environnements de calcul ou outils sensibles.
* **Conflit potentiel :** Le seul risque est l'ordre dans la variable `$PATH`. Si un outil est présent dans les deux, le premier trouvé sera exécuté.
* **Conseil :** Gardez Homebrew en priorité dans votre shell principal et n'appelez Nix que via des environnements isolés par projet.



---

## 2. Compilation manuelle : Le "Chemin Recommandé"
Si vous compilez manuellement (par exemple `ffmpeg`) alors que Homebrew est installé, le risque majeur est le **shadowing** : votre compilateur peut lier par erreur des bibliothèques de Homebrew, créant une dépendance invisible qui cassera lors de la prochaine mise à jour de Brew.

Pour isoler vos builds manuels, suivez ces règles strictes :

### A. Utiliser un préfixe d'installation dédié
Ne compilez jamais dans `/usr/local` ou `/opt/homebrew`. Utilisez un répertoire isolé par outil.
* **Option de compilation :** `--prefix=/opt/custom/ffmpeg-version` (ou dans votre `$HOME`).

### B. Isoler les flags de compilation
Pour éviter que le compilateur n'aille "piocher" dans les dossiers de Homebrew, vous devez forcer les chemins de recherche.

Lors du `./configure`, utilisez explicitement :
```bash
./configure --prefix=/opt/custom/ffmpeg \
            --extra-cflags="-I/opt/custom/include" \
            --extra-ldflags="-L/opt/custom/lib" \
            --disable-shared --enable-static
```
*Note : Adaptez ces flags selon le logiciel (souvent `CFLAGS` et `LDFLAGS`).*

### C. Privilégier le liage statique (`--enable-static`)
C'est la réponse technique à votre problème. En compilant `ffmpeg` (ou autre) en **statique**, vous incluez toutes les bibliothèques nécessaires à l'intérieur du binaire final.
* **Avantage :** Le binaire devient autonome. Vous pouvez mettre à jour Homebrew sans crainte ; votre `ffmpeg` manuel ne dépend plus des `.dylib` changeantes de `/opt/homebrew/lib`.
* **Inconvénient :** Le binaire est plus lourd et ne bénéficie pas des mises à jour de sécurité automatiques des bibliothèques partagées.

---

## 3. Analyse critique de votre stratégie

Le danger de votre approche est la **"pollution" de l'environnement de build**. Même avec un `--prefix` isolé, les outils de build (comme `pkg-config`) vont naturellement chercher des fichiers `.pc` dans les répertoires de Homebrew.

**Faille majeure :** Si vous compilez `ffmpeg` manuellement en le liant dynamiquement à une version de `libx264` installée par Homebrew, votre `ffmpeg` manuel **cassera** dès que Homebrew passera à une version majeure de `x264` (changement de nom du fichier `.dylib`).

### Ma recommandation technique :
1.  **Pour la propreté :** Utilisez **Nix** pour tout ce qui nécessite de la stabilité. Nix gère le liage statique et l'isolation des dépendances de manière native et mathématique.
2.  **Pour le spécifique :** Si vous devez absolument compiler manuellement, faites-le dans un **conteneur Docker** (image `alpine` ou `debian`), compilez en statique, puis extrayez le binaire final sur votre macOS. C'est la seule façon de garantir qu'aucune scorie de Homebrew ne s'est glissée dans votre build.

Si vous persistez dans la compilation manuelle sur l'hôte, assurez-vous de vider temporairement votre `$PATH` de toute référence à Homebrew durant la phase de compilation.

