Jeremy Lin
I think, for a lot of coder like me who use widows systems for a long time, I probably don't know what makefile is. Because the IDE in widows (like VS) is doing the work for you silently, but when you enter the Unix/linux system, that makefile will be the problem you have to face, and will not write makefile, It also explains from one side whether a person has the ability to work in a large project. Because makefile is related to the compilation rules of the whole project. There are countless source files in a project, they are stored in several directories by type, function and module, and makefile defines a series of rules to specify which files need to be compiled first, which files need to be compiled, which files need to be recompiled, and even more complex function operations. Because makefile is like a shell script, it can also execute OS commands. Makefile brings a good place is-"automated compilation", once written, only need a make command, the entire project is automatically compiled, greatly improving 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, GNU's make under Linux.
Makefile Introduction
The Make command executes, requires a Makefile file, To tell the make command what to do to compile and link the program.
First, we use an example to illustrate Makefile's writing rules. In order to give everyone a perceptual knowledge. This example comes from the GNU Make manual, in which we have 8 C files, and 3 header files, and we're going to write a makefile to show how the Make command compiles and links the files. Our rules are:
1) If the project is not compiled, all of our C files are compiled and linked.
2) If a few C files of this project are modified, then we only compile the modified C file and link the target program.
3) If the header file for this project is changed, then we need to compile the C file referencing the header files and link the target program.
As long as our makefile is well written and all of this is done with just one make command, the make command automatically and intelligently determines which files need to be recompiled based on the current file modification, compiling the required files and linking the target program yourself.
One, makefile rules
Before we tell about this makefile, let's take a cursory look at Makefile's rules.
target ...: prerequisites ...
command
...
...
Target is a destination file, which can be either an object or an executable file. It can also be a label, which is described in the following "pseudo-targets" section for labels.
Prerequisites is to generate the desired file or target for that target.
command is what the make needs to execute. (Arbitrary shell Command)
This is a file dependency, that is, target one or more of the destination files depend on the files in the prerequisites, and their generation rules are defined in the command. White point is that if more than one file in the prerequisites is newer than the target file, command-defined commands are executed. This is the rule of makefile. This is the core content of makefile.
At the end of the makefile thing, it seems like my document is over. Oh. Not really, this is Makefile's main line and core, but to write a good makefile is not enough, I will be back 1.1 points to combine my work experience to you slowly come. There's a lot of content. :)
second example
As mentioned earlier, if a project has 3 header files, and 8 C files, our makefile should look like this in order to complete the three rules described 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 disp LAY.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 Buffe R.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< C19/>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 the makefile easier to read. We can save this content in the file "Makefile" file, and then directly enter the command "make" in this directory to generate execution file edit. If you want to delete the execution file and all the intermediate target files, simply execute "make clean".
In this makefile, the target file contains: Execute file Edit and intermediate target file (*.O), and the dependent file (prerequisites) is the. c file and the. h file after the colon. Each of the. o files has a set of dependent files, and these. o files are also dependent files that execute file edit. Dependency is essentially a 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, so be sure to start with a TAB key. Remember, make and no matter how the command works, he just executes the defined command. Make compares the modified date of the targets file and the prerequisites file, and if the date of the prerequisites file is newer than the date of the targets file, or target does not exist, then make executes the subsequent defined command.
To illustrate the point is that clean is not a file, it is just an action name, a bit like the C language of lable, its colon after nothing, then make will not automatically find the dependency of the file, will not automatically execute the commands defined later. To execute subsequent commands, the lable name is clearly indicated after the make command. Such a method is very useful, we can in a makefile to define the unused compilation or compiler-independent commands, such as program packaging, program backup, and so on.
Third, how make is working
In the default way, we only enter the Make command. So
1, make A file named "Makefile" or "Makefile" is found under the current directory.
2, if found, it will find the first target file in the file (target), in the example above, he will find " edit this file and put this file as the final target file.
3, if the edit file does not exist, or edit depends on the file modification time of the. o file is more than edit This file is new, then he will execute the command defined later to generate the edit file.
4, if edit depends on the. o file also exists, then make will find the target. o file in the current file
5, of course, your C files and H files are there, so make generates. o files and then uses. o The ultimate task of life make, which is to execute the file edit.
This is the dependency of the entire make, which makes a layer-by-layer look at the dependencies of the file until the first target file is finally compiled. In the search process, if there is an error, such as the last dependent file can not be found, then make will directly exit, and error, and for the definition of the command errors, or the compilation is unsuccessful, make does not ignore. Make just file dependencies, that is, if after I find a dependency, the file after the colon is not, then I am sorry, I do not work.
From the above analysis, we know that, like clean, is not directly or indirectly associated with the first target file, then the command defined later will not be automatically executed, however, we can display to make execution. That is, the command-"make clean", which clears all the target files for re-compilation.
So in our programming, if this project has been compiled, and when we modify one of the source files, such as file.c, then according to our dependence, our target FILE.O will be recompiled (that is, the command defined after this dependency relationship), so the FILE.O file is also the latest , so FILE.O file modification time is newer than edit, so edit will be re-linked (see the edit target file after the definition of the command).
And if we change the "command.h", then the KDB.O, COMMAND.O, and FILES.O will be recompiled and the edit will be re-linked.
Iv. using Variables in makefile
In the example above, let's take a look at the rules of Edit:
EDIT:MAIN.O kbd.o command.o display.o insert.o search.o files.o utils.occ-o edit main.o kbd.o command.o display.o inser T.O SEARCH.O FILES.O UTILS.O
we can see that the [. O] File string has been repeated two times, and if our project needs to add a new [. o] File, then we need to add in two places (should be three places and a place in clean). Of course, our makefile is not complicated, so we are not tired in two places, but if Makefile becomes complex, then we may forget a place to join and cause compilation to fail. Therefore, in order to makefile easy maintenance, we can use variables in makefile. The makefile variable is also a string, which can be better understood as a macro in the C language.
For example, we declare any variable name, called OBJECTS, OBJECTS, Objs, Objs, obj, or obj, as long as the obj file can be represented. We define this variable at the beginning of the makefile as follows:
objects = MAIN.O kbd.o command.o display.o insert.o search.o files.o UTILS.O
Thus, we can easily use this variable in our makefile in the form of "$ (objects)", so our modified version makefile becomes as follows:
objects = MAIN.O kbd.o command.o display.o insert.o search.o files.o utils.oedit: $ (objects) Cc-o edit $ (objects) MAIN.O: MAIN.C defs.hcc-c main.ckbd.o:kbd.c defs.h command.hcc-c kbd.ccommand.o:command.c defs.h command.hcc-c COMMAND.CDI SPLAY.O:DISPLAY.C defs.h buffer.hcc-c display.cinsert.o:insert.c defs.h buffer.hcc-c insert.csearch.o:search.c def S.h buffer.hcc-c search.cfiles.o:files.c defs.h buffer.h command.hcc-c files.cutils.o:utils.c defs.hcc-c utils.ccle AN:RM Edit $ (objects)
If a new. o file is added, we simply need to modify the variable objects.
Five, let make automatic deduction
GNU make is very powerful, it can automatically deduce the file and the command behind the file dependencies, so we don't have to write a similar command after each [. o] File, because our make will automatically recognize and deduce the command ourselves.
As soon as make sees a [. o] File, it automatically adds the [. c] File to the dependency, and if makes finds a whatever.o, then WHATEVER.C is the WHATEVER.O dependent file. And Cc-c Whatever.c will also be deduced, so our makefile no longer need to write so complicated. Our new makefile is in the oven again.
objects = MAIN.O kbd.o command.o display.o insert.o search.o files.o utils.occ = Gccedit: $ (objects) Cc-o edit $ (objects) Main.o:defs.hkbd.o:defs.h command.hcommand.o:defs.h command.hdisplay.o:defs.h buffer.hinsert.o:defs.h Buffer.hse Arch.o:defs.h buffer.hfiles.o:defs.h buffer.h command.hutils.o:defs.h.phony:cleanclean:rm Edit $ (objects)
This method, the "cryptic rule" of make. The contents of the above file, ". Phony "means that clean is a pseudo-target file.
Vi. Alternative style of makefile
Since our make can automatically deduce the command, then I see that the pile of [. O] and [. h] Dependencies are a bit uncomfortable, so many repetitive [. h], can you put it together, OK, no problem, this is easy for make, who calls it a function of automatically deriving commands and files? Take a look at the newest style of makefile.
objects = MAIN.O kbd.o command.o display.o insert.o search.o files.o utils.oedit: $ (objects) Cc-o edit $ (objects) $ (object s): DEFS.HKBD.O command.o files.o:command.hdisplay.o insert.o search.o files.o:buffer.h.phony:cleanclean: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 both. I also see your preferences. I do not like this style, one is the document depends on the relationship can not see clearly, and second, if more than one file, to add a few new. o files, it is not clear.
Vii. rules for emptying target files
Each makefile should write a rule that clears the target file (. O and Execute file), which is not only easy to recompile, but also helps keep the file clean. This is a "culture" (hehe, remember my "programming accomplishment"). The general style is:
CLEAN:RM Edit $ (objects)
A more robust approach is to:
. Phony:cleanclean:-rm Edit $ (objects)
As I said before. Phony means that clean is a "pseudo-target". and a small minus sign in front of the RM command means that some files may be in trouble, but don't worry, keep doing what's behind. Of course, clean rules do not put in the beginning of the file, otherwise, it will become the default goal of make, I believe that no one is willing to do so. 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 relevant details:
composition of the makefile file
The makefile file consists mainly of the following 5 parts:
- Explicit rules: Explicit rules describe how to generate one or more target files. This is clearly indicated by the writer of the makefile, to generate the file, the file's dependent file, the generated command.
- Obscure rule: Because our make has the function of automatic derivation, so the obscure rule lets us write makefile in a relatively brief way, this is supported by make.
- Definition of a variable: in makefile We define a series of variables, which are usually strings, a bit like a macro in your C language, and when Makefile is executed, the variables are extended to the corresponding reference position.
- File indication: It includes three parts, one refers to another makefile in one makefile, just like the include in C, and the other is to specify a valid part of makefile according to certain circumstances, just like the precompiled # if in C language And there is a command that defines a multiline.
- Note: Only line comments in Makefile, like the Unix shell script, are 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, for example: "\#".
Finally, it is worth mentioning that the command in makefile must start with the [Tab] key.
FileName of the Makefile
By default, the make command searches the current directory for files named "Gnumakefile", "Makefile", and "makefile" in the order found to interpret the file. In these three file names, it is best to use the "Makefile" file name, because the first character of this file name is uppercase, so there is a sense of purpose. It is best not to use "Gnumakefile", which is the GNU make recognition. There are other make that are only sensitive to the "makefile" file name in full lowercase, but basically, most of them support both the "makefile" and "makefile" default filenames.
Of course, you can use a different file name to write makefile, such as: "Make.linux", "Make.solaris", "Make.aix", etc., if you want to specify a specific makefile, you can use make "-F" and "--file" parameters , such as: Make-f make.linux or make--file Make.aix.
The Make tool's exit code
Makefile file after execution has an exit code, the exit code has the following three conditions:
- 0--indicates successful execution of makefile file;
- Makefile indicates an error occurred while executing the file;
- 2--returns 2 If the user uses the-Q option for make and makes causes some targets not to be updated.
Refer to other Makefile
Using the Include keyword in makefile can include other makefile, much like the C # # #, where the contained file is placed in the current file's containing location. The syntax for include is:
Include <filename>;
FileName can be the file mode of the current operating system shell (can include path and wildcard characters)
There can be some empty characters in front of the include, but it must never be the [Tab] key to start. Include and <filename>; 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
When the make command starts, it will look for the other makefile indicated by the include and place its contents in its current position. It's like a C + + # include directive. If the file does not specify an absolute path or a relative path, make will look in the current directory first, and if not found in the current directory, make will also be found in the following several directories:
If make executes with the "-I" or "--include-dir" parameter, then make will look in the directory specified in this parameter.
If the directory <prefix>;/include (typically:/usr/local/bin or/usr/include) exists, make will also look for it.
If a file is not found, make generates a warning message, but the fatal error does not occur immediately. It will continue to load other files, and once the makefile has been read, make will retry the files that are not found, or cannot be read, and if not, make will be presented with a fatal message. If you want make to ignore the unreadable files and continue, you can add a minus "-" before the include. Such as:
-include <filename>;
It indicates that no error will continue to occur, regardless of any errors in the include process. The related commands that are compatible with other versions of Make are sinclude, and the effect is the same as this one.
environment variable makefiles
If the environment variable makefiles is defined in your current environment, make makes an action similar to include in the value of this variable. The values in this variable are other makefile, separated by a space. But, unlike include, the makefile "target" introduced from this environment variable will not work, and if the file defined in the environment variable finds an error, make will ignore it.
But here I still recommend not to use this environment variable, because as long as this variable is defined, then when you use make, all the makefile will be affected by it, this is not what you want to see. In this case, just to tell you that there may be times when your makefile appear strange, then you can see if there is any definition of this variable in the current environment.
How make Works
The GNU make works at the following steps:
- Read into all the makefile.
- Read the other makefile that are included.
- Initializes a variable in the file.
- Derive the cryptic rules and analyze all the rules.
- Create a dependency chain for all the target files.
- Depending on the dependencies, decide which targets to regenerate.
- Executes the build command.
1-5 steps for the first stage, and 6-7 for the second stage. In the first stage, if the defined variable is used, make will expand it to the location in use. But make does not start all at once, making uses procrastination tactics, and if a variable appears in a dependency rule, the variable will be expanded within it only if the dependency is determined to be used.
Refs:
[1] Chenhao. write Makefile with me. CSDN BLOG. (Most of this article is from this, recommended)
[2] Wu Yue. Linux C Programming Encyclopedia. Tsinghua University Press.
This address: http://blog.csdn.net/linj_m/article/details/45066337
More resources please follow blog: linjm-machine vision Weibo: Lin Jianmin-Machine Vision
Linux Growth path (Makefile Quick Start)