Linux makefile
gcc
GCC is the compiler used to compile code. There are some common output files after compilation: A static library (document).c Preprocessed C language source code. H HEADER file of C language source code. I Preprocessed C language source code
GCC compilation process:
C and h files are preprocessed to generate. I files, which are then compiled to generate assembly language code. S files are processed to generate object files.
Let’s create a file and write a simple code
#include <stdio.h>
int main(a)
{
printf("HelloWorld");
}
Copy the code
pretreatment
Preprocessing instruction:
gcc -E helloWorld.c -o helloWorld.i
Copy the code
There is an extra. I file after executionThen through the LS -L command to view the details of the file, you can see the size of the file, after preprocessing from 59B to 16335B, increased several timesThe reason for the larger size: we referred to the header file stdio.h before, and after the preprocessing, all the contents in.h were copied to this file, so the size of the file became larger.
You can view the details of the file from less Helloworld. I:
To produce assembler
The -s command is mainly used here. As you can see from the following figure, it can operate directly on.c and.i files because the preprocessing operation is already integrated in -s
Generate object file
In the same way, -o also integrates preprocessing and assembler operations, so it can operate directly on.c files:Let’s look at the details of the file:Here you can see that the.o file is smaller than the.s and.i files, because the.o file is just an executable file, but it doesn’t have the ability to execute. The.o file is the machine code that converts the assembly file into a binary file.
Executable files
GCC can read binary.o files directly, so you can use this instruction to generate an executable: GCC helloWorld. O -o myHello
Look at the file size of myHello, which is larger again. As we mentioned earlier, the.o file is an executable file, but it is not executable. To make it executable, GCC needs to add some configuration to the original.o files to make it executable.
digression
As you can see, we can compile.c directly to generate the executable, so what’s the use of the process we learned earlier to generate.i,.s,.o. Although the instructions are now integrated and can be used directly, we still need to know a little bit about these processes, because unlike Java, which is an interpreted language, C is a compiled language. For example, sometimes a program may go wrong not in a.C file, but in some other file. So these fundamental things still need to be understood.
In addition, this method is only used when the header file is an official library. If you use another library, this step will be wrong.
Makefile
Concept: When we compile with GCC, if we have many.c files, we need to enter instructions one by one, which is too cumbersome, so the Makefile comes into being. Makefiles are essentially scripts that simplify many repetitive operations.
Multifile compilation
So I’m going to start with a bunch of dot c files and dot h files, and what I’m going to do here is add, subtract and divide three functions, and I’m going to write them in C.Then myproject.c writes the main function:
#include <stdio.h>
#include "myadd.h"
#include "mysub.h"
#include "mymul.h"
void main(a)
{
int n1 = 5;
int n2 = 20;
int n3 = 3;
printf("%d\n", myAdd(n1, n2));
printf("%d\n", mySub(n2, n3));
printf("%d\n", myMul(n1, n2));
}
Copy the code
How to compile several files is as follows:Obviously, doing this is cumbersome. There are many instructions to execute, which we can do with makefiles.
The makefile rules
target:depend command
The target file can be an intermediate file or the final execution file depend, which refers to the file required to generate the target file or the command to be executed by the target command: make
For example, in this directive:
gcc -c mymul.c -o mymul.o
Copy the code
Mymul.c is a dependency and mymul.o is a target
Order of makefile execution: the first makefile is executed by default. When the first makefile is executed, it looks for all dependencies. If not, it looks for any scripts that can generate dependencies. Example:
test:prog.o code.o gcc -o test prog.o code.o prog.o:prog.c gcc -c prog.c -o prog.o code.o:code.c gcc -c code.c -o code.o clean: rm -f *.oCopy the code
O and code. O files are generated by compiling the. C file. Then run the first command to generate the required test file.
A simple makefile instance
Write a makefile:
myProject: myProject.o myadd.o mysub.o mymul.o
gcc *.o -o myProject
myProject.o: myProject.c
gcc -c myProject.c -o myProject.o
myadd.o:myadd.c
gcc -c myadd.c -o myadd.o
mysub.o:mysub.c
gcc -c mysub.c -o mysub.o
mymul.o:mymul.c
gcc -c mymul.c -o mymul.o
clean:
rm -f *.o
Copy the code
As shown in the figure, once you have written the Makefile, it is very convenient to simply type make to execute the instructions you have already writtenOnce all is compiled, if you want to remove unnecessary files, such as.o files, you can make clean the file you wrote in the makefile.
Makefile variables and wildcards
The variable is the string OBJ = a, B, c — OBJ is a, B, and C, OBJ := a, b, c — OBJ is a, b, c — OBJ is a, b, c — OBJ is a, b, c — OBJ is a, b, c — OBJ is a, b, c — OBJ is a, b, c — OBJ is a, b, c — OBJ is a, b, c — OBJ is a, b, c — — matches an unknown thing
So, the original code can evolve like this:
OBJ:=myadd.o mysub.o mymul.o
OBJ+=myProject.o
myProject:$(OBJ)
gcc $(OBJ) -o myProject
*.o:*.c
gcc -c *.c -o *.o
clean:
rm -f *.o myProject
Copy the code
The visible code is cleaner and easier to change later, but it could be cleaner.
$@ — represents the target file $^ — represents the dependent file
The code evolves again:
target=myProject
OBJ:=myadd.o mysub.o mymul.o
OBJ+=myProject.o
CC:=gcc
CFLAGS:=-c
$(target):$(OBJ)
$(CC) $^ -o $@
*.o:*.c
$(CC) $(CFLAGS) $^ -o $@
clean:
rm -f *.o $(target)
Copy the code
In this way, the subsequent modification can directly change the amount, very convenient