Environnements et Outils de Développement Cours 6 Building with make



Similar documents
How To Use The C Preprocessor

The C Programming Language course syllabus associate level

Programmation Systèmes Cours 4 Runtime user management

How To Port A Program To Dynamic C (C) (C-Based) (Program) (For A Non Portable Program) (Un Portable) (Permanent) (Non Portable) C-Based (Programs) (Powerpoint)

Application Programming Using the GNOME Libraries

Building Software Systems. Multi-module C Programs. Example Multi-module C Program. Example Multi-module C Program

MPLAB TM C30 Managed PSV Pointers. Beta support included with MPLAB C30 V3.00

How to Write a Simple Makefile

Programmation Systèmes Cours 7 IPC: FIFO

C Programming Review & Productivity Tools

An Incomplete C++ Primer. University of Wyoming MA 5310

Building Programs with Make. What does it mean to Build a Program?

GNU Make. A Program for Directing Recompilation GNU make Version 3.80 July Richard M. Stallman, Roland McGrath, Paul Smith

8.5. <summary> Cppcheck addons Using Cppcheck addons Where to find some Cppcheck addons

Linux/UNIX System Programming. POSIX Shared Memory. Michael Kerrisk, man7.org c February 2015

Brent A. Perdue. July 15, 2009

Illustration 1: Diagram of program function and data flow

The Clean programming language. Group 25, Jingui Li, Daren Tuzi

1 Abstract Data Types Information Hiding

An Introduction to Assembly Programming with the ARM 32-bit Processor Family

SQLITE C/C++ TUTORIAL

Object Oriented Software Design II

PHP Debugging. Draft: March 19, Christopher Vickery

PetaLinux SDK User Guide. Application Development Guide

Chapter 13 - The Preprocessor

Makefiles and ROOT. Sean Brisbane 12/12/11

PKCS #11 opencryptoki for Linux HOWTO

Introduction to Scientific Computing Part II: C and C++ C. David Sherrill School of Chemistry and Biochemistry Georgia Institute of Technology

public static void main(string[] args) { System.out.println("hello, world"); } }

ASCII Encoding. The char Type. Manipulating Characters. Manipulating Characters

Virtuozzo Virtualization SDK

Tutorial on C Language Programming

System Calls and Standard I/O

The GenomeTools Developer s Guide

CpSc212 Goddard Notes Chapter 6. Yet More on Classes. We discuss the problems of comparing, copying, passing, outputting, and destructing

GNU Make. A Program for Directing Recompilation GNU make Version 4.1 September Richard M. Stallman, Roland McGrath, Paul D.

Programmation Systèmes Cours 9 UNIX Domain Sockets

Table of Contents. The RCS MINI HOWTO

Applied Programming and Computer Science, DD2325/appcs15 PODF, Programmering och datalogi för fysiker, DA7011

Applying Clang Static Analyzer to Linux Kernel

PART-A Questions. 2. How does an enumerated statement differ from a typedef statement?

Project 2: Bejeweled

Informatica e Sistemi in Tempo Reale

Programming Languages CIS 443

5 Arrays and Pointers

The make utility. Basics

Dalhousie University CSCI 2132 Software Development Winter 2015 Lab 7, March 11

Fortify on Demand Security Review. Fortify Open Review

Software documentation systems

Linux Driver Devices. Why, When, Which, How?

csce4313 Programming Languages Scanner (pass/fail)

CMPT 373 Software Development Methods. Building Software. Nick Sumner Some materials from Shlomi Fish & Kitware

V850E2/ML4 APPLICATION NOTE. Performance Evaluation Software. Abstract. Products. R01AN1228EJ0100 Rev Aug. 24, 2012

Introduction to Programming II Winter, 2014 Assignment 2

Sources: On the Web: Slides will be available on:

How To Write Portable Programs In C

Applied Informatics C++ Coding Style Guide

Next, the driver runs the C compiler (cc1), which translates main.i into an ASCII assembly language file main.s.

Lecture 3. Arrays. Name of array. c[0] c[1] c[2] c[3] c[4] c[5] c[6] c[7] c[8] c[9] c[10] c[11] Position number of the element within array c

Running your first Linux Program

SMTP-32 Library. Simple Mail Transfer Protocol Dynamic Link Library for Microsoft Windows. Version 5.2

Channel Access Client Programming. Andrew Johnson Computer Scientist, AES-SSG

C Dynamic Data Structures. University of Texas at Austin CS310H - Computer Organization Spring 2010 Don Fussell

As previously noted, a byte can contain a numeric value in the range Computers don't understand Latin, Cyrillic, Hindi, Arabic character sets!

Operating Systems. Privileged Instructions

Visual Basic Programming. An Introduction

Magit-Popup User Manual

Lab 4: Socket Programming: netcat part

GUJARAT TECHNOLOGICAL UNIVERSITY, AHMEDABAD, GUJARAT COURSE CURRICULUM. Course Title: Advanced Computer Programming (Code: )

Qt Signals and Slots. Olivier Goffart. October 2013

CPSC 226 Lab Nine Fall 2015

Understand for FORTRAN

WebPublish User s Manual

Specific Simple Network Management Tools

Setting up PostgreSQL

General Software Development Standards and Guidelines Version 3.5

Advanced UNIX Programming with Linux. 1 Getting Started 2 Writing Good GNU/Linux Software 3 Processes 4 Threads 5 Interprocess Communication

GTask Developing asynchronous applications for multi-core efficiency

Unix Security Technologies. Pete Markowsky <peterm[at] ccs.neu.edu>

LOW LEVEL FILE PROCESSING

GTk+ and GTkGLExt Build Process for Windows 32- bit

The following themes form the major topics of this chapter: The terms and concepts related to trees (Section 5.2).

CORBA Programming with TAOX11. The C++11 CORBA Implementation

gbuild: State of the LibreOffice build system

Using the Radmind Command Line Tools to. Maintain Multiple Mac OS X Machines

INT322. By the end of this week you will: (1)understand the interaction between a browser, web server, web script, interpreter, and database server.

Member Functions of the istream Class

AN AES encryption and decryption software on LPC microcontrollers. Document information

Lecture 11 Doubly Linked Lists & Array of Linked Lists. Doubly Linked Lists

ECE 341 Coding Standard

6.s096. Introduction to C and C++

Oracle Tuxedo Systems and Application Monitor (TSAM)

Unix Shell Scripts. Contents. 1 Introduction. Norman Matloff. July 30, Introduction 1. 2 Invoking Shell Scripts 2

RTI Monitoring Library Getting Started Guide

Using C to Access Data Stored in Program Memory on the TMS320C54x DSP

TNM093 Practical Data Visualization and Virtual Reality Laboratory Platform

Introduction to Information Security

Textbook: T. Issariyakul and E. Hossain, Introduction to Network Simulator NS2, Springer

Netscape Internet Service Broker for C++ Programmer's Guide. Contents

Transcription:

Environnements et Outils de Développement Cours 6 Building with make Stefano Zacchiroli zack@pps.univ-paris-diderot.fr Laboratoire PPS, Université Paris Diderot URL http://upsilon.cc/zack/teaching/1314/ed6/ Copyright 2012 2013 Stefano Zacchiroli 2009 Luca Padovani License Creative Commons Attribution-ShareAlike 4.0 International License http://creativecommons.org/licenses/by-sa/4.0/deed.en_us Stefano Zacchiroli (Paris Diderot) Make 1 / 42

The build process (reminder) Stefano Zacchiroli (Paris Diderot) Make 2 / 42

Monolitic solution #include <stdio. h> #include <stdlib. h> void swap ( int * x, int * y ) {... int gcd ( int m, int n ) {... int main ( int argc, char* argv [ ] ) {... $ gcc main. c $ Stefano Zacchiroli (Paris Diderot) Make 3 / 42

Modularization Let s split main program into 3 modules : 1 main program (main.c) 2 GCD (Greated Common Divisor) computation (gcd.c) 3 value exchange (swap.c) Either : $ gcc c main. c $ gcc c gcd. c $ gcc c swap. c $ gcc main. o gcd. o swap. o or $ gcc c main. c gcd. c swap. c $ gcc main. o gcd. o swap. o or even $ gcc *. c $ Stefano Zacchiroli (Paris Diderot) Make 4 / 42

Inter-module code consistency void swap ( int * x, int * y ) { int t = *x ; *x = *y ; *y = t ; int gcd ( int m, int n ) { while (m > 0) { i f (m < n ) swap(m, n ) ; m = n ; return n ; $ gcc o gcd *. c. / gcd 5 6 Segmentation f a u l t $ Stefano Zacchiroli (Paris Diderot) Make 5 / 42

Headers #ifndef SWAP_H #define SWAP_H void swap ( int *, int * ) ; #endif /* SWAP_H */ #include "swap. h" int gcd ( int m, int n ) { while (m > 0) { i f (m < n ) swap(m, n ) ; /* error! */ m = n ; return n ; $ gcc c gcd_wrong. c gcd_wrong. c : In function gcd : gcd_wrong. c : 7 : warning : passing argument 1 of swap makes pointer from integer without a cast gcd_wrong. c : 7 : warning : passing argument 2 of swap makes pointer from integer without a cast Stefano Zacchiroli (Paris Diderot) Make 6 / 42

Correct version #ifndef GCD_H #define GCD_H int gcd ( int, int ) ; #endif /* GCD_H */ #include "gcd. h" /* important! */ #include "swap. h" int gcd ( int m, int n ) { while (m > 0) { i f (m < n ) swap(&m, &n ) ; m = n ; return n ; Stefano Zacchiroli (Paris Diderot) Make 7 / 42

Planning build with make make allows to plan and describe once and for all the build process in a Makefile gcd : main. c gcd. c swap. c gcc o gcd main. c gcd. c swap. c clean : rm f gcd gcd and clean are targets of specified rules after ":" you have the target s prerequisites in subsequent line(s), prefixed by a tabulation character, you have the commands that allow to build a target Stefano Zacchiroli (Paris Diderot) Make 8 / 42

make behavior If a Makefile (or a makefile) exists, executing make will try to obtain its first target An alternative Makefile can be specified using make -f The variant make target will try to obtain the given target (instead of the first one in the Makefile) With make -n we can examin the command sequence that make would execute, without actually executing them (dry run mode) make n gcc o gcd main. c gcd. c swap. c Stefano Zacchiroli (Paris Diderot) Make 9 / 42

Makefile variables It often comes handy to make parametric rules, based on the value of variables. SOURCES = main. c gcd. c swap. c gcd : $( SOURCES) gcc o gcd $( SOURCES) clean : rm f gcd The reference $(SOURCES) expands to the string main.c gcd.c swap.c Note In spite of having the same syntax, Make s $(SOURCES) has nothing to do with Shell s command substitution $(code...). One is expanded by make, the other by the shell, and the semantics is radically different. Stefano Zacchiroli (Paris Diderot) Make 10 / 42

How make works When you invoke make target, make computes the (acyclic!) graph of dependencies that are needed to obtain target SOURCES = main. c gcd. c swap. c gcd : $( SOURCES) gcc o gcd $( SOURCES) clean : rm f gcd to obtain gcd we need main.c gcd.c swap.c to obtain main.c we don t need anything, as the file is already available ditto for gcd.c ditto for swap.c the prerequisites for gcd (i.e. its dependencies) are now satisfied, so we run the command(s) associated to the target gcd Stefano Zacchiroli (Paris Diderot) Make 11 / 42

How make works : unsatisfied prerequisites SOURCES = main. c gcd. c swop. c gcd : $( SOURCES) gcc o gcd $( SOURCES) clean : rm f gcd make does not know that the Makefile is wrong $ make f Makefile. err make: *** No rule to make target swop. c, needed by gcd. Stop. Stefano Zacchiroli (Paris Diderot) Make 12 / 42

How make works : time make laziness Before running the command(s) associated to a target t, make verify two things : 1 the time T t of last modifications of target t assumption : targets are files 2 the most recent time T d of modifications of t dependencies If T t > T d, the target is more recent than each of its dependencies Therefore, no need to rebuild t, and the associated command(s) will be ignored Stefano Zacchiroli (Paris Diderot) Make 13 / 42

How make works : time example $ l s l t o t a l 32 rwxr xr x 1 zack zack 7412 mar 6 19:23 gcd rw r r 1 zack zack 155 mar 6 19:23 gcd. c rw r r 1 zack zack 81 mar 6 19:23 gcd. h rw r r 1 zack zack 327 mar 6 19:24 main. c rw r r 1 zack zack 75 mar 6 19:28 Makefile rw r r 1 zack zack 65 mar 6 19:27 swap. c rw r r 1 zack zack 88 mar 6 19:23 swap. h $ make gcc o gcd main. c gcd. c swap. c $ l s l t o t a l 32 rwxr xr x 1 zack zack 7412 mar 6 19:30 gcd rw r r 1 zack zack 155 mar 6 19:23 gcd. c rw r r 1 zack zack 81 mar 6 19:23 gcd. h rw r r 1 zack zack 327 mar 6 19:24 main. c rw r r 1 zack zack 75 mar 6 19:28 Makefile rw r r 1 zack zack 65 mar 6 19:27 swap. c rw r r 1 zack zack 88 mar 6 19:23 swap. h $ make make: gcd i s up to date. Stefano Zacchiroli (Paris Diderot) Make 14 / 42

Towards separate compilation $ make make: gcd i s up to date. $ touch gcd. c $ l s l rwxr xr x 1 zack zack 7412 mar 6 19:30 gcd rw r r 1 zack zack 155 mar 6 19:31 gcd. c rw r r 1 zack zack 81 mar 6 19:23 gcd. h rw r r 1 zack zack 327 mar 6 19:24 main. c rw r r 1 zack zack 75 mar 6 19:28 Makefile rw r r 1 zack zack 65 mar 6 19:27 swap. c rw r r 1 zack zack 88 mar 6 19:23 swap. h $ make gcc o gcd main. c gcd. c swap. c all.c files get recompiled even if only one has changed! Stefano Zacchiroli (Paris Diderot) Make 15 / 42

Separate compilation SOURCES = main. c gcd. c swap. c OBJS = main. o gcd. o swap. o gcd : $( OBJS ) gcc o gcd $( OBJS ) main. o : main. c gcd. h gcc c main. c gcd. o : gcd. c gcd. h swap. h gcc c gcd. c swap. o : swap. c swap. h gcc c swap. c clean : rm f gcd $( OBJS ) dependencies are now more precisely associated to each target and we also take into account.h files now Stefano Zacchiroli (Paris Diderot) Make 16 / 42

Separate compilation example $ make gcc c main. c gcc c gcd. c gcc c swap. c gcc o gcd main. o gcd. o swap. o $ touch gcd. c $ l s l t o t a l 40 rw r r 1 zack zack 231 Dec 12 13:12 Makefile rw r r 1 zack zack 322 Dec 12 13:08 main. c rw r r 1 zack zack 836 Dec 12 13:13 main. o rwxr xr x 1 zack zack 12668 Dec 12 13:13 gcd rw r r 1 zack zack 156 Dec 12 13:13 gcd. c rw r r 1 zack zack 81 Dec 12 13:08 gcd. h rw r r 1 zack zack 436 Dec 12 13:13 gcd. o rw r r 1 zack zack 65 Dec 12 13:08 swap. c rw r r 1 zack zack 88 Dec 12 13:08 swap. h rw r r 1 zack zack 312 Dec 12 13:13 swap. o $ make gcc c gcd. c gcc o gcd main. o gcd. o swap. o Stefano Zacchiroli (Paris Diderot) Make 17 / 42

Towards a more proper Makefile SOURCES = main. c gcd. c swap. c OBJS = $(SOURCES:%. c=%.o ) gcd : $( OBJS ) gcc o gcd $( OBJS ) main. o : main. c gcd. h gcc c main. c gcd. o : gcd. c gcd. h swap. h gcc c gcd. c swap. o : swap. c swap. h gcc c swap. c clean : rm f gcd $( OBJS ) Other useful transformation $( basename src /foo. c src 1.0/bar hacks ) => src /foo src 1.0/bar hacks $( addprefix src /, foo bar ) => src /foo src /bar $( wildcard *. c ) => gcd. c main. c swap. c See make manual, Functions for transforming text Stefano Zacchiroli (Paris Diderot) Make 18 / 42

Automatic variables Automatic variables are predefined (and context-dependent) variables that you can use in Makefile-s. Using automatic variables simplify writing rules. Using automatic variables will become necessary with implicit rules. SOURCES = main. c gcd. c swap. c OBJS = $(SOURCES:%. c=%.o ) gcd : $( OBJS ) gcc o $@ $( OBJS ) main. o : main. c gcd. h gcc c $< gcd. o : gcd. c gcd. h swap. h gcc c $< swap. o : swap. c swap. h gcc c $< clean : rm f gcd $( OBJS ) Stefano Zacchiroli (Paris Diderot) Make 19 / 42

Some (not so) frequently used automatic variables $@ full target name $< name of the first dependency $? names of the dependencies that are more recent than target $ˆ names of all dependencies (merging duplicates) $+ names of all dependencies (not merging duplicates) $(@D) target s directory (dir/foo.o dir) $(@F) target s base name (dir/foo.o foo.o) $(<D) directory of the first dependency $(<F) base name of the first dependency... See make manual, Automatic Variables Stefano Zacchiroli (Paris Diderot) Make 20 / 42

Implicit rules main. o : main. c gcd. h gcc c $< gcd. o : gcd. c gcd. h swap. h gcc c $< swap. o : swap. c swap. h gcc c $< # same command # same command # same command An implicit rules defines a rule pattern SOURCES = main. c gcd. c swap. c OBJS = $(SOURCES:%. c=%.o ) gcd : $( OBJS ) gcc o $@ $( OBJS ) %.o : %.c @echo " building $(@:%.o=%)... " @gcc c $< main. o : main. c gcd. h gcd. o : gcd. c gcd. h swap. h swap. o : swap. c swap. h clean : rm f gcd $( OBJS ) Stefano Zacchiroli (Paris Diderot) Make 21 / 42

Larger project, more directories $ l s lr. : t o t a l 12 rw r r 1 zack zack 394 Dec 12 14:03 Makefile rw r r 1 zack zack 137 Dec 12 13:42 common. h drwxr xr x 7 zack zack 238 Dec 12 14:09 io rw r r 1 zack zack 386 Dec 12 13:42 main. c drwxr xr x 5 zack zack 170 Dec 12 14:09 sorting. / io : t o t a l 20 rw r r 1 zack zack 260 Dec 12 14:08 Makefile rw r r 1 zack zack 367 Dec 12 14:05 reader. c rw r r 1 zack zack 121 Dec 12 13:59 reader. h rw r r 1 zack zack 159 Dec 12 13:45 writer. c rw r r 1 zack zack 124 Dec 12 13:45 writer. h. / sorting : t o t a l 12 rw r r 1 zack zack 221 Dec 12 14:08 Makefile rw r r 1 zack zack 499 Dec 12 14:02 sort. c rw r r 1 zack zack 113 Dec 12 14:01 sort. h Stefano Zacchiroli (Paris Diderot) Make 22 / 42

main.c #include <stdio. h> #include "common. h" #include " reader. h" #include " writer. h" #include " sort. h" string lines [ MAXLINES ] ; int main ( ) { int n_lines = read_lines ( lines, MAXLINES ) ; i f ( n_lines > 0) { sort ( lines, 0, n_lines 1 ) ; write_ lines ( lines, n_lines ) ; return 0; else i f ( n_lines < 0) { f p r i n t f ( stderr, " error : too many input lines \n" ) ; return 1; Stefano Zacchiroli (Paris Diderot) Make 23 / 42

common.h #ifndef COMMON_H #define COMMON_H #define MAXLINES 5000 #define MAXLEN 1000 typedef char* string ; #endif /* COMMON_H */ Stefano Zacchiroli (Paris Diderot) Make 24 / 42

io/reader.h & io/reader.c #ifndef READER_H #define READER_H #include "common. h" int read_lines ( string [ ], int ) ; #endif /* READER_H */ #include <stdio. h> #include <stdlib. h> #include <string. h> #include " reader. h" int read_lines ( string line [ ], int max_lines ) { int len ; int n_lines = 0; char buffer [MAXLEN + 1 ] ; while ( fgets ( buffer, MAXLEN, stdin ) ) { line [ n_lines ] = ( string ) malloc ( sizeof ( char ) * strlen ( buffer ) ) ; strcpy ( l i n e [ n_lines ], buffer ) ; n_lines ++; return n_lines ; Stefano Zacchiroli (Paris Diderot) Make 25 / 42

io/writer.h & io/writer.c #ifndef WRITER_H #define WRITER_H #include "common. h" void write_lines ( string [ ], int ) ; #endif /* WRITER_H */ #include <stdio. h> #include " writer. h" void write_ lines ( string line [ ], int n_lines ) { int i ; for ( i = 0; i < n_lines ; i ++) fputs ( l i n e [ i ], stdout ) ; Stefano Zacchiroli (Paris Diderot) Make 26 / 42

sorting/sort.c #include <string. h> #include " sort. h" void swap ( string line [ ], int i, int j ) { string temp = l i n e [ i ] ; l i n e [ i ] = l i n e [ j ] ; l i n e [ j ] = temp; void sort ( string l i n e [ ], int l e f t, int right ) { i f ( l e f t < right ) { int i, l a s t ; swap ( line, l e f t, ( l e f t + right ) / 2 ) ; l a s t = l e f t ; for ( i = l e f t + 1; i <= right ; i ++) i f ( strcmp ( l i n e [ i ], l i n e [ l e f t ] ) < 0) swap ( line, ++last, i ) ; swap ( line, l e f t, l a s t ) ; sort ( line, l e f t, l a s t 1 ) ; sort ( line, l a s t + 1, right ) ; Stefano Zacchiroli (Paris Diderot) Make 27 / 42

Makefile NAME = sort SOURCES = main. c OBJS = $(SOURCES:%. c=%.o ) INCLUDES = I. I i o Isorting IOLIB = io / l i b i o. a SORTINGLIB = sorting / libsorting. a a l l : make C io make C sorting make $(NAME) $(NAME) : $( OBJS ) $( IOLIB ) $( SORTINGLIB ) gcc o $@ $^ %.o : %.c gcc c $( INCLUDES ) $< main. o : clean : io /reader. h io / writer. h common. h make C io clean make C sorting clean rm f $(NAME) $( OBJS ) Stefano Zacchiroli (Paris Diderot) Make 28 / 42

io/makefile SOURCES = reader. c writer. c OBJS = $(SOURCES:%. c=%.o ) INCLUDES = I.. / a l l : l i b i o. a l i b i o. a : $( OBJS ) ar cru $@ $^ ranlib $@ %.o : %.c gcc c $( INCLUDES ) $< reader. o : reader. h.. /common. h writer. o : writer. h.. /common. h clean : rm f l i b i o. a $( OBJS ) Stefano Zacchiroli (Paris Diderot) Make 29 / 42

sort/makefile SOURCES = sort. c OBJS = $(SOURCES:%. c=%.o ) INCLUDES = I.. / a l l : libsorting. a libsorting. a : $( OBJS ) ar cru $@ $^ ranlib $@ %.o : %.c gcc c $( INCLUDES ) $< sort. o : clean :.. /common. h rm f libsorting. a $( OBJS ) Stefano Zacchiroli (Paris Diderot) Make 30 / 42

Building the project example $ make make C io make[ 1 ] : Entering directory io gcc c I.. / reader. c gcc c I.. / writer. c ar cru l i b i o. a reader. o writer. o ranlib l i b i o. a make[ 1 ] : Leaving directory io make C sorting make[ 1 ] : Entering directory sorting gcc c I.. / sort. c ar cru libsorting. a sort. o ranlib libsorting. a make[ 1 ] : Leaving directory sorting make sort make[ 1 ] : Entering directory. gcc c I. I i o Isorting main. c gcc o sort main. o io / l i b i o. a sorting / libsorting. a make[ 1 ] : Leaving directory. $ Stefano Zacchiroli (Paris Diderot) Make 31 / 42

Dependencies on external libraries Most programs rely on functionalities offered by external libraries, i.e. libraries other than the C standard library (that comes with the compiler). To the end of building an executable that uses external libraries, we need to take care of : 1 ensure that external library header files (.h) are available at compile time 2 ensure that libraries (static.a and/or dynamic.so) are available at link time Stefano Zacchiroli (Paris Diderot) Make 32 / 42

common.h & main.c #ifndef COMMON_H #define COMMON_H typedef char* string ; #endif /* COMMON_H */ #include <stdio. h> #include <glib. h> #include " reader. h" #include " writer. h" #include " sort. h" int main ( ) { GPtrArray * lines = read_lines ( ) ; g_assert ( lines ) ; i f ( lines >len > 0) { sort ( lines ) ; write_ lines ( lines ) ; return 0; else return 1; Stefano Zacchiroli (Paris Diderot) Make 33 / 42

io/reader.c #define MAXLEN 1000 (#include-s omitted) GString * read_line ( ) { gint len ; GString * buffer = g_string_new ( " " ) ; gchar chunk [MAXLEN ] ; do { i f ( fgets ( chunk, MAXLEN, stdin ) ) g_string_append ( buffer, chunk ) ; else return NULL; while (! strchr ( chunk, \n ) ) ; return buffer ; GPtrArray * read_lines ( ) { GPtrArray * lines = g_ptr_array_new ( ) ; GString * line ; while ( ( l i n e = read_line ( ) ) ) g_ptr_array_add ( lines, line ) ; return lines ; Stefano Zacchiroli (Paris Diderot) Make 34 / 42

io/writer.h & io/writer.c #ifndef WRITER_H #define WRITER_H #include <glib. h> void write_ lines ( GPtrArray * ) ; #endif /* WRITER_H */ #include <stdio. h> #include " writer. h" void write_ line ( GString * line, gpointer user_data ) { g _ r e t u r n _ i f _ f a i l ( l i n e!= NULL ) ; fputs ( line >str, stdout ) ; void write_ lines ( GPtrArray * lines ) { g _ r e t u r n _ i f _ f a i l ( lines!= NULL ) ; g_ptr_array_foreach ( lines, ( GFunc ) write_ line, NULL ) ; Stefano Zacchiroli (Paris Diderot) Make 35 / 42

io/sort.h & io/sort.c #ifndef SORT_H #define SORT_H #include <glib. h> void sort ( GPtrArray * ) ; #endif /* SORT_H */ #include <string. h> #include " sort. h" gint compare_lines ( const GString ** s1, const GString ** s2 ) { g _ r e t u r n _ v a l _ i f _ f a i l ( s1!= NULL, 0 ) ; g _ r e t u r n _ v a l _ i f _ f a i l ( s2!= NULL, 0 ) ; return strcmp ( ( * s1) >str, ( * s2) > s t r ) ; void sort ( GPtrArray * lines ) { g _ r e t u r n _ i f _ f a i l ( lines!= NULL ) ; g_ptr_array_sort ( lines, (GCompareFunc) compare_lines ) ; Stefano Zacchiroli (Paris Diderot) Make 36 / 42

Makefile NAME = sort SOURCES = main. c OBJS = $(SOURCES:%. c=%.o ) INCLUDES = I. I i o Isorting pkg config glib 2.0 cflags LIBS = pkg config glib 2.0 libs IOLIB = io / l i b i o. a SORTINGLIB = sorting / libsorting. a a l l : make C io make C sorting make $(NAME) $(NAME) : $( OBJS ) $( IOLIB ) $( SORTINGLIB ) gcc o $@ $^ $( LIBS ) %.o : %.c gcc c $( INCLUDES ) $< main. o : io /reader. h io / writer. h common. h clean : make C io clean make C sorting clean rm f $(NAME) $( OBJS ) Stefano Zacchiroli (Paris Diderot) Make 37 / 42

io/makefile SOURCES = reader. c writer. c OBJS = $(SOURCES:%. c=%.o ) INCLUDES = I.. / pkg config glib 2.0 cflags a l l : l i b i o. a l i b i o. a : $( OBJS ) ar cru $@ $^ ranlib $@ %.o : %.c gcc c $( INCLUDES ) $< reader. o : reader. h.. /common. h writer. o : writer. h.. /common. h clean : rm f l i b i o. a $( OBJS ) Stefano Zacchiroli (Paris Diderot) Make 38 / 42

sorting/makefile SOURCES = sort. c OBJS = $(SOURCES:%. c=%.o ) INCLUDES = I.. / pkg config glib 2.0 cflags a l l : libsorting. a libsorting. a : $( OBJS ) ar cru $@ $^ ranlib $@ %.o : %.c gcc c $( INCLUDES ) $< sort. o : clean :.. /common. h rm f libsorting. a $( OBJS ) Stefano Zacchiroli (Paris Diderot) Make 39 / 42

Building the project example $ make make C io make[ 1 ] : Entering directory io gcc c I.. / pkg config glib 2.0 cflags reader. c gcc c I.. / pkg config glib 2.0 cflags writer. c ar cru l i b i o. a reader. o writer. o ranlib l i b i o. a make[ 1 ] : Leaving directory io make C sorting make[ 1 ] : Entering directory sorting gcc c I.. / pkg config glib 2.0 cflags sort. c ar cru libsorting. a sort. o ranlib libsorting. a make[ 1 ] : Leaving directory sorting make sort make[ 1 ] : Entering directory sort glib gcc c I. I i o Isorting pkg config glib 2.0 cflags main. c gcc o sort main. o io / l i b i o. a sorting / libsorting. a pkg config \ glib 2.0 libs make[ 1 ] : Leaving directory sort glib $ ldd sort Stefano Zacchiroli (Paris Diderot) Make 40 / 42

State of the project discussion tool names (gcc, ar, make,...) and their invocation syntax are hard-coded in Makefile-s building needs the existence of specific libraries and fails abruptly if the corresponding prerequisites are not available maintaining the project across several directories is clumsy and error-prone Makefile-s do not implement targets to package, install, and uninstall the software All those aspects are tolerable for small projects. They become too constraining for large and complex projects. Stefano Zacchiroli (Paris Diderot) Make 41 / 42

References GNU Make homepage : http://www.gnu.org/software/make/ GNU Make manual $ info make M-x info in Emacs http://www.gnu.org/software/make/manual/ book : Managing Projects with GNU Make, Robert Mecklenburg, 3rd ed. O Reilly, 2004. available online at http://oreilly.com/catalog/make3/book/index.csp under the terms of the GNU Free Documentation License Stefano Zacchiroli (Paris Diderot) Make 42 / 42