IMPORTANT: Per accedir als fitxer de subversion: http://acacha.org/svn (sense password). Poc a poc s'aniran migrant els enllaços. Encara però funciona el subversion de la farga però no se sap fins quan... (usuari: prova i la paraula de pas 123456)

Exemple senzill pels impacients

Instal·leu el paquet build-essential:

$ sudo apt-get install build-essential 
S'està llegint la llista de paquets... Fet 
S'està construint l'arbre de dependències       
Reading state information... Fet           
S'instal·laran els següents paquets extres:
  dpkg-dev g++ g++-4.2 libc6-dev libstdc++6-4.2-dev libtimedate-perl linux-libc-dev patch
Paquets suggerits:
  debian-keyring g++-multilib g++-4.2-multilib gcc-4.2-doc libstdc++6-4.2-dbg glibc-doc manpages-dev \ 
libstdc++6-4.2-doc diff-doc
S'instal·laran els següents paquets NOUS:
  build-essential dpkg-dev g++ g++-4.2 libc6-dev libstdc++6-4.2-dev libtimedate-perl linux-libc-dev patch
0 actualitzats, 9 nous a instal·lar, 0 a eliminar i 0 no actualitzats.
Es necessita obtenir 8702kB d'arxius.
After this operation, 34,3MB of additional disk space will be used.
Voleu continuar [S/n]? 

Es recomanable instal·lar els paquets suggerits:

$ sudo apt-get install debian-keyring g++-multilib g++-4.2-multilib gcc-4.2-doc \
libstdc++6-4.2-dbg glibc-doc manpages-dev libstdc++6-4.2-doc diff-doc

Ara ja teniu totes les eines necessàries per a compilar aplicacions en C. Per exemple, el típic hola mon. Primer creem un directori on treballar:

$ cd
$ mkdir holamon
$ cd holamon

Ara instal·leu un Editor de text per a modificar el fitxer. Per exemple ho podeu fer amb joe:

$ sudo apt-get install joe
$ joe holamon.c

Escriviu el següent codi:

#include <stdio.h>

int main() {
   printf("Hola mon!\n");
   return 0;
}

I compilem amb:

$ gcc -Wall holamon.c -o holamon

On:

  • gcc: És el compilador de C de GNU (gNU C Compiler)
  • -Wall: Són les opcions passades al compilador gcc.
  • holamon.c: és el codi font en C
  • -o holamon: indiquem el nom del fitxer binari executable que creem.

Veiem que s'ha creat un fitxer executable nou anomenat holamon:

$ ls -l
total 16
-rwxr-xr-x 1 sergi sergi 6364 2008-06-28 10:37 holamon
-rw-r--r-- 1 sergi sergi   79 2008-06-28 10:37 holamon.c
-rw-r--r-- 1 sergi sergi   78 2008-06-28 10:37 holamon.c~

Sabem que és executable per la x dels permisos (vegeu Permisos Linux). L'executem amb:

$ ./holamon 
Hola mon!

Eines

GNU toolchain

CompilacioMuntatge3.png

GNU toolchain és un terme que s'utilitza per referir-se a un conjunt d'eines de programació creades pel projecte GNU. Aquestes eines s'utilitzen en cadena (s'utilitzen en sèrie) per tal de desenvolupar aplicacions i sistemes operatius.

GNU toolchain té un rol vital en la creació del kernel de Linux, BSD i en programari per a sistemes encastats.

Els projectes inclosos a GNU Toolchain són:

En cada fase (veieu imatge de la dreta) intervé una eina diferent de la cadena:

  • Edició: Editors de text com vi, emacs, joe... o Entorns de desenvolupament Integral (IDE)
  • Compilació: En sistemes Unix típicament GCC
  • Muntatge: Intervenen el assemblador GNU i el enllaçador de GNU (ld)
    • Llibreries: De llibreries em podem trobar moltes però la més important és la llibreria estàndard de C. En sistemes Unix la implementació d'aquesta llibreria més utilitzada és glibc (GNU libc).
  • Carregador: El carregador en sistemes Unix és la crida al sistema execve.


GNU Compiler Collection (GCC)

Gccegg-65.png

GNU Compiler Collection (GCC) és un conjunt de compiladors i un front-end creat pel projecte GNU per a diferents llenguatges de programació. GCC és el component clau de GNU toolchain i és el compilador oficial dels sistemes GNU/Linux, BSD i Mac OS X. GCC ha estat portat a altres arquitectures, programari propietari i sistemes com Symbian, Playstation o Sega Dreamcast.

Originalment és deia GNU C Compiler perquè només era capaç de treballar amb el llenguatge de programació C (GCC 1.0 va ser creat el 1987). Més tard es va incorporar suport per a C++. Actualment també es pot utilitzar per compilar els següents llenguatges de programació:

  • Fortran
  • Pascal
  • Objective C
  • Java
  • Ada
  • ...

GCC es distribuït per la Free Software Foundation (FSF) sota les llicències GNU General Public License (GNU GPL) i GNU Lesser General Public License (GNU LGPL), GCC és programari lliure.

Recursos:

Exemples d'ús

Exemple hello.c:

#include <stdio.h>
int main (void) {
 printf ("Hello, world!\n");
 return 0;
}
  • Obtenir la versió:
$ gcc -v
Usant especificacions internes.
Target: i486-linux-gnu
Configurat amb: ../src/configure -v --enable-languages=c,c++,fortran,objc,obj-c++,treelang --prefix=/usr --enable-shared --with-system-zlib  
--libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --enable-nls --with-gxx-include-dir=/usr/include/c++/4.1.3 --program- suffix=-4.1  
--enable-__cxa_atexit --enable-clocale=gnu --enable-libstdcxx-debug --enable-mpfr --enable-checking=release i486-linux-gnu
Model de fils: posix
gcc versió 4.1.3 20070929 (prerelease) (Ubuntu 4.1.2-16ubuntu2)
$ gcc -Wall hello.c -o hello

La opció -o indica el nom del fitxer executable (fitxer amb codi màquina). hello.c és el codi font i la opció -Wall indica que volem que es mostrin tots els avisos/warnings (és molt recomanable utilitzar aquesta opció sempre). Per executar el programa:

$ ./hello
Hello, world!

Si no s'especifica l'opció -o:

 $ gcc -Wall hello.c

El fitxer de sortida és el fitxer:

a.out

També executable (./a.out).

$ gcc -Wall main.c hello_fn.c -o newhello


$ gcc main.o hello.o -o hello

S'utilitza el paràmetre -g.

$ gcc -Wall -g null.c

Ara ja podem utilitzar gdb per depurar.

$ gcc -Wall -I/opt/gdbm-1.8.3/include -L/opt/gdbm-1.8.3/lib dbmain.c -lgdbm

o alternativament utilitzar la variable d'entorn:

$ LIBRARY_PATH=/opt/gdbm-1.8.3/lib
$ export LIBRARY_PATH

També són importants les variables d'entorn:

$ LD_LIBRARY_PATH=/opt/gdbm-1.8.3/lib
$ export LD_LIBRARY_PATH

i

C_INCLUDE_PATH=.:/opt/gdbm-1.8.3/include:/net/include
$ gcc -Wall -O0 test.c -lm

GNU make

Exemples d'ús

Creeu un fitxer anomenat Makefile

CC=gcc 
CFLAGS=-Wall
main: main.o hello_fn.o 

clean:
 	rm -f main main.o hello_fn.o

Aquest fitxer indica que utilitzarem gcc com a compilador i amb l'opció -Wall i que crearem un executable a partir dels fitxers objecte main.o i hello_fn.o. Com a norma implícita, al seu torn, els fitxer .o es generen a partir dels fitxers .c equivalents.

La norma clean no té dependències i elimina els fitxers compilats.

Per utilitzar aquest fitxer podem executar:

$ make

Si no donem cap opció s'exeduta la primera norma (en aquest cas main)

Si volem executar la norma clean executem:

$ make clean

GNU Binutils

Les proporciona el paquet:

binutils

tal i com podem observar executant:

$ dpkg -S /usr/bin/nm
binutils: /usr/bin/nm

Les comandes que ens proporciona aquest paquet són:

$ dpkg -L binutils | grep /usr/bin
/usr/bin/size
/usr/bin/objdump
/usr/bin/ar
/usr/bin/strings
/usr/bin/ranlib
/usr/bin/objcopy
/usr/bin/addr2line
/usr/bin/readelf
/usr/bin/nm
/usr/bin/strip
/usr/bin/c++filt
/usr/bin/as
/usr/bin/gprof
/usr/bin/ld 

Enllaçador GNU (ld)

$ man ld
...
ld - The GNU linker


Serveix per enllaçar fitxers objecte (*.o) a un programa. Aquests enllaços són estàtics. Les bilioteques compartides tenen extensió *.so i es gestionen amb ld.so.

ld.so

Consulteu ld.so

Assamblador GNU (as)

Comanda nm

Mostra la taula de símbols:

$ nm a.out 
08049484 d _DYNAMIC
08049558 d _GLOBAL_OFFSET_TABLE_
08048458 R _IO_stdin_used
         w _Jv_RegisterClasses
08049474 d __CTOR_END__
08049470 d __CTOR_LIST__
0804947c d __DTOR_END__
08049478 d __DTOR_LIST__
0804846c r __FRAME_END__
08049480 d __JCR_END__
08049480 d __JCR_LIST__
0804957c A __bss_start
08049570 D __data_start
08048410 t __do_global_ctors_aux
08048320 t __do_global_dtors_aux
08049574 D __dso_handle
         w __gmon_start__
0804840a T __i686.get_pc_thunk.bx
08049470 d __init_array_end
08049470 d __init_array_start
080483a0 T __libc_csu_fini
080483b0 T __libc_csu_init
         U __libc_start_main@@GLIBC_2.0
0804957c A _edata
08049580 A _end
08048438 T _fini
08048454 R _fp_hw
08048274 T _init
080482f0 T _start
0804957c b completed.5982
08049570 W data_start
08048350 t frame_dummy
08048374 T main
08049578 d p.5980
         U puts@@GLIBC_2.0  


GNU Debugger (GDB)

El primer de tot per poder depurar es utilitzar el paràmetre -g al compilar.

$ gcc -g hello.c

Un exemple:

int foo (int *p);

int
main (void)
{
  int *p = 0;   /* null pointer */
  return foo (p);
}  

int
foo (int *p)
{
  int y = *p;
  return y;
} 
$ gcc -Wall -g null.c
$ ./a.out 
Segmentation fault (core dumped)

Realment els cores normalment no es volquen al disc dur perquè:

$ ulimit -c
0

Ho podem modificar amb:

$ ulimit -c unlimited

I aleshores:

$ gdb a.out core
Core was generated by `./a.out'.
Program terminated with signal 11, Segmentation fault.
Reading symbols from /lib/libc.so.6...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2...done.
Loaded symbols for /lib/ld-linux.so.2
#0  0x080483ed in foo (p=0x0) at null.c:13
13        int y = *p;
(gdb)

Podem veure l'error amb:

(gdb) print p
$1 = (int *) 0x0

Mostrar backtrace:

(gdb) backtrace
#0  0x080483ed in foo (p=0x0) at null.c:13
#1  0x080483d9 in main () at null.c:7

Col·locant un punt d'interrupció a main:

$ gdb a.out

(gdb) break main

Breakpoint 1 at 0x80483c6: file null.c, line 6.
(gdb) run
Starting program: a.out 
Breakpoint 1, main () at null.c:6
6         int *p = 0;   /* null pointer */

Movent-se pel programa:

(gdb) step
7         return foo (p);

Mostrant valors de variables:

gdb) print p
$1 = (int *) 0x0

Modificant variables:

(gdb) set variable p = malloc(sizeof(int))
(gdb) print p
$2 = (int *) 0x40013f98    (address allocated by malloc)
(gdb) set variable *p = 255
(gdb) print *p
$3 = 255

Continuar amb l'execució:

(gdb) finish
Run till exit from #0  0x08048400 in foo (p=0x40013f98) 
at null.c:15
0x080483d9 in main () at null.c:7
7         return foo (p);
Value returned is $13 = 255
(gdb) continue
Continuing.
Program exited with code 0377.

Recursos:

Depurar un programa amb paràmetres

$ gdb programa
...
(gdb) run parametre1 parametre2 parametre3 ...

Entorns gràfic (ncurses) per a gdb

$ sudo apt-get install cgdb
...
$ cgdb

GNU build system (autotools)

Diagrama de flux d'autoconf i automake

GNU build system, també coneguts com Autotools, és un conjunt d'eines de programació creat pel projecte GNU. Aquestes eines estan dissenyades per assistir als programadors en la tasca de crear codi portable a diferents sistemes Unix. GNU build system és part de la GNU toolchain i és molt utilitzat en molts projectes de programari lliure. La eina és GPL però es poden crear/portat programari propietari amb aquestes eines.

Hi han tres eines principals:

  • autoconf: Autoconf és una eina per produir scripts de Shell que automàticament configuren el codi font per adaptar-lo a diferents tipus de sistemes Unix (plataformes). Utilitza uns fitxer anomenats 'configure.ac' per crear un scripts de shell anomenat configure.
  • automake: Automake és una eina de programació que produeix fitxers makefile portables per a diferents plataformes Unix. Els makefiles produïts segueixen els estàndards de codificació de GNU.
  • libtool: GNU Libtool és una eina de programació de GNU utilitzada per a crear llibreries portables a diferents plataformes.

Recursos:

GNU coding Estàndards

Linux libc vs GNU libc

Va haver-hi un temps en que va haver-hi un fork de GNU libc. Actualment ja no és així i tots dos projectes són el mateix (GNU libc). Consulteu els recursos.

Recursos:

Llibreria estàndard de C. Gnu libc (glibc)

La llibreria estàndard de C, també coneguda com a libc, és una col·leció de fitxers de capçalera i rutines de llibreria utilitzada per implementar operacions comunes com operacions d'E/S, gestió de cadenes de caràcters, etc.

Tot i que al principi no era així, actualment libc forma part de l'estàndard ISO de C.

La implementació més utilitzada d'aquestes llibreries estàndard és la GNU C Library, també coneguda com a glibc.

En sistemes Debian aquesta llibreria és proporcionada per:

$ dpkg -l libc6
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Installed/Config-f/Unpacked/Failed-cfg/Half-inst/t-aWait/T-pend
|/ Err?=(none)/Hold/Reinst-required/X=both-problems (Status,Err: uppercase=bad)
||/ Nom                               Versió                           Descripció
+++-=================================-=================================-===============================================================================
ii  libc6                             2.6.1-1ubuntu10                   GNU C Library: Shared libraries

Les llibreries es troben normalment a les carpetes del sistema:

/usr/lib
/lib

Podem consultar les llibreries amb la comanda:

$ dpkg -L libc6 | grep lib

NOTA: En versions noves de Debian/Ubuntu el paquet és libc-bin:

$ dpkg -L libc-bin | grep bin

La documentació es troba a:

/usr/share/doc/libc6

Les comandes que proporciona aquest paquet són:

$ dpkg -L libc6 | grep bin
 /usr/bin
/usr/bin/iconv
/usr/bin/getent
/usr/bin/getconf
/usr/bin/catchsegv
/usr/bin/tzselect
/usr/bin/ldd
/usr/bin/zdump
/usr/bin/rpcinfo
/usr/sbin
 /usr/sbin/zic
/usr/sbin/iconvconfig
/sbin
/sbin/ldconfig
/sbin/ldconfig.real
NOTA: Cal tenir en compte que el paquet libc6 no aporta el codi font de les llibreries estàndard de C

Per treballar amb el codi font i les capçaleres de les llibreries estàndard de C, tenim el paquet libc6-dev:

$ dpkg -l libc6-dev
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Installed/Config-f/Unpacked/Failed-cfg/Half-inst/t-aWait/T-pend
|/ Err?=(none)/Hold/Reinst-required/X=both-problems (Status,Err: uppercase=bad)
||/ Nom                               Versió                           Descripció
+++-=================================-=================================-===============================================================================
ii  libc6-dev                         2.6.1-1ubuntu10                   GNU C Library: Development Libraries and Header Files

Amb:

$ dpkg -L libc6-dev

Consultem els fitxers d'aquest paquet.

Els executables són:

$ dpkg -L libc6-dev | grep bin
/usr/bin
/usr/bin/gencat
/usr/bin/mtrace
/usr/bin/rpcgen
/usr/bin/sprof

Les llibreries es troben a:

/usr/lib/
$ dpkg -L libc6-dev | grep /usr/lib

I les capçaleres (fitxers *.h) és troben a:

/usr/include
$ dpkg -L libc6-dev | grep include

Comandes

getconf

A una Ubuntu karmic 9.10 aquesta ordre es proporcionada pel paquet libc-bin:

$ dpkg -S /usr/bin/getconf
libc-bin: /usr/bin/getconf

Es poden consultar tots els paràmetres de configuració relacionats amb la llibreria estàndard de C amb:

$ getconf -a

La llista és llarga i per aquesta raó us recomanem utilitzar un paginador com more o less:

$ getconf -a | more
LINK_MAX                           32000
_POSIX_LINK_MAX                    32000
MAX_CANON                          255
_POSIX_MAX_CANON                   255
MAX_INPUT                          255
_POSIX_MAX_INPUT                   255
NAME_MAX                           255
_POSIX_NAME_MAX                    255
PATH_MAX                           4096
_POSIX_PATH_MAX                    4096
PIPE_BUF                           4096
_POSIX_PIPE_BUF                    4096
SOCK_MAXBUF                        
...

Es poden consultar paràmetres concrets amb:

$ getconf LOGIN_NAME_MAX
256

Destaquem els següents paràmetres:



Consulteu també el manual:

$ man getconf

Llibreries dinàmiques (shared object .so files)

També conegudes com llibreries compartides.

Carrega dinàmica de llibreries:

S'utilitzen les funcions dl* (man dlopen): dladdr, dlclose, dlerror, dlopen, dlsym, dlvsym

void* sdl_library = dlopen("libsdl.so", RTLD_LAZY);
if(sdl_library == NULL) {
   // report error ...
} else {
   // use the result in a call to dlsym
}

Recursos

Comanda ldconfig

Consulteu ldconfig.

Comanda ldd

Consulteu ldd.

Si executeu aquestes comandes en màquines diferents veureu que les adreces de memòria no tenen per que coincidir.

cpp

És el preprocessador de C:

Mostrar les MACROS predefinides:

$ cpp -dM /dev/null
#define __DBL_MIN_EXP__ (-1021)
#define __FLT_MIN__ 1.17549435e-38F
#define __CHAR_BIT__ 8
#define __WCHAR_MAX__ 2147483647
...

Comanda file

Mostra informació sobre els fitxers compilats (executables):

Fitxer executable:

$ file a.out 
a.out: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), for GNU/Linux 2.6.8, dynamically linked (uses shared libs), not stripped

El tipus de fitxer binari és Executable and Linkable Format (ELF) que és un format de fitxer estàndard per a executables, codi objecte, llibreries compartides i core dumps.

Llibreria compartida:

$ file /lib/libcap.so.1.10 
/lib/libcap.so.1.10: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), stripped

Core dump:

$ file core
core: ELF 32-bit LSB core file Intel 80386, version 1 (SYSV), SVR4-style

LSB és Linux Standard Base.

Els fitxers executables de Windows no segueixen aquest estàndard:

$ file /media/sda1/windows/system32/hal.dll 
/media/sda1/windows/system32/hal.dll: MS-DOS executable PE  for MS Windows (DLL) (native) Intel 80386 32-bit

Depurador Valgrind

http://en.wikipedia.org/wiki/Valgrind

ANSI C

El següent codi és ANSI C

#include <stdio.h>

int
main (void)
{
  const char asm[] = "6502";
  printf ("the string asm is '%s'\n", asm);
  return 0;
}

Però amb gcc us donarà el següent error de compilació:

$ gcc -Wall prova1.c
prova1.c: In function ‘main’:
prova1.c:6: error: expected identifier or ‘(’ before ‘asm’
prova1.c:7: error: expected expression before ‘asm’
prova1.c:12:7: avís: no hi ha caràcter de fi de línia al final del fitxer

El compilador GCC suporta C estàndard (ANSI C) més extensions de GNU.

Per compilar amb GCC ANSI C:

$ gcc -Wall -ansi ansi.c

També pot passar al revés, que no compili un programa en ANSI C perquè té extensions de GNU:

#include <math.h>
#include <stdio.h>

int 
main (void) 
{
  printf ("the value of pi is %f\n", M_PI);
  return 0;
}

La variables M_PI no és ANSI C:

$ gcc -Wall -ansi pi.c
pi.c: In function `main':
pi.c:7: `M_PI' undeclared (first use in this function)
pi.c:7: (Each undeclared identifier is reported only once
pi.c:7: for each function it appears in.)

També podem utilitzar l'opció pedantic per tal de mostrar avisos sobre incompatibilitats amb la ISO:

int 
main (int argc, char *argv[])
{
  int i, n = argc;
  double x[n];  

  for (i = 0; i < n; i++)
    x[i] = i;

  return 0;
}
$ gcc -Wall -ansi -pedantic gnuarray.c 
gnuarray.c: In function `main':
gnuarray.c:5: warning: ISO C90 forbids variable-size 
 array `x'

Per compilar altres versions de l'estàndard s'utilitza el paràmetre -std :

-std=c89 or -std=iso9899:1990
    The original ANSI/ISO C language standard (ANSI X3.159-1989, ISO/IEC 9899:1990). GCC incorporates the corrections in the two ISO Technical Corrigenda  
to the original standard. 
-std=iso9899:199409
   The ISO C language standard with ISO Amendment 1, published in 1994. This amendment was mainly concerned with internationalization, such as adding 
support for multibyte characters to the C library. 
-std=c99 or -std=iso9899:1999
    The revised ISO C language standard, published in 1999 (ISO/IEC 9899:1999).

Enllaços externs