Clang Tutorial
Clang Tutorial
2. Proyecto LLVM 2
3. Ventajas de Clang 3
4. Instalación 4
4.1. Instalación manual . . . . . . . . . . . . . . . . . . . . . . . . . . 5
4.2. Instalación con paquetes APT . . . . . . . . . . . . . . . . . . . . 5
5. Opciones 5
1
2 PROYECTO LLVM 2
1. Introducción a Clang
Clang es un compilador de código abierto para los lenguajes de la familia C:
C, C++, Objective-C y Objective-C++1 [1]. Se trata de un compilador reciente,
cuyo desarrollo comenzó en 2005 y su primera versión con licencia de código
abierto se produjo en 2007. La versión actual de Clang es la 3.7, lanzada en sep-
tiembre de 2015, aunque el desarrollo es bastante activo y salen nuevas versiones
del producto con cierta frecuencia. El origen de este compilador, que surge del
proyecto LLVM, será comentado en §2. En este documento, se emplea la versión
3.6 para sistema Ubuntu 14.04, aunque también se darán algunas indicaciones
respecto a las versión 3.4 cuando sea necesario.
Clang está escrito en C++ y puede ser utilizado en sistemas operativos ba-
sados en Unix. El compilador más conocido y usado para estos lenguajes ha
sido y sigue siendo GCC (GNU Compiler Collection), desarrollado por el pro-
yecto GNU para dar soporte a diversos lenguajes de programación. Sin em-
bargo, existe una gran variedad de compiladores para estos y otros lenguajes
(http://en.wikipedia.org/wiki/List_of_compilers). Clang a día de hoy
puede ser usado como una alternativa directa al compilador GCC, ofreciéndonos
ciertas ventajas, entre las que destaca su diseño modular para el análisis estático
del código. Estas ventajas serán enumeradas en §3, y el análisis estático basado
en el árbol de sintaxis abstracta será abordado en §6 y §7.
Para facilitar su uso a usuarios acostumbrados a GCC, el proyecto Clang ha
buscado que el frontend sea altamente compatible con este compilador. De esta
manera, podemos encontrar que el uso por línea de comandos es muy similar
y que muchas de las opciones incluidas son compartidas, como se verá más
adelante en §5. Para completar el documento, se mostrará la instalación de la
herramienta en §4 y se darán unos apuntes finales sobre el análisis estático de
código en §8.
2. Proyecto LLVM
Para entender el origen de Clang, primero es necesario conocer la existencia
del proyecto LLVM. LLVM es un proyecto de código abierto que busca la creación
de compiladores para cualquier lenguaje de programación, proporcionando la
infraestructura necesaria para su desarrollo. No obstante, hay que destacar que,
inicialmente, la idea del proyecto era centrarse en los lenguajes C y C++. Dentro
de un compilador, podemos distinguir entre frontend y backend: el frontend
traduce el código fuente en una representación intermedia, la cual es entendible
por el backend, que convierte finalmente esta representación en código máquina.
LLVM, como backend, provee de las capas intermedias para conformar un sistema
de compilación completo, tomando la representación interna generada por el
frontend creado para un determinado lenguaje de programación.
LLVM, siguiendo en la línea de compatibilidad con GCC, puede ser configu-
rado para ser usado con este compilador a fin de poder disponer de un frontend
y poder tratar cualquiera de los lenguajes que GCC incluye2 . Es decir, que se
este documento nos centramos en los lenguajes C y C++.
1 En
2 AunqueGCC inicialmente se diseñó para compilar lenguaje C, posteriormente se extendió
para abarcar también a C++. Más adelante se desarrollaron frontends para otros lenguajes,
que pueden consultarse en http://gcc.gnu.org/frontends.html
3 VENTAJAS DE CLANG 3
puede utilizar GCC como frontend para un determinado lenguaje, de forma que
se emplee LLVM como backend para constituir una herramienta completa. Sin
embargo, existen varios subproyectos en el proyecto LLVM para la construcción
de nuevos frontends para diferentes lenguajes que trabajen de forma específica
sobre LLVM (http://llvm.org/ProjectsWithLLVM), tal como Ruby, Python o
PHP. Muchos de estos proyectos han atraído la atención para su uso tanto en
desarrollos comerciales como de código abierto.
Clang es uno de los subproyectos originados del proyecto LLVM y que se
dedica a la familia de lenguajes de C. Se trata de uno de los proyectos más
consolidados, ya que incluso se distribuye con las versiones de LLVM, y, como
proyecto de código abierto, es posible utilizar las bibliotecas que emplea. Clang
forma parte de las versiones que lanza LLVM desde su versión 2.6 en octubre de
2009, lo que demuestra la madurez e importancia del mismo.
3. Ventajas de Clang
Como se comentó en §1, una de las mayores ventajas de Clang es el diseño
modular de su desarrollo, que parece ser uno de los pilares desde la concep-
ción del proyecto. Esto nos permite disponer de una API muy bien diseñada y
poder emplearla para la construcción de nuestras propias herramientas para el
análisis del código, de la misma manera en la que el frontend lo hace al com-
pilarlo. En otras palabras, como proyecto de código abierto, podemos reutilizar
las bibliotecas que nos ofrece el proyecto Clang para embeber de forma senci-
lla el compilador en las nuevas aplicaciones que estemos desarrollando, lo cual
no es tan sencillo en otros compiladores como GCC. Entre las actividades que
podemos emprender gracias a esto, podemos mencionar el análisis estático, la
refactorización o la generación de código.
A continuación, se enumeran algunas de las ventajas que el proyecto Clang
proclama:
Uno de sus objetivos es reducir el tiempo de compilación y el uso de la
memoria. Su arquitectura puede permitir de forma más directa el crear
perfiles del coste de cada capa. Además, cuanta menos memoria toma el
código, mayor cantidad del mismo se podrá incluir en memoria al mismo
tiempo, lo cual beneficia el análisis del código.
Informa de errores y avisos de una manera muy expresiva para que sea lo
más útil posible, indicando exactamente el punto en el que se produce el
error e información relacionada con el mismo.
Por otra parte, podemos comentar las siguientes ventajas de Clang sobre
GCC:
4. Instalación
En la siguiente página, http://clang.llvm.org/get_started.html, apa-
recen instrucciones para comenzar con Clang. Como el compilador forma parte
de las versiones de LLVM, lo mejor es acceder a http://llvm.org/releases/
para obtener la última versión. En caso de que quieras involucrarte en el desa-
rrollo del proyecto, puedes seguir las instrucciones del apartado “Building Clang
and Working with the Code” para obtener el código, y también acceder a la pá-
gina http://clang.llvm.org/get_involved.html para saber cómo actuar en
este caso.
Para el enlazado del código mostrado en §7, es posible que necesite instalar
las siguientes librerías a fin de evitar errores comunes con el enlazador ld de
GNU:
5. Opciones
El formato de uso de Clang es el siguiente:
o C++, puedes obtenerlos tras instalar el paquete build-essential mediante la orden sudo
apt-get install build-essential
6 ÁRBOL DE SINTAXIS ABSTRACTA 6
sed -r "s/\x1B\\[([0-9]{1,2}(;[0-9]{1,2})*)?[mGK]//g" \
ast_ejemplo_auxiliar.txt > ast_ejemplo_final.txt
7 ANÁLISIS ESTÁTICO CON CLANG 8
using namespace c l a n g : : t o o l i n g ;
using namespace llvm ;
using namespace c l a n g ;
class FindNumberClassesVisitor
: public R e c u r s i v e A S T V i s i t o r <F i n d N u m b e r C l a s s e s V i s i t o r >{
public :
e x p l i c i t F i n d N u m b e r C l a s s e s V i s i t o r ( ASTContext ∗ Context )
: Context ( Context ) { c o u n t e r = 0 ; }
i f ( FullLocation . isValid ()
&& ! Context−>getSourceManager ( ) .
isInSystemHeader ( FullLocation ) )
c o u n t e r ++;
}
return true ;
}
unsigned i n t g e t C o u n t e r ( ) { return c o u n t e r ; }
private :
ASTContext ∗ Context ;
unsigned i n t c o u n t e r ;
};
7 http://clang.llvm.org/doxygen/
7 ANÁLISIS ESTÁTICO CON CLANG 10
v i r t u a l void H a n d l e T r a n s l a t i o n U n i t (
c l a n g : : ASTContext &Context ) {
V i s i t o r . T r a v e r s e D e c l ( Context . g e t T r a n s l a t i o n U n i t D e c l ( ) ) ;
llvm : : o u t s ( ) << " El ␣ t o t a l ␣ de ␣ c l a s e s ␣ e s : ␣ "
<< V i s i t o r . g e t C o u n t e r ( ) << " \n " ;
}
private :
FindNumberClassesVisitor V i s i t o r ;
};
c l a s s FindNumberClassesAction :
public c l a n g : : ASTFrontendAction {
public :
v i r t u a l s t d : : unique_ptr<ASTConsumer> CreateASTConsumer (
c l a n g : : C o m p i l e r I n s t a n c e &Compiler , llvm : : S t r i n g R e f I n F i l e ) {
return s t d : : unique_ptr<c l a n g : : ASTConsumer>(
new FindNumberClassesConsumer (
&Compiler . getASTContext ( ) ) ) ;
}
};
8 Este código ha sido validado en la versión 3.4 de Clang, pero es posible que algún método
varíe en versiones posteriores, por lo que sería necesario adaptar el código a los cambios
introducidos.
7 ANÁLISIS ESTÁTICO CON CLANG 11
Version 3.4 Este código no es compatible hacia atrás con la versión 3.4 de
Clang debido a varios cambios que se realizaron en las librerías en la versión
3.5. Los cambios a realizar son los siguientes:
Cambiar:
c l a s s FindNumberClassesAction :
public c l a n g : : ASTFrontendAction {
public :
v i r t u a l s t d : : unique_ptr<ASTConsumer> CreateASTConsumer (
c l a n g : : C o m p i l e r I n s t a n c e &Compiler , llvm : : S t r i n g R e f I n F i l e ) {
return s t d : : unique_ptr<c l a n g : : ASTConsumer>(
new FindNumberClassesConsumer (
&Compiler . getASTContext ( ) ) ) ;
}
};
por:
c l a s s FindNumberClassesAction :
public c l a n g : : ASTFrontendAction {
public :
v i r t u a l c l a n g : : ASTConsumer ∗ CreateASTConsumer (
c l a n g : : C o m p i l e r I n s t a n c e &Compiler , llvm : : S t r i n g R e f I n F i l e ) {
return new FindNumberClassesConsumer (
&Compiler . getASTContext ( ) ) ;
}
};
Cambiar:
por:
Cambiar:
por:
CXX := clang++
RTTIFLAG := -fno-rtti
CXXFLAGS := $(shell llvm-config --cxxflags) $(RTTIFLAG)
LLVMLDFLAGS := $(shell llvm-config --ldflags --libs --system-libs)
SOURCES = clases_file.cpp
OBJECTS = $(SOURCES:.cpp=.o)
EXES = $(OBJECTS:.o=)
CLANGLIBS = \
-lclangFrontend \
-lclangSerialization \
-lclangDriver \
-lclangTooling \
-lclangParse \
-lclangSema \
-lclangAnalysis \
-lclangEdit \
-lclangAST \
-lclangASTMatchers \
-lclangLex \
-lclangBasic \
-lclangRewrite
clases_file: clases_file.o
$(CXX) -o $@ $^ $(CLANGLIBS) $(LLVMLDFLAGS)
Version 3.4 Para la versión 3.4, realizar los siguientes cambios en el makefile:
Cambiar:
LLVMLDFLAGS := $(shell llvm-config --ldflags --libs \
--system-libs)
por:
LLVMLDFLAGS := $(shell llvm-config --ldflags --libs) \
-ldl
Cambiar:
-lclangRewrite
por:
-lclangRewriteCore \
-lclangRewriteFrontend
Si nos fijamos en el comando, este termina en --; justo tras estos guiones
podemos indicar opciones a Clang (vea §5) si fuese necesario, por ejemplo, para
señalar que hay una cabecera que ha de ser buscada en otro directorio (vea §8
para conocer una alternativa a este sistema).
Si el fichero ejemplo_clases.cpp es el siguiente:
c l a s s A;
class A {};
class B {};
class C;
Clase : A
Clase : B
El total de clases es: 2
Referencias
[1] Clang: a C language family frontend for LLVM clang.llvm.org Acceso:
04/11/2014. 2
REFERENCIAS 15
[5] Larry Olson. A collection of code samples showing usage of Clang and LLVM
as a library https://github.com/loarabia/Clang-tutorial/ Acceso:
04/11/2014. 14
[6] Elias Penttilä. Improving C++ software quality with static code analysis.
Tesis de Master, Aalto University, School of Science, Mayo 2014. 14
Este documento se escribió con Emacs, procesó con LATEX 2ε , y convirtió a PDF
mediante pdflatex. La versión de Clang y LLVM empleada ha sido la 3.6, en el sistema
GNU/Ubuntu Linux 14.04.
Se han usado los tipos Latin Modern.
Copyright © 2015 Pedro Delgado Pérez, Departamento de Ingeniería Informática,
Universidad de Cádiz.