Lo Sviluppo di Applicazioni per Linux

In quest’ultimo periodo anche le grandi aziende si stanno muovendo verso il mondo Linux, purtroppo la carenza di strumenti di sviluppo rapido per questo ambiente ha frenato considerevolmente il suo utilizzo in azienda, relegandolo ai sistemi server. In questo articolo vedremo le basi della programmazione in ambiente Linux con gli strumenti che il sistema operativo ci mette a disposizione, in modo da scoprirne le potenzialità ed imparare quindi ad utilizzare gli strumenti più evoluti che permettono uno sviluppo più rapido delle applicazioni.
Iniziamo dal protagonista principale del processo di sviluppo: il compilatore. Con tutte le distribuzioni Linux viene fornito a corredo GCC, che definirlo un semplice compilatore sarebbe poco, in quanto riunisce una serie di strumenti di sviluppo: GCC infatti consente di compilare e linkare qualsiasi sorgente gli passiamo. GCC ha anche la possibilità di compilare, con moduli aggiuntivi, oltre allo standard C anche altri linguaggi come il C++ o il Fortran o Java; inoltre GCC può lavorare come cross-compiler ovvero produrre binari per processori diversi.
La sintassi di base di GCC è decisamente semplice:

gcc [opzioni] file

dove file è il nome del nostro file sorgente ed opzionalmente preceduto dalle varie opzioni. Il numero di quest’ultime è veramente impressionante; cercheremo di analizzare quelle di uso comune, rimandando alla documentazione del compilatore per le restanti. Per effettuare una compilazione completa del nostro sorgente è sufficiente scrivere:

gcc hello.c

In questo modo il compilatore capirà dall’estensione del file che gli stiamo passando un programma scritto in C e creerà il file binario a.out. Se vogliamo che il risultato della compilazione abbia un altro nome possiamo aggiungere l’opzione -o seguita dal nome con il quale vogliamo chiamare il programma. In pratica con una sola linea di comando abbiamo innescato diverse fasi della compilazione:

  • esecuzione dei comandi del preprocessore eventualmente presenti nel sorgente
  • compilazione dal linguaggio sorgente al linguaggio Assembler
  • compilazione ( assemblaggio ) del sorgente Assembler
  • link con le librerie

Se vogliamo essere informati su cosa GCC sta facendo possiamo aggiungere l’opzione -v che mostrerà le fasi affrontate durante la compilazione con un’esauriente spiegazione. In un’unica linea di comando è possibile lanciare la compilazione di più file sorgenti, in questo modo si evita di compilare uno ad uno i vari file ed alla fine linkarli insieme.
Oltre alle opzioni di contorno di GCC che abbiamo già visto, ce ne sono alcune molto importanti. Tra le più utilizzate abbiamo -I, che permette di dire al compilatore dove cercare gli eventuali file da includere nelle operazioni di compilazione, è possibile indicare più directory con lo stesso comando. Altra opzione utilizzata è -D che permette di assegnare un valore ad una macro del preprocessore.
Anche se siamo dei guru della programmazione, prima o poi capiterà di fare un errore di battitura o altro, in questi casi ( errori di sintassi ) il compilatore avvertirà il programmatore dell’errore e della riga nel sorgente dove si trova. Esistono fondamentalmente due tipi di avvertimenti:

  • warnings – sono degli avvertimenti che non pregiudicano la creazione dell’eseguibile, ma che andrebbero presi in considerazione per un corretto funzionamento del programma
  • errors – sono degli errori gravi che fanno interrompere il processo di compilazione e che il programmatore deve modificare direttamente alla linea specificata

Per default il compilatore non visualizza i warnings, ma è comunque buona regola abilitarli con l’opzione -Wall, che attiva tutti gli avvertimenti, è anche possibile essere più selettivi e scegliere quali visualizzare. Esiste anche l’opzione -Werror che trasforma tutti i warnings in errors impedendo così la compilazione in sorgenti non perfetti.
Oltre agli errori in cui potremmo incappare durante la preparazione del sorgente, si può incorrere in errori ben più gravi, ovvero quelli che avvengono a run-time, in questo caso il compilatore non può rilevarli durante la fase di compilazione in quanto difficili da prevedere a priori. Occorre intervenire quindi con un debugger per analizzare le singole istruzioni ed i valori delle variabili per rimuovere gli errori logici; per questo compito GNU mette a disposizione lo strumento gdb, un potente debugger.
Molto spesso le nostre applicazioni ricorreranno a funzioni già implementate e raccolte in altre librerie, questo per evitare di dover riscrivere degli algoritmi già implementati ed ottimizzati da tempo da altri programmatori. Lo stesso Linux fornisce delle librerie standard, le glibc, che possiedono le funzioni basilari come la printf. Queste librerie standard risiedono in directory che il compilatore conosce, mentre se volessimo inserire delle librerie esterne che risiedono in directory non di default, dobbiamo trovarle ed includerle nel nostro programma. Per prima cosa dobbiamo informare GCC dove trovare queste librerie con l’opzione -L, poi con -l andremo a specificare il nome della libreria che intendiamo utilizzare. Ad esempio per utilizzare le librerie ncurses dobbiamo inserire l’opzione -lncurses. Normalmente Linux utilizza il link condiviso di tutte le librerie per evitare di creare file binari di grandi dimensioni con pezzi di codice ripetuto, ma se volessimo utilizzare un link statico ed avere tutto il codice esterno inserito nel nostro eseguibile dobbiamo mettere l’opzione -static.
Il compilatore GCC per default produce codice non ottimizzato, ma è possibile renderlo tale attraverso delle opzioni suddivise per livello:

  • -O1 : ottimizza i possibili salti presenti nel codice e le chiamate alle funzioni
  • -O2 : effettua tutte le ottimizzazioni disponibili, escluse quelle che potrebbero aumentare la dimensione del binario generato
  • -O3 : come il livello precedente, ma eventuali funzioni semplici vengono spostate direttamente nella funzione chiamante ( funzioni inline )

Oltre a queste esistono molte altre opzioni che possono rendersi utili in particolari occasioni ed in cui abbiamo la necessità di ottimizzare al massimo il codice binario ottenuto, le potete visualizzare nella pagina man del compilatore.
Riassumere tutte le potenzialità offerte dal compilatore ufficiale del progetto GNU ed il relativo debugger in un solo articolo è impresa impossibile, ho cercato quindi di dare le informazioni sufficienti per poter scrivere e compilare i nostri sorgenti e permettere di iniziare a prendere confidenza con la programmazione in ambiente Linux.

Pubblicato
Categorie: Linux Taggato

Di Giampaolo Rossi

Sviluppatore software da oltre 16 anni.