Loading lang_c_01_build...
int // cette fonction doit renvoyer un entier main(void) // définition d'une fonction main() sans paramètre { printf("entering main()\n"); // appel d'une fonction printf() avec une chaîne littérale printf("leaving main()\n"); // un second appel return 0; // voici l'entier que cette fonction doit renvoyer }
{ }(accolades).
#include <stdio.h>
indent(1);
void indent(int depth);
#include <stdio.h>
void indent(int depth) { while(depth!=0) { printf("| "); depth=depth-1; } }
<stdio.h>).
|. Puisque nous disposons maintenant de plusieurs fichiers sources, nous allons légèrement modifier le procédé de fabrication du programme exécutable en ayant recours à la compilation séparée
#include <stdio.h>
typedef const char *Tag; // déclaration du type Tag
void indent(Tag tag, // un nouveau paramètre de type Tag int depth) { while(depth!=0) { printf("%s", tag); // affichage de ce nouveau paramètre depth=depth-1; } }
<stdio.h>pour prendre connaissance de la déclaration de la fonction printf(), nous allons fournir un fichier d'en-tête qui déclare les fonctionnalités que le module_A.c définit. Ouvrez votre éditeur de texte préféré pour rédiger le contenu d'un nouveau fichier nommé module_A.h, par exemple : $ gedit module_A.h & ↵ Dans celui-ci saisissez (par copier/coller) le texte suivant :
typedef const char *Tag;
void indent(Tag tag, int depth);
#include "module_A.h" #include <stdio.h>
void indent(Tag tag, int depth) { while(depth!=0) { printf("%s", tag); depth=depth-1; } }
#include <stdio.h> #include "module_A.h"
int main(void) { indent(1); printf("entering main()\n"); indent(1); printf("leaving main()\n"); return 0; }
<et
>(chevrons).
indent("* ", 1);
// ...c'est à vous de compléter le début de ce fichier...
void doSomething(Tag tag, int depth) { indent(tag, depth); printf("entering doSomething()\n"); indent(tag, depth); printf("...working hard...\n"); indent(tag, depth); printf("leaving doSomething()\n"); }
int main(void) { indent("* ", 1); printf("entering main()\n"); doSomething("| ", 2); indent("* ", 1); printf("leaving main()\n"); return 0; }
#ifndef MODULE_A_H #define MODULE_A_H
// ...ici l'ancien contenu du fichier...
#endif // MODULE_A_H
#define MODULE_A_H 1
#~~~~ linker command to produce the executable file ~~~~ prog01 : prog01.o module_A.o module_B.o gcc prog01.o module_A.o module_B.o -o prog01
#~~~~ compiler commands for every source file ~~~~ prog01.o : prog01.c gcc prog01.c -c -std=c99 -pedantic
module_A.o : module_A.c gcc module_A.c -c -std=c99 -pedantic
module_B.o : module_B.c gcc module_B.c -c -std=c99 -pedantic
#~~~~ remove generated files ~~~~ clean : rm -f prog01 *.o
...
#~~~~ compiler commands for every source file ~~~~ prog01.o : prog01.c module_A.h module_B.h gcc prog01.c -c -std=c99 -pedantic
module_A.o : module_A.c module_A.h gcc module_A.c -c -std=c99 -pedantic
module_B.o : module_B.c module_B.h module_A.h gcc module_B.c -c -std=c99 -pedantic
...
#~~~~ settings ~~~~ CC=gcc CFLAGS=-std=c99 -pedantic -g
...
#~~~~ compiler commands for every source file ~~~~ prog01.o : prog01.c module_A.h module_B.h ${CC} prog01.c -c ${CFLAGS}
module_A.o : module_A.c module_A.h ${CC} module_A.c -c ${CFLAGS}
module_B.o : module_B.c module_B.h module_A.h ${CC} module_B.c -c ${CFLAGS}
...
{}(accolades, ou encore (), parenthèses).
...
#~~~~ linker command to produce the executable file ~~~~ prog01 : prog01.o module_A.o module_B.o ${CC} $^ -o $@
#~~~~ compiler commands for every source file ~~~~ prog01.o : prog01.c module_A.h module_B.h ${CC} $< -c ${CFLAGS}
module_A.o : module_A.c module_A.h ${CC} $< -c ${CFLAGS}
module_B.o : module_B.c module_B.h module_A.h ${CC} $< -c ${CFLAGS}
...
...
#~~~~ dependencies ~~~~ prog01 : prog01.o module_A.o module_B.o prog01.o : prog01.c module_A.h module_B.h module_A.o : module_A.c module_A.h module_B.o : module_B.c module_B.h module_A.h
#~~~~ generic linker command to produce an executable file ~~~~ % : %.o ${CC} $^ -o $@
#~~~~ generic compiler commands for every source file ~~~~ %.o : %.c ${CC} $< -c ${CFLAGS}
...
...
#~~~~ dependencies ~~~~ prog01 : prog01.o module_A.o module_B.o -include *.d
...
...
#~~~~ remove generated files ~~~~ clean : rm -f prog01 *.o *.d
CFLAGS=-std=c99 -pedantic -MMD -g \ -Werror -Wall -Wextra -Wconversion -Wc++-compat \ -Wwrite-strings -Wold-style-definition -Wvla
#ifndef MODULE_A_H #define MODULE_A_H
typedef const char *Tag;
void indent(Tag tag, int depth);
#endif // MODULE_A_H
#include "module_A.h" // this module #include <stdio.h> // printf()
void indent(Tag tag, int depth) { while(depth!=0) { printf("%s", tag); depth=depth-1; } }
#ifndef MODULE_B_H #define MODULE_B_H
#include "module_A.h" // Tag
void doSomething(Tag tag, int depth);
#endif // MODULE_B_H
#include "module_B.h" // this module #include "module_A.h" // Tag, indent() #include <stdio.h> // printf()
void doSomething(Tag tag, int depth) { indent(tag, depth); printf("entering doSomething()\n"); indent(tag, depth); printf("...working hard...\n"); indent(tag, depth); printf("leaving doSomething()\n"); }
#include <stdio.h> // printf() #include "module_A.h" // indent() #include "module_B.h" // doSomething()
int main(void) { indent("* ", 1); printf("entering main()\n"); doSomething("| ", 2); indent("* ", 1); printf("leaving main()\n"); return 0; }
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # this GNU-makefile relies on the GCC toolchain # nb: on Windows, the Mingw-w64 package provides the mingw32-make.exe command # ( see https://web.enib.fr/~harrouet/dev_tools/#windows.mingw )
#~~~~ control global settings ~~~~ # make opt=2 --> enable optimisation, then disable debug, but keep symbols # make opt=1 --> enable optimisation, then disable debug # make opt=0 --> disable optimisation, then enable debug opt=0 # make clang=1 --> use clang/clang++, not gcc/g++ # make clang=0 --> use gcc/g++, not clang/clang++ clang=0 # make wasm=1 --> target webassembly rather than the native platform # make wasm=0 --> target the native platform rather than webassembly wasm=0
#~~~~ build library or programs ~~~~ # if LIB_TARGET is provided, this library will be built (with its # platform-specific name), otherwise ${EXE_PREFIX}* programs will be built LIB_TARGET= EXE_PREFIX=prog
#~~~~ detect operating system ~~~~ ifneq (${OS},Windows_NT) ifneq (,${findstring Ubuntu,${shell lsb_release -i 2>/dev/null}}) OS:=Ubuntu else ifneq (,${findstring Raspbian,${shell lsb_release -i 2>/dev/null}}) # Standard distribution for Raspberry-Pi OS:=Raspbian else OS:=${strip ${shell uname -s}} endif ifneq (,${findstring Microsoft,${shell cat /proc/version 2>/dev/null}}) # Windows-Subsystem-for-Linux OS:=${OS}_WSL endif endif
#~~~~ adjust project-specific settings ~~~~ CPPFLAGS= # CPPFLAGS+=-I header/path LDFLAGS= # LDFLAGS+=-L library/path -Wl,-rpath,library/path -l library_name CFLAGS= CXXFLAGS= BINFLAGS= ifneq (,${findstring Windows_NT,${OS}}) # nothing special for now else ifneq (,${strip ${LIB_TARGET}}) BINFLAGS+=-fPIC endif ifneq (,${findstring Darwin,${OS}}) # nothing special for now else ifneq (,${findstring Ubuntu,${OS}}) # sanitizer sometimes requires gold-linker on Ubuntu LDFLAGS+=-fuse-ld=gold else ifneq (,${findstring Raspbian,${OS}}) # some warnings may appear when mixing g++-6 and g++-7 on Raspbian CXXFLAGS+=-Wno-psabi else # nothing special for now endif endif endif
#~~~~ adjust platform-specific features (Posix/Windows/Emscripten...) ~~~~ ifneq (,${findstring Windows_NT,${OS}}) LIB_PREFIX= LIB_SUFFIX=.dll EXE_SUFFIX=.exe SKIP_LINE=echo. REMOVE=del /q else LIB_PREFIX=lib ifneq (,${findstring Darwin,${OS}}) LIB_SUFFIX=.dylib else LIB_SUFFIX=.so endif EXE_SUFFIX= SKIP_LINE=echo REMOVE=rm -rf endif ifeq (${strip ${wasm}},1) LIB_PREFIX:=lib LIB_SUFFIX:=.bc EXE_SUFFIX:=.html endif
#~~~~ deduce file names ~~~~ ifneq (,${strip ${LIB_TARGET}}) LIB_TARGET:=${LIB_PREFIX}${strip ${LIB_TARGET}}${LIB_SUFFIX} MAIN_C_FILES= MAIN_CXX_FILES= else LIB_TARGET:= MAIN_C_FILES=${wildcard ${strip ${EXE_PREFIX}}*.c} MAIN_CXX_FILES=${wildcard ${strip ${EXE_PREFIX}}*.cpp} endif COMMON_C_FILES=${filter-out ${MAIN_C_FILES},${wildcard *.c}} COMMON_CXX_FILES=${filter-out ${MAIN_CXX_FILES},${wildcard *.cpp}} # MAIN_OBJECT_FILES=${sort ${patsubst %.c,%.o,${MAIN_C_FILES}} \ ${patsubst %.cpp,%.o,${MAIN_CXX_FILES}}} COMMON_OBJECT_FILES=${sort ${patsubst %.c,%.o,${COMMON_C_FILES}} \ ${patsubst %.cpp,%.o,${COMMON_CXX_FILES}}} OBJECT_FILES=${MAIN_OBJECT_FILES} ${COMMON_OBJECT_FILES} DEPEND_FILES=${patsubst %.o,%.d,${OBJECT_FILES}} EXE_FILES=${sort ${patsubst %.c,%${EXE_SUFFIX},${MAIN_C_FILES}} \ ${patsubst %.cpp,%${EXE_SUFFIX},${MAIN_CXX_FILES}}} # GENERATED_FILES=${DEPEND_FILES} ${OBJECT_FILES} ${LIB_TARGET} ${EXE_FILES} ifneq (,${findstring Darwin,${OS}}) GENERATED_FILES+=${wildcard *.dSYM} endif ifeq (${strip ${wasm}},1) GENERATED_FILES+=${patsubst %.html,%.js,${EXE_FILES}} GENERATED_FILES+=${patsubst %.html,%.html.mem,${EXE_FILES}} GENERATED_FILES+=${patsubst %.html,%.wasm,${EXE_FILES}} GENERATED_FILES+=${patsubst %.html,%.wast,${EXE_FILES}} endif GENERATED_FILES+=${wildcard output_* *~}
#~~~~ compiler/linker settings ~~~~ CPPFLAGS+=-MMD -pedantic -Wall -Wextra -Wconversion -Wno-sign-conversion CPPFLAGS+=-Wno-unused -Wno-unused-parameter CPPFLAGS+=-Werror -Wfatal-errors CFLAGS+=-std=c99 -Wc++-compat -Wwrite-strings -Wold-style-definition -Wvla CXXFLAGS+=-std=c++17 -Wno-missing-braces LDFLAGS+= BINFLAGS+= ifeq (${strip ${wasm}},1) CC=emcc CXX=em++ CPPFLAGS+=-Wno-dollar-in-identifier-extension LDFLAGS+=-s ALLOW_MEMORY_GROWTH=1 else ifeq (${strip ${clang}},1) CC=clang CXX=clang++ else CC=gcc CXX=g++ endif # ifneq (,${strip ${MAIN_CXX_FILES} ${COMMON_CXX_FILES}}) # force c++ link if there is at least one c++ source file LD:=${CXX} else LD:=${CC} endif
#~~~~ debug/optimisation settings ~~~~ ifneq (${strip ${opt}},0) CPPFLAGS+=-DNDEBUG BINFLAGS+=-O3 -ffast-math # BINFLAGS+=-fopt-info-vec-optimized ifneq (${strip ${wasm}},1) BINFLAGS+=-march=native endif ifeq (${strip ${opt}},2) # optimise but keep symbols for profiling BINFLAGS+=-g -fno-omit-frame-pointer else BINFLAGS+=-fomit-frame-pointer endif else CPPFLAGS+=-UNDEBUG BINFLAGS+=-g -O0 ifeq (${strip ${wasm}},1) # sanitizer is not available yet with Emscripten else ifneq (,${findstring Windows_NT,${OS}}) # sanitizer is not available yet on Windows else BINFLAGS+=-fsanitize=address,undefined ifneq (,${findstring Raspbian,${OS}}) # dynamic sanitizer libraries may not be found on Raspbian BINFLAGS+=-static-libasan -static-libubsan endif endif endif
#~~~~ main target ~~~~ all : ${EXE_FILES} ${LIB_TARGET}
rebuild : clean all
.SUFFIXES: .SECONDARY: .PHONY: all clean rebuild
#~~~~ linker command to produce the library (if any) ~~~~ ${LIB_TARGET} : ${COMMON_OBJECT_FILES} @echo ==== linking [opt=${opt}] $@ ==== ${LD} -shared -o $@ $^ ${BINFLAGS} ${LDFLAGS} @${SKIP_LINE}
#~~~~ linker command to produce the executable files (if any) ~~~~ %${EXE_SUFFIX} : %.o ${COMMON_OBJECT_FILES} @echo ==== linking [opt=${opt}] $@ ==== ${LD} -o $@ $^ ${BINFLAGS} ${LDFLAGS} @${SKIP_LINE}
#~~~~ compiler command for every source file ~~~~ %.o : %.c @echo ==== compiling [opt=${opt}] $< ==== ${CC} -o $@ $< -c ${BINFLAGS} ${CPPFLAGS} ${CFLAGS} @${SKIP_LINE}
%.o : %.cpp @echo ==== compiling [opt=${opt}] $< ==== ${CXX} -o $@ $< -c ${BINFLAGS} ${CPPFLAGS} ${CXXFLAGS} @${SKIP_LINE}
-include ${DEPEND_FILES}
#~~~~ remove generated files ~~~~ clean : @echo ==== cleaning ==== ${REMOVE} ${GENERATED_FILES} @${SKIP_LINE}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#~~~~ linker command to produce the executable file ~~~~ prog01 : prog01.o module_A.o module_B.o gcc prog01.o module_A.o module_B.o -o prog01
#~~~~ compiler commands for every source file ~~~~ prog01.o : prog01.c module_A.h module_B.h gcc prog01.c -c -std=c99 -pedantic
module_A.o : module_A.c module_A.h gcc module_A.c -c -std=c99 -pedantic
module_B.o : module_B.c module_B.h module_A.h gcc module_B.c -c -std=c99 -pedantic
#~~~~ remove generated files ~~~~ clean : rm -f prog01 *.o
#~~~~ settings ~~~~ CC=gcc CFLAGS=-std=c99 -pedantic -MMD -g \ -Werror -Wall -Wextra -Wconversion -Wc++-compat \ -Wwrite-strings -Wold-style-definition -Wvla
#~~~~ dependencies ~~~~ prog01 : prog01.o module_A.o module_B.o -include *.d
#~~~~ generic linker command to produce an executable file ~~~~ % : %.o ${CC} $^ -o $@
#~~~~ generic compiler commands for every source file ~~~~ %.o : %.c ${CC} $< -c ${CFLAGS}
#~~~~ remove generated files ~~~~ clean : rm -f prog01 *.o *.d