As a newly graduated from college, the company soon encountered a modest threshold-not understand makefile. But makefile is related to the process of compiling and linking, a good makefile file can greatly improve the efficiency of compiling project files, eliminating the trouble of manual compilation.
I can't write makefile. Although it will not affect the progress of the project, from other places to copy a little modified to be able to use, but for us "program Ape" This is really a feeling very uncomfortable. So, Baidu, Google (PS: Spit slot, not xx words Google has been completely unable to use, Bing's effect is better than Baidu, a variety of look at the information, look at Daniel's blog, perhaps I am more stupid, or perhaps the information on the Internet is not very suitable for our new people, the lack of vivid examples to explain, So decided to do their own research, and to share the process to everyone, hope that the new people after reading this article will be able to do their own, for their own projects to write the appropriate makefile.
One, why write makefile
First of all, we have to determine our goal, Makefile is used to do.
For a long time I was engaged in the development of the Windows environment, so I do not know what makefile is a thing. As long as you are accustomed to the use of VS, Eclipse, and so excellent IDE do development, just click a button, the program can be run. But after entering the company, is engaged in the UNIX environment of development work, without the IDE, how to let me write the code to run after compiling.
Here, the role of makefile is reflected in the simple four words-"automatic compilation." Once the makefile of the entire project has been written, only a simple make command is needed to automate the compilation. Of course, to be exact, make is the command tool that helps us achieve what we want to do, and makefile is equivalent to a rule file, and the make program follows the rules specified by makefile to determine which files need to be compiled and which files need to be compiled, Which files need to be recompiled.
As the saying goes, lazy people create the whole world, programmers are in the process of constantly lazy to get progress, the most fundamental purpose of using Makefile is to simplify our work.
Here we start from the beginning, step-by-step to learn how to write a makefile file it.
starting from a single file
1, the compilation of a single file
To help you learn, this article is based on a common Linux platform, the system for Centos6.5, using the GNU make tool for compiling, project files in C + + format. This assumes that this article is to see the C + + program is compiled and other basic knowledge and related commands have a certain understanding, in view of space limitations, if there is not clear, please check the relevant information.
Let's say we have a test.cpp file in the SRC directory and how we compile it.
G++-o Test Test.cpp
Executing this command in the shell interface, a executable program named Test is generated in the current directory, and you can use./test to execute the program and see the output.
Now we try to implement this compilation using the writing Makefile method. First in the current directory to create a new file and named "Makefile", so that the compilation of the direct use of the Gmake command, the default use of "Makefile" file to compile, or other names, so you need to use the "gmake-f filename" Format to specify the makefile file.
The contents of the makefile file are as follows:
Test:test.cpp
G++-o Test Test.cpp
Execute the gmake command under the shell interface, knock down the carriage, OK.
As you can see, g++-otest test.cpp This command has been automatically executed, generating a program named Test.
2. Description Rule of Makefile
At this point, we have completed one of the simplest makefile documents and made a big step towards our ultimate goal.
Some people will ask, the legendary automated compiling it. Does every file have to write its own file name and command.
Don't worry, let's analyze the makefile file first.
TARGET ...:P rerequisites ...
COMMAND
...
...
This is the simplest description of the makefile file, it can be said that this is the most essential part of the makefile, the other parts are around the most basic description of the rule. Let me explain:
Target: The object file that the rule generates, usually the name of the program that needs to be generated (such as the program name test that appears earlier) or the procedure file (similar. o file).
Prerequisites: The dependencies of a rule, such as the one in the previous makefile file, we rely on to generate the test program is test.cpp.
Command: The command-line that a rule needs to execute, usually a compilation command. Notice here that each line of command needs to start with the [TAB] character.
Look at the makefile file we've written before, this rule, translated in plain natural language:
1, if the target test file does not exist, create it according to the rule.
2. The target test file exists and any one of the dependencies in the test file is newer than the target file (such as modifying a function, the file is updated), and regenerating it according to the rule.
3, the target test file exists, and it is newer than all dependencies, so do nothing.
When we execute the gmake command for the first time, the test file does not exist, so the G++-o Test test.cpp command is executed to create the test file.
When we execute the gmake again, we will be prompted to update the file and do nothing.
At this point, if you modify the Test.cpp command, execute the gmake command again.
Because the dependency is newer than the target file, g++-o test test.cpp the command is executed again.
Now that we've learned how to write a simple makefile file, every time we modify the source file, we can get the program we want to build with the gmake command, without having to repeatedly knock g++-O test test.cpp this command.
compilation of three or more files
1. Compile multiple files using the command line
A project can not have only one file, learned the compilation of a single file, the natural need to consider how to compile multiple files.
Similarly, suppose the following 7 files are present in the current directory, Test.cpp, W1.h, W1.cpp, W2.h, W2.cpp, W3.h, W3.cpp. Where test.cpp contains the main function and references W1.h, W2.h, and W3.h. We need to generate a program named Test.
Under the shell interface, in order to compile our project correctly, we need to knock down the following commands:
g++-c-o W1.ow1.cpp
G++-c-o W2.O W2.cpp
g++-c-o w3.o W3.cpp
At this time, the current directory will generate W1.O, W2.O, w3.o three. o files. It should be noted here that the "-C" command is compiled, not linked, and usually used when generating an. o file.
g++-o testtest.cpp w1.o w2.o w3.o
After executing this command, the compiler succeeded and got the test file we wanted.
2. Compile multiple files using makefile
Since the makefile of individual files will be written, it is not a problem to believe that multiple files extrapolate.
Makefile specific contents are as follows:
TEST:TEST.CPPW1.O W2.O W3.O
g++-o test test.cpp w1.o w2.o w3.o
W1.o:w1.cpp
g++-c-o w1.o W1.cpp
W2.o:w2.cpp
g++-c-o w2.o W2.cpp
W3.o:w3.cpp
g++-c-o w3.o W3.cpp
Note here that the goal of the first rule that we write will be the "ultimate goal", the program we eventually want to build, and here is the "test" file. According to our "ultimate goal", make is automatically deduced, for example, "ultimate goal" depends on the. o file, make will look for the rules to generate these. o files, and then execute the corresponding command to generate these files, so that the layer by layer recursively, until the final generation of the "ultimate goal."
As shown in the figure above, although the rules for generating the test file are written first, the commands required to generate W1.O, W2.O, w3.o are executed before the g++-o test test.cpp w1.o, depending on the W1.O, W2.O, W3.o,make. W3.O to generate the test file.
3, use pseudo target to clear process file
We can now automatically compile multiple files of the project, but when we need to recompile all, do we manually one to delete those generated. o files.
Now that the makefile has been used, our goal is to automate the compilation, so these cleanup process files must be handled with one command.
We only need to add the following lines to the end of the makefile file:
Clean
-rm–f Test *.O
OK, easy to handle, and then execute Gmakeclean under the shell interface. Take a closer look, is not all the. o files and the final generated program files have been cleared.
Here, RM is the Linux delete file or directory command, preceded by the "-" symbol means ignore the error of performing RM. The "-f" argument refers to forced deletion, ignoring files that do not exist.
Such a goal is called "pseudo Target", which is specified by the "Gmake Target name", and then executes the command under this target rule.
use variables to simplify makefile
As a "lazy" programmer, the problem is now. If according to the above, in the number of documents and the name of the same situation is really no problem, but if we add a file, it is not going to modify the makefile, a project more than may have hundreds of documents, so the management of how much trouble.
Remember when we were under Linux if we wanted to see all the CPP files in the current directory, the commands that were used.
Ls*.cpp
With this command, we can display all the CPP file names in the interface. In Makefile we can also use similar rules to simplify and further reduce the changes to makefile files during subsequent development.
The modified makefile file is as follows:
target= Test
Cpp_files = $ (Shell ls *.cpp)
BASE = $ (basename $ (cpp_files))
OBJS = $ (addsuffix. O, $ (addprefix obj/,$ (BASE))
$ (TARGET): $ (OBJS)
-rm-f $@
g++-O $ (TARGET) $ (OBJS)
Obj/%.o:%.cpp
@if Test! -D "obj"; Then\
Mkdir-pobj;\
Fi
g++-c-o $@ $<
Clean
-rm-f Test
-rm-f OBJ/*.O
Is not a moment to feel the feeling of the mind. Don't worry, this is because we have used some new syntax and command, in fact, in essence and we have written before the makefile file is a meaning, below we will analyze article by article.
(1) TARGET = Test
Define a variable, save the target file name, where we need to generate the program name called Test.
(2) cpp_files = $ (Shell ls *.cpp)
Defines a variable that contains the file name of all files with a. cpp suffix, separated by a space.
Here, the format of the & (Shell command) shows that this will be replaced with the output of the shell command after it is executed, as is the result of entering LS *.cpp at the command line.
(3) BASE = $ (basename $ (cpp_files))
Defines a variable that contains the filename of all files with a. cpp suffix to remove the suffix section.
$ (cpp_files) is a reference to cpp_fifes this variable content, I believe that learned how to write shell command of the students will certainly not unfamiliar. BaseName is a function that removes the suffix part of a filename, such as "Test.cpp," which, after that, becomes "test".
(4) Objs = $ (addsuffix. O, $ (addprefix obj/,$ (BASE) )
Define a variable that contains all the. cpp-suffix files to remove the suffix section plus ". O".
Like BaseName, Addsuffix and Addprefix are called functions as well. The role of Addprefix is to prefix each filename with "obj/", and addsuffix to add a suffix to each file name, followed by ". O" after the filename. For example, "test" is transformed into a "OBJ/TEST.O".
Why add "obj/" before the filename.
It's not necessary, it's just that I feel like putting all the. o files in an obj directory. Unified management will make the directory structure more clear, including later. d files will be unified in the DEP directory. Of course, you can also choose not to do so, but all in the current directory.
(5) $ (TARGET): $ (OBJS)
-rm-f $@
g++-o $ (TARGET) $ (OBJS)
This descriptive rule is similar to what we've written before, except that we use a variable to replace it. One thing to note here is the strange symbol $@, which means the name of the target file for this rule, which is equivalent to $ (target).
Replacing the variables here with the actual values in our previous project is equivalent to:
TEST:TEST.OW1.O W2.O W3.O
-rm–f Test
G++-o test TEST.O w1.o w2.o w3.o
If you follow this notation, when we add a w4.cpp file, we need to modify the makefile, and if we use a variable to replace it, then we do nothing, and then execute the gmake command again directly.
(6) Obj/%.o:%.cpp
@if Test!-d "obj"; then\
mkdir-p obj;\
fi;
g++-c-o $@ $<
This is the rule that sequentially generates the. o files for all CPP files.
%.O and%.C indicate the name of the file ending with. O and. C. Because we're going to put all the. o files in the obj directory, so here we prefix "%.O" with "obj/".
The first three lines of the following command line, the specific purpose is to check whether the current directory is named "obj" directory, if not, then use the mkdir command to create this directory. If you do not understand the students should first look at Shell programming related knowledge.
The $@ in the last sentence has been explained before, representing the name of the target file for the rule, and the $< corresponds to the name of the first dependent file in the dependency of the rule.
such as Obj/test.o:test.cpp
Then the value of $@ is "TEST.O",$< The value is "Test.cpp"
(7) Clean:
-rm-f Test
-rm-f OBJ/*.O
There's nothing to talk about here, just a few changes to the. o file path.
Here, I'm sure you have some clues about how to use makefile to compile a small project. Use this makefile file, no matter how many files you add to this directory, gently loosen a gmake command to fix, no need to add a new file to modify the makefile.
But don't you think there are still a lot of problems?
What to do if there is a reference relationship between the files.
What to do if you put the. h file and the. cpp file in a different directory.
What if I want to generate a static library and then refer to the static library elsewhere.
If I want to migrate the program to a UNIX platform and use a different compiler, I want to modify all the makefile in turn.
We can try to solve the above problems by ourselves, and we will continue to solve them by example in the following pages.