Compiler llvm, clang, libc++abi et libc++
Introduction
Les dates de rédaction et de dernière modification de ce type d’article sont importantes (voir le pied pde page du billet). Par exemple, j’ai rencontré des problèmes qui ont été résolu depuis.
Pour fixer les idées, je rappelle que je suis sous Windows 7, dans une VirtualBox 4.2.12 où je fais tourner Debian 7.0 Wheezy 64 bits. J’espère toutefois que cet article donnera des pistes si jamais vous rencontrez des problèmes similaires.
Table of Contents
- Pour bien commencer
- llvm et clang
- Faisons un premier test
- Faisons un autre test avec Sanitizer
- libc++abi et libc++
- Faisons un autre test
- Compilation de clang avec clang
- Faisons un dernier test
- Conclusion temporaire
- Teaser à propos de la suite
Articles qui peuvent être utiles
Ne commencez pas par tout lire… Vous allez mourir car certains points sont un peu “chauds”. Cela dit, dans quelques jours, quand vous en aurez marre et que vous voudrez tout jeter par la fenêtre… Il est possible que vous y trouviez, là aussi, 2 ou trois pistes.
- http://sylvestre.ledru.info/blog/
- http://18739c.ece.cmu.edu/alpha-1/debugging-debian/tools/clang/
- http://solarianprogrammer.com/2013/01/17/building-clang-libcpp-ubuntu-linux/
- http://dragoonsheir.wordpress.com/2013/03/16/wayland-and-c11-programming-part-1-of-n/
- http://clang.llvm.org/get_started.html
- http://comments.gmane.org/gmane.comp.compilers.clang.devel/22540
- http://lists.alioth.debian.org/pipermail/soc-coordination/2012-July/001316.html
- http://lists.alioth.debian.org/pipermail/soc-coordination/2012-July/001316.html
Pour bien commencer
Bon allez, c’est parti… Dans VirtualBox, je commence par donner 3Go de RAM à la machine virtuelle (j’en ai 8 physiquement dans le PC) et j’en profite pour lui donner aussi 4 processeurs. Le coup des 3 Go est important, ne le négligez pas car sinon ça va partir en sucette à la compile ou au link. Je suppose que l’‘on démarre dans le répertoire ($HOME). On commence par récupérer ce dont on a besoin (oui, oui je sais on aurait pu mettre tous les apt-get sur une même ligne mais je trouve que c’est plus didactique comme ça.)
$ su
apt-get install cmake
apt-get install make
apt-get update
apt-get upgrade
apt-get install gcc
apt-get install g++
apt-get install subversion
exit
llvm et clang
Ensuite il faut créer un répertoire llvm
(ce n’est pas très malin comme nom, choisissez autre chose si possible) où on va télécharger llvm, clang et leurs amis…
$ mkdir llvm
$ cd llvm
$ svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm
On a donc une arborescence qui ressemble à : $HOME/llvm/llvm/
C’est pour ça que je disais que choisir “lvm” comme nom de premier répertoire dans $HOME n’était pas malin
$ cd llvm/tools
$ svn co http://llvm.org/svn/llvm-project/cfe/trunk clang
$ cd ../..
$ cd llvm/tools/clang/tools
$ svn co http://llvm.org/svn/llvm-project/clang-tools-extra/trunk extra
$ cd ../../../..
$ cd llvm/projects
$ svn co http://llvm.org/svn/llvm-project/compiler-rt/trunk compiler-rt
$ cd ~/llvm/
Histoire de ne pas “pourrir” notre belle arborescence on va créer un répertoire “build” pour créer llvm et clang. On aura donc 2 répertoires (llvm et build) dans le répertoire $HOME/llvm
$ mkdir build
$ cd build
$ ../llvm/configure --enable-optimized --enable-targets=host-only
Ça va prendre un peu de temps. Ceci fait, on lance la création de llvm et de clang avec make
$ make -j 8
$ su
# make install
# exit
Le -j 8
propose à make d’utiliser jusqu’à 8 “jobs” en parallèle. Ça tombe bien on a donné 4 cœurs à la machine virtuelle. Cela dit l’opération va prendre beaucoup de temps mais normalement à ce stade ça doit rouler sans problème. Profitez-en peut être pour aller, sur le web, lire un ou deux des articles ci-dessus.
Faisons un premier test
Faisons un test sur un code très, très simple.
#include <iostream>
#include <vector>
using namespace std;
int main(){
cout << "Hello World" << endl;
vector<int> vec;
vec.push_back(10);
vec.push_back(20);
for(int i:vec){
cout << i << endl;
}
return 0;
}
Si on compile le code source en question avec g++
$ g++ -std=c++0x test1.cpp -o test1
Après avoir testé que tout marche bien, voilà ce que donne ldd
$ ldd test1
linux-vdso.so.1 => (0x00007fffc11d8000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007ff891901000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007ff89167f000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007ff891468000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff8910de000)
/lib64/ld-linux-x86-64.so.2 (0x00007ff891c13000)
Maintenant qu’on a clang on peut aussi compiler test1.cpp
avec :
clang++ -std=c++0x test1.cpp -o test1
Si on demande à ldd de nous indiquer les lib utilisées, voilà ce que l’on obtient :
$ ldd test1
linux-vdso.so.1 => (0x00007fff2adff000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f260f583000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f260f301000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f260f0ea000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f260ed60000)
/lib64/ld-linux-x86-64.so.2 (0x00007f260f894000)
On remarque que l’exécutable utilise les bibliothèques fournies par gcc.
D’autre part, notez qu’on peut aussi invoquer la compilation via la ligne suivante :
$ clang++ -std=c++11 test1.cpp -o test1
Cela dit, même si la compilation du code test2.cpp (voir un peu plus bas) passe bien (pas de warning, rien…) à l’exécution ça part en vrille avec un message du style :
terminate called after throwing an instance of 'std::regex_error'
what(): regex_error
Abandon
C’est normal. En effet test2 utilise des regular expression qui font partie des specs C++11, qui sont normalement supportées par clang mais pas encore par gcc. Enfin bref, il faut qu’on lie notre clang avec une bibliothèque qui supporte C++11.
Faisons un autre test avec Sanitizer
#include <stdlib.h>
int main() {
char *x = (char*)malloc(10 * sizeof(char*));
free(x);
return x[5];
}
Si on compile avec :
$ clang -fsanitize=address test3.cpp -o test3
Lors de l’exécution voilà ce que l’on obtient :
=================================================================
==3133==ERROR: AddressSanitizer: heap-use-after-free on address 0x60700000dfb5 at pc 0x42fcc3 bp 0x7fff85463610 sp 0x7fff85463608
READ of size 1 at 0x60700000dfb5 thread T0
#0 0x42fcc2 (/home/philippe/devel/test3/test3+0x42fcc2)
#1 0x7f087eaf9eac (/lib/x86_64-linux-gnu/libc.so.6+0x1eeac)
#2 0x42fa2c (/home/philippe/devel/test3/test3+0x42fa2c)
0x60700000dfb5 is located 5 bytes inside of 80-byte region [0x60700000dfb0,0x60700000e000)
freed by thread T0 here:
#0 0x421251 (/home/philippe/devel/test3/test3+0x421251)
#1 0x42fc4e (/home/philippe/devel/test3/test3+0x42fc4e)
#2 0x7f087eaf9eac (/lib/x86_64-linux-gnu/libc.so.6+0x1eeac)
previously allocated by thread T0 here:
#0 0x421391 (/home/philippe/devel/test3/test3+0x421391)
#1 0x42fc14 (/home/philippe/devel/test3/test3+0x42fc14)
#2 0x7f087eaf9eac (/lib/x86_64-linux-gnu/libc.so.6+0x1eeac)
Shadow bytes around the buggy address:
0x0c0e7fff9ba0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c0e7fff9bb0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c0e7fff9bc0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c0e7fff9bd0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c0e7fff9be0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c0e7fff9bf0: fa fa fa fa fa fa[fd]fd fd fd fd fd fd fd fd fd
0x0c0e7fff9c00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c0e7fff9c10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c0e7fff9c20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c0e7fff9c30: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c0e7fff9c40: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Heap right redzone: fb
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack partial redzone: f4
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
ASan internal: fe
==3133==ABORTING
libc++abi et libc++
Pour pouvoir supporter C++11, il faut créer libc++abi
et libc++
(ABI = application binary interface). Afin de séparer les combattants je propose de créer un répertoire libstdcxx
dans $HOME
pour y construire les deux lib en question.
$ cd
$ mkdir libstdcxx
$ cd libstdcxx
$ svn co http://llvm.org/svn/llvm-project/libcxxabi/trunk libcxxabi
$ svn co http://llvm.org/svn/llvm-project/libcxx/trunk libcxx
À la fin, on a 2 répertoires libcxxabi
et libcxx
dans le répertoire $HOME/libstdcxx
Création de libc++abi :
$ cd libcxxabi/include
$ echo | g++ -Wp,-v -x c++ - -fsyntax-only
Dans la sortie console, il faut noter la ligne qui ressemble à : /usr/lib/gcc/x86_64-linux-gnu/4.7/include
. Dans mon cas j’obtiens un truc du style :
/usr/include/c++/4.7
/usr/include/c++/4.7/x86_64-linux-gnu
/usr/include/c++/4.7/backward
/usr/lib/gcc/x86_64-linux-gnu/4.7/include
/usr/local/include
/usr/lib/gcc/x86_64-linux-gnu/4.7/include-fixed
/usr/include/x86_64-linux-gnu
/usr/include
Afin d’aider le compilateur, copions, à partir du répertoire qu’on vient d’identifier, le fichier unwind.h
là où il l’attend :
$ cp /usr/lib/gcc/x86_64-linux-gnu/4.7/include/unwind.h .
Il ne faut pas oublier le “.” tout à la fin de la ligne ci-dessus.
Ceci fait il faut éditer le script buildit
$ cd ../lib
$ nano buildit
Bon, là y a un peu de boulot. En effet il faut :
- Supprimer
-stdlib=libc++
de la ligne EXTRA_FLAGS - Retrouver le case
$TRIPLE
puis un peu plus bas le case*)
- Supprimer le
-lstdc++
deLDSHARED_FLAG
(c’est tout à la fin de la définition) - Retrouver la ligne
for FILE in ../src/*.cpp; do
- Ajouter
-I../../libcxx/include
juste après$EXTRA_FLAGS
Sauver (CTRL + O), quitter (CTRL + X) nano puis taper dans la console
$ TRIPLE=-linux- ./buildit
Dans mon cas, cela n’a pas marché, j’avais des messages du style :
error: no member named 'aligned_alloc' in the global namespace
using ::aligned_alloc;
~~^
À la suite de diverses recherches et discussions (voir http://dragoonsheir.wordpress.com/2013/03/16/wayland-and-c11-programming-part-1-of-n/ et https://groups.google.com/forum/?fromgroups=#!topic/llvm-dev/5isiIWNpjv8 ) j’ai pu appliquer un patch. À partir d’un répertoire $HOME/tmp
dans lequel j’avais un fichier linux2.diff
, j’ai dû faire :
$ cp ../libstdcxx/libcxx/include/__config ./__config.bak
$ patch -p0 --dry-run ../libstdcxx/libcxx/include/__config < linux2.diff
$ patch -p0 ../libstdcxx/libcxx/include/__config < linux2.diff
Une fois le patch appliqué on recommence la procédure afin de compiler lic++abi
et dans la console on rentre la commande suivante :
$ TRIPLE=-linux- ./buildit
À la fin (si tout se passe bien) on se retrouve avec un fichier libc++abi.so.1.0
dans ./
Il faut installer le fichier en question à la bonne place dans l’arborescence.
$ su
cp libc++abi.so.1.0 /usr/lib/
cd /usr/lib
ln -s libc++abi.so.1.0 libc++abi.so
ldconfig
cd -
exit
Création de libc++ :
On approche du but! Il ne reste plus qu’à compiler libc++
. Dans le répertoire $HOME
on va créer un répertoire build_libc++ à côté des répertoires libcxx
et libcxxabi
.
$ cd ../../
$ mkdir build_libc++
$ cd build_libc++
$ CC=clang CXX=clang++ cmake -G "Unix Makefiles" -DLIBCXX_CXX_ABI=libcxxabi -DLIBCXX_LIBCXXABI_INCLUDE_PATHS="../libcxxabi/include" -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr ../libcxx
$ make -j 8
$ su
# make install
# exit
Ayé !!! Heu… En fait pas tout à fait. En effet, comme on a compilé clang avant libc++
on ne peut pas utiliser clang uniquement avec -stdlib=libc++
. À ce stade voilà toutefois ce que l’on peut faire pour inciter clang à utiliser libc++
et libc++abi
:
$ clang++ -stdlib=libc++ test1.cpp -lc++abi -o test1
Si jamais le warning vous gêne on peut faire :
$ clang++ -std=c++11 -stdlib=libc++ test1.cpp -lc++abi -o test1
Faisons un autre test
Si on compile test1
avec la ligne ci-dessus et si on lance ldd dessus voilà ce que l’on obtient.
$ ldd test1
linux-vdso.so.1 => (0x00007fffc51ff000)
libc++abi.so.1 => /usr/lib/libc++abi.so.1 (0x00007fb8964d4000)
libc++.so.1 => /usr/lib/libc++.so.1 (0x00007fb89621b000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fb895f98000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fb895d82000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb8959f8000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fb8957db000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007fb8955d3000)
/lib64/ld-linux-x86-64.so.2 (0x00007fb89672c000)
Pour rappel voilà ce que l’on avait la dernière fois quand on avait compilé test1 avec clang
$ ldd test1
linux-vdso.so.1 => (0x00007fff2adff000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f260f583000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f260f301000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f260f0ea000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f260ed60000)
/lib64/ld-linux-x86-64.so.2 (0x00007f260f894000)
On voit donc que dorénavant test1
est lié avec les lib de clang (libc++abi
et libc++
).
Pour le reste, je ne comprends pas trop la présence de libgcc_s
, libc
etc. J’aurai pensé qu’elles auraient été remplacées par des lib issues de clang. Faudra que je cherche/comprenne avant de revenir sur le sujet (stay tuned).
Compilation de clang avec clang
Puisque libc++
est construite, on peut dorénavant compiler clang en utilisant libc++
en lieu et place de libstdc++
. Super ! On va compiler clang avec clang !
$ cd ~/llvm/build
$ ../llvm/configure --enable-optimized --enable-targets=host --enable-cxx11=yes --enable-libcpp=yes --with-extra-ld-options="-lc++abi" 2>&1 | tee -a configure_trace.txt
$ VERBOSE=1 make -j 8 2>&1 | tee -a make_trace.txt
Rappelons-nous qu’avant on avait fait simplement :
$ ../llvm/configure --enable-optimized --enable-targets=host
$ make -j 8
Pour ceux qui le souhaitent, la liste des options possibles pour “configure” se trouve dans le fichier ~/llvm/llvm/configure
aux alentours de la ligne 1404 en ce qui me concerne. Au pire faites une recherche sur Optional Features. Bien sûr le VERBOSE=1
permet d’avoir plus d’informations à l’écran lors du make. En fait j’ai été obligé d’utiliser ce mode car, comme on le verra, j’ai eu des problèmes. À propos du 2>&1 | tee -a filename.txt
faut pas trop s’inquiéter. C’est juste un moyen d’avoir dans le fichier “filename.txt” la totalité de ce qui se passe à l’écran lors du configure
ou du make
.
Comme je l’ai dit, en ce qui me concerne j’ai eu des problèmes (encore) au niveau du make
. En gros j’ai rencontré 2 types de soucis.
Premier type de problème
À priori y avait des problèmes de fichiers include. Pour résoudre le problème j’ai relancé la commande suivante :
$ echo | g++ -Wp,-v -x c++ - -fsyntax-only
Comme précédemment cela me donnait la liste des chemins d’include utiles. Ensuite il a fallu modifier le fichier InitHeaderSearch.cpp en faisant :
$ cd ~/llvm
$ nano llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp
Ensuite, dans le fichier en question il faut faire une recherche (CTRL + W sous nano) du mot “FIXME:” et modifier le code en s’inspirant de ce qui suit :
// FIXME: temporary hack: hard-coded paths.
//AddPath("/usr/local/include", System, true, false, false);
AddPath("/usr/include/c++/4.7", System, true);
AddPath("/usr/include/c++/4.7/x86_64-linux-gnu/.", System, true);
AddPath("/usr/include/c++/4.7/backward", System, true);
AddPath("/usr/lib/gcc/x86_64-linux-gnu/4.7/include", System, true);
AddPath("/usr/local/include", System, true);
AddPath("/usr/lib/gcc/x86_64-linux-gnu/4.7/include-fixed", System, true);
AddPath("/usr/include/x86_64-linux-gnu", System, true);
AddPath("/usr/include", System, true);
Notez qu’il n’y a bien que 3 paramètres (et pas 5 comme on peut le voir sur d’autres sites web) dans la fonction AddPath. Ceci fait, on sauve (CTRL + O), on quitte (CTRL + X) et c’est parti. Rebelotte :
$ cd ~/llvm/build
$ ../llvm/configure --enable-optimized --enable-targets=host --enable-cxx11=yes --enable-libcpp=yes --with-extra-ld-options="-lc++abi" 2>&1 | tee -a configure_trace.txt
$ VERBOSE=1 make -j 8 2>&1 | tee -a make_trace.txt
$ su
# make install
# exit
Deuxième type de problème
C’est ceux sur lesquels je suis en ce moment (18/05/2013). En fait avec la version que je viens de récupérer je n’ai plus rencontré les problèmes de chemins à modifier dans InitHeaderSearch.cpp (le patch a été appliqué). Dorénavant, tout se passe bien à la compilation mais ça ratatouille au link. Voilà ce que je vois ce soir :
llvm[4]: Linking Release+Asserts Shared Library libclang.so
clang++ -I/home/philippe/llvm/build/include -I/home/philippe/llvm/build/tools/clang/tools/libclang -I/home/philippe/llvm/llvm/include -I/home/philippe/llvm/llvm/tools/clang/tools/libclang -D_DEBUG -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS$
-lclangFrontend -lclangDriver -lclangTooling -lclangSerialization -lclangParse -lclangSema -lclangARCMigrate -lclangRewriteFrontend -lclangRewriteCore -lclangAnalysis -lclangEdit -lclangAST -lclangLex -lclangBasic -lclangForma$
llvm[4]: Building Release+Asserts Archive Library libclang.a
/bin/rm -f /home/philippe/llvm/build/Release+Asserts/lib/libclang.a
ar cru /home/philippe/llvm/build/Release+Asserts/lib/libclang.a /home/philippe/llvm/build/tools/clang/tools/libclang/Release+Asserts/ARCMigrate.o /home/philippe/llvm/build/tools/clang/tools/libclang/Release+Asserts/CIndex.o /home/philip$
ranlib /home/philippe/llvm/build/Release+Asserts/lib/libclang.a
make[4]: quittant le répertoire « /home/philippe/llvm/build/tools/clang/tools/libclang »
make[4]: entrant dans le répertoire « /home/philippe/llvm/build/tools/clang/tools/c-index-test »
llvm[4]: Compiling c-index-test.c for Release+Asserts build
if clang -I/home/philippe/llvm/build/include -I/home/philippe/llvm/build/tools/clang/tools/c-index-test -I/home/philippe/llvm/llvm/include -I/home/philippe/llvm/llvm/tools/clang/tools/c-index-test -D_DEBUG -D_GNU_SOURCE -D__STDC_CONST$
then /bin/mv -f "/home/philippe/llvm/build/tools/clang/tools/c-index-test/Release+Asserts/c-index-test.d.tmp" "/home/philippe/llvm/build/tools/clang/tools/c-index-test/Release+Asserts/c-index-test.d"; else /bin/rm "/home$
llvm[4]: Linking Release+Asserts executable c-index-test (without symbols)
clang++ -I/home/philippe/llvm/build/include -I/home/philippe/llvm/build/tools/clang/tools/c-index-test -I/home/philippe/llvm/llvm/include -I/home/philippe/llvm/llvm/tools/clang/tools/c-index-test -D_DEBUG -D_GNU_SOURCE -D__STDC_CONSTAN$
-lLLVMBitReader -lLLVMAsmParser -lLLVMX86Disassembler -lLLVMX86AsmParser -lLLVMX86CodeGen -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMMCParser -lLLVMCodeGen -lLLVMObjCARCOpts -lLLVMScalarOpts -lLLVMInstCombine -lLLVMTransformUtils$
/home/philippe/llvm/build/Release+Asserts/lib/libclang.so: undefined reference to `std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string const&)'
/home/philippe/llvm/build/Release+Asserts/lib/libclang.so: undefined reference to `std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(char const*, std::allocator<char> const&)'
/home/philippe/llvm/build/Release+Asserts/lib/libclang.so: undefined reference to `std::string::_Rep::_M_destroy(std::allocator<char> const&)'
/home/philippe/llvm/build/Release+Asserts/lib/libclang.so: undefined reference to `std::string::_Rep::_S_empty_rep_storage'
/home/philippe/llvm/build/Release+Asserts/lib/libclang.so: undefined reference to `std::string::assign(std::string const&)'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[4]: *** [/home/philippe/llvm/build/Release+Asserts/bin/c-index-test] Erreur 1
make[4]: quittant le répertoire « /home/philippe/llvm/build/tools/clang/tools/c-index-test »
make[3]: *** [all] Erreur 1
make[3]: quittant le répertoire « /home/philippe/llvm/build/tools/clang/tools »
make[2]: *** [all] Erreur 1
make[2]: quittant le répertoire « /home/philippe/llvm/build/tools/clang »
make[1]: *** [clang/.makeall] Erreur 2
make[1]: quittant le répertoire « /home/philippe/llvm/build/tools »
make: *** [all] Erreur 1
J’ai beau chercher pour l’instant je ne trouve pas de solution. Ce qu’il y a de bizarre c’est qu’en allant sur le web ce type d’erreur (undefined reference
) ressemble aux erreurs générées lorsque c’est libstc++
(gcc) qui est liée au lieu de libc++
(clang). À ce stade je cherche, cherche…
Un gros merci fulvioesposito qui via son blog m’a donné LA solution. Faut juste faire un make clean
afin de mettre tout le monde d’accord. Les commandes à utiliser deviennent donc :
$ cd ~/llvm/build
$ make clean
$ ../llvm/configure --enable-optimized --enable-targets=host --enable-cxx11=yes --enable-libcpp=yes --with-extra-ld-options="-lc++abi" 2>&1 | tee -a configure_trace.txt
$ VERBOSE=1 make -j 8 2>&1 | tee -a make_trace.txt
$ su
# make install
# exit
Tout doit bien se passer maintenant
Faisons un dernier test
Si on compile le code test2.cpp
ci-dessous avec la commande suivante tout se passe bien :
$ clang++ -std=c++11 -stdlib=libc++ test2.cpp -lc++abi -o test2
Pour info voici le code de test2:
#include <iostream>
#include <regex>
#include <string>
using namespace std;
int main(){
string input;
regex rr("((\\+|-)?[[:digit:]]+)(\\.(([[:digit:]]+)?))?((e|E)((\\+|-)?)[[:digit:]]+)?");
//As long as the input is correct ask for another number
while(true){
cout<<"Give me a real number!"<<endl;
cin>>input;
//Exit when the user inputs q
if(input=="q")
break;
if(regex_match(input,rr))
cout<<"float"<<endl;
else{
cout<<"Invalid input"<<endl;
}
}
}
Conclusion temporaire
Si on s’amuse à faire
$ ldd /usr/local/bin/clang
Voilà ce que l’on obtient
linux-vdso.so.1 => (0x00007fffde0df000)
libc++abi.so.1 => /usr/lib/libc++abi.so.1 (0x00007f699b8be000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f699b6a2000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f699b499000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f699b295000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f699b013000)
libc++.so.1 => /usr/lib/libc++.so.1 (0x00007f699ad58000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f699ab42000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f699a7b8000)
/lib64/ld-linux-x86-64.so.2 (0x00007f699bb16000)
Si maintenant on fait
ldd /lib/x86_64-linux-gnu/libgcc_s.so.1
Voilà ce que l’on voit :
linux-vdso.so.1 => (0x00007fffb27ff000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f76b1bed000)
/lib64/ld-linux-x86-64.so.2 (0x00007f76b2198000)
Autrement dit si on arrive à s’affranchir de ligcc_s
dans clang on supprimera aussi libc
. D’après ce que je crois avoir compris, la recommandation est de construire clang à partir de la lib compiler-rt pour y arriver. C’est ce sur quoi je suis actuellement. La suite au prochain épisode.
Teaser à propos de la suite
Ne perdez pas trop de temps ici. Pour l’instant cette section est surtout pour moi et c’est vraiment “en travaux”.
Pour finir, comment ça marche toutes ces lib ? Voilà ce que je crois avoir compris dans le cas de gcc
Application - libstdc++ - libgcc-s - libc
- Application : c’est mon code c++
- libstdc++ : lib qui permet le support du c++ (STL)
- libgcc-s : bibliothèque partagée pour le support des exceptions
- libc :
Dans le cas de clang, finalement, si on veut une pile complètement indépendante de gcc, il faudra que l’on ait un truc du style
Application - libc++ - libc++abi - libunwind - librt - libc
- Application : c’est mon code c++
- libc++ : c’est la lib qui permet le support du c++11 (STL, remplace libstdc++)
- libc++abi : lib de bas niveau
- libunwind : bibliothèque de support pour les exceptions (remplace libgcc-s)
- libcxxrt : c’est la bibliothèque runtime du compilateur (remplace libgcc-s)
- libc :
À ce stade il faut donc qu’on arrive à intégrer compiler-rt
et libunwind
dans notre pile. C’est les deux pièces manquantes. En effet on a clang
, libc++
et libc++abi
.
Ce qui n’est pas très cool c’est qu’en cherchant un peu, d’un côté on nous dit que compiler-rt
ne peut être crée toute seule (la lib fait partie de l’arborescence llvm) et d’un autre on nous dit qu’on peut créer libc++
en s’appuyant sur libcxxrt
mais que cette dernière doit être compilée et disponible là où le linker l’attend… Heu on se mord la queue là. Non ?