Installazione dell’ambiente di sviluppo MinGW + MSYS + EMACS + FLTK

Da anni uso l’ambiente di sviluppo in oggetto per fare i miei “programmini”.

Per chi non lo sapesse abbiamo:

  • MinGW: Compilatore C/C++ per Windows, praticamente il porting del GCC presente su piattaforma UNIX (Linux in particolare).
  • MSYS: Emulatore del terminale Linux, con alcuni comandi tipici dell’ambiente Bash.
  • EMACS: Insieme a vi, uno degli editor storici del mondo UNIX.
  • FLTK: Framework C++ per sviluppare software con interfaccia grafica multipiattaforma.

Bene, ecco i passaggi da fare (su Windows) per ottenere questo ambiente di sviluppo funzionante:

  • Scaricare MinGW da http://sourceforge.net/projects/mingw e installarlo nella locazione di default ( C:\MinGW ), lasciando il nome di default ( MinGW) e selezionando i seguenti componenti aggiuntivi:
    • C++ Compiler
    • MSYS Basic System
  • Scaricare e installare EMACS da http://ftp.gnu.org/gnu/emacs/windows (nel momento in cui scrivo – 20.45 03/09/2010 – l’ultima versione disponibile risulta essere emacs-23.2-bin-i386.zip ); per installarlo, aperto lo zip, decomprimere il tutto in C:\MinGW\bin (dovrebbe creare una sotto-cartella di nome simile a “emacs-23.2”) e lanciare C:\MinGW\bin\emacs-??.?\addpm.exe e rispondere affermativamente quando chiede se installarlo lì.

N.B.: Ricordo che EMACS è il migliore editor del pianeta e chi non lo usa
deve crepare lapidato.

  • Sul desktop non viene messa nemmeno un’icona; se questa cosa sta sulle palle, si può rimediare trascinando le icone:
    • Start -> Tutti i Programmi -> MinGW -> MinGW Shell
    • Start -> Tutti i Programmi -> GNU Emacs -> Emacs
  • Ora bisogna fare in modo che da MinGW Shell ci sia modo di lanciare EMACS; io l’ho abbreviato in “e” (e penso che tutto il mondo dovrebbe fare così), quindi procedere come segue:
      • Aprire MinGW Shell (Start -> Tutti i Programmi -> MinGW -> MinGW Shell)
      • Tasto destro del Mouse sulla barra del titolo e scegliere “Proprietà”
      • Spuntare “Modalità Modifica Rapida”
      • In “Tipo di carattere” scegliere “10×18”
      • Cliccare su “OK” e scegliere “Salva le proprietà per le finestre future con lo stesso titolo”
      • Digitare i seguenti comandi (ATTENTO: può variare la cartella di EMACS):
     cd /c/MinGW/bin
     echo '/c/MinGW/bin/emacs-23.2/bin/runemacs.exe "$@"' > e
     chmod.exe +x e
     cd
     e
    • In EMACS usare la combinazione “CTRL+x f” e aprire il file “.emacs” (non esiste, lo stiamo creando nella HOME)
    • Fare un copia/incolla delle seguenti righe:
      (custom-set-variables
      ;; custom-set-variables was added by Custom.
      ;; If you edit it by hand, you could mess it up, so be careful.
      ;; Your init file should contain only one such instance.
      ;; If there is more than one, they won't work right.
      '(case-fold-search t)
      '(column-number-mode t)
      '(current-language-environment "Italian")
      '(default-input-method "italian-postfix")
      '(global-font-lock-mode t nil (font-lock))
      '(inhibit-startup-screen t)
      '(pc-selection-mode t nil (pc-select))
      '(save-place t nil (saveplace)))
      (custom-set-faces
      ;; custom-set-faces was added by Custom.
      ;; If you edit it by hand, you could mess it up, so be careful.
      ;; Your init file should contain only one such instance.
      ;; If there is more than one, they won't work right.
      '(default ((t (:stipple nil :background "black" :foreground "white" :inverse-video nil :box nil :strike-through nil :overline nil :underline nil :slant normal :weight normal :height 120 :width normal :family "adobe-courier"))))
      '(cursor ((t (:background "white" :foreground "black")))))
      ;; keybindings
      (global-set-key "\C-x\C-g" 'goto-line)
      (global-set-key [(f1)] (lambda () (interactive) (manual-entry (current-word))))
      ; TILDE C+M+ì
      (define-key global-map (kbd "C-M-ì") (lambda () (interactive) (insert ?~ )))
      (fset 'uda_protect_variable
      [C-insert ?\C-x ?2 C-home ?\M-% S-insert return S-insert ?} home right ?{ return ?! ?\C-x ?o ?\C-x ?1])
      (fset 'uda_remove_line_number
      [?\C-\M-% ?^ ?\[ ?  ?0 ?- ?9 ?\] ?* return return ?!])
      (mouse-wheel-mode t)
      (column-number-mode 1)
      ;;(server-start)
      (menu-bar-mode)
      ;;(tool-bar-mode)
      
      ;; Kill All Buffers without prompting.
      ;; Modified from kill-some-buffers in files.el, which prompts too much.
      (defun kill-all-buffers ()
      "Kill all buffers without prompting."
      (interactive)
      (let ((list (buffer-list)))
      (while list
      (let* ((buffer (car list))
      (name (buffer-name buffer)))
      (kill-buffer buffer))
      (setq list (cdr list)))))
    • Chiudere salvando con “CTRL+x CTRL+c y”

N.B.: Ora EMACS si apre con la configurazione giusta e consente, tra le varie cose, di raggiungere una determinata riga con “CTRL+x CTRL+g”

Se la mancanza del menu in alto è ritenuta grave(però poi i comandi che apro usando “F10” vanno scelti da menu ….), usare:

ALT+x toggle-menu-bar-mode-from-frame

Io comunque consiglio di abituarsi al tasto “F10” e navigare con le accelerazioni da tastiera; ad esempio il Revision Control System lo gestisci da: F10 t v

  • Scaricare UDC (UDA Data Copy) da qui: http://digilander.libero.it/udasoft/Software/multiplatform/udc/udc-1.6.00.zip e installarlo sempre in C:\MinGW\bin
  • Nel terminale dare i seguenti comandi:
    cd /c/MinGW/bin
    mv udc udc-1.6.00
    ln -s udc-1.6.00/udc.exe udc
    ln -s udc-1.6.00/libregex.dll
  • Aprire la cartella  C:\MinGW\bin\udc-1.6.00 , copiare udc.exe, aprire “Esplora Risorse” sul tasto “Start” di Windows, selezionare la cartella “SendTo” e *INCOLLARE COME COLLEGAMENTO*, quindi rinominare il link, ad esempio in “UDA Data Copy”.

N.B.: Questo consente di aprire i file UNIX visualizzandoli correttamente e, volendo, fare parecchie altre cose (vedere guida del programma).

  • Quando si apre la shell di MinGW, la HOME directory si trova in un percorso simile al seguente:

C:\MinGW\msys\1.0\home\nome_utente

dando il “cd”, si finisce automaticamente in questa cartella; per comodità è quindi utile mettere i propri sorgenti in suddetta directory.

Tutti i sorgenti che andremo ora a compilare andranno messi lì.

  • Ora installiamo l’RCS (Revision Control System); lo si trova qui:
    http://www.cs.purdue.edu/homes/trinkle/RCSe, nel momento in cui scrivo – 10.09 04/09/2010 – i files da scaricare sono:
    http://www.cs.purdue.edu/homes/trinkle/RCS/rcs57pc1.zip
    http://www.cs.purdue.edu/homes/trinkle/RCS/rcs57pc2.zip
    http://www.cs.purdue.edu/homes/trinkle/RCS/rcs57pc3.zip
    i file vanno decompressi in C:\MinGW\bin\RCS(bisogna creare la cartella RCS).Aprire MinGW Shell e dare i seguenti comandi:

    cd /c/MinGW/bin
    for file in /c/MinGW/bin/RCS/bin/win32/*; do ln -s ${file}; done
    cd
    export TZ=GMT-0

    In Windows cliccare con il tasto destro del mouse su “Risorse del Computer”, quindi scegliere “Proprietà”, scegliere la tabella “Avanzate”, cliccare su “Variabili d’ambiente”, il bottone “Nuovo” (uno dei due, io ho usato quello per il solo utente) e usare per “Nome Variabile” il valore “TZ” e per “Valore Variabile” la stringa “GMT-0” (chiaramente senza virgolette).
    Confermare con OK, OK.

    In Windows cliccare con il tasto destro del mouse su “Risorse del Computer”, quindi scegliere “Proprietà”, scegliere la tabella “Avanzate”, cliccare su “Variabili d’ambiente”, il bottone “Nuovo” (uno dei due, io ho usato quello per il solo utente) e usare per “Nome Variabile” il valore “RCSINIT” e per “Valore Variabile” la stringa “-x,v/” (chiaramente senza virgolette).
    Confermare con OK, OK.

    N.B.: E’ possibile che, facendo il check-out di sorgenti provenienti da un altro sistema, il sistema comunichi un messaggio di errore circa la necessita’ di ripristinare il blocco sul file; rispondere “yes” e ripetere l’operazione di check-out.

    Ora gli ultimi 2 comandi per completare l’installazione:

    cd
    mkdir src

    Dentro src andremo a mettere i nostri sorgenti.

Per verificare (e guardare un paio di comandi) se il sistema RCS è funzionante, procediamo in questo modo da terminale MinGW:

cd src
e main.cpp

dentro ci andiamo a scrivere:

/* Il classico Hello World ! */
#include <stdio.h>

int main (int argc, char** argv) {
  printf("Hello World !\n");
  return 0;
}

Salviamo con “CTRL+x CTRL+s”; ora facciamo il check-in del sorgente con “F10 t v c”; la prima volta che usiamo il sistema di controllo revisione in una cartella nuova, EMACS chiede quale strumento vogliamo usare (non c’è solo RCS, ce ne sono parecchi altri), quindi andiamo a scrivere “RCS” al suo prompt.

Dopodiché ci chiederà dove posizionare il “repository”, cioè il suo database; ci basta dare INVIO per usare la cartella stessa (lui crea una sotto-cartella di nome RCS in automatico).

A questo punto il sorgente “main.cpp” non è più modificabile, ne abbiamo fatto il check-in.

Proviamo a compilare il sorgente (quando avremo creato il makefile, ci sarà modo di farlo direttamente da EMACS, con parecchie altre utilità):

gcc main.cpp -o main
./main

Ora modifichiamo “main.cpp” facendo check-out con “F10 t v c”; aggiungiamo una riga in modo che diventi come segue:

/* Il classico Hello World ! */
#include <stdio.h>

int main (int argc, char** argv) {
  printf("Hello World !\n");
  printf("Prova di RCS.\n");
  return 0;
}

Salviamo con “CTRL+x CTRL+s” e chiediamo a RCS di fare una analisi della cartella con “F10 t v v” e INVIO per confermare quella corrente; EMACS elencherà quali file sono stati modificati nella cartella. Se con il cursorse si va sul nome di un file e si preme INVIO, EMACS apre quel file.

Proviamo a fare check-in del file così modificato; lo si può fare sia con “F10 t v c”, sia con la scorciatoia “CTRL+x v v”.

Ora ci chiede di elencare, in una apposita finestra, le modifiche che abbiamo operato sul file; per coerenza si può adottare uno stile per modificare il “VC-log”, ovvero una sintassi di questo tipo:

XXX: descrizione modifica

dove XXX è una sigla di tre lettere che può essere ADD (Aggiunto codice), MOD (Modificato codice), FIX (Corretto BUG) e WRN (Warning, avvertimento).

Il tutto, inizialmente, va scritto su unica riga e quindi formattato con il comando offerto da EMACS, vediamo come con un esempio, scriviamo per il nostro “main.cpp” la seguente riga:

MOD: Aggiunto ulteriore output. Stiamo provando il sistema RCS con EMACS; vediamo come funziona la sua formattazione automatica dentro il VC-log.

Quando siamo a fine riga, diamo un “ALT+q” ed EMACS formatta automaticamente il
ritorno a capo; la riga diventa così:

MOD: Aggiunto ulteriore output. Stiamo provando il sistema RCS con
EMACS; vediamo come funziona la sua formattazione automatica dentro il
VC-log.

Giustifichiamo una rientranza nella seconda riga; ci spostiamo all’inizio di quest’ultima e diamo un “ALT+i” seguito da un “ALT+q”; il risultato è il seguente:

MOD: Aggiunto ulteriore output. Stiamo provando il sistema RCS con
      EMACS; vediamo come funziona la sua formattazione automatica
      dentro il VC-log.

dovremo fare così per ogni eventuale riga che abbiamo scritto dentro al log. Questo consente di tenere traccia delle modifiche che un sorgente ha subito. Confermiamo il check-in, salvando il log, con “CTRL+c CTRL+c”. Possiamo vedere il log dei cambiamenti del sorgente corrente con “F10 t v S”.

Ora passiamo ad usare il sistema “ediff“, in modo che EMACS ci visualizzi le differenze tra il sorgente attuale e quello “checkinato”.

Usiamo “CTRL+x o” per passare da un buffer all’altro e “CTRL+x 1” per visualizzarne uno solo; ora facciamo check-out con “CTRL+x v v”, quindi modifichiamo il sorgente alla riga 7 in modo che diventi come la seguente:

printf("Prova di RCS; vediamo il sistema ediff in funzione.\n");

Salviamo con “CTRL+x CTRL+s” e usiamo l’ediff con “F10 t v w”; EMACS mostrerà le differenze; in grigio il codice rimasto uguale, in bianco quello cambiato con un “!” in testa.

Possiamo avere una conferma che “main.cpp” è stato cambiato usando l’analisi della cartella “F10 t v v” e INVIO.

Se il file così cambiato non ci sta bene, possiamo annullare la modifica con (ritornare nel buffer del file modificato con “CTRL+x o”) “F10 t v R”; EMACS si accorge che il file è stato modificato ed elenca da solo le modifiche eseguite, chiedendoci se le vogliamo scartare. Rispondiamo scrivendo “yes” (è fiscale, vuole proprio “yes” per esteso, per essere sicuro che sappiamo cosa stiamo facendo).

Magicamente il file torna esattamente come prima ed è in read-only.
Dando un’occhiata al menu che appare con “F10 t v” si può notare come siano presenti numerose altre opzioni che possono tornare utili.

Vediamo un’altra peculiarità di emacs; creiamo il makefile con “CTRL+x f makefile” e INVIO, quindi scriviamo quanto segue (notare che ci sono delle rientranze che vanno realizzate con il tasto “TAB” della tastiera, altrimenti si otterrà un messaggio di errore in fase di compilazione):

# A simple MAKEFILE
CFLAGS=-I.
DEPS=
OBJ=main.o
TARGET=main
CC=g++

.cpp.o: $(DEPS)
  $(CC) -g -c -o $@

lt; $(CFLAGS) $(TARGET): $(OBJ) $(CC) -g -o $@

lt; $(CFLAGS) clean: rm -fv *~ $(TARGET).exe $(TARGET) *.o

Salviamo con “CTRL+x CTRL+s” e proviamo subito; al terminale diamo

make clean

quindi torniamo in EMACS e usiamo “F10 t c” confermando con INVIO (salvo non si voglia aggiungere opzioni; ad esempio su Linux uso “make -k linux”).

Questo è comodo, ma molto più comodo è quando ci sono errori !

In quel caso, appaiono nella finestra di compilazione e, selezionandoli (ci si va sopra e si preme INVIO), EMACS ci apre il file incriminato direttamente alla riga dell’errore.

Inoltre non dobbiamo necessariamente salvare i file quando li modifichiamo; nel momento in cui chiediamo ad EMACS di compilare, sarà lui a chiederci se vogliamo salvarli.

Infine è arrivato il momento di usare il DEBUGGER !

EMACS è integrato con GDB; usiamo “F10 t d” con INVIO per avviare la relativa finestra.

Con r + INVIO si avvia il programma ma, volendo, ci sono anche i pulsanti.

Per inserire un “breakpoint” in un sorgente è sufficiente aprirlo, andare alla riga desiderata e dare “CTRL+x barra_spaziatrice”; EMACS aggiunge un pallino rosso alle righe dove è presente un breakpoint.

Ad esempio, facciamo check-out del nostro “main.cpp” e modifichiamolo in questo modo:

/* Il classico Hello World ! */

#include <stdio.h>

int main (int argc, char** argv) {
  int    iNumero = 0;

  printf("Hello World !\n");

  if (argc > 1) {
    sscanf(argv[1], "%d", &iNumero);
    printf("Numero Convertito: %d\n", iNumero);
  }

  return 0;
}

Quindi compiliamo il tutto con “F10 t c”, ci spostiamo alla riga 10 e inseriamo un breakpoint con “CTRL+x barra_spaziatrice”; ora passiamo al debugger (in genere rimane attiva la finestra dell’ultimo sorgente aperto e, nella finestra sotto, viene messo il report della compilazione, quindi uso “CTRL+x o” per passare in quest’ultima e “CTRL+x k” per chiuderla, ritornando alla finestra del debugger) e lanciamo il programma passandogli anche un parametro con “r 099”.

GDB blocca l’esecuzione scrivendo:

Breakpoint 1, main (argc=2, argv=0x3e2510) at main.cpp:10

Qui possiamo fare diverse cose; ad esempio vedere il “backtrace” (si scrive proprio “backtrace” e si da INVIO), per conoscere l’ordine delle chiamate a funzione (nel nostro caso c’è solo una riga, ma se avessimo avuto una serie concatenata di chiamate a funzione, qui avremmo la lista e sapremmo “come siamo arrivati fino a qui”).
Possiamo anche vedere il valore di una variabile, sia in modo temporaneo:

print iNumero

(sono comandi da dare al prompt, considerando che EMACS, premendo il TAB, può eseguire il completamento automatico, riconoscendo funzioni e variabili) in modo da ottenere:

(gdb) print iNumero
$1 = 0

o in modo permanente, ad esempio:

display iNumero

ottenendo:

(gdb) display iNumero
1: iNumero = 0

ora possiamo passare all’istruzione successiva con il Next (n + INVIO) e vedere come EMACS sposta la freccia “>” di esecuzione alla riga successiva; premendo INVIO si ripete l’ultimo comando (Next, nel nostro caso) e si può vedere come varia la variabile quando superiamo la funzione “sscanf()”.

Se ci fosse stata una funzione e volevamo entrare dentro al codice di quest’ultima, anziché “n” dovevamo usare “s” (Step).

Con “c” (Continue) si continua l’esecuzione del programma fino all’istruzione successiva.

Con il comando “delete” cancelliamo tutti i breakpoints, mentre con “undisplay” tutte le variabili automaticamente monitorate.

Un sommario delle parole chiave di GDB puoi trovarlo qui:
http://refcards.com/docs/peschr/gdb/gdb-refcard-a4.pdf

Per dimostrare quanto è potente GDB operiamo una modifica al sorgente:

/* Il classico Hello World ! */

#include <stdio.h>

int main (int argc, char** argv) {
  int    iNumero = 0;

  printf("Hello World !\n");

  if (argc > 1) {
    sscanf(argv[1], "%d", &iNumero);
    printf("Numero Convertito: %d\n", iNumero);

    for (int i = iNumero; i > 0; i--) {
      printf("Countdown: %d\n", i);
    }
  }

  return 0;
}

Cancelliamo tutti i breakpoints con “delete” (con “info b” otteniamo una lista di quelli attivi) e ne aggiungiamo uno realmente utile:

break main.cpp:15 if i == 80

Sì, hai capito bene, questo ferma l’esecuzione del ciclo nel momento in cui la variabile “i” raggiunge il valore “80”. Ma quanto è utile ???

E poi che non ho mai provato ad usare tutto il resto, ma fare le cose “a printf” è una pazzia …

Infine, per uscire da GDB usare il comando “q” (è indispensabile, altrimenti EMACS si incazza).

Per uscire da EMACS usare “CTRL+x CTRL+c”. Se ci sono dei buffers aperti e si desidera chiuderli, usare “CTRL+x k”.

Un’altra cosa che non sto qui a spiegare ma vale senz’altro la pena guardare è il sistema EDIFF, simile a quello dell’RCS, ma che oltre ad analizzare le differenze tra due sorgenti, consente anche di “allinearli” (cioè trasferire le differenze riscontrate da una parte all’altra) in modo che oserei definire “intelligente” (lo trovi nel menu “F10 t 1”).

Autore: BuDuS

Disegnatore Meccanico, con la passione per l'Informatica. Come hobby, produco piccoli software di (in)utilità.