Épisode 1 — on découvre Lucebox et on décide de le packager pour Olares.
Épisode 2 — premier build, 2h de compile pour 11 undefined references vers cuMemCreate, cuMemMap, etc.
Fix appliqué : LIBRARY_PATH qui pointe vers /usr/local/cuda/lib64/stubs + symlink libcuda.so → libcuda.so.1. Logique. Je relance.
2h plus tard
Re-compile. Re-link. Et là…
/usr/bin/ld: warning: libcuda.so.1, needed by libggml-cuda.so.0.9.11, not found
/usr/bin/ld: libggml-cuda.so.0.9.11: undefined reference to `cuMemCreate'
... 11 undefined references identiques
La même erreur. À la lettre. Comme si je n’avais rien fait.
Là, première règle du debug : si vous croyez avoir corrigé le problème mais qu’il revient identique, c’est que vous n’avez pas corrigé le vrai problème. Time to read the manual.
Ce que LIBRARY_PATH fait vraiment
LIBRARY_PATH est un environment variable que gcc/clang utilisent pour résoudre les bibliothèques directement référencées par la commande de link. Si vous faites gcc main.c -lfoo et que libfoo.so est dans un répertoire listé par LIBRARY_PATH, ld trouvera. OK.
Mais si vous faites gcc main.c -lbar, et que libbar.so à l’intérieur dépend d’une autre lib libfoo.so, alors LIBRARY_PATH n’aide pas. ld va chercher libfoo.so dans son search path système standard (/lib, /usr/lib, /usr/lib/x86_64-linux-gnu, etc.) et nulle part ailleurs.
C’est ce qu’on appelle une indirect dependency. Et c’est exactement notre cas : on link test_dflash qui dépend de libggml-cuda.so qui dépend de libcuda.so.1. ld va trouver libggml-cuda.so (lib directe) mais pas libcuda.so.1 (lib indirecte) — parce qu’il ne regarde pas dans LIBRARY_PATH pour les indirects.
Le warning de ld le disait littéralement :
not found (try using -rpath or -rpath-link)
J’avais lu mais pas vraiment compris. La doc de ld confirme :
-rpath-link=DIR: When using ELF or SunOS, one shared library may require another. […] If-rpath-linkis specified, the linker will use that for indirect resolution.
Bingo.
Le vrai fix
Faut passer le path stubs au linker via CMAKE_EXE_LINKER_FLAGS et CMAKE_SHARED_LINKER_FLAGS, pas via LIBRARY_PATH :
RUN cmake -B build -S . \
-DCMAKE_BUILD_TYPE=Release \
-DGGML_CUDA=ON \
-DCMAKE_CUDA_ARCHITECTURES="120" \
-DCMAKE_EXE_LINKER_FLAGS="-Wl,-rpath-link,/usr/local/cuda/lib64/stubs" \
-DCMAKE_SHARED_LINKER_FLAGS="-Wl,-rpath-link,/usr/local/cuda/lib64/stubs" \
&& cmake --build build --target test_dflash -j $(nproc)
Note que je suis aussi passé de "86;89;120" à juste "120". Pourquoi ? Parce que je ne vais pas distribuer cette image au monde entier — elle ne va tourner que sur mon Olares One sm_120. Diviser le compile time par ~3 sans rien perdre. Si on cible plus large plus tard, on rajoutera.
56 minutes plus tard
[ 98%] Built target dflash27b
[100%] Building CXX object CMakeFiles/test_dflash.dir/test/test_dflash.cpp.o
[100%] Linking CXX executable test_dflash
[100%] Built target test_dflash
#13 DONE 3337.7s
Yes ! Built target test_dflash. Le binaire DFlash CLI est compilé. 56 min cette fois (cache CUDA partiellement réutilisé depuis le build précédent + une seule arch). Pas mal du tout.
Sauf que test_dflash c’est juste le CLI de bench Lucebox. Pour faire du vrai serving HTTP OpenAI-compatible, il me faut llama-server, qui se compile depuis le sous-module deps/llama.cpp du fork Lucebox. Build #2.
Et là, surprise — c’est pas la même cmake invocation, c’est dans un sous-projet, et j’ai pas dupliqué le -rpath-link. Du coup quand je lance le build de llama-server…
(Vous voyez où je veux en venir.)
Épisode 4 : 1h plus tard, ld me ressort exactement les mêmes 11 undefined references. À très vite !
Disclosure — Tous les benchmarks de ce post tournent sur mon propre Olares One. Si le contenu vous a été utile et que vous envisagez d’en acheter un, commander via ce lien de parrainage vous donne 400 $ de réduction (3 599 $ au lieu de 3 999 $) et me rapporte 200 $. Je le mentionne par transparence — et oui, accessoirement, ça aide à faire vivre le blog (hébergement, domaine, et le temps que je passe à écrire ici). Lien valable jusqu’à fin juin 2026 environ.