Makefile is important.
What is makefile. Maybe a lot of WINODWS programmers don't know this, because the Windows IDE does the work for you, but I think that to be a good and professional programmer, Makefile still have to understand. It's like there are so many HTML editors now, but if you want to be a professional, you still have to understand the meaning of the HTML logo. Especially in Unix software compiled, you can not write makefile, will not write makefile, from a side to explain whether a person has the ability to complete large-scale projects . Because, makefile is related to the compilation rules of the whole project. A project in the source file does not count, its type, function, modules are placed in several directories, makefile defined a series of rules to specify which files need to compile first, which files need to compile, which files need to recompile, and even more complex functional operations, Because makefile is like a shell script, it can also execute operating system commands. The benefit of makefile IS-"automated compilation", once written, only need a make command, the entire project completely automatic compilation, greatly improve the efficiency of software development. Make is a command tool, a command tool that interprets instructions in makefile, and in general, most Ides have this command, such as: Delphi's Make,visual C + + Nmake,linux under GNU. It can be seen that makefile has become a method of compiling engineering.
There are fewer articles on how to write makefile, which is why I want to write this article. Of course, different manufacturers make different, but also have various syntax, but its essence is in the "file dependencies" on the fuss, here, I only to the GNU make, my environment is Redhat Linux 8.0,make version is 3.80. Surely, this make is the most widely used and the most used. It is also the most consistent with the IEEE 1003.2-1992 Standard (POSIX.2).
In this document, will be the source code for C/A + + as our foundation, so there must be some knowledge of C + + compilation, related to this aspect, and please see the relevant compiler documentation. The default compiler here is GCC and cc under UNIX.
0.1 about program compiling and linking
Here, I would like to say more about the procedures of compiling some of the norms and methods, in general, whether C, C + +, or PAS, the first to compile the source file into the intermediate code file , under Windows is the. obj file, Unix is an. o file, that is, Object file, This action is called compilation (compile). Then a lot of object file is synthesized to execute the file, this action is called link.
at compile time , the compiler needs the correct syntax, the declaration of functions and variables. For the latter, it is usually the location where you need to tell the compiler header file (the header file should be just a declaration, and the definition should be placed in a C + + file), and as long as all the syntax is correct, the compiler can compile the intermediate target file. In general, each source file should correspond to an intermediate target file (o file or obj file).
links are mainly linked functions and global variables, so we can use these intermediate target files (o files or obj files) to link our applications. The linker does not care about the source file where the function resides, just the intermediate object file of the function, most of the time, because there are too many source files, there are too many intermediate target files generated by the compilation, and when the link needs to clearly indicate the intermediate target filename, which is inconvenient for compiling, We're going to pack the middle target file, which is called " library file"in Windows, the. lib file, under Unix, is archive file, which is. A.
To sum up, the source file first generates an intermediate target file, which is then generated by the intermediate target file. At compile time, the compiler detects only the program syntax, and whether the function or variable is declared. If the function is not declared, the compiler gives a warning, but can generate object File. And when you link a program, the linker will look for the implementation of the function in all object file, if cannot find, that will report link error code (Linker error), in VC, this kind of error is generally: Link 2001 error, meaning say, linker failed to find the realization of function. You need to specify the objectfile of the function.
Well, to be sure, GNU make has a lot of content, gossip less, or let's start. 1 Makefile Introduction
When the make command executes, a Makefile file is required to tell the make command how to compile and link the program.
First, we use an example to illustrate the writing rules of Makefile. In order to give everyone a sense of awareness. This example comes from the GNU Make Manual, in which our project has 8 C files, and 3 header files, and we're going to write a makefile to tell make commands how to compile and link the files. Our Rules are:
1. If the project has not been compiled, then all of our C files will be compiled and linked.
2. If a few C files of this project are modified, we only compile the modified C file and link the target program.
3. If the header file for this project has been changed, we need to compile the C file referencing the header files and link the target program.
As long as our makefile is well written, all of this we can do with just one make command, and the make command automatically intelligently determines which files need to be recompiled based on the current file modifications to compile the required files and linked target programs. the rules of 1.1 makefile
Before telling this makefile, let's take a rough look at the makefile rules.
target ...: Prerequisites ...
Command
...
...
-------------------------------------------------------------------------------
target is either an object file, or it can be an executable file. It can also be a label (label), which is described in the following "pseudo target" section for the label.
Prerequisites is the file or target that is needed to generate the target.
command is what you need to execute. (Arbitrary shell commands)
This is a file dependency, that is, target files of one or more objects depend on the files in prerequisites, and their generation rules are defined in the command. The white point is that if more than one file in prerequisites is newer than the target file, the commands defined by the command are executed. This is the makefile rule. Which is the core content of makefile.
At the end of the story, that's what makefile is all about, as if my document should be over. Oh. Not all, this is the main line and the core of makefile, but to write a good makefile is not enough, I will be followed by 1.1 points to combine my work experience to you slowly come. There's a lot of content. :) 1.2 An example
As mentioned earlier, if a project has 3 headers, and 8 C files, our makefile should look like this in order to complete the three rules mentioned above.
EDIT:MAIN.O kbd.o command.o display.o \
INSERT.O SEARCH.O FILES.O UTILS.O
Cc-o edit main.o kbd.o command.o display.o \
INSERT.O SEARCH.O FILES.O UTILS.O
MAIN.O:MAIN.C Defs.h
Cc-c MAIN.C
KBD.O:KBD.C Defs.h Command.h
Cc-c KBD.C
COMMAND.O:COMMAND.C Defs.h Command.h
Cc-c COMMAND.C
DISPLAY.O:DISPLAY.C Defs.h Buffer.h
Cc-c display.c
Insert.o:insert.c Defs.h Buffer.h
Cc-c insert.c
SEARCH.O:SEARCH.C Defs.h Buffer.h
Cc-c search.c
FILES.O:FILES.C defs.h buffer.h Command.h
Cc-c FILES.C
UTILS.O:UTILS.C Defs.h
Cc-c UTILS.C
Clean:
RM Edit MAIN.O kbd.o command.o display.o \
INSERT.O SEARCH.O FILES.O UTILS.O
The backslash (\) is the meaning of the line break. This makes it easier for makefile to read easily. We can save this content in a file "Makefile" or "Makefile", and then enter the command "make" directly in the directory to generate the Execute file edit. If you want to delete the execution file and all the intermediate target files, simply execute the "make clean".
In this makefile, the destination file (target) contains: Execute file Edit and intermediate object file (*.O), and dependent files (prerequisites) are those. c files and. h files after the colon. Each. o file has a set of dependent files, and these. o files are also dependent files for executing file edit. The essence of dependencies is the description of which files are generated by the target file, in other words, which files are updated by the target file.
After defining the dependencies, the subsequent line defines how to generate the operating system commands for the target file , and must begin with a TAB key. Remember that make does not matter how the command works, but he executes the commands that are defined. Make compares the modified dates of the targets and prerequisites files, and if the prerequisites file has a date that is newer than the date of the targets file, or if Target does not exist, make executes the subsequent defined command.
The point here is that clean is not a file, it's just an action name, a bit like the lable in C, with nothing in it, so that make doesn't automatically find the dependencies of the file, and does not automatically execute the commands that are defined later. To execute the subsequent command, it is obvious that the name of the lable should be indicated after the make command. Such a method is very useful, we can in a makefile to define not compile or compile-independent commands, such as program packaging, program backup, and so on. How 1.3 make Works
In the default way, we just enter the make command. So
1. Make will find a file named "Makefile" or "Makefile" in the current directory.
2. If found, it will find the first target file in the file (target), in the above example, he will find "edit" this file, and the file as the final target file.
3. If the edit file does not exist, or if the subsequent. o file on which edit is dependent is newer than the edit file, he will execute the command defined later to generate the edit file.
4. If the. o file that the edit relies on also exists, make will find a dependency on the target. o file in the current file, and then generate an. o file based on that rule if found. (This is sort of like a stack process)
5. Of course, your C files and H files are present, so make generates the. o file and then declares the final task of make with the. o file, which is the execution file edit.
This is the dependency of the entire make, and makes will find the dependencies of the files layer by layer until the first target file is finally compiled. In the process of searching, if there is an error, such as the last dependent file can not be found, then make will exit directly and error, and for the defined command errors, or the compilation is not successful, make at all ignore. Make just the dependency of the file, that is, if after I find the dependency, the file after the colon is still out, then I am sorry, I do not work.
With this analysis, we know that, like clean, which is not directly or indirectly associated with the first target file, the commands defined later will not be automatically executed, but we can show that we want to make execution. This is the command-"Make clean", which clears all the target files for recompilation .
So in our programming, if this project has been compiled, when we have modified one of the source files, such as file.c, then depending on our dependence, our target FILE.O will be recompiled (that is, the command defined after this dependency relationship), so the file.o file is up to date, so FILE.O's file modification time is newer than edit, so edit will be relink (see edit The command defined after the document is marked.
And if we change the "Command.h", then KDB.O, COMMAND.O, and FILES.O will be recompiled, and edit will be linked again. using variables in 1.4 makefile
In the example above, let's look at the rules for Edit:
EDIT:MAIN.O kbd.o command.o display.o \
INSERT.O SEARCH.O FILES.O UTILS.O
Cc-o edit main.o kbd.o command.o display.o \
INSERT.O SEARCH.O FILES.O UTILS.O
We can see that the string of [. O] Files has been repeated two times, and if our project needs to add a new [. o] File, then we need to add two places (three places and one place in clean). Of course, our makefile is not complicated, so add in two places is not tired, but if the makefile become complex, then we will be able to forget a need to join the place, resulting in the compilation failed. Therefore, in order to makefile the easy maintenance, we can use the variable in the makefile. The makefile variable is a string, and it may be better to understand the macro in C language.
For example, we declare a variable, called OBJECTS, OBJECTS, Objs, Objs, obj, or obj, anyway, whatever it takes to be able to represent the obj file. We defined this at the beginning of the makefile:
objects = main.o kbd.o command.o display.o \
INSERT.O SEARCH.O FILES.O UTILS.O
So we can conveniently use this variable in our makefile as "$ (objects)" , so our improved version makefile becomes the following:
objects = main.o kbd.o command.o display.o \ insert.osearch.o files.o UTILS.O
edit: $ (objects) cc-o Edit $ ( objects) main.o:main.c defs.h cc-c MAIN.C   KBD.O:KBD.C defs.h command.h cc-c KBD.C   COMMAND.O:COMMAND.C defs.h command.h cc-c command.c display.o:display.c defs.h buffer.h cc-c display.c insert.o:insert.c Defs.h buffer.h cc-c insert.c SEARCH.O:SEARCH.C defs.h buffer.h cc-c search.c    FILES.O:FILES.C defs.h buffer.h command.h cc-c FILES.C   UTILS.O:UTILS.C defs.h cc-c Utils.c clean:       RM Edit $ (objects)
So if a new. o file is added, we simply need to modify the objects variable.
For more on the subject of variables, I will give you one by one ways to follow. 1.5 Let make automatically deduce
GNU's make is so powerful that it automatically infers the commands behind the file and file dependencies, so we don't have to write a similar command after every [. O] File because our make automatically recognizes and infers the command ourselves.
As soon as make sees an [. o] File, it automatically adds the [. c] File to the dependency, and if make finds a whatever.o, then WHATEVER.C is WHATEVER.O's dependent file. And Cc-c Whatever.c will also be deduced, so that our makefile no longer need to write so complicated. Ours is the new makefile.
objects = main.o kbd.o command.o display.o \ insert.o search.o files.o UTILS.O Edit: $ (objects) Cc-o Edit $ (objects) Main.o:defs.h kbd.o:defs.h command.h command.o:defs.h command.h display.o:defs.h bu Ffer.h insert.o:defs.h buffer.h search.o:defs.h buffer.h files.o:defs.h buffer.h command.h utils.o:defs.h . Phony:clean CLEAN:RM Edit $ (objects)
This approach, the "obscure rule" of make. Above the contents of the file, ". Phony "indicates that clean is a pseudo target file.
For more detailed "obscure rules" and "pseudo target files", I will give you one by one ways to follow. 1.6 Alternative style of makefile
So that our make can automatically deduce the command, then I see the heap [. O] and [. h] Dependencies are a little uncomfortable, so many repetitions [. h], can you just fold it up, OK, no problem, this is easy for make, who has the ability to automatically derive commands and files. Take a look at the latest style of makefile.
objects = main.o kbd.o command.o display.o \ insert.o search.o files.o UTILS.O Edit: $ (objects) Cc-o Edit $ (objects) $ (objects): Defs.h kbd.o command.o files.o:command.h display.o insert.o search.o FILES.O: Buffer.h. Phony:clean CLEAN:RM Edit $ (objects)
This style makes our makefile very simple, but our file dependencies seem a bit messy. You can't have your cake and eat it. Also see your liking. I do not like this style, one is that the dependence of the file can not see clearly, the second is if the file is more than one, to add a few new. o File, it is not clear. 1.7 rules for emptying the target file
Each makefile should write a rule that clears the target file (. o and execution file), which is not only easy to recompile, but also helps keep the files clean. This is a "self-cultivation" (hehe, still remember my "programming accomplishment"). The general style is:
Clean
RM Edit $ (objects)
A more robust approach would be to:
. Phony:clean
Clean:
-RM Edit $ (objects)
As I said before,. Phony meaning that clean is a "pseudo target". and a small minus sign in front of the RM command means that there may be problems with some files, but don't worry, keep doing what's behind. Of course, clean rules should not be placed at the beginning of a file, otherwise, this becomes the default target of make, and no one is willing to do that. The unwritten rule is that "clean is always at the end of the file."
The above is a makefile of the general picture, but also the basis of makefile, there are many makefile the following details, ready to do. Come when you are ready.
2 Makefile General statement what's in 2.1 makefile.
The makefile contains five things: explicit rules, obscure rules, variable definitions, file instructions, and annotations.
1. Explicit rules. Explicit rules explain how to generate one or more of the target files. This is clearly indicated by the Makefile writer, the file to be generated, the file's dependent file, the generated command.
2. Vague rules. Because our make has the function of automatically derivation, the obscure rules allow us to write makefile in a rough way, which is supported by made.
3. Definition of variable. In makefile we want to define a series of variables, which are usually strings, and this is a bit of a macro in your C language, where the variables are extended to the appropriate reference location when the makefile is executed.
4. Documentation instructions. It includes three parts, one is referencing another makefile in one makefile, as in the C language, and the other refers to a valid part of the makefile specified in some circumstances, just as the precompiled #if in C language And there is the command to define a multiline. I'll tell you about this part in a later section.
5. Note. The only line comment in Makefile is the same as the Unix shell script, which is annotated with the "#" character, which is like "//" in C + +. If you want to use the "#" character in your makefile, you can escape it with a backslash, such as "\#".
Finally, it is worth mentioning that the commands in makefile must start with the [Tab] key. 2.2Makefile of file name
By default, the make command searches the current directory for files named "Gnumakefile," "Makefile," and "Makefile ," and finds an explanation for the file. In these three filenames, it is best to use the filename "Makefile" because the first character of the file name is uppercase, so there is an obvious sense of purpose. It is best not to use "Gnumakefile", which is the GNU make recognition. There are other make only sensitive to all lowercase "makefile" file names, but basically, most do support both the "makefile" and "makefile" default filenames.
Of course, you can use other file names to write makefile, such as: "Make.linux", "Make.solaris", "Make.aix", and so on, if you want to specify a specific makefile, you can use make "F" and " File parameter , such as: Make-f make.linux or make--file Make.aix. 2.3 Refer to other makefile
Using the Include keyword in makefile can include other makefile, much like the #include of the C language, where the included files are placed in the original mode as they are in the current file. The syntax for include is:
include<filename>filename can be the file mode of the current operating system shell (can contain paths and wildcard characters)
you can have some empty characters in front of the include, but you must never start with a [Tab] key. Include and can be separated by one or more spaces. For example, you have a few makefile:a.mk, B.mk, C.mk, and a file called Foo.make, and a variable $ (bar) that contains e.mk and F.MK, then the following statement:
Include Foo.make *.mk $ (bar)
Equivalent to:
Include Foo.make a.mk b.mk c.mk e.mk f.mk
The make command starts with the search for the other makefile that are indicated by the include and places its contents in the current location. It's like the #include instruction of C + +. If the file does not specify an absolute or relative path, make will first look in the current directory, and if it is not found in the current directory, make will also look in the following directories:
1. If make executes with a "-I" or "--include-dir" parameter, make will look for it in the directory specified by this parameter.
2. If the directory/include (generally:/usr/local/bin or/usr/include) exists, make will also find it.
If a file is not found, make generates a warning message, but no immediate fatal error occurs. It will continue to load other files, and once the makefile is completed, make will retry the files that are not found, or cannot be read, and if not, make will appear with a fatal message. If you want make to ignore files that cannot be read, you can add a minus sign "-" before the include. Such as:
-include<filename>
This means that no matter what errors are found in the include process, do not continue with the error. The related command for the other version make compatibility is Sinclude, and the effect is the same as this one. 2.4 environment variable makefiles
If you have defined an environment variable makefiles in your current environment, make makes a value similar to include in the variable. The value in this variable is the other makefile, separated by a space. It's just that, unlike include, the makefile "target" introduced from this environment change does not work, and if the file defined in the environment variable finds an error, make will ignore it.
But here I recommend not to use this environment variable, because as long as the variable is defined, then when you use make, all the makefile will be affected by it, which is not what you want to see. To mention this here, just to tell you that there may be times when your makefile is strange, then you can see if there is a variable defined in the current environment. How 2.5 make works
GNU's make work steps down: (Want other make is similar)
1. Read all the makefile.
2. Read the other makefile included.
3. Initialize the variables in the file.
4. Deduce obscure rules and analyze all rules.
5. Create a chain of dependencies for all target files.
6. Depending on the dependencies, decide which targets to regenerate.
7. Execute build command.
1-5 steps for the first stage, 6-7 for the second stage. In the first phase, if the defined variable is used, make will expand it in the position used. But make does not start all at once, make uses delaying tactics, and if the variable appears in the rules of the dependency, then the variable will only expand inside it if it is decided to use it.
Of course, you don't have to be clear about the way you work, but knowing this way you'll be more familiar with make. With this foundation, the follow-up part is easy to understand. 3 Makefile Writing rules
The rule contains two parts, one is a dependency , and one is the method of generating the target .
In makefile, the order of the rules is important becausethere should be only one final goal in Makefile , and all other goals are associated with this goal, so make sure you know what your ultimate goal is. In general, there may be a lot of goals defined in makefile, but the goals in the first rule will be established as the ultimate goal. If there are many goals in the first rule, then the first goal will be the ultimate goal. Make is the goal that is accomplished.
Well, let's take a look at how to write the rules. 3.1 Rule Examples
FOO.O:FOO.C defs.h # foo Module
Cc-c-G foo.c
See this example, you should not be very unfamiliar, as has been said before, FOO.O is our goal, FOO.C and Defs.h is the target of the source file, and only one command "cc-c-G foo.c" (beginning with the TAB key). This rule tells us two things:
1. File dependencies, foo.o rely on foo.c and defs.h files, if foo.c and defs.h file dates are newer than FOO.O file dates, or if FOO.O does not exist, then dependencies occur.
2. If you generate (or update) FOO.O files. That's the CC command, which explains how to generate the foo.o file. (Of course foo.c file include Defs.h file) 3.2 syntax of the rule
Targets:prerequisites
Command
...
or so:
Targets:prerequisites; Command
Command
...
Targets is the filename, separated by a space, and you can use wildcard characters. In general, our goal is basically a file, but it can also be multiple files.