lunes, 27 de enero de 2014

Instalando SublimeClang para SublimeText en Ubuntu 13.10: autocompletado de C++

Supongo que tener un blog y no publicar nada es una tontería, ¿verdad?
Pero, con el permiso de Saramago, quizá "no tenía nada que decir", claro.

El caso es que se me ha ocurrido que pudiera ser de utilidad documentar cómo he conseguido que el fantástico editor de textos Sublime Text 3 me ofrezca autocompletado y comprobación "en vivo" de errores en código C/C++/ObjC. Todo ello gracias al plugin SublimeClang.


Sublime Text 3 tiene muchas características que lo hacen increiblemente interesante. Que se me vengan a la cabeza: es muy ligero; la posibilidad de usar varios cursores a la vez (¿cómo se podía programar sin usar varios cursores?); los 'snipets'; no necesitar usar el ratón; pero, sobre todo, los plugins.

SublimeText permite escribir plugins en Python para aumentar su funcionalidad. Sin estos plugins, SublimeText es notable, pero es con ellos que se convierte en el mejor editor de código fuente que conozco. Se convierte incluso en un mini-IDE que cubre sobradamente mis necesidades.

Llevo un tiempo buscando alternativas al Eclipse CDT para programar en C++. Y creo que SublimeText junto al plugin SublimeClang y unos cuantos snipets me son más que suficientes.

Desafortunadamente, SublimeClang es muy complicado de instalar y su autor (Fredrik Ehnbom) lo ha dejado de mantener.
He conseguido instalarlo y que me funcione en Ubuntu 13.10 y quizás sea de utilidad a otros si comparto cómo lo conseguí.

Antes que nada, conviene saber que si se intenta usar el plugin Package Control para instalar SublimeClang, no funcionará. Al menos a mí no me ha funcionado. Y he intentado mil variantes. Lo que sí me ha funcionado, y eso es lo que aquí describo, es instalarmelo de forma manual.

SublimeClang utiliza los "bindings" Python de la librería libclang. Estos bindings necesitan para funcionar disponer de la librería de enlace dinámico "libclang.so". Los bindings Python de libclang utilizados por SublimeClang son los de la versión 3.4. Y, afortunadamente, Ubuntu 13.10 dispone de la librería liblclang 3.4. Así que lo primero es instalarla para evitarnos compilarla desde los fuentes:
sudo apt-get install libclang-3.4-dev cmake
He aprovechado para instalar CMake porque nos será necesario.

La primera vez que Sublime Text 3 arranca, se crea el directorio $HOME/.config/sublime-text-3 donde almacenará, entre otros, los paquetes instalados.
Si todavía no lo has arrancado nunca, hazlo y después cierralo.
Nos cambiamos entonces al subdirectorio Packages de dicho directorio:
cd ~/.config/sublime-text-3/Packages
Y ahora debemos descargar el plugin en sí:
git clone --recursive https://github.com/quarnster/SublimeClang SublimeClang
Si estás detrás de un proxy, este paso te va a dar muchos quebraderos de cabeza. Quizás en otra entrada del blog cuente cómo conseguí, a duras penas, "atravesar" el proxy de mi empresa. Pero no será en este.

El caso es que si todo te fué bien, deberías tener creado el directorio SublimeClang.
Pero no es lo único: SublimeClang usa un subproyecto Git que también deberías tener creado. Haz un
ls -l ~/.config/sublime-text-3/Packages/SublimeClang/internals/parsehelp
y te debe mostrar esto:
-rw-rw-r-- 1 test test     24 ene 24 13:51 __init__.py
-rw-rw-r-- 1 test test  21579 ene 24 13:51 parsehelp.py
-rw-rw-r-- 1 test test   1650 ene 24 13:51 unittest.cpp
-rw-rw-r-- 1 test test 160576 ene 24 13:51 unittest.py

Si acaso no se hizo, puedes probar esto:
cd ~/.config/sublime-text-3/Packages/SublimeClang
git pull && git submodule foreach --recursive git pull origin master
    Si esto también te fallara, puedes probar a volver a crear el submódulo:
cd ~/.config/sublime-text-3/Packages/SublimeClang
git rm internals/parsehelp
git submodule add https://github.com/quarnster/parsehelp.git internals/parsehelp
Fíjate que esta vez uso https en vez de git como protocolo. Esto necesité hacerlo por el tema del proxy.


Ahora toca compilar una de las librerías que vienen con SublimeClang.
Y será necesario que libclang.so esté en su sitio.
Aprovechandonos de que la hemos instalado en Ubuntu, es sencillo:
cd ~/.config/sublime-text-3/Packages/SublimeClang/internals
cp /usr/lib/llvm-3.4/lib/libclang.so .
chmod a+x libclang.so
Y ya por fin compilamos:
cd ../src
mkdir build
cd build/
cmake ..
make
Al final, deberíamos tener dos librerías de enlace dinámico en el subdirectorio "internals":
  • libclang.so
  • libcache.so
Y un ldd sobre ellas no debería fallar:
~/.config/sublime-text-3/Packages/SublimeClang/internals$ ldd libclang.so
        linux-vdso.so.1 =>  (0x00007fff4eb1d000)
        libLLVM-3.4.so.1 => /usr/lib/x86_64-linux-gnu/libLLVM-3.4.so.1 (0x00007fbed92c3000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fbed90a6000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fbed8ea1000)
        libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fbed8b9d000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fbed8987000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fbed85be000)
        libffi.so.6 => /usr/lib/x86_64-linux-gnu/libffi.so.6 (0x00007fbed83b6000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fbed80b2000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fbedb91d000)
~/.config/sublime-text-3/Packages/SublimeClang/internals$ ldd libcache.so
        linux-vdso.so.1 =>  (0x00007fffb93fe000)
        libclang.so => /home/test/.config/sublime-text-3/Packages/SublimeClang/src/../internals/libclang.so (0x00007f793619f000)
        libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f7935e68000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f7935c52000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f793588a000)
        libLLVM-3.4.so.1 => /usr/lib/x86_64-linux-gnu/libLLVM-3.4.so.1 (0x00007f7933fe1000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f7933dc4000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f7933bc0000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f79338bb000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f7937139000)
        libffi.so.6 => /usr/lib/x86_64-linux-gnu/libffi.so.6 (0x00007f79336b3000)
Ejecuta ahora Sublime Text y abre la consola (view > show console). Deberías encontrar estas líneas:
reloading plugin SublimeClang.staticanalyzer
reloading plugin SublimeClang.sublimeclang
Have SublimeClang package: 1.0.41
Have SublimeClang libcache: 1.0.41
Si es así, todo va bien. Sigamos.
Crea un nuevo fichero vacío y sálvalo con una extension C++. Por ejemplo, "prueba.cc"
En la parte de abajo del Sublime, en la línea de información, debería aparecer algo similar a "Reparsing 'prueba.cc' done".
Eso indica que SublimeClang está funcionando.

Teclea el siguiente contenido:
struct A
{
    void f();
    int g(bool b);
};

int main()
{
    A a;
    a.
Justo en ese momento, cuando has tecleado el punto, debe aparecer un popup que nos da a elegir entre las únicas dos posibilidades:
  • f()
  • g(bool b)
Si es así, enhorabuena. Si no es así... uf, yo me pasé horas pegándome con estas cosas.

Pero el plugin va mas allá. Imaginemos que en vez de f o g nos encabezonamos en poner pepe:
struct A
{
    void f();
    int g(bool b);
};

int main()
{
    A a;
    a.pepe();
}
En cuanto salvemos el fichero, SublimeClang "compilará" el fichero y nos marcará los errores:
    prueba.cc:11,4 - Error - no member named 'pepe' in 'A'

Un ejemplo visual:


Ea, ahí van todos los comandos que he ido describiendo, por si quieres copy&pastear:

sudo apt-get install libclang-3.4-dev cmake
cd ~/.config/sublime-text-3/Packages
git clone --recursive https://github.com/quarnster/SublimeClang SublimeClang
cd ~/.config/sublime-text-3/Packages/SublimeClang/internals
cp /usr/lib/llvm-3.4/lib/libclang.so .
chmod a+x libclang.so
cd ../src
mkdir build
cd build/
cmake ..
make

Cosas que me dejo para otras entradas del blog:

  • mis preferencias de teclado (¡por defecto, ctrl+espacio no hace saltar el autocompletado!)
  • cómo pasar parámetros al compilador interno de SublimeClang.
  • cómo navegar por el código (si, SublimeClang también permite navegar por el código)
  • cómo hacer para que se obtengan los parámetros anteriores del propio sistema de compilación.
  • cómo hice para que SublimeClang funcionara con codificaciones distintas de UTF-8. Si se te ocurre guardar el fichero fuente C++ en una codificación distinta de UTF-8, el plugin falla.


No hay comentarios:

Publicar un comentario