========================================================================== Section 2 Notes ========================================================================== - 1. Manually compiling your first C program - 2. Using Make to automate compilation - 3. Manually compling and linking your first C program - 4. Using Make to automate compilation and linking * As in the tutorial, log into ecelinux from your laptop % ssh -X cb535@ecelinux-01.ece.cornell.edu % ssh -X cb535@ecelinux-02.ece.cornell.edu - don't forget to source the setup script! % source setup-ece2400.sh -------------------------------------------------------------------------- 1. Manually compiling your first C program -------------------------------------------------------------------------- - create a directory to work in % mkdir -p $HOME/ece2400/sec2/ex1 - write a simple C program % cd $HOME/ece2400/sec2/ex1 % geany main.c % nano main.c #include int avg( int x, int y ) { int sum = x + y; return sum / 2; } int main() { int a = 10; int b = 20; int c = avg( a, b ); printf( "average of %d and %d is %d\n", a, b, c ); return 0; } - compile the C program using gcc (open-source GNU C compiler) % cd $HOME/ece2400/sec2/ex1 % gcc -o main main.c - '-o' specifies the desired file name for the compiled binary - execute the binary % cd $HOME/ece2400/sec2/ex1 % ./main - try averaging 10 and 15 - is the result what you expect? - remove the program binary % cd $HOME/ece2400/sec2/ex1 % rm -rf main -------------------------------------------------------------------------- 2. Using Make to automate compilation -------------------------------------------------------------------------- - manually compiling C programs is tedious and error prone - make is a tool to help automate "making" C program binaries - make uses a "Makefile" to figure out how to make the C program binary - a Makefile is a collection of rules - each rule specifies how to make one file - example make rule target: prerequisite1 prerequisite2 linux command to make target from prerequistes - write a simple Makefile % cd $HOME/ece2400/sec2/ex1 % geany Makefile % nano Makefile main: main.c gcc -o main main.c clean: rm -rf main - instead of use the TAB key to insert a TAB - the first rule specifies how to make main from main.c - the second rule is a "phony" rule for cleaning generated files - first verify that there is no main program binary % cd $HOME/ece2400/sec2/ex1 % ls - now make the program binary % cd $HOME/ece2400/sec2/ex1 % make main % ls - the argument to make specifies what you want to make - make will print out the commands it is running - verify that the program binary now exists with ls - go aheand and execute the program binary % cd $HOME/ece2400/sec2/ex1 % ./main - try running make multiple times % cd $HOME/ece2400/sec2/ex1 % make main % make main - make only executes a rule if the prerequisite changed - reduces the number of steps required to build large projects - let's use clean to clean up the generated program binary % cd $HOME/ece2400/sec2/ex1 % make clean % ls - the default "target" to make is the first rule in the Makefile % cd $HOME/ece2400/sec2/ex1 % make % ./main - very useful pattern is to make a binary and then execute it % cd $HOME/ece2400/sec2/ex1 % make main && ./main -------------------------------------------------------------------------- 3. Manually compling and linking your first C program -------------------------------------------------------------------------- - let's create a program with more than one C program source file - C program source files other than the file containing main usually have a header file (.h) - the header file _declares_ functions but does not _define_ them - the source file _defines_ functions - other source files include the header file to be able to call the functions in the corresponding source file - source files are compiled into object file - the linker links all of the object file to create program binary - create a directory to work in % mkdir -p $HOME/ece2400/sec2/ex2 - write the header file with the function declaration for min % cd $HOME/ece2400/sec2/ex2 % geany min.h % nano min.h int min( int x, int y ); - write the source file with the function definition for min % cd $HOME/ece2400/sec2/ex2 % geany min.c % nano min.c #include "min.h" int min( int x, int y ) { if ( x < 7 ) { return x; } return y; } - write the top-level program source file % cd $HOME/ece2400/sec2/ex2 % geany main.c % nano main.c #include #include "min.h" int main() { int a = 6; int b = 9; int c = min( a, b ); printf( "min of %d and %d is %d\n", a, b, c ); return 0; } - compile the C source file for min into an object file first % cd $HOME/ece2400/sec2/ex2 % gcc -c -o min.o min.c - notice the extra '-c' command line option for compiling object files - object file only has machine instructions for min % cd $HOME/ece2400/sec2/ex2 % objdump -dC min.o - compile the C source file for main into an object file next % cd $HOME/ece2400/sec2/ex2 % gcc -c -o main.o main.c - object file only has machine instructions for main % cd $HOME/ece2400/sec2/ex2 % objdump -dC main.o - link the two objects into an executable program binary, and execute % cd $HOME/ece2400/sec2/ex2 % gcc -o main main.o min.o % ./main - executable binary has machine instructions for min, main, printf, etc % cd $HOME/ece2400/sec2/ex2 % objdump -dC main - remove generated object files and program binary % cd $HOME/ece2400/sec2/ex2 % rm -rf min.o main.o main -------------------------------------------------------------------------- 4. Using Make to automate compilation and linking -------------------------------------------------------------------------- - more files, more steps, ever more tedious - use make to automate all steps - write a Makefile for compiling multiple files % cd $HOME/ece2400/sec2/ex2 % geany Makefile % nano Makefile min.o: min.c min.h gcc -c -o min.o min.c main.o: main.c min.h gcc -c -o main.o main.c main: main.o min.o gcc -o main main.o min.o clean: rm -rf min.o main.o main - now make the program binary % cd $HOME/ece2400/sec2/ex2 % make main % ./main - notice that make runs all three steps we ran manually above - you can also make intermediate steps % cd $HOME/ece2400/sec2/ex2 % make clean % make main.o % make main - notice that when making main we only needed to compile min.o - make is smart enough to figure out that main.o is up to date - the default target is always the first rule - to make the default be main add a dummy rule at the top of Makefile % cd $HOME/ece2400/sec2/ex2 % geany Makefile % nano Makefile all: main ... - now the phony target all builds everything, but that is also default % cd $HOME/ece2400/sec2/ex2 % make clean % make && ./main