Il comando make. Per produrre un eseguibile da un programma C sono necessari tre passi compiuti dai seguenti moduli:

Documenti analoghi
Corso di Sistemi Operativi A.A CHIAMATE DI SISTEMA PER IL CONTROLLO DEI PROCESSI. Fabio Buttussi

System call per la gestione di processi

La famiglia di system call exec. Modulo 6. Laboratorio di Sistemi Operativi I Anno Accademico

System Calls per la Gestione dei Processi

Il processo figlio : utilizza lo stesso codice che sta eseguendo il padre ;

Processi: Exit, Wait, Exec

Sistemi Operativi. Marzo-Giugno 2011 matricole congrue 0 mod 3. Controllo dei processi - I

I Processi nel SO UNIX

Università di Roma Tor Vergata Corso di Laurea triennale in Informatica Sistemi operativi e reti A.A Pietro Frasca.

Controllo dei Processi 1

Laboratorio di Sistemi Operativi Marzo-Giugno 2008 matricole congrue 0 mod 3

Corso di Programmazione Concorrente Processi. Valter Crescenzi

I Processi nel Sistema Operativo Unix

eseguire comandi dati dall'utente, utilizzando una macchina reale, di livello inferiore,

Programmazione di sistema in Linux: System Call per il controllo processi. E. Mumolo, DIA

perror: individuare l errore quando una system call restituisce -1

Unità Didattica 1 Linguaggio C. Fondamenti. Struttura di un programma.

Riepilogo sulla Concorrenza

Makefile. Il file dependency system di Unix (serve ad automatizzare il corretto aggiornamento di più file che hanno delle dipendenze)

I Processi nel Sistema Operativo Unix. Gerarchie di processi Unix. Stati di un processo Unix. Stati di un processo Unix.

Laboratorio di Sistemi Operativi Marzo-Giugno 2008 matricole congrue 0 mod 3

Primo passo: il preprocessor. Il preprocessore. Esempi di direttive al preprocessore: #include. Esempi di direttive al preprocessore: #define

Processi Concetti di base. Esecuzione parallela e sequenziale Il concetto di processo Gestione dei processi

Gestione dei processi

Controllo dei Processi. M. R. Guarracino - Primitive di Controllo dei Processi

Sistemi Operativi. Esercitazione 2 Compilazione, Makefile e Processi

Programmazione multiprocesso

In generale può essere utile che i due processi eseguano del codice diverso

Appunti tratti dal videocorso on-line di Algoritmi e Programmazione Avanzata By ALeXio

prova.c #include <stdio.h> char funzione(char); codice oggetto del main()

Componenti di un sistema operativo

Chiamate di sistema per la Gestione dei processi in POSIX. E.Mumolo, DEEI

Primi passi col linguaggio C

il tipo di parallelismo dipende dal grado di cooperazione

Processi UNIX. I Processi nel SO UNIX. Gerarchie di processi UNIX. Modello di processo in UNIX

Corso di Laboratorio di Sistemi Operativi

1. PARALLELISMO E PROCESSI. 1.1 La necessità del parallelismo

ACSO Programmazione di Sistema e Concorrente

Linea di comando. Compilazione. Aprire una shell di DOS tramite:

Lab. di Sistemi Operativi - Esercitazione n 7- -Gestione dei processi Unix-

Perché il linguaggio C?

Processi in Linux. Stru/ura file eseguibili

Esame Laboratorio di Sistemi Operativi Cognome Nome Mat.

BREVISSIMA GUIDA AL SISTEMA UNIX / LINUX

Sistemi Operativi Teledidattico

Compilazione e Makefile

Processi in UNIX. Spazio di sistema (residente) Tabella dei. file APERTI OPEN FILE. Tabella dei codici

AXO. Operativo. Architetture dei Calcolatori e Sistema. programmazione di sistema

Esempio. Le istruzioni corrispondono a quelle di sopra, ma sono scritte in modo simbolico. E indipendente dalla machina

System calls. permettono ai programmi utente di richiedere servizi al Sistema Operativo. servizi come scrittura di file, stampa su video, ecc.

Gestione dei processi

Processi in Linux. Igino Corona 20 Ottobre 2009

CREAZIONE PROCESSI IN UNIX 20

Utilizzo di make e di Makefile per compilare programmi in C e in C++

Principles of Concurrent Programming

Il preprocessore. Direttiva define Direttiva include Direttiva if

Principles of Concurrent Programming

Esame Laboratorio di Sistemi Operativi Cognome Nome Mat.

1 PANORAMICA SUL LINGUAGGIO C

Sistemi Operativi Anno Accademico 2011/2012. Segnali: Interrupt software per la gestione di eventi asincroni

Le direttive del Preprocessore

C O P Y R I G H T ( C ) W W W. F O N D A M E N T I. I N F O

Preprocessore, linker e libreria standard

Fondamenti di informatica, Sez. Ing. Informatica, Ing. Gestionale, Ing. Ambientale II prova in itinere, 29 Gennaio 2009

Progetto II: Il linguaggio C e le chiamate di sistema sui processi

Funzioni e. Alessandra Giordani Mercoledì 16 maggio 2012

Organizzazione di un SO monolitico

Linguaggio C. Appunti per il corso di Laboratorio di Algoritmi e Strutture Dati. Stefano Aguzzoli

Complementi. - Ridefinizione di tipo - - Costrutto switch - - Programmazione su più file - - Parametri della funzione main - Funzione system -

Concetto di Processo Scheduling dei Processi Operazioni sui Processi Processi cooperanti Comunicazione tra processi

Introduzione alla programmazione. Walter Didimo

Breve Riepilogo del Linguaggio C

I SISTEMI OPERATIVI (1)

Quinta Esercitazione. Principali primitive di accesso ai File

Algoritmo. La programmazione. Algoritmo. Programmare. Procedimento di risoluzione di un problema

Esercitazione di Lab. di Sistemi Operativi 1 a.a. 2011/2012

Compilazione separata

Esercitazione. Uso di funzioni e librerie di funzioni

Interprocess communication: Pipe

Laboratorio in C su Processi e POSIX IPC (Inter Process Communications) Dalla nona lezione di laboratorio in avanti

Processi in Unix. Capitolo 8 -- Stevens

Processi. Descrittore di Processo (PCB) Context Switch Primitive per la creazione e terminazione dei processi. Il descrittore di processo (PCB)

Comandi principali di Linux (1)

Processore Danilo Dessì. Architettura degli Elaboratori.

Compilazione separata. Come realizzare correttamente un piccolo progetto su piu' file

File binari e file di testo

Sistemi Operativi T. Esercizi

Il sistema C è formato dal linguaggio C, dal preprocessore, dal compilatore, dalle librerie e da altri strumenti di supporto.

Input/output da file I/O ANSI e I/O UNIX FLUSSI E FILE FLUSSI FLUSSI di TESTO FLUSSI BINARI FILE

Introduzione al DEV C++

INTERPROCESS COMMUNICATION 27

Corso di Laboratorio di Sistemi Operativi

L ambiente UNIX/Linux. Strumenti per la programmazione C Stefano Quer Dipartimento di Automatica e Informatica Politecnico di Torino

Spazio di indirizzamento virtuale

Funzioni. Unità 1. Domenico Daniele Bloisi. Corso di Fondamenti di Informatica Ingegneria delle Comunicazioni BCOR Ingegneria Elettronica BELR

I puntatori. Un puntatore è una variabile che contiene l indirizzo di un altra variabile. puntatore

Lezione 3: Programmazione della Shell di Unix

Signalling (IPC) Signalling (segnalazione)

Gestione dei file. Stefano Ferrari. Università degli Studi di Milano Programmazione. anno accademico

Linguaggi di Programmazione

Transcript:

Il comando make Sviluppando programmi complessi, si è spesso portati a suddividere il codice sorgente in diversi file. La fase di compilazione quindi richiede maggior tempo, anche se le modifiche apportate riguardano soltanto una piccola parte dell intero progetto. Il comando make è uno strumento che aiuta il programmatore nella fase di sviluppo, tenendo traccia delle modifiche apportate e delle dipendenze fra i vari file, ricompilando soltanto quanto necessario. Per produrre un eseguibile da un programma C sono necessari tre passi compiuti dai seguenti moduli: 1. Compilatore (fase preceduta dall invocazione del preprocessore): converte il codice sorgente in linguaggio Assembly (linguaggio di basso livello). 2. Assembler: converte il codice in linguaggio Assembly in linguaggio macchina (direttamente eseguibile dal processore). 3. Linker: collega il codice macchina prodotto dalla fase precedente a quello delle funzioni di libreria utilizzate nel programma (e.g., printf).

Compilazione con più file sorgente Compilatore file1.c Assembler file1.s file1.o Linker file.h a.out file2.s file2.o file2.c Si può pensare all intero processo come al risultato dell esecuzione dei comandi seguenti: > cc -c file1.c > cc -c file2.c > cc file1.o file2.o N.B.: eseguendo il compilatore con l opzione -c il processo si ferma dopo l esecuzione dell Assembler, producendo i file con estensione.o invece dell eseguibile a.out.

Grafo delle dipendenze a.out file1.o file2.o file1.c file.h file2.c Il grafo mette in luce le dipendenze fra i vari file (e.g., file2.o dipende sia da file.h che da file2.c. Quindi, in caso di modifiche a quest ultimo, percorrendo il grafo verso l alto notiamo che devono essere aggiornati anche file2.o e a.out, mentre i rimanenti file vengono lasciati inalterati.

Il Makefile Il grafo delle dipendenze viene codificato in un file di testo chiamato Makefile che risiede nella stessa directory dei file sorgente. Esempio di Makefile: a.out: file1.o file2.o cc file1.o file2.o file1.o: file.h file1.c cc -c file1.c file2.o: file.h file2.c cc -c file2.c Un Makefile è composto da regole specificate dalla seguente sintassi (l ordine delle regole non è importante): target : source file(s) command # Importante: command deve essere preceduto da un <Tab> Il comando make controlla le date di ultima modifica dei file. Ogni volta che un file (source) ha una data di modifica più recente di quella dei file che da esso dipendono (target), questi ultimi vengono aggiornati eseguendo i comandi specificati nelle regole del Makefile.

Utilizzo di make Se le regole sono memorizzate in un file chiamato Makefile o makefile è sufficiente digitare il comando make seguito dal target che si vuole aggiornare (altrimenti si deve usare l opzione -f per specificare il file corretto). Se non si specifica alcun target, viene eseguito automaticamente il primo (per questo solitamente la prima regola è quella che permette di ottenere il risultato finale). Esempio: a.out: file1.o file2.o cc file1.o file2.o file1.o: file.h file1.c cc -c file1.c file2.o: file.h file2.c cc -c file2.c clean: rm -f *.o a.out La prima esecuzione di make lancia i seguenti comandi: > cc -c file1.c > cc -c file2.c > cc file1.o file2.o Il comando make clean provoca sempre l esecuzione di rm -f *.o a.out in quanto clean è un target senza dipendenze.

Le macro di make Il comando make consente di definire ed utilizzare delle macro per memorizzare dei valori. Ad esempio: OBJECTS = file1.o file2.o La macro può in seguito essere espansa utilizzando la sintassi $(OBJECTS). Esempio: OBJECTS = file1.o file2.o a.out: $(OBJECTS) cc $(OBJECTS) file1.o: file.h file1.c cc -c file1.c file2.o: file.h file2.c cc -c file2.c I valori di una macro possono anche essere specificati da linea di comando: make OBJECTS=file1.o file2.o sovrascrivendo l eventuale valore assegnato alla macro nel Makefile.

Macro predefinite Esistono delle macro predefinite di uso comune: CC specifica il compilatore C da utilizzare (default: cc); CFLAGS: opzioni di default da passare al compilatore; $@ nome del target corrente; $? lista dei file sorgente (prerequisiti) della regola corrente che hanno una data più recente del target; $^ lista dei file sorgente (prerequisiti) della regola corrente.

La programmazione di sistema Il kernel è la parte di Unix che corrisponde al sistema operativo vero e proprio: è sempre residente in memoria e gestisce sia i processi che l I/O. La programmazione di sistema consiste nell utilizzare l interfaccia di system call fra il kernel e le applicazioni che girano sotto Unix. Tutti i programmi che girano sotto Unix in ultima analisi fanno uso di tale interfaccia; anche le librerie di sistema si appoggiano sulle system call. User space (programma e dati) Program code Library routine fopen open user code open kernel code Kernel space (risorse di sistema)

System call Per i programmi C che utilizzano le system call queste ultime si comportano come delle funzioni. Ogni system call ha un prototipo; ad esempio: pid_t fork(void); e può essere utilizzata come una funzione di libreria od una funzione definita dall utente: pid_t pid; pid = fork(); Convenzionalmente le system call restituiscono un valore negativo (tipicamente -1) per indicare che è avvenuto un errore. Esistono vari tipi di system call relative a: controllo di processi, gestione di file, comunicazione tra processi, segnali.

Controllo di processi getpid, getppid, getgrp ecc.: PPID, gruppo ecc.). forniscono degli attributi dei processi (PID, fork: crea un processo figlio duplicando il chiamante. exec: trasforma un processo sostituendo un nuovo programma nello spazio di memoria del chiamante. wait: permette la sincronizzazione fra processi; il chiamante attende la terminazione di un processo correlato. exit: termina un processo.

La system call fork (I) Il prototipo è pid_t fork(); dove pid t è un tipo speciale definito in <sys/types.h> e, solitamente, corrisponde ad un tipo intero. Il tipico esempio di chiamata è il seguente: #include <unistd.h> /* include la definizione di pid_t */ pid_t pid;... pid=fork(); Il valore restituito da fork serve a distinguere tra processo genitore e processo figlio; infatti al genitore viene restituito il PID del figlio, mentre a quest ultimo viene restituito 0. Il processo figlio è letteralmente una copia del padre (se si eccettua il PID diverso); infatti i valori delle variabili del figlio avranno gli stessi valori di quelle corrispondenti del padre. Tuttavia, siccome i due processi occupano fisicamente aree diverse di memoria, variazioni nelle variabili dell uno non influenzano le variabili dell altro, a meno che non siano dei descrittori di file.

La system call fork (II) printf( One\n ); PC pd=fork(); printf( Two\n ); A fork prima dopo printf( One\n ); printf( One\n ); pd=fork(); printf( Two\n ); PC pd=fork(); printf( Two\n ); PC B C

Esempio di utilizzo di fork #include <stdio.h> #include <unistd.h> main() { pid_t pid; printf("un solo processo con PID %d.\n",(int)getpid()); printf("chiamata a fork...\n"); pid=fork(); } if(pid == 0) printf("sono il processo figlio (PID: %d).\n",(int)getpid()); else if(pid>0) printf("sono il genitore del processo con PID %d.\n",pid); else printf("si e verificato un errore nella chiamata a fork.\n");

La famiglia di system call exec Se fork fosse l unica primitiva per creare nuovi processi, la programmazione in ambiente Unix sarebbe alquanto ostica visto che si potrebbero creare soltanto copie dello stesso processo. La famiglia di primitive exec può essere utilizzata per superare tale limite in quanto le varie system call di quest ultima permettono di iniziare l esecuzione di un altro programma sovrascrivendo la memoria di un processo. execl execle execlp execv execvp execve In realtà tutte le funzioni chiamano in ultima analisi execve che è l unica vera system call della famiglia. Le differenze tra le varianti stanno nel modo in cui vengono passati i parametri.

Esempio di utilizzo di execl #include <stdio.h> #include <unistd.h> main() { printf("esecuzione di ls\n"); execl("/bin/ls", "ls", "-l", (char *)0); } perror("la chiamata di execl ha generato un errore\n"); exit(1); Si noti che execl elimina il programma originale sovrascrivendolo con quello passato come parametro. Quindi le istruzioni che seguono una chiamata a execl verranno eseguite soltanto in caso si verifichi un errore durante l esecuzione di quest ultima ed il controllo ritorni al chiamante.

Esempio di utilizzo di execl printf(...); PC execl( /bin/ls,...); exec /* 1a linea di ls */ PC prima dopo

Utilizzo combinato di fork e exec (I) L utilizzo combinato di fork per creare un nuovo processo e di exec per eseguire nel processo figlio un nuovo programma costituisce un potente strumento di programmazione in ambiente Unix: #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> void fatal(char *s) { perror(s); exit(1); }

Utilizzo combinato di fork e exec (II) main() { pid_t pid; } switch(pid = fork()) { case -1: fatal("fork failed"); break; case 0: execl("/bin/ls", "ls", "-l", (char *)0); fatal("exec failed"); break; default: wait((int *)0); printf("ls completed\n"); exit(0); }

Utilizzo combinato di fork e exec (III) pid = fork(); PC fork A prima dopo wait((int *)0); PC execl( /bin/ls,...); PC A exec B wait((int *)0); PC /* 1a linea di ls */ PC A B

Esercizi Scrivere un programma C che prende in input sulla linea di comando tre parametri file1, file2, file3 ed esegue la seguente lista di comandi Unix: cp file1 file2 sort file2 -o file3 cat file3 Scrivere un programma C (chiamandolo run.c) che esegue quanto passato sulla linea di comando. Ad esempio: > run ls -l > run wc -c...