Chen Hao (Haoel)
Overview -
What is makefile? Perhaps many of WinodWs's programmers don't know this, because those Windows IDE has done this job, but I think it is necessary to make a good and Professional programmer, makefile still wants. This seems to have so many HTML editors, but if you want to be a professional, you still have to understand the meaning of HTML's identity. Especially in UNIX software, you can't write makefile yourself, will not write makefile, from one side, explain whether a person has the ability to complete large-scale projects.
Because Makefile is related to the compilation rules of the entire project. Source files in an engineering are not countful, which are placed in a number of directorys according to the type, function, and modules. 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 re- Compile, even more complex functional operations, because Makefile is like a shell script, which can also perform commands of the operating system.
The benefits brought by makefile are - "Automated Compilation", once written, only one make command, complete automatic compilation, greatly improve the efficiency of software development. Make is a command tool that is a command tool that explains the command in Makefile. In general, most of the IDE has this command, such as: Delphi Make, Visual C NMAKE, Linux GNU Make. It can be seen that Makefile has become a compilation method in engineering.
Now telling how to write Makefile's article is relatively small, this is the reason I want to write this article. Of course, the Make of different organizers is different, and there are different grammar, but their essence is in "document-dependent", here, I only tell the GNU's Make, my environment is Redhat Linux 8.0, Make's version is 3.80. By, this make is the most widely used and the most used. And it is still the most follow-in (POSIX.2) of IEEE 1003.2-1992.
In this document, it will be based on the source code of C / C as our foundation, so it will inevitably involve knowledge of compilation of C / C , related to this, please check the relevant compiler documents. The compiler default here is GCC and CC under UNIX.
About the compilation and link of the program ----------
Here, I think more about some norms and methods of program compilation. In general, both C, C , or PAS, first compile the source file into an intermediate code file, it is .OBJ file under Windows, UNIX The next is .o file, Object File, this action is called compilation. Then use a lot of Object File synthesizes the execution file, this action is a link (LINK).
When compiling, the compiler needs the correctness of the syntax, the function of the function and the variable declaration. For the latter, it is usually the location you need to tell the compiler header file (the header should just declare, and the definition should be placed in the C / C file), 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). When linking, primarily link 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 manage the source file where the function is located, only the intermediate target file (Object file) of the function, in most, because the source file is too much, there are too many intermediate target files generated, and the middle is clearly pointed out in the link. The target file name, this is very inconvenient, so we have to make a package to the middle target file, which is called "library file" under Windows, that is, the .lib file, under UNIX, is Archive file, that is, .a file.
Summary, the source file will generate an intermediate target file and then generate an execution file by the intermediate target file. At compiler, the compiler only detects the program syntax, and the function, whether the variable is declared. If the function is not declared, the compiler gives a warning, but can generate Object File. When the linker, the linker finds the implementation of a function in all Object File. If you can't find it, you will report the link error code (Linker Error), under VC, this error is generally: Link 2001 Error, meaning, the linker failed to find the implementation of the function. You need to specify the Object File of the function.
Ok, the words come true, GNU's make has a lot of content, idle, or let us start.
Makefile introduction -------
When the make command is executed, you need a Makefile file to tell the make command to compile and link programs.
First, we use an example to illustrate the writing rules of Makefile. In order to give you a real understanding. This example comes from the GNU's Make User Manual, in this example, our project has 8 C files, and 3 head files, we have to write a Makefile to tell the make command how to compile and link these files. Our rules are: 1) If this project is not compiled, all of our C files should be compiled and linked. 2) If a few C files in this project are modified, then we only build the modified C file and link the target program. 3) If the header file of this project is changed, then we need to compile C files that reference these header files and link the target program.
As long as our makefile is well written enough, all of this, we can complete with a make command, and the make command will automatically intelligently determine which files need to be recompiled according to the current file modification, so that they need to compile it. Files and link target programs.
I. Makefile rules
Before telling this makefile, let's take a look at the rules of Makefile first.
Target ...: prerequisites ... command ... Target is also a target file, which can be Object File or a executable file. It can also be a label, which is a narrative in subsequent "Pseudo Target" chapters for labels.
Prerequisites is to generate the files required by Target or target.
Command is also a command that make Make needs to be executed. (Any shell command)
This is a dependency of a file, that is, Target This or more target files depends on the file in Prerequisites, which generates rules defined in Command. To put it bluntly, if there is more than one file in Prerequisites, the command defined by Command is executed more than the TARGET file. This is the rule of Makefile. That is, the core content in Makefile.
When I said, Makefile's thing is like this, as if I have this document. Ha ha. Not too, this is the main line and core of Makefile, but it is not enough to write a makefile. I will get a little bit of work experience in conjunction with my work experience. The content is more. :)
Second, one example
As mentioned earlier, if a project has 3 head files, and 8 C files, we should be the following this look in order to complete the three rules mentioned earlier.
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 change. This is more convenient for Makefile easy to read. We can save this content in a file that "makefile" or "makefile", and then enter the command "make" directly in this directory to generate an execution file Edit. If you want to delete the execution file and all intermediate target files, then just make "make clean" as long as you do it. In this makefile, the target file (target) contains: execute file edit and intermediate target file (*.), Dependent file (prerequisites) is those .c files and .h files behind the colon. Each .o file has a set of dependencies, and these .o files are also performing file edit reliance on files. The dependence is essentially indicated by which files are generated by the target file, in other words, which files are updated.
After defining the dependency, subsequent rows define how to generate the operating system command of the target file, be sure to start with a Tab key. Remember, Make does not care how the command works, he only does the defined command. Make will compare the modification date of the targets file and prerequisites file. If the date of the Prerequisites file is more than the date of the targets file, or the target does not exist, Make will perform a subsequent command.
Here, it will be that Clean is not a file, it is just a one action name, it is a bit like Lable in the C language, and there is nothing after his colon. So, Make will not automatically find the dependency of the file. You will not automate the commands defined later. To perform the subsequent command, you will clearly indicate the name of this Lable after the make command. Such methods are very useful, we can define unused compiles or compilers in a makefile, such as program packaging, procedures, and so on.
Third, how is Make works in the default mode, that is, we only enter the Make command. So, 1, make will find the name "makefile" or "makefile" in the current directory. 2, if you find it, it will find the first target file in the file. In the above example, he will find the "Edit" file and use this file as the final target file. 3, if the Edit file does not exist, or the file modification time behind the EDIT is better than the Edit file, then he will perform the commands defined later to generate the Edit file. 4, if the EDIT is dependent on the .o file, Make will find the dependence of the target as the .o file in the current file, if you find it, generate the .o file according to the rule. (This is a bit like a stack process) 5. Of course, your C file and H file exist, so Make will generate .o file, then use .o file life make the ultimate task, that is, the execution file Edit . This is the dependence of the entire make, and make a layer of relying on the document again until the first target file is finally compiled. In the process of finding, if an error occurs, if the last dependent file cannot be found, Make will exit directly and report the error, and the error of the defined command, or the compilation is unsuccessful. Make only the dependence of the document, that is, if I find the dependencies, the file behind the colon is still, then I am sorry, I will not work. Through the above analysis, we know that like Clean, it is not directly or indirectly associated with the first target file, then the commands that will be later defined will not be executed automatically, however, we can display to execute it as you want. That is, command - "make clean" to clear all target files to recompile. So in our programming, if this project has been compiled, when we modify one of the source files, such as file.c, then according to our dependence, our target file.o will be compiled (that is The commands defined later later), so File.o's files are also the latest, so file.o's file modification time is more new than Edit, so Edit will be resinted (see Edit target file for details) The command that is defined). And if we changed "command.h", then kdb.o, command.o and files.o will be recompiled, and Edit will be linked. IV. Makefile uses variables in the above example, 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.o cc - o Edit main.o kbd.o command.o display.o / insert.o search.o files.o utils.o We can see the string of the [.o] file twice, if our project needs Join a new [.o] file, then we need to add (it should be three places, there is also a place in Clean).
Of course, our makefile is not complicated, so it is not tired in two places, but if Makefile is complicated, then we may have forgetting a place you need to join, but causing compilation to fail. So, for the easy maintenance of Makefile, we can use variables in Makefile. Makefile variables are also a string, understanding the macros in C language may be better. For example, we declare a variable called Objects, Objects, Objs, Objs, Obj, or Obj, anyway, no matter what, you can represent the OBJ file. We will define this at Makefile: Objects = main.o kbd.o command.o display.o / insert.o search.o files.o utils.o, we can easily in our makefile "$ (Objects)" is used to use this variable, so our improvement version makefile turns the following: 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: 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 - 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) Then if there is a new .o file join, we only need to simply modify the Objects variable. With regard to the topic of variables, I will give you a way. 5. Let Make automatically derive the GNU's Make very powerful. It can automatically derive the files and the commands behind the document dependencies, so we don't have to write similar orders after each [.o] file, because we Make will automatically identify and derive commands themselves. As long as Make sees an [.o] file, it will automatically put the [.c] file in the dependencies, if Make finds a wh dayver.o, then wherever.c will be the dependency of whatver.o . And cc -c whatver.c will also be derived, so our makefile will never write so complicated. We are new Makefile and released.
Objects = main.o kbd.o command.o display.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 buffer.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 method is Make's "Confirgin Rules". In the above file content, ". Phony" means that Clean is a pseudo target file. With more detailed "hidden rules" and "pseudo target files", I will give you a way. Sixth, alternative Makefile is just our makers can automatically derive the order, then I see that the bunch of [.o] and [.h] is a bit uncomfortable, so much repetition [.h], can It is gathers, well, no problem, this is easy for Make, who told it to provide automatic derivation of commands and files? Let's take a look at the latest style makefile. Objects = main.o kbd.o command.o display.o / insert.o search.o files.o utils.o Edit: $ (Objects) CC -O Edit $ (Objects): Defs.h KBD .o command.o files.o: command.h display.o insert.o search.o files.o: buffer.h .phony: Clean: RM Edit $ (Objects) This style makes our makefile become Very simple, but our documentation is a bit messy. You can not have it both ways. I still see your preference. I don't like this style. First, the dependency of the document is unclear. Second, if there are more files, join a few new .o files, it will not be clear. Seven, the rules of the empty target document should write a rule that empty the target file (.o and execution file), which is not only easy to compile, but also to keep the file clean. This is a "cultivation" (huh, I still remember my "programming cultivation"). The general style is: Clean: RM Edit $ (Objects) is more robust to: .phony: Clean Clean: -rm Edit $ (Objects) said before, .phony means that Clean is a "pseudo-target". . The meaning of adding a small minus sign in front of the RM command is that maybe some files have problems, but do not manage, continue to do. Of course, the rules of Clean do not place the beginning of the file, otherwise, this will become the default target of Make, I believe who is not willing to do this.
The rules of incomplete are - "Clean has never placed the last file". The above is the profile of makefile, is also the foundation of Makefile, and there are many Makefile related details, is it ready? Ready to get ready. Makefile's summary ------- First, what is Makefile? Makefile mainly includes five things: explicit rules, murgee rules, variable definitions, file instructions, and comments. 1. Explicit rules. Explicit rules illustrate how to generate one or more target files. This is clearly pointed out by Makefile's writing, the file, dependent file, the generation of the file, the resulting command. 2, the macious rules. Since our makers have automatic derived features, the concealed rules allow us to write Makefile relatively roughly, which is supported by Make. 3, the definition of the variable. In Makefile, we want to define a series of variables, the variables are generally strings, this a bit in your C language macro, when Makefile is executed, the variables are extended to the corresponding reference location. 4, file instructions. It includes three parts, one is to reference another Makefile in a makefile, just like include in the C language; the other means that the effective part in the makefile is specified according to some cases, just like the precompilation in the C language. #iF is the same; there is a multi-line command. I will talk about this part of the content. 5, comment. Makefile is only a row of comments, like UNIX's shell script, which comes with "#" characters, which is like "//" in C / C . If you want to use the "#" characters in your makefile, you can use the backstelvers to escape, such as "/ #". Finally, it is also worth mentioning that in the Makefile command, you must start with the [Tab] button. Second, Makefile's file name default, the make command will find the file name "gnumakefile", "makefile", "makefile", "makefile", "makefile", and find the file. In these three file names, it is best to use "makefile" file name, because this file name is the first character for uppercase, which has a dedicated feeling. It is best not to use "gnumakefile", this file is the GNU's Make recognition. There are additional Make only sensitive to the full-written "Makefile" file name, but basically, most of the Make supports "makefile" and "makefile" two default file names. Of course, you can use other file names to write makefile, such as "make.linux", "make.solaris", "make.aix", etc. If you want to specify a specific makefile, you can use Make's "-f" And "--file" parameters such as: make -f make.linux or make --file make.aix. Third, the reference to other makefiles In Makefile uses the include keywords to include other makefiles, which is like a C language #include, the included files are placed in the current file in the current file. Include's grammar is: includeFileName can be the file mode of the current operating system shell (which can be saved and wildcard) can have some empty characters in front of the include, but must not be the [Tab] button. INCLUDE and
You can separate with one or more spaces. For example, you have such Makefile: A.mk, B.mk, C.mk, and a file called foo.make, and a variable $ (bar), which contains E.MK and F.MK , Then, the following statement: include foo.make * .mk $ (bar) is equivalent to: include foo.make a.mk b.mk c.mk E.mk f.mk make command, you will find Include The other Makefile pointed out, and places its content in the current position. Just like the #include directive of C / C . If the file does not specify an absolute path or relative path, Make will first look for in the current directory, if you are not found in the current directory, Make will find: 1, if Make is executed, With the "-i" or "-include-dir" parameter, Make will find the directory specified by this parameter. 2, if the directory
/ include (usually: / usr / local / bin or / usr / include), make it will also go.
If there is no file, make Make generate a warning message, but it will not immediately appear. It will continue to load other files. Once make Makefile's read, make will try again, or if it cannot be read, Make will only have a fatal information. If you want Make ignore those files that you can't read, continue to execute, you can add a minus "-" in front of Include. Such as: -include
It means that no matter what error occurs regardless of the incline process, do not report error to continue. And other version make-compatible related commands are sinclude, which is the same as this.
Fourth, environment variables makefiles If you define environment variables Makefiles in your current environment, make makes values in this variable similar to include in Include. The value in this variable is the other makefile, separated by spaces. However, it is different from the include that "target" from the Makefile introduced from this environment will not work. If the file defined in the environment variable finds an error, Make will ignore. But here I still recommend not using this environment variable, because as long as this variable is defined, when you use Make, all Makefile will be affected by it, this is not what you want to see. Here, this is just to tell you, maybe sometimes your makefile has a strange thing, then you can see if this variable is defined in the current environment. 5. Make's work mode GNU's Make operation steps in operation steps: (I want to come to other Make is also similar) 1. Read all Makefile. 2, read into other Makefiles of include. 3. Initialize the variables in the file. 4. Divide the murchest rules and analyze all rules. 5. Create a dependency chain for all target files. 6. Depending on the dependencies, decide which goals should be regenerated. 7, execute the generated command. 1-5 Steps to the first stage, 6-7 is the second phase. In the first phase, if the defined variable is used, Make will expand it in the location where it is used. But Make will not completely start immediately. Make uses delay tactics. If the variable appears in the rules of dependencies, then the variable is only expanded within it only when this reliance is determined. Of course, this way you don't have to be clear, but you know this way you will be more familiar with Make. With this foundation, the subsequent part is easy to understand. Makefile's summary ------- First, what is Makefile? Makefile mainly includes five things: explicit rules, murgee rules, variable definitions, file instructions, and comments. 1. Explicit rules. Explicit rules illustrate how to generate one or more target files. This is clearly pointed out by Makefile's writing, the file, dependent file, the generation of the file, the resulting command. 2, the macious rules. Since our makers have automatic derived features, the concealed rules allow us to write Makefile relatively roughly, which is supported by Make. 3, the definition of the variable. In Makefile, we want to define a series of variables, the variables are generally strings, this a bit in your C language macro, when Makefile is executed, the variables are extended to the corresponding reference location. 4, file instructions. It includes three parts, one is to reference another Makefile in a makefile, just like include in the C language; the other means that the effective part in the makefile is specified according to some cases, just like the precompilation in the C language. #iF is the same; there is a multi-line command. I will talk about this part of the content. 5, comment. Makefile is only a row of comments, like UNIX's shell script, which comes with "#" characters, which is like "//" in C / C . If you want to use the "#" characters in your makefile, you can use the backstelvers to escape, such as "/ #". Finally, it is also worth mentioning that in the Makefile command, you must start with the [Tab] button.
Second, Makefile's file name default, the make command will find the file name "gnumakefile", "makefile", "makefile", "makefile", "makefile", and find the file. In these three file names, it is best to use "makefile" file name, because this file name is the first character for uppercase, which has a dedicated feeling. It is best not to use "gnumakefile", this file is the GNU's Make recognition. There are additional Make only sensitive to the full-written "Makefile" file name, but basically, most of the Make supports "makefile" and "makefile" two default file names. Of course, you can use other file names to write makefile, such as "make.linux", "make.solaris", "make.aix", etc. If you want to specify a specific makefile, you can use Make's "-f" And "--file" parameters such as: make -f make.linux or make --file make.aix. Third, the reference to other makefiles In Makefile uses the include keywords to include other makefiles, which is like a C language #include, the included files are placed in the current file in the current file. Include's grammar is: includeFileName can be the file mode of the current operating system shell (which can be saved and wildcard) can have some empty characters in front of the include, but must not be the [Tab] button. INCLUDE and
You can separate with one or more spaces. For example, you have such Makefile: A.mk, B.mk, C.mk, and a file called foo.make, and a variable $ (bar), which contains E.MK and F.MK So, the following statement:
Include foo.make * .mk $ (bar) is equivalent to: include foo.make a.mk b.mk c.mk E.mk f.mk make command, other makefile indicated by INCLUDE, and Place their content in the current position. Just like the #include directive of C / C . If the file does not specify an absolute path or relative path, Make will first look for in the current directory, if you are not found in the current directory, Make will find: 1, if Make is executed, With the "-i" or "-include-dir" parameter, Make will find the directory specified by this parameter. 2, if the directory
/ include (usually: / usr / local / bin or / usr / include), make it will also go.
If there is no file, make Make generate a warning message, but it will not immediately appear. It will continue to load other files. Once make Makefile's read, make will try again, or if it cannot be read, Make will only have a fatal information. If you want Make ignore those files that you can't read, continue to execute, you can add a minus "-" in front of Include. Such as: -include
It means that no matter what error occurs regardless of the incline process, do not report error to continue. And other version make-compatible related commands are sinclude, which is the same as this.
Fourth, environment variables makefiles If you define environment variables Makefiles in your current environment, make makes values in this variable similar to include in Include. The value in this variable is the other makefile, separated by spaces. However, it is different from the include that "target" from the Makefile introduced from this environment will not work. If the file defined in the environment variable finds an error, Make will ignore. But here I still recommend not using this environment variable, because as long as this variable is defined, when you use Make, all Makefile will be affected by it, this is not what you want to see. Here, this is just to tell you, maybe sometimes your makefile has a strange thing, then you can see if this variable is defined in the current environment. 5. Make's work mode GNU's Make operation steps in operation steps: (I want to come to other Make is also similar) 1. Read all Makefile. 2, read into other Makefiles of include. 3. Initialize the variables in the file. 4. Divide the murchest rules and analyze all rules. 5. Create a dependency chain for all target files. 6. Depending on the dependencies, decide which goals should be regenerated. 7, execute the generated command. 1-5 Steps to the first stage, 6-7 is the second phase. In the first phase, if the defined variable is used, Make will expand it in the location where it is used. But Make will not completely start immediately. Make uses delay tactics. If the variable appears in the rules of dependencies, then the variable is only expanded within it only when this reliance is determined. Of course, this way you don't have to be clear, but you know this way you will be more familiar with Make. With this foundation, the subsequent part is easy to understand. Sixth, the goal in the rules of multi-objective makefile can be more than one, which supports multi-objective, there is a possible number of targets to depend on one file, and the resulting command is generally similar. So we can merge them. Of course, the execution command of the generation rules of multiple targets is the same, which may have to bring trouble, but in our use of an automated variable "$ @" (about automated variables, it will be described later), this Variables show a collection of all goals in the current rules, which may be abstract, or look at an example. BIGOUTPUT LITTLEOUT: TEXT.G Generate Text.g - $ (Subst Output, $ @)> $ @ 上 规 规 等 等 价 于于: g -little> LittleOutput, "$" in-$ (subst output, $ @) means executing a MakeFile function, the function is called subst, which is the parameter. About the function will be described later. This function here is the meaning of the string, "$ @" indicates the collection of the target, just like an array, "$ @" takes out the goal, and it is committed to the command. Seven, static mode static mode can be more easily defined for multi-objective rules, allowing us to make our rules more flexible and flexible. Let's first look at the grammar ::
:
...
Targets defines a range of target files that can have wildcards. Is a collection of goals. Target-Parrtern is a model of Targets, that is, the target set mode. Prereq-Parrterns is the dependency mode of the target, which is defined for the mode of Target-Parrtern. This three things may still be clear, or an example to explain it. If we define "% .o", it means our
The collection is ended with ".o", and if we
Define into "% .c", meaning
The target set formed is defined in the secondary definition.
"%" In the mode (that is, the end of [.o] is ended), and adds the new collection of [.c].
So, our "target mode" or "dependency mode" should have "%" characters, if you have "%" in your file name, you can use a backslash "/" to indicate, to indicate Real "%" characters. See an example: Objects = foo.o bar.o all: $ (objects):% .o:% .C $ (cc) -c $ (cflags) $ @ 上 上Indicates that our goals are got from $ Object, "%. O" indicates all the goals ending with ".o", that is, "foo.o bar.o", that is, the variable $ Object Collection mode, and Dependent mode "% .C" is "% .o" "%", which is "foo bar", and add ".c" suffix, so our dependence is "foo.c" Bar.c. The "$ <" and "$ @" are automated variables in the command, "$ <" indicates that all dependence target sets (that is, "foo.c bar.c"), "$ @" indicates the target set (also It is "foo.o bar.o"). As a result, the following rules are equivalent to the following rules: foo.o: foo.c $ (cc) -c $ (cflags) foo. c c foo.o bar.o: bar.c $ (cc) -c $ (cflags) bar.c -o bar.o, if we "% .o" has hundreds, then we can write a bunch of "Static Mode Rules" with this very simple "Static Mode Rule" Rules are really efficient. The Usage of Static Mode Rules is flexible, if you are used, it will be a very powerful feature. Look at an example: files = foo.elc bar.o lose.o $ (Filter% .o, $ (files)):% .o:% .C $ (cc) -c $ (cflags) $ <-O $ @ $ (File% .elc, $ (files)):% .elc:% .el emacs -f batch-byte-compile $ <$ (file% .o, $ (files) indicating the Filter function called Makefile Filter the "$ FILTER" set, as long as the mode is "% .o". Its content, I don't have to say more. This example shows greater flexibility in makefile. 8. Automatic generation dependency in Makefile, our dependencies may need to include a series of headers, such as if there is a "#include" defs.h "in our main.c, then our dependency It should be: main.o: main.c defs.h However, if it is a relatively large engineering, you must know which C files contain which headers, and you need to be careful when you join or delete the header file. Modify Makefile, this is a very maintenance of work. In order to avoid this heavy and easy error, we can use a function of compilation of C / C . Most C / C compilers support a "-m" option, that is, automatically find the header files contained in the source file and generate a dependency.
For example, if we perform the following command: cc -m main.c Output is: main.o: main.c defs.h is then automatically generated by the compiler, so that you don't have to manually write a number The dependencies of the document are automatically generated by the compiler. It is necessary to remind a sentence that if you use the GNU's C / C compiler, you have to use the "-mm" parameter, otherwise, "-m" parameters will also include some standard libraries' header files. The output of gcc -m main.c is: main.o: main.c defs.h /usr/include/stdio.h /usr/include/features.h //usr/include/sys/cdefs.h / usr / Include / gnu / stubs.h //usr/lib/gcc-lib/i486-suse-linux/2.95.3/include/stddef.h //usr/include/bits/types.h / usr / include / bits / PthreadTypes.h / /usr/include/bits/sched.h /usr/include/libio.h / /usr/include/_g_config.h /usr/include/wchar.h / /usr/include/bits/wchar.h /usr/include/gconv.h //usr/lib/gcc-lib/i486-suse-linux/2.95.3/include/stdarg.h //usr/include/bits/stdio_lim.h gcc -mm main.c The output is: main.o: main.c defs.h So, how the compiler is associated with our makefile. Because in this way, our makefile should also regenerate according to these source files, let Makefile dependent on the source file? This feature is not realistic, but we can have other means to go back to this function. The GNU organization recommends putting the compiler to automatically generated dependencies of each source file in a file, generate a "name.d" Makefile file for each "name.c" file, [D] file Store the dependency of the [.c] file in place. Thus, we can write the [.c] file and [.d] file dependency, and let the make automatically update or self-contained [.d] files, and contain it in our master makefile, so we will It can automatically generate the dependence of each file.
Here, we give a pattern rule to generate [.d] files:% .d:% .c @set -E; RM -F $ @; / $ (cc) -m $ (cppflags) $> $ @. $$$$; / SED 'S, / ($ * /) /. O [:] *, / 1.o $ @:, g' <$ @; $$$$> $ @; / rm -f $ @. $$$$ This rule means that all [.d] files depend on the [.c] file, "RM -F $ @" means deleting all the goals, that is, [.d ] File, the second line means that for each dependency file "$ <", it is [.c] file generation dependencies, "$ @" represents the "% .d" file, if there is a C file is Name.c, then "%" is "name", "$$$$" means a random number, the second line generated files may be "name.d.12345", the third line uses the sed command to do it. A replacement, please refer to the related use documentation about the usage of the SED command. The fourth line is to delete a temporary file. All in all, this mode is to do is to join the "dependency of the [.d] file in the dependencies generated by the compiler, which means: main.o: main.c defs.h is converted to: main.o main.d : main.c defs.h, our [.d] file will also be updated automatically, and will be automatically generated. Of course, you can also join in this [.d] file is not just dependence, including generating The command can also be added one and let each [.d] file contain a decree rule. Once we finish this job, then we have to put these automatically generated rules into our master makefile. We can use the "include" command of Makefile to introduce other makefile files (previously speaking), for example: Sources = foo.c bar.c include $ (Sources: .c = .d) in the above statement "$ ".c = .d" in ".c = .d" is to make a replacement, replace all the strings of the variable $ (Sources) to [.d], about this " Replace "content, I will have more detailed descriptions later. Of course, you have to pay attention to the order, because INCLUDE is filed as a file, the target in the [.D] file that is first loaded will become the default target. Writing Commands ---- Command Lines in each rule and the command line of the operating system shell are consistent. Make will execute a command in order, each command must begin with the [Tab] key, unless, the command is followed by the semicolon behind the dependency rule. The space in the command line or the blank line will be ignored, but if the space or the blank line is opened with a Tab key, Make will think it is an empty command. We can use different shells under UNIX, but make the make commands are performed by the "/ Bin / SH" - UNIX standard shell. Unless you specifically specify a further shell. Makefile, "#" is an comment, very like "//" in C / C , and the subsequent bank characters are commented. First, the display command usually, make the command line to be executed before the command is executed to the screen.
When we use the "@" character before the command line, then this command will not be displayed by Make, the most representative example, we use this feature to display some information on the screen. Such as: @echo is compiling XXX module ... When Make is executed, it will output "Compiling XXX Modules ..." strings, but will not output commands, if there is no "@", then, Make will output: Echo is compiling XXX module ... is compiling XXX modules ... If Make is executed, bring the Make parameter "-n" or "--just-print", then it is just Display commands, but not execute commands, this feature is very good for we debugging our makefile, see what our writing command is executed or what is the order. The Make parameter "-s" or "--slient" is a full disable command display. Second, the command execution When relying on the target is new to the target, the Make will perform a subsequent command when the target of the rules needs to be updated. It should be noted that if you want to apply the result of the previous command to the next command, you should use the semicolon to separate these two commands. For example, your first command is a CD command, you want the second command to run on the CD, then you can't write these two commands on both lines, but should write these two commands. On a row, separated by a semicolon. Such as: example 1: Exec: CD / Home / HCHEN PWD Example 2: Exec: CD / Home / Hchen; PWD When we perform "make exec", the CD in the first example does not work, and the PWD will print the current Makefile directory, and in the second example, the CD works, and the PWD will print "/ home / hcha". Make is typically executing commands using the system shell defined in the environment variable shell, by default, using UNIX standard shell - / bin / sh to execute the command. But it is a bit special under MS-DOS because there is no shell environment variable under MS-DOS, of course you can also specify. If you specify the form of a UNIX style, first, Make will find a command interpreter in the path specified by Shell. If you can't find it, you will find it in the current directory in the current drive, if you can't find it, It will be found in all paths defined in the PATH environment variable. In MS-DOS, if your defined command interpreter is not found, it will give you a command interpreter, such as ".exe", ". Com", ".", ". Sh", etc. Third, the command error Whenever the command is running, make will detect the return code of each command. If the command returns success, then make will execute the next command. When all the commands in the rule have returned successfully, this rule is successful. . If a command in a rule is wrong (the command exits is not zero), the make will terminate the execution of the current rule, which will be possible to terminate all rules. Sometimes, the error of the command does not mean that it is wrong. For example, the mkdir command, we must build a directory, if the directory does not exist, then MKDIR will be executed successfully, and all the best, if the directory exists, then it is wrong. The reason why we use MKDIR is to have such a directory, so we do not want MKDIR to go wrong and terminate the rules.
In order to do this, ignore the error of the command, we can add a minus "-" (after the Tab key) in the Makefile command line, the tag is not that the command is not wrong. Such as: clean: -rm -f * .o has a global approach to add "-i" or "--ignore-errors" parameters, then all commands in makefile ignore errors. And if a rule is ".ignore" as a target, all commands in this rule will ignore the error. These are methods of preventing an error in different levels, you can set it according to your different. There is also a "-k" or "--keep-going", which is "-k" or "--keep-going", this parameter is that if the command in a rule is wrong, then the execution of the rule, But continue to perform other rules. Fourth, nested to execute make in some big projects, we will put our different modules or different functional files in different directories, we can write a directory Makefile in each directory, this has It is good to make our makefile more concise, and not to write all things in a makefile, which will hardly maintain our makefile, this technology has a very good benefit to compile and segment compilation of our modules. For example, we have a subdirectory called subdir. There is a Makefile file in this directory to indicate the compilation rules for the files in this directory. Then our total control Makefile can be written like this: Subsystem: CD Subdir && $ (Make) Its equivalent: Subsystem: $ (MAKE) -c Subdir Definition $ (Make) macro variable means, maybe our make needs some Parameters, so defined as a variable is more conducive to maintenance. These two examples means to enter the "subdir" directory first, then execute the make command. We call this Makefile ", the total control Makefile" can be passed to the subkey Makefile (if you show the declaration), but will not cover the variable defined in the subkefile of the next layer, unless specified "-e "parameter. If you want to pass a variable into a subordinate Makefile, you can use this statement: export If you don't want some variables to be delivered to the subordinate Makefile, then you can declare: UNEXPORT
Such as: Example 1: Export variable = value Its equivalent: Variable = value export variable equals: export variable: = value It is equivalent to: variable: = value export variable example 2: Export variable = value Price: variable = value export variable If you want to pass all variables, as long as an export is OK. There is no need to follow, indicating that all variables are passed. It should be noted that there are two variables, one is the shell, one is makeflags, these two variables don't care if you export, it is always necessary to pass to the next Makefile, especially the makefiles variable, which contains the parameter information of Make, If we have a Make parameter or define this variable in the upper Makefile when performing "Total Makefile", the makefiles variable will be these parameters and will be transferred to the lower Makefile, which is a system-level environment variable. However, several parameters in the make command are not transmitted down, they are "-c", "- f", "- h" "- o" and "-w" (detail about the Makefile parameter will be described later. If you don't want to pass parameters to the lower layer, then you can come: Subsystem: CD Subdir && $ (Make) Makeflags = If you define environment variables makeflags, then you have to be sure that you will be used. If there are "-t", "- n", and "-q" parameters, then there will be unexpected results, perhaps you will panic unusually. There is also a more useful parameter, "- w" or "-print-directory" in "Nesting Execution", which will output some information in the opportunity of Make, so that you see the current working directory. For example, if our subordinate make directory is "/ home / hchen / gnu / make", if we use "make -w" to execute, then we will see: make: Entering Directory `/ Home / hchen / gnu / make '. When you leave the directory after completing the underlying Make, we will see: make: leaving directory `/ home / hchen / gnu / make' When you use the" -c "parameter to specify the subceline of Makefile When "- W" will be opened automatically. If there is "-s" ("- slient") or "--no-print-directory" in the parameter, "- w" is always invalid. V. Define Command Pack If some of the same command sequences appear in Makefile, we can define a variable for these same command sequences.
Defining the syntax of this command sequence begins with "Define" to end with "endef", such as: Define Run-Yacc Yacc $ (Firstword $ ^) mv y.tab.c $ @ Endef here, "Run-Yacc" is this The name of the command package, does not reintegrate with the variable in the makefile. Two lines in "define" and "endef" are command sequences. The first command in this command package is running the YACC program because the YACC program always generates "Y. Tab.c" files, so the second line command is to change this file. Or put this command to a sample to see it. Foo.c: foo.y $ (run-yacc) We can see, we want to use this command package, we seem to use the variable. In this command package, "$ ^" in the command package "Run-Yacc" is "foo.y", "$ @" is "foo.c" (related to this special variable starting with "$" We will introduce later), Make is executing each command in the command package when executing the command package.
Using variables ---- The variables defined in makefile are like a macro in the C / C language. He represents a text string. When it is executed in the makefile, it will automatically start the original model. Use place. It is different from C / C that you can change its value in makefile. In Makefile, variables can be used in "target", "dependency", "command", or other parts of Makefile. The name word of the variable can contain characters, numbers, and underscore (can be digital start), but should not contain ":", "#", "=" or empty characters (spaces, Enter, etc.). Variables are sensitive, "foo", "foo", and "foo" are three different variable names. The traditional Makefile variable name is a new name method, but I recommend using a variable name with case, such as: Makeflags. This avoids conflicts with the system's variables, and accidents occur. Some variables are very strange strings, such as "$ <", "$ @", etc., these are automated variables, I will introduce later. First, the basic variable of the variable needs to give initial values when the declaration is declared, and when in use, you need to add "$" symbol before using the "$" symbol, but it is best to use small brackets "()" or braces "{}" Variables are given. If you want to use a real "$" character, you need to use "$$". Variables can be used in many places, such as "depends", "dependencies", "command", and new variables. Let's take an example: Objects = program.o foo.o utils.o program: $ (Objects) $ (Objects): Defs.h variable will be exactly exactly using it, Like the macro in C / C , for example: foo = C Prog.O: PROG. $ (Foo) $ (foo) - $ (foo) prog. $ (Foo) get: prog.o : prog.c cc -c prog.c, of course, don't do this in your makefile, here is just an example to indicate the true appearance of the variable in the Makefile. It can be seen that it is a "alternative" principle. In addition, the variable plus parentheses is completely used for more securely using this variable, in the above example, if you don't want to add parentheses, it can, but I still recommend that you add parentheses to the variable. Second, the variables in the variable When the value of the variable, we can use other variables to construct the value of the variable, there are two ways to define variables with variables in both Makefile. First, look at the first way, that is, the "=" number, "=" is the variable, the right side is the value of the variable, the value of the right variable can be defined anywhere in the file, that is, The variables in the right side are not necessarily a value that has been defined, and it can also use the value of the following definition.
Such as: foo = $ (bar) bar = $ (UGH) UGH = Huh? All: Echo $ (foo) We Execute "Make All" will play the value of the variable $ (foo) is "huh?" ($ (Foo) The value of $ (bar), $ (bar) is $ (UGH), $ (UGH) value is "huh?"), And the variable can be defined using the rear variables. This feature has a good place, and there is a bad place. Well, we can push the true value of the variable to the back to define, such as: cflags = $ (incrude_dirs) -o include_dirs = -ifoo -ibar "cflags "When you are expanded in the command, it will be" -ifoo -ibar -o ". But this form is also in a bad place, that is, recursive definition, such as: cflags = $ (cflags) -o or: a = $ (b) b = $ (a) This will make Make fall into the unlimited variable expansion Go, of course, our make is the ability to detect such definitions and will report an error. There is also if you use a function in a variable, then this way makes our maket time very slow, worse, he will use two Make functions "Wildcard" and "shell" unpredictable error. Because you won't know how many times the two functions will be called. To avoid this method, we can use another variable to define variables in another variable. This method uses ": =" operators, such as: x: = foo y: = $ (x) bar x: = late its equivalent: y: = foo bar x: = latter is worth mentioning , This method, the previous variable cannot use the rear variable, only the previously defined variables can be used. If this is true: Y: = $ (x) bar x: = foo So, Y's value is "bar" instead of "foo bar". The above is a relatively simple variable is used, let us look at a complex example, including Make's function, conditional expression and a system variable "MakeElevel": IFEQ (0, $ {MakeElevel}) CUR -dir: = $ (Shell PWD) Whoami: = $ (Shell Whoami) Host-type: = $ (shell arch) Make: = $ {host-type} why = $ {ha} Endif About the conditional expression and function, we will say later, for the system variable "MakeElevel", it means that if our make has a nested action (see "Nesting using Make", then, this The variable records our current makefile call layers.
Let's introduce two definition variables, we need to know, please take an example, if we want to define a variable, its value is a space, then we can come: nullstring: = space: = $ (nullstring) # END of the line nullstring is an EMPTY variable, where there is no, and our space value is a space. Because it is difficult to describe a space on the right side of the operator, the technique used here is used, first using an EMPTY variable to indicate the value of the variable start, and the "#" comment is used to indicate the termination of the variable definition, so We can define the variables of a space. Please note that this feature of "#" is worth noting that this feature of the comment "#" is worth noting that if we define a variable: Dir: = / foo / bar # Directory to put the ferobs in dirctory value is the value of this variable is "/ Foo / bar", followed by 4 spaces, if we use this variable to specify other directories - "$ (dir) / file" then finish. There is also a more useful operator is "? =", First look at the example: foo? = Bar its meaning, if the foo is not defined, the value of the variable foo is "bar", if Foo is previously defined, Then this language will not do anything, equivalent: IFEQ ($ (Origin foo), undefined) foo = bar endif.3, the variable advanced usage is introduced here to introduce the advanced use of the two variables, the first is the variable value Alternative. We can replace the common parts in variables, "$ (var: a = b)" or "$ = b)", it means that all of the variables "VAR" "A "" A "" "A" "end" is replaced with "B" string. The "end" here means "space" or "ending". Still watching an example: foo: = AO boity CO bar: = $ (foo: .o = .c) This example, we define a "$ (foo)" variable, and the second line means "$ (Foo)" is replaced with ".o" string "end" all replaces ".c", so our "$ (bar)" value is "AC BC CC". Another variable replacement technique is defined in "static mode" (see the previous chapter), such as: foo: = AO BO CO bar: = $ (foo:%. O =%. C) This depends on the retrieval word There is the same mode in the string, and a "%" character must be included in the mode. This example also allows the value of the $ (bar) variable to "AC BC CC". The second advanced utility is - "The value of the variable is changed as a variable." Let's take an example: x = y y = z A: = $ ($ (x)) In this example, $ (x) value is "y", so $ ($ (x)) is $ (y) The value of $ (a) is "z". (Note, "x = y", not "x = $ (y)") we can also use more levels: x = y y = z z = u A: = $ ($ ($ () )) The value of $ (a) here is "u", the relevant derivation is left to the reader to do it.
Let us be more complicated, use the first way to use variables in variable definitions "to see an example: x = $ (y) y = z z = Hello A: = $ ($)) here $ ($ (X)) is replaced with $ ($ (y)) because the $ (y) value is "Z", so the end result is: A: = $ (z), that is, "Hello" . Complex again, we add a function: x = variable1 variable2: = Hello Y = $ (SUBST 1, 2, $ (x)) z = y A: = $ ($ (z))) This example is , "$ ($ ($ ($ (Z)))" Extension to "$ (Y)", and it is once again extended to "$ ($ (SUBST 1, 2, $ (x))". The value of $ (x) is "variable1", the SUBST function replaces all the "1" strings in "variable1" into "2" strings, "Variable1" becomes "variable2", then takes the value, so , Finally, the value of $ (a) is the value of $ (variable2) - "Hello". (Oh, it is difficult to "in this way, or you can use multiple variables to form a variable name, then take the value: first_second = Hello a = first b = second all = $ ($ A_ $ b) The "$ A_ $ B" here consists of "first_second", so the value of $ (all) is "Hello". Let's take a look at the examples of the first technology: a_objects: = AO bo 1_objects: = 1.o 2.o 3.o Sources: = $ ($ (a1) _Objects: .o = .c) This example, If the value of $ (a1) is "a", then the value of $ (Sources) is "AC BC CC"; if the value of $ (a1) is "1", then $ (Sources) value is "1) .c 2.c 3.c. Take another example of this technology and "function" and "conditional statements": ifdef do_sort func: = sort else func: = Strip Endif Bar: = Adbgqc foo: = $ ($ (FUNC) $ (bar)) In this example, if "do_sort" is defined, then: foo: = $ (sort adbgqc), the value of $ (foo) is "abcdgq", and if "do_sort" is not defined, then: foo: = $ (Sort ADBGQC), calling the Strip function. Of course, "the value of the variable is variable", which can also be used on the left side of the operator: DIR = Foo $ (DIR) _Sources: = $ (Wildcard $ (DIR) / *. C) Define $ (DIR ) _Print Lpr $ ($ (DIR) _Sources) Endef This example defines three variables: "DIR", "foo_sources" and "foo_print".
Fourth, additional variables We can use the " =" operator to add value to the variable, such as: Objects = main.o foo.o bar.o utils.o Objects = another.o, our $ (Objects) value Change: "Main.o foo.o bar.o utils.o noidher.o" (ANOTHER.O is added) Use the " =" operator, which can simulate this example below: Objects = main. o foo.o bar.o utils.o Objects: = $ (Objects) Another.o is different from " =" is more concise. If the variable is not defined before, " =" will automatically turn "=", if there is a variable definition in front, " =" will inherit the assassifier of the previous operation. If the previous one is ": =", " =" will assign a value in ": =" as its assignment, such as: variable: = value variable = more equals: variable: = value variable: = $ (Variable , if this is the case: variable = value variable = more because the previous assignment is "=", " =" will be assigned as "=", then there will be no variables. Repeating the definition, this is very bad, so Make will automatically solve this problem for us, we don't have to worry about this problem. V. Override indicator If the variable is usually set, the assignment of this variable will be ignored in the Makefile. If you want to set the value of such parameters in makefile, then you can use the "OVERRIDE" indicator. Its syntax is: Override =
Override
: =
Of course, you can also add: Override
=
For multi-line variables, we use the define indicator, before the define indicator, you can also use the Ovveride indicator, such as: Override define foo bar endef six, multi-line variables There is also a way to set variable values to use define. Keyword. The value of setting the variable using the define keyword can have a wrap, which facilitates the definition of a series of commands (before we told the "command package" technology to use this keyword). The define indicator is followed by the name of the variable, and restarts the value of the defined variable, the definition is the end of the Endef keyword. Its work mode is the same as the "=" operator. The value of the variable can contain functions, commands, text, or other variables. Because the command needs to begin with the [Tab] key, if you don't start with the [Tab] button with the defined command variable, Make will not think it is a command. The following example shows the usage of define: Define TW-LINES Echo foo echo $ (bar) Endef seven, environment variables Make runtime system environment variables can be loaded into the Makefile file when Make starts running, but if Makefile This variable has been defined, or this variable is brought by the Make command line, then the value of the system's environment variable will be overwritten. (If Make specifies the "-e" parameter, the system environment variable will override the variable defined in Makefile), so we can use the "cflags" environment variable in the environment variable, then we can use in all makefiles. This variable is. This has a relatively good benefit to our compilation parameters. If you define cflags in makefile, this variable in makefile will use the value of the system environment variable, a common and personalized unity, which is very similar to the "global variable" and "local variable" if it is not defined. When Make nested (see chapter "Nested Call chapter), the variable defined in the upper Makefile will be passed to the lower Makefile in the way system environment variables. Of course, by default, the variables set by the command line will be passed. And define the variables in the file, if you want to pass down MakeFile, you need to use the exprot keyword to declare. (See the previous chapter) Of course, I don't recommend that many variables are defined in the system environment, so that when we don't have to make Makefile, it has the same set of system variables, which may bring more trouble. 8. The variables we are talking to the target variable are all "global variables", and we can access these variables throughout the file. Of course, except "automated variables", such as "$ <", such as "$ <" belongs to the "rule variable", and the value of this variable depends on the rules and definitions of dependent targets. Of course, I can also set local variables for a target. This variable is called "target-specific variable", which can be with "global variable", because its role range is only in this rule and the joint rules Therefore, its value is only valid within the scope of action. The value of global variables other than the rule chain will not affect the rule chain. Its syntax is ::
: Overide
It can be various assignment expressions, such as "=", ": =", " =" or "? =". The second syntax is to target the variables brought by the Make command line or the system environment variable.
This feature is very useful, when we set a variable, this variable will act to all rules caused by this goal. Such as: prog: cflags = -g prog: prog.o foo.o bar.o $ (cflags) prog.o foo. bar.o prog.o: prog.c $ (cc) $ (cflags ) Prog.c foo.o: foo.c $ (cc) $ (cflags) foo.c bar.o: bar.c $ (cc) $ (cflags) bar.c In this example, no matter the global $ What is the value of cflags, in the PROG target, and all the rules it triggered (Prog.o Foo. bar.o rules), the value of $ (cflags) is "-g" nine, mode variables In the GNU's Make, the pattern variable is supported. In the above target variable, we know that the variable can be defined on a target. The advantage of mode variables is that we can give a "mode" to define variables on all targets that meet this mode. We know that Make's "mode" is generally at least one "%", so we can define target variables in [.o] at the end of [.o] in the following way:% .o: cflags = -o, mode The syntax and "target variable" of the variable:
: OVERRIDE
OVERRIDE is also a variable that is incorporated on the system environment, or the variable specified by the Make command line. Use condition judgment ------ Use condition judge, allowing Make to select different execution branches depending on the different conditions of runtime. The conditional expression can be a value of a comparison variable, or a value of comparison variables and constants. First, the example below, determines if the $ (CC) variable "GCC", if yes, use the GNU function to compile the target. Libs_for_gcc = -lgnu Normal_Libs = Foo: $ (Objects) IFEQ ($ (CC), GCC) $ (CC) -o Foo $ (Objects) $ (libs_for_gcc) ELSE $ (CC) -o Foo $ (Objects) $ ( NORMAL_LIBS) ENDIF visa We can see three keywords from the above example: IFEQ, Else, and Endif. IFEQ means the beginning of the conditional statement, and specifies a conditional expression, the expression contains two parameters, separated by commas, and the expression is enclosed in parentheses. Else indicates the condition of the conditional expression. Endif indicates the end of a conditional statement, and any conditional expression should end with ENDIF. When our variable $ (cc) value is "GCC", the rules of the target foo are: foo: $ (Objects) $ (cc) -o foo $ (objects) $ (libs_for_gcc) while our variable $ (cc) The value is not "GCC" (such as "cc"), the rules of the target foo are: foo: $ (ibjects) $ (cc) -o foo $ (objects) $ (Normal_Libs) Of course, we can also put the above Examples are more concise: libs_for_gcc = -lnu Normal_Libs = IFNU NORMAL_LIBS = IFEQ ($ (cc), gcc) Libs = $ (libs_for_gcc) Else Libs = $ (Normal_Libs) Endif Foo: $ (Objects) $ (cc) -o foo $ (Objects) $ (libs) Second, the syntax of the syntax condition expression is: ENDIF
as well as:
Else
ENDIF
among them
Indicates the keyword, such as "IFEQ". This keyword has four.
The first is "IFEQ" IFEQ before we have seen.
,
)
IFEQ '
'' '
'
IFEQ "
""
"
IFEQ "
"'
'
IFEQ '
""
"
The value of comparison parameters "arg1" and "arg2" are the same. Of course, we can also use the Make function in the parameter. Such as: IFEQ ($ (Strip $ (Foo)),)
ENDIF
The "strip" function is used in this example. If the return value of this function is empty, then
Effective.
The second condition key is "ifneq". Grammar is: IFNEQ (
,
)
IFNEQ '
'' '
'
IFNEQ "
""
"
IFNEQ "
"'
'
IFNEQ ''
"
Its comparison parameter "arg1" and "arg2" are the same, if different, it is true. Similar to "IFEQ". The third condition key is "IFDEF". Grammar is: ifdef
If the variable
The value is not empty, then the expression is true. Otherwise, the expression is false. of course,
It can also be a return value of a function. Note that ifdef only tests if a variable has a value, it does not extends the variable to the current location. Or come to see two examples:
Example 1: bar = foo = $ (bar) ifdef foo frobozz = yes else frobozz = no endif example: foo = ifdef foo frobozz = yes else frobozz = no Endif's first example, "$ (frobozz) value is "Yes", the second is "no". The fourth condition key is "ifndef". Its syntax is: IFNDEF
I don't have much to say this, and "ifdef" is the opposite. in
On this line, excess space is allowed, but you can't start with the [Tab] key (otherwise it is considered a command). The comment "#" is also safe. "Else" and "Endif" are the same, as long as it is not to start with the [Tab] button.
In particular, Make is the value of the conditional expression when reading Makefile, and selects the statement according to the value of the conditional expression, so don't put the automated variables (such as "$ @", etc.) In the conditional expression, since the automation variable is only running. Moreover, in order to avoid confusion, MAKE does not allow the entire condition statement into two parts in different files. Using a function ---- In Makefile, you can use a function to handle the variable, so that our commands or rules are more flexible and intelligent. The function supported by Make is not much, but it is enough for our operation. After the function is called, the return value of the function can be used as a variable. First, the function call syntax function calls, very like variables, is also identified by "$", its syntax is as follows: $
)
Or $ {
}
Here,
It is a function name, and Make supports a lot of functions.
It is the parameters of the function, and the parameters are brought by a comma "," separated between the function names and parameters. The function is called "$", enclosing the function name and parameters in parentheses or curly brackets. It feels like a variable, is it? The parameters in the function can use variables. For the unity of styles, the function and variables are best, such as "$ (Subst A, B, $ (x))", rather than "subs", B, $ {x}) "form. Because the unity will be clearer, it will also reduce some unnecessary trouble.
Still come and see an example: comma: =, empty: = space: = $ (empty) $ (EMPTY) foo: = ABC BAR: = $ (Subst $ (Space), $ (Comma), $ (Foo)) In this example, the value of $ (COMMA) is a comma. $ (space) Download a space, $ (foo) value is "ABC", $ (bar) defined, calling the function "subst", this is a replacement function, this function has three Parameters, the first parameter is replaced by the string, the second parameter is replacing the string, the third parameter is a string of the operation. This function is also replacing the space in $ (foo) into a comma, so the value of $ (bar) is "A, B, C". Second, string processing functions $ (SUBST,
,
)
Name: String Replacement Function - Subst. Function: put the strings
middle
Character string replacement
.
Returns: The function returns a string that is replaced.
Example: $ (Subst Ee, EE, Feet on The Street), replacing "EE" in "Feet on The Street" into "EE", the return result is "Feet on the street". $ (PATSUBST
,
,
)
Name: Mode string replacement function - Patsubst. Function: Find
Words (words "spaces", "tab" or "Enter" "Separation" in line with the pattern
If you match,
replace. Here,
The wildcard "%" may include a string of any length. in case
"%" Also contains "%", then,
This "%" will be
The string represented by the "%". (You can use "/" to escape, "/%" to represent the "%" character of the true meaning)
Returns: The function returns a string that is replaced.
Example: $ (PATSUBST% .C,%. O, XCC bar.c) Replace the string "XCC bar.c" in line with [% .o], return results "XCO BAR .o "Note: This is a bit similar to the relevant knowledge that we have said in front of the" variable chapter ". Such as: "$ (VAR:
=
) "
Equivalent
"$ (PATSUBST
,
$ (var) ",
And "$ (VAR:
=
) "
It is equivalent to
"$ (PATSUBST%
%
, $ (var) ".
For example, it is: Objects = foo.o bar.o baz.o,
Then, "$ (Objects: .o = .c)" and "patrsubst% .O,%. C, $ (objects))" are the same.
$ (Strip
)
Name: Go to Net Gift Function - Strip. Function: remove
The null characters start and end in the string.
Returns: Returns the string value of the removed space.
Example:
$ (Strip A B C)
Take the string "a b c" to the beginning and end space, the result is "a b c". $ (Findstring
,
)
Name: Find string functions - Findstring. Function: in the string
Look out
String.
Return: If you find it, then return
Otherwise returns an empty string.
Example:
$ (FindString A, A, B C) The first function returns "A" string, the second return "" string (empty string) $ (Filter,
)
Name: Filter function - Filter. Function:
Mode filtering
Words in strings, reserved compliance mode
Words. There can be multiple modes.
Return: Return to match the pattern
String.
Example:
Sourcees: = foo.c bar.c baz.s Ugh.h foo: $ (Sources) CC $ (Filter% .C%. S, $ (Sources)) -O Foo $ (Filter% .C% .s, The value returned by $ (SOURCES) is "foo.c bar.c baz.s". $ (Filter-Out
,
)
Name: Reverse filter function - Filter-out. Function:
Mode filtering
Words in strings, remove compliance mode
Words. There can be multiple modes.
Return: Return does not match the mode
String.
Example:
Objects = main1.o foo.o main2.o bar.o mains = main1.o main2.o $ (Filter-Out $ (MAINS), $ (Objects)) The return value is "foo.o bar.o". $ (Sort
)
Name: Sort Function - Sort. Function: give a string
Sort in words (ascending).
Returns: Returns the sorted string.
Example: $ (Sort Foo Bar LOSE) Returns "Bar Foo Lose".
Remarks: The sort function will go
The same word.
$ (word
,
)
Name: Take a word function - Word. Function: Take strings
B
Words. (From the beginning)
Return: Return to the string
B
Words. in case
ratio
The number of words is large, then return to the empty string.
Example: $ (Word 2, Foo Bar Baz) Return value is "bar".
$ (WordList,
,
)
Name: Take a string string function --wordList. Function: from string
Neutralize
Start to
Word string.
with
Is a number.
Return: Return to the string
Neutral
Until
Word string. in case
ratio
The number of words is large, then return to the empty string. in case
more than the
The number of words, then return from
Start, to
Ended a string.
Example: $ (WordList 2, 3, Foo Bar Baz) Return value is "bar baz".
$ (Words
)
Name: Word Number Statistics - Words. Function: Statistics
The number of words in the string.
Return: return
The number of words in.
Example: $ (Words, Foo Bar Baz) Return value is "3".
Remarks: If we are going to take
The last word, we can do this: $ (Word $
),
).
$ (Firstword
)
Name: First single word function --firstword. Function: Take strings
The first word in the middle.
Return: Return to the string
The first word.
Example: $ (FIRSTWORD FOO BAR) The return value is "foo".
Remarks: This function can be implemented with a Word function: $ (Word 1,
).
The above is all string operation functions, and if mixed, you can complete a more complex function. Here, an example of a reality is given. We know that make uses the "vPath" variable to specify the search path of "dependent file". Thus, we can use this search path to specify the search path parameters of the compiler to the header file cflags, such as: Override CFLAGS = $ (PatSubst%, - I%, $ (Subst:,, $ (vpath)) if we "$ (VPath) value is" src: ./ Headers ", then" $ (PatSubst%, - I%, $ (Subst:,, $ (vPath)) "will return" -isrc -i .. / Headers, this is the parameter of the CC or GCC search header file path. Third, the file name operation function Let's introduce the function we need to process the file name. The parameter string of each function will be treated as one or a series of file names. $ (DIR)
Name: Take a directory function - DIR. Function: From the file name sequence
Take out the directory part. The directory section refers to the part before the last backslash ("/"). If there is no backslash, then "back" ./ ".
Return: Return to file name sequence
Directory section.
Example: $ (Dir src / foo.c Hacks) The return value is "src / ./".
$ (Notdir
)
Name: Take the file function - NOTDIR. Function: From the file name sequence
Take out the non-directory part. The non-directory part refers to the part after the last backslash ("/").
Return: Return to file name sequence
The non-directory part.
Example: $ (notdir src / foo.c Hacks) Return value is "foo.c Hacks".
$ (SUFFIX
)
Name: Take the suffix function - SUFFIX.
Function: From the file name sequence
Take out the suffix of each file name.
Return: Return to file name sequence
The suffix sequence, if the file has no suffix, return the empty string.
Example: $ (SUFFIX SRC / FOO.c SRC-1.0 / bar.c Hacks) Return Value ".c .c".
$ (BaseName
)
Name: Take the prefix function - Basename. Function: From the file name sequence
Take out the prefix section of each file name.
Return: Return to file name sequence
The prefix sequence, if the file is not prefix, return the empty string.
Example: $ (BaseName Src / Foo.c SRC-1.0 / bar.c Hacks) Return Value is "SRC / FOO SRC-1.0 / Bar Hacks".
$ (AddsuFFix
,
)
Name: Add the assales - ADDSUFFIX. Function: Put the suffix
Add
Every word in the middle.
Returns: Returns the file name sequence of the plus suffix.
Example: $ (addsuffix .c, foo bar) Return value is "foo.c bar.c".
$ (AddPRefix
,
)
Name: Add the prefix function - ADDPREFIX. Function: Put the prefix
Add
Every word in the middle.
Returns: Returns the file name sequence of the added prefix.
Example: $ (AddPRefix SRC /, FOO BAR) Return Value is "SRC / Foo Src / Bar".
$ (Join
,
)
Name: Connection function - Join. Function: put
The word in correspondence
The word behind. in case
Word bit comparison
Many, then, then,
Many words in the middle will remain. in case
Word bit comparison
More, then,
Many words will be copied
in.
Returns: Returns the connected string.
Example: $ (Join AAA BBB, 111 222 333) Return value is "AAA111 BBB222 333".
FOREACH function
The Foreach function is very different from other functions. Because this function is used for looping, the Foreach function in the makefile is almost in the FOR statement in the UNIX standard shell (/ bin / sh), or the Foreach statement in the c-shell (/ bin / csh). Built. Its syntax is:
$ (Foreach,
,
)
The meaning of this function is to put parameters
The words in the words are taken out by one of the variables specified by the parameter, and then execute
The expression contained. every time
Will return a string, during the loop process,
Each of the returned characters will be separated by a space, and finally, when the entire cycle ends,
The entire string of each string returned is the return value of the Foreach function.
So, it is best to be a variable name.
Can be an expression, but
This parameter is usually used in order
Words in. for example:
Names: = a b c d
Files: = $ (Foreach N, $ (Names), $ (N) .o)
In the above example, the words in the $ (name) will be taken out, and save the variable "n", "$ (n) .o" calculates a value each time according to "$ (N)", these values Space separation, finally the return as a Foreach function, so (files) value is "AO BO CO DO".
Note that the parameters in Foreach are a temporary local variable. After the foreach function is executed, the parameter variable will not function, and its scope is only in the foreach function.
V. IF functions
The IF function is very similar to the conditional statement supported by the GNU's Make - IFEQ (see the chapter described earlier), the syntax of the IF function is:
$ (if
,
)
Or
$ (if
,
,
)
It can be seen that the IF function can contain "ELSE" sections, or not. That is, the parameter of the IF function can be two or three.
The parameter is an expression of IF. If it returns a non-empty string, then this expression is equivalent to returning, so
Will be calculated, otherwise
Will be calculated.
The return value of the IF function is if
That is true (non-empty string), that
Will it be the return value of the entire function, if
For fake (empty string), then
Will it be the return value of the entire function, if
Nothing is defined, then the entire function returns the empty string.
and so,
with
There is only one calculated.
Sixth, Call function
The Call function is the only function that can be used to create new parameters. You can write a very complex expression. In this expression, you can define many parameters, then you can use the Call function to pass parameters to this expression. Its syntax is:
$ (Call
,
,
,
...)
When Make executes this function,
Variables in the parameters, such as $ (1), $ (2), $ (3), etc., will be parametric
,
,
Replace it in turn. and
The return value is the return value of the Call function. For example: Reverse = $ (1) $ (2)
Foo = $ (Call Reverse, A, B)
So, the value of foo is "a b". Of course, the order of the parameters can be customized, not necessarily sequential, such as: Reverse = $ (2) $ (1)
Foo = $ (Call Reverse, A, B)
The value of the FOO at this time is "B A".
Seven, Origin functions
The Origin function is not like other functions, he does not operate the value of the variable, he just tells you where your variable is coming? Its syntax is:
$ (Origin
)
note,
Is the name of the variable, it should not be referenced. So you'd better not
Use "$" characters in. The origin function tells you the "birth situation" of this variable with its return value. Below, it is the return value of the origin function:
"Undefined"
in case
Never defined, the origin function returns this value "undefined".
Default "
in case
It is a default definition, such as "CC" variable, this variable we will tell later.
"Environment"
in case
It is an environment variable, and when Makefile is executed, the "- e" parameter is not opened.
File
in case
This variable is defined in the Makefile.
"Command Line"
in case
This variable is defined by the command line.
"OVERRIDE"
in case
It is redefined by the OVERRIDE indicator.
Automatic "
in case
It is an automated variable in the run. About automation variables will be described later.
This information is very useful for we write makefile, for example, suppose we have a Makefile package that packs a definition file Make.def, defined a variable "Bletch" in make.def, and there is an environment variable in our environment "BLETCH", at this time, we want to judge, if the variable comes from the environment, then we will redefine it, if you come from the Make.DEF or the command line, then we don't redefine it. So, in our makefile, we can write this:
IFDEF BLETCH
Ifeq "$ (Origin Bletch)" Environment "
Bletch = BARF, GAG, ETC.
ENDIF
ENDIF
Of course, you may say that you can redefine the variables in the environment using the Override keyword? Why do you need this step? Yes, we use Override to achieve such an effect, but Override is too rude, it will overwrite the variables defined from the command line, and we just want to redefine the environment, and do not want to redefine the command line Come.
Eight, shell function
The shell function is not like other functions. As the name suggests, its parameters should be the command of the operating system shell. It and the reverse "` "are the same function. That is to say, the shell function returns the output after executing the operating system command as a function. Thus, we can generate a variable with an operating system command and a string handle command awk, sed, etc., such as:
Contents: = $ (Shell Cat Foo)
Files: = $ (shell echo * .c)
Note that this function will generate a shell program to execute the command, so you have to pay attention to its run performance, if you have some complicated rules in your makefile, and use this function, so you are harmful to your system performance. . Especially the macked rules of makefile may make your shell function to do much more than what you imagine. Nine, control the function of MAKE
Make provides some functions to control the operation of Make. Typically, you need to detect some runtime information when running makefile, and determine this information, you let Make continue, or stop.
$ (Error
)
Produce a fatal mistake,
Yes is the error message. Note that the Error function will not generate error messages in one use, so if you define it in a certain variable, it is also possible to use this variable in a subsequent script. E.g:
Example 1:
IFDef Error_001
$ (Error Error IS $ (Error_001))
ENDIF
Example 2:
Err = $ (Error Found An Error!)
.Phony: ERR
Err:; $ (ERR)
The example will generate an Error call when the variable error_001 is defined, and the example two will occur when the directory ERR is executed.
$ (WARNING
)
This function is like an Error function, but it does not let Make exits, just output a warning message, and make continues.
Make's run ------ Generally, the simplest is to enter the Make command directly on the command line, and the make command will find the makefile of the current directory to execute, everything is automatic. But sometimes you may just want Make to recompile certain files, not the entire project, and sometimes you have several compilation rules, you want to use different compilation rules in different times, and so on. This chapter is to tell how to use the make command. First, Make's exit code make commands have three exit codes: 0 - means successfully executed. 1 - Any error occurs if the Make is running, it returns 1. 2 - If you use the "-q" option of make, and make make some targets don't need to be updated, then returns 2. Make's related parameters we will tell in subsequent chapters. Second, the specified Makefile We said that GNU Make finds the default Makefile rules to find three files in the current directory - "gnumakefile", "makefile", and "makefile". It is found in order to find these three files, once found, start reading this file and execute. Currently, we can also assign a special name for Makefile to the Make command. To achieve this feature, we want to use the "-f" or "-file" parameter ("--makefile" parameter). For example, we have a Makefile name is "hchen.mk", then we can let Make to execute this file: make -f hchen.mk If the command line in Make is, you don't only use it once. " f "Parameters, then all specified Makefile will be delivered together to Make. Third, the specified goal is generally, MAKE's ultimate goal is the first target in Makefile, and other objectives are generally coming from this target. This is the default behavior of Make. Of course, in general, your Makefile's first goal is made up of many targets, you can indicate Make to complete the target you specify. To achieve this, it is very simple. You need to directly follow the target after the board command (as shown in the "Make Clean" form) any target in Makefile can be specified as the ultimate goal, but except "-" Head, or contains "=" target, because there is a target of these characters, will be parsed into command line parameters or variables. Even the goals we have clearly written can also become the ultimate goal of Make, that is, as long as Make can find its implicit rules, this implicit target can also be specified as the ultimate goal. There is a Make environment variable called "makecmdgoals". The list of the ultimate target you specify is stored in this variable. If you don't specify the target, this variable is null. This variable allows you to use in some particular situations. For example, the following example: Sources = foo.c bar.c ifneq ($ (Makecmdgoals), Clean) INCLUDE $ (Sources: .c = .d) Endif Based on this example, as long as the command we entered is not "Make Clean" Then Makefile automatically contains two Makefiles "foo.d" and "bar.d".
With the specified ultimate goal, you can easily compile our programs, such as the following example: .phony: all all: proG1 prog2 prog3 prog4 From this example, we can see that there are four need to compile in this makefile Program - "Prog1", "PROG2", "PROG3", and "PROG4", we can use the "Make All" command to compile all the targets (if you put all the first goals, then just execute "Make "), We can also use" make prop2 "to compile the target" prog2 "separately. Often Make can specify all the goals in all makefile, then "pseudo-target", so we can make our makefile to complete different things based on this nature. In UNIX world, when the software is released, especially the release of this open source software, its Makefile contains compilation, installation, packaging and other functions. We can refer to this rule to write the goals in our makefile. "All" pseudo-objective is the goal of all goals, and its feature is generally compiled all the goals. "Clean" pseudo-objective function is to delete all files created by Make. "Install" pseudo-objective function is to install the compiled program, in fact, copy the target execution file to the specified target. "Print" The function of this pseudo-target is to illustrate the changed source file. "TAR" pseudoactive function is to package the source package backup. That is a TAR file. "DIST" pseudo-target function is to create a compressed file, which is generally pressed into the z file. Or GZ file. "Tags" pseudo-objective function is to update all the goals for complete recompilation. "Check" and "Test" are generally used to test the process of Makefile. Of course, a project's makefile does not have to write such a goal, these things are gnu's things, but I think the GNU has a certain thing (waiting for the program files under your UNIX. You will find these features very useful), it is just a description. If you want to write this function, it is best to use this name to name your goals, so that some, the normative benefits is - do not explain, Everyone understands. And if you have these features in your makefile, one is very practical, and the other is that you can look very professional (not the work of the beginner). Fourth, the inspection rules are sometimes, we don't want our rules in our makefile, we just want to check our commands or execute the sequence. So we can use the following parameters of the make command: "-n" "--just-print" "--dry-run" "--Recon" does not execute parameters, these parameters are just print commands, regardless of the goal to update, The rules and the commands under the joint rules are printed, but they do not execute, these parameters are very useful for us to debug Makefile. "-T" "--Touch" means that the time update of the target file, but does not change the target file. That is, Make pretend to be compiled, but is not a real compilation target, just turn the target into a compiled state.
The behavior of "-q" "--question" is the meaning of finding the target, that is, if the target exists, then what else does not output, and of course, it will not perform compilation, if the target does not exist, it will print An error message. "-W"
"--What-if =
"
"--Ssume-new =
"
"--New-file =
"
This parameter needs to specify a file. Generally, the source file (or dependent file), Make will run according to the rule, in general, in general, can be used with the "-n" parameter to view the rule command that occurred in this dependency file.
Another interesting usage is to combine "-P" and "-v" to output the information when Makefile is executed (this will be described later). V. Make's parameters list all the parameters definitions of all GNU Make 3.80. Other versions of the MAKE of the manufacturer are similar, but the specific parameters of other manufacturers make specific parameters, please refer to the respective product documents. The role of "-b" "- m" these two parameters is to ignore compatibility with other version of Make. "-B" "- always-make" thinks that all goals need to be updated (recompile). "-C
"--Directory =
"Specify a directory to read the Makefile. If there are multiple" -c "parameters, the Make's interpretation is the back path as the relative path as the previous directory as the specified directory. Such as:" Make -C ~ hchen / Test -c PROG "equivalent to" make -c ~ hchen / test / prog ".
"-Debug [=
]
Output MAKE debugging information. It has several different levels to choose from, if there is no parameters, that is, the simplest debugging information is output. Below is
Take the value:
A - is AlL, output all debugging information. (Will be very much)
B - is BASIC, only the simple debugging information is output. That is, the output does not require recompile.
v - is also verbose, above the level of B option. The output information includes which makefile is parsed, does not need to be recompiled dependent file (or dependent target), and the like.
i - that is, Implicit, the implicit rule is output.
J - is also the JOBS, the output execution rules, such as the PID, return code, etc. of the command.
m - is Makefile, output Make Read Makefile, update makefile, and executes Makefile information.
"-D" is equivalent to "--debug = a".
"-E" "- Environment-overrides" indicates the value of the value of the environment variable overrides the variable defined in the Makefile.
"-F =
"
"--File =
"
"--Makefile =
"
Specifies the Makefile that needs to be executed.
"-H" "- help" displays help information.
"-I" "- ignore-errors" ignores all errors during execution.
"-I
"" --NClude-dir =
"Specify a search target that is included. You can use multiple" -i "parameters to specify multiple directories.
"-J [
]
"--Jobs [=
]
Refers to the number of running commands at the same time. If there is no this parameter, how much can be run when Make runs the command. If there is more than one "-j" parameter, then only the last "-j" is valid. (Note this parameter is useless in MS-DOS)
"-K" "- keep-going" error does not stop running. If generated a target fail, it will not be executed if the goal is dependent on it.
"-L
"
"--Load-average [=" - max-loading [=
]
Specifies the load of the Make run command.
"-N" "- Just-print" "- DRY-RUN" "- Recon" only outputs the command sequence during execution, but does not execute.
"-O
"
"--OLD-FILE =
"
"--Ssume-il =
"
Not regenerated specified
Even if the dependency file of this goal is new in it.
"-P" "- print-data-based" outputs all data in Makefile, including all rules and variables. This parameter will make a simple makefile output a bunch of information. If you just want to output information, you can use the "Make -QP" command without performing Makefile. If you want to see the preset variables and rules before performing makefile, you can use "make -f / dev / null". The information of this parameter output will contain the file name and line number of your makefile file, so use this parameter to debug your makefile will be very useful, especially when your environment variable is very complicated.
"-Q" "- question" does not run the command, nor does it output. Just check if the specified target needs to be updated. If it is 0, it means to update, if it is 2, an error occurs.
"-R" "- no-builtin-rules" is forbidden to use Make to use any implicit rules.
"-R" "- no-builtin-variabes" prohibits make from using any implicit rules that do on variables.
"-S" "- Silent" - Quiet "does not output the output of the command at the command.
"-S" "- no-keyp-going" "- STOP" cancels the "-k" option. Because some, make inherited from the environment variable "makeflags". So you can use this parameter in the command line to make the "-k" option in the environment variables failed.
"-T" "- touch" is equivalent to Unix's touch command, just turning the dates of the target into the latest, that is, blocking the command to generate the target from running.
"-V" "- version" outputs the version of the Make program, copyright, etc. About Make.
"-W" "- print-directory" outputs information before and after running Makefile. This parameter is useful for tracking nested calls Make.
"--NO-print-Directory" prohibits "-w" option.
"-W
"
"--What-if =
"
"--New-file =
"
"--Ssume-file =
"
Assumption
You need to update, if you use the "-n" option, then this parameter outputs the running action when the target update is output. If there is no "-n", just like the "touch" command running UNIX, make
The modification time is the current time.
"--Warn-undefined-variables" As long as Make finds an undefined variable, then the warning message is output.
Implied rules ----
When we use makefile, there are some frequent uses, and use frequent frequencies. For example, we compile the C / C source program as an intermediate target file (UNIX is [.o] file, Windows is [. OBJ] file). This chapter tells some "implied" in makefile, earlier, no need to write the rules.
"Implied rules" is also a practice. Make will run according to this "convention" heart, even if there is no writing rules in our makefile. For example, compiling the [.c] file into the rule of [.o] file, you don't have to write it all, make it automatically derived this rule and generates the [.o] file we need.
The "Implied Rule" will use some of our system variables, we can change the value of these system variables to customize the parameters of the rules of the rules. If the system variable "cflags" can control compiler parameters when compiling. We can also write down your implicit rules through the Mode Rules. There will be many restrictions with "Suffix Rules" to define implicit rules. Using Mode Rules will be more intelligent and clear, but the Suffix Rules can be used to ensure our makefile compatibility. We understand the "implicit rules", allowing us to better serve us, will let us know something "convention and customary", and not so that we feel inexplicable when we are running Makefile. Of course, anything is contradictory, water can be boat, can also come to the boat, so sometimes the "implied rules" will also cause non-small troubles. Only by knowing it, we can use it better.
First, use implied rules If you want to use an implicit rule to generate the goals you need, you need to do this is not to write the rules of this goal. So, make attempts to automatically derive the rules and commands that generate this goal. If Make can automatically derive the rules and commands of this goal, then this behavior is the automatic derivation of implicit rules. Of course, the implicit rules are some things that make prior approximately. For example, we have a Makefile below:
Foo: foo.o bar.o cc -o foo foo.o bar.o $ (cflags) $ (ldflags)
We can notice that this makefile has not written on how to generate rules and commands for both objects of foo.o and bar.o. Because Make's "Implied Rule" feature automatically automatically derives the dependence targets and generation commands of these two goals.
Make will find the rules that can be used in your own Implicit Rules library. If you find it, you will use it. If you can't find it, you will report it wrong. In the example above, the implied rule called for the Make call is to set the dependency file of [.o] to [.c], and use C Compile command "CC -C $ (cflags) [.c] "To generate the goal of [.o]. In other words, we don't have to write down the following two rules:
FOO.O: FOO.C CC -C foo.c $ (cflags) bar.o: bar.c cc -c bar.c $ (cflags)
Because this is already a "agreement", make and us set up the rules of the "CC" to generate the [.o] file with the CC ", which is implicit rules.
Of course, if we write your own rules for the [.o] file, Make will not automatically derive and call the implicit rules, which will be faithfully executed in accordance with our write.
Also, in the "implied rules library" of Make, each implied rule has its order in the library, the more often used, so this will cause us to show us even if we show The target dependence is specified, and MAKE will not be tubed. Such a rule (no command):
FOO.O: foo.p
Relying on the file "foo.p" (source file of the Pascal program) may become meaningless. If there is a "foo.c" file in the directory, then our implicit rules will take effect, and will generate a foo.o file through the compiler of C. Because, in the implicit rule, the rule of PASCAL appears after the rule of C, so Make finds the rules that can generate foo.o will no longer look for the next rule. If you really don't want any implicit rules to derive, then you don't just write the "dependency rules" without writing the command.
Second, the implicit rule list here We will tell all the implicit rules of all pre-set (which is Make built). If we don't know the rules, Make will find the required rules and commands in these rules. Of course, we can also use Make's parameters "-r" or "--no-builtin-rules" option to cancel all pre-set implicit rules. Of course, even if we specify the "-r" parameter, some implicit rules will take effect, because there are many implicit rules that use the Suix Rules to define, so as long as there is implicit rules Suffix List (also defined in the target .Suffixes dependent target), the implicit rules will take effect. The default suffix list is: .out, .a, .ln, .o, .c, .cc, .c, .p, .f, .f, .r, .y, .l, .s, .s , .mod, .ssym, .def, .h, .info, .dvi, .tex, .texinfo, .Texi, .txinfo, .w, .ch .web, .sh, .elc, .l. For details, we will talk later.
Still let's take a look at the common implicit rules.
1. Compile the implied rules of the C program. "
The dependent target of .o "is automatically derived"
.c ", and its generation command is" $ (cc) -c $ (cppflags) $ (cflags) "
2, compile the implicit rules for C programs. "
The dependent target of .o "is automatically derived"
.cc "or"
.C ", and its generation command is" $ (cxx) -c $ (cppflags) $ (cflags) "." It is recommended to use the suffix of C source files, not ".c")
3, compile the implicit rules for the PASCAL program. "
The dependent target of .o "is automatically derived"
.p ", and its generation command is" $ (pc) -c $ (pflags) ".
4, compile the implicit rules for the Fortran / RatFor program. "
The dependent target of .o "is automatically derived"
"or"
"Or"
.f ", and its generation command is:
".F" "$ (fc) -c $ (fflags)"
".F" "$ (fc) -c $ (fflags) $ (cppflags)"
".F" "$ (fc) -c $ (fflags) $ (rflags)"
5, preprocess the implicit rules for the Fortran / RatFor program. "
The dependent target of .F "is automatically derived"
"or"
.F "This rule is just converting the Ratfor or a pre-processed Fortran program to a standard Fortran program. The command used is:
".F" $ (fc) -f $ (cppflags) $ (fflags)
".R" "$ (fc) -f $ (fflags) $ (rflags)"
6. Compile the implicit rules for the MODULA-2 program. "
The dependent target of the target of .sym will be automatically derived as "
.def, and its generation command is: "$ (M2C) $ (m2flags) $ (deffflags)". "
"The dependent target of the goal will be automatically derived"
.MOD ", and its generation command is:" $ (M2C) $ (M2FLAGS) $ (Modflags).
7, assembly and assembly pre-processing implicit rules. "
The dependent target of .o "is automatically derived"
.s ", the default use of the compilation" AS ", and its generation command is:" $ (as) $ (asflags) "."
The dependence of the target of .s "is automatically derived"
.S ", default use C pre-encoder" CPP ", and its generation command is:" $ (as) $ (asflags) ".
8, link the implicit rules for the Object file. "
"Goal depends on"
.o, running the linker generation by running C's compiler (generally "LD"), which generates commands: "$ (CC) $ (LDFLAGS) .o $ (LDLIBS)". this The rules are valid for only one source file, and it is also valid for multiple Object files (generated by different source files). For example, the following rules:
x: y.o z.o
And "x.c", "y.c" and "z.c" exist, the implicit rule will execute the following command:
Cc -c x.c -o x.o cc -c y.c -o y.O cc -c z.c -o z.O CC x.o y.O z.O -O X RM-F x.o rm -f y.O rm -f z.o
If there is no source file (such as X.c in the above example) and your target name (as X) in the above example, you'd better write your own generation rules, otherwise, implicit rules will report an error.
9. Implicit rules when YACC C procedures. "
The dependent file of .c "is automatically derived as" NY "(YACC generated file), and its generation command is:" $ (YACC) $ (YFALGS) ". (" YACC "is a syntax analyzer, please ask for details View related information)
10. Implicit rules when Lex C procedures. "
.c "dependent files are automatically derived as" N.L "(LEX generated files), and its generation command is:" $ (lex) $ (lfalgs) ". (About" lex "details See the relevant information)
11. Implicit rules when Lex RatFor programs. "
The dependent file is automatically derived as "N.L" (LEX generated file), and its generation command is: "$ (lex) $ (lfalgs)".
12. Create an implicit rules for the LINT library from the C program, YACC file or LEX file.
"
.ln "(LINT generated file) The dependencies are automatically derived to" N.c ", which generates commands:" $ (lint) $ (lintfalgs) $ (cppflags) -i ". For"
Y "and"
.l "is also the same rule.
Third, the variables used by the implicit rules are basically used in the commands in the implicit rules, basically use some pre-set variables. You can change these variables in your makefile, or incorporate these values in the command line of make, or set these values in your environment variable, no matter how, just set these specific variables, Then it will work for implicit rules. Of course, you can also use Make's "-r" or "--no-builtin-variables" parameter to cancel the role of the variable you defined on the implicit rule.
For example, the first implicit rule-compiling the implied rule of the C program is "$ (cc) -c $ (cflags) $ (cppflags). Make default compile command is "CC", if you redefine the variable "$ (cc)" to "GCC", turn the variable "$ (cflags)" to "-g", then implicit rules The command will be executed in "GCC -C -G $ (cppflags).
We can divide the variables used in the implicit rules into two: one is a command, such as "CC"; one is the parameter phase, such as "cflags". Below is the variables used in all implicit rules:
1. The variables of the command.
AR function library package program. The default command is "ar". AS assembly language compiler. The default command is "AS". CC C language compiler. The default command is "CC". CXX C language compiler. The default command is "G ". CO expands the file program from the RCS file. The default command is "CO". The preprocessor of the CPP C program (output is a standard output device). The default command is "$ (cc) -e". FC FORTRAN and RATFOR compiler and pre-processes. The default command is "F77". GET extension files from the SCCS file. The default command is "get". Lex Lex method analyzer program (for C or Ratfor). The default command is "lex". PC Pascal language compiler. The default command is "PC". YACC YACC Grammar Analyzer (for C procedures). The default command is "YACC". Yaccr Yacc Grammar Analyzer (for the Ratfor program). The default command is "Yacc -R". MakeInfo converts the TexInfo source file (.TEXI) to the INFO file program. The default command is "makeinfo". Tex creates a program from the Tex DVI file from the TEX source file. The default command is "tex". Texi2DVI creates a program from the TexInfo source file to create an army TEX DVI file. The default command is "texi2dvi". Weave converts web to tex program. The default command is "weave". CWEAVE converts C Web to TEX program. The default command is "CWEAVE". Tangle converts the web to the Pascal language program. The default command is "tangle". Ctangle converts C Web to C. The default command is "ctangle". RM deletes the file command. The default command is "RM -F". 2. These variables below the command parameters are the parameters of the relevant order. If there is no default value, its default value is empty. Arflags Function Library Package Ar Command Parameters. The default is "RV". Asflags assembly language compiler parameters. (When ".s" or ".s" file is displayed clearly). CFLAGS C language compiler parameters. CXXFLAGS C language compiler parameters. COFLAGS RCS command parameters. CPPFLAGS C Preprocessor parameters. (C and Fortran compilers are also used). FFlags Fortran language compiler parameters. GFLAGS SCCS "Get" program parameters. LDFLAGS linker parameters. (Such as "LD") LFLAGS LEX Grammar Analyzer Parameters. Pflags Pascal language compiler parameters. The Fortran compiler parameter of the RFLAGS Ratfor program. YFLAGS YACC Grammar Analyzer Parameters.
Fourth, the implicit rules chain sometimes, one goal may be rooted by a series of implicit rules. For example, an [.o] file generation may be first included with the [.y] file of YACC first [.c], then generate it again by the compiler of C. We call this series of implicit rules "implicit rules chain".
In the above example, if the file [.c] exists, then directly call the implied rules of the compiler, if there is no [.c] file, but there is a [.y] file, then YACC implicit rules Will be called, generate the [.c] file, then call the impact rules for C-compilation ultimately by [.c] to generate the [.o] file to achieve the goal.
We call this [.c] file (or target) called an intermediate goal. Anyway, Make will work hard to automatically derive all methods of generating the goals, regardless of the intermediate targets, they will take all implicit rules and the rules you write, and try to achieve goals, so sometimes May make you feel strange, how do my goal be generated? How is my makefile be crazy? By default, there are two places in the intermediate target, it is different from the general goals: the first difference is that the intermediate rule is triggered unless the intermediate target does not exist. The second difference is that as long as the target is successful, then the resulting intermediate target file will be deleted in "RM -F" during the final goal.
Typically, a file that is specified by Makefile to target or dependent the target cannot be treated as an intermediary. However, you can clearly illustrate a file or a target is an intermediary target, you can use pseudo-target ". InterMediate" to force the declaration. (Such as: .intermediate: MID)
You can also prevent Make from automatically deleting intermediate targets. To do this, you can use pseudo-target ". Secondary" to force statements (such as: .secondary: sec). You can also specify your goals to specify (eg:%. O) into the target ".precious" dependent object to save the intermediate file generated by the implicit rule.
In the "Implied Rules Chain", it is forbidden to appear twice or more, so that in order to prevent unlimited recursive conditions when Make is automatically derived.
Make will optimize some special implicit rules without generating an intermediate file. For example, from the file "foo.c" to generate the target program "foo", according to the truth, make it compiles the generation of the intermediate file "foo.o", then links into "foo", but in actual conditions, this action can be by one The "cc" command is completed (cc -o foo foo.c), so optimized rules will not generate an intermediate file.
V. Define mode rules
You can use the pattern rules to define an implicit rule. A mode rule seems to have a general rule, just in rules, the definition of the target needs to have a "%" character. "%" Means that one or more arbitrary characters. In the dependent target, "%" can also be used, but only the value of "%" in the target is dependent on its objectives. One thing to note is that the "%" deployment occurs after the expansion of variables and functions, the expansion of variables and functions occurs when Make loads Makefile, while "%" in the mode rule occurs at runtime. 1. Mode rule introduction mode rules, at least in the target definition of the rule, "%", otherwise, it is a general rule. The "%" definition in the target represents the matching of the file name, "%" represents any non-empty string of length. For example: "%. C" indicates the file name ending with ".c" (the file name is at least 3), and "s.%. C" is indicated by "s." Start, ". C" ending The file name (the file name is at least 5). If "%" is defined in the target, then "%" value in the target determines the value of "%" in the target, that is, the "%" "%" in the target determines the dependency target "%" " For example, there is a pattern rule as follows:% .O:% .c; its meaning is, pointing out how to generate the corresponding [.o] file from all [.o] files. If the goal to be generated is "a.o B.O", "% C" is "a.c B.c". Once the "%" mode in the target is determined, the make will be asked to match all the file names in the current directory. Once the Make is found, the Make will rule, so in the mode rules, the target may be Multiple, if there is a mode matching multiple targets, Make will generate all mode destination. At this time, make cares about the dependencies of the dependent file name and the generation of the target. 2, the mode rule example below, the following example is expressed, compiling all [.c] files into [.o] files.% .O:% .C $ (cc) -c $ (cflags) $ (cppflags) $ <-o $ @, "$ @" indicates all the targets of all targets, "$ <" indicates all the values that depend on the target. These strange variables are called "automated variables" and will be detailed later. There are two objectives in this example below to pattern:% .TAB.C% .Tab.h:% .y bison -d $ .tab.c "and" .tab.h "file. (where," "Represents an arbitrary string). If our executive" foo "depends on the file" parse.tab.o "and" scan.o ", and the file" scan.o "depends on the file" parse.tab.h " If the "parse.y" file is updated, "Bison -D Parse.y" will be executed once, so "Parse.tab.o" and "scan.o" dependency files It is aligned. (Suppose, "parse.tab.o" is generated by "parse.tab.c", and "scan.o" is generated by "scan.c", and "foo" is "Parse.tab.o" And "scan.o" link is generated, and the dependence on the foo and its [.o] file is also written, then all the goals will be met) 3. Automated variables in the above mode rules, target and dependent files are files, then how do we write a command to complete the corresponding goal from different dependency files? Because every time the pattern rule is parsed, it will be different targets and dependencies. Automated variables are completed. In front, we have already proposed by the automated variables, I believe that you have seen it here has a sense of sensibility. The so-called automated variable is that this variable will automatically remove a series of files defined in the mode until all the modes of matching are finished. This automation variable should only appear in the rule command. Below is all automation variables and their description: $ @ represents the target file set in the rule. In the mode rule, if there are multiple targets, "$ @" is a collection of mode definitions that matches the target. $% Is only when the goal is in a library file, indicating the target member name in the rule. For example, if a goal is "foo.a (bar.o)", then "$%" is "bar.o", "$ @" is "foo.a". If the target is not a library file (UNIX is [.a], Windows is [.lib] under [.lib]), then its value is empty. $ Four variables ($ @, $ <, $%, $ *) will only have a file when extension, and the other three values are a list of files. These seven automation variables can also obtain the directory name of the file or the file name in the current directory, just match "D" or "F". This is the characteristics of the old version of GNU Make. In the new version, we can use the function "DIR" or "notdir". The meaning of "D" is Directory, which is the directory, "f" meaning is File, that is, the file. Here is the meaning of "D" or "f", respectively, with "D" or "f", indicating the "$ @" directory section (not the end of the slash), if "$ @" value "Dir / foo.o", "$ (@d) is" DIR ", and if there is no slash in" $ @ ", its value is". "(Current directory). $ (@ F) means "$ @" file part, if the "$ @" value is "dir / foo.o", then "$ (@ f)" is "foo.o", "$ (@f) "It is equivalent to function" $ (notdir $ @). "$ (* D)" "$ (* f)" and the same as described above, is also the directory section and file part of the file. For the above example, "$ (* d)" returns "DIR", and "$ (* f)" returns "foo" "$ (% d)" "$ (% f)" indicating a function package file, respectively. Members' directory section and file part. This contains different directories in "Member" in the form of "Archive" forms, "MEMBER". "$ (" $
The directory part and file part of the dependency file are respectively respectively, respectively. "$ (^ D)" "$ (^ f)" represents all directory sections and file parts of the dependencies. (None of the same) "$ ( D)" "$ ( f)" represents all directory sections and file parts of all dependencies. (Can have the same) "$ (? D)" "$ (? F)" indicates the directory section and the file section of the updated dependencies. Finally, I want to remind it that for "$ <", in order to avoid unnecessary trouble, we will add parentheses to the specific characters behind $, for example, "$ (<)" is more than "$ <"It is better. It is important to note that these variables are only used in rules, and they are generally "Explicit Rules" and "Static Mode Rules" (see chapters of the "Writing Rules"). It doesn't make sense in implicit rules. 4. Matching Matches Generally, a target mode has a prefix or a suffix "%", or there is no prefix, which is directly a "%". Because "%" represents one or more characters, in the defined mode, we call the contents of "%" match "stem", such as "% .c", "Test.c" "Test" is "stem". Because when there is "%" in the target and dependent target, "stem" depends on the target will pass to the target, and "stem" in the target. When a mode match contains a file with a slash (actually not often included), then the directory portion will be first removed, then matched, then add the directory back. When the transmission of "stem", we need to know this step. For example, there is a mode "E% T", the file "src / EAT" matches this mode, so "SRC / A" is its "stem", if this mode is defined in the dependent target, and is dependent on this mode There is also a mode "C% R", then the target is "src / car". ("Stem" is transmitted) 5. Heavy duty built-in implicit rules You can overload built-in implicit rules (or define a brand new), for example, you can re-construct and build a different command, Such as:% .O:% .C $ (cc) -c $ (cppflags) $ (cflags) -d $ (date) You can cancel the built-in implicit rules, as long as you don't write the command later. Such as:% .O:% .s, you can also redefine a new implicit rule, which in the hidden rules depends on where you write this rule. The front position is before. 6. The "suffix rule" suffix rule is a comparison method for a comparison of old-fashioned definition rules. Suffix rules will be gradually replaced by mode rules. Because pattern rules are stronger clearer. GNU Make is equally compatible with the old version of Makefile. There are two ways to suffix rules: "Double Suffix" and "Single Human Supper". Double complications define a pair of suffixes: the suffix of the target file and the suffix on the destination (source file). Such as ".c.o" is equivalent to "% o:% C". Single suffix rules only define a suffix, that is, the suffix of the source file. Such as ".c" is equivalent to "%:% .c". The suffix defined in the suffix rule should be made by Make. If a suffix is made by Make, then this rule is a single binding rule, and if the two consecutive suffixes are recognized by Make, it is a double suffix rule. For example: ". C" and ".o" are made by Make. Thus, if you define a rule is ".c.o" then it is the two suffix rules, meaning ".c" is the suffix of the source file, ". O" is the suffix of the target file. As shown in the following example: .co: $ (cc) -c $ (cflags) $ (cppflags) -o $ @ $ 5. For the first mode rule in the list: 1) derive its "stem" S, S should be t or n matched in "%" non-empty portions in the mode. 2) Calculate dependencies. Replace "%" in the dependency file into "stem" S. If there is no flap character in the target mode, the D is added to the beginning of the first dependency file. 3) Test if all dependencies are exist or are existed. (If there is a file being defined as a target file for another rule, or an explicit rule dependent file, then this file is called "reasonable") 4) If all dependencies exists or correct, or There is no dependency file. Then this rule will be adopted and exit the algorithm. 6. If you have passed through step 5, there is no mode rule to be found, then you will do something a further search. For the first mode rule existing in the list: 1) If the rule is termination rule, then ignore it, continue the next mode rule. 2) Calculate dependencies. (Step 5) 3) Test if all dependencies exist or correct. 4) For non-existent dependent files, recursive calls this algorithm lookup that he can be found by implicit rules. 5) If all dependencies exists or properly, or there is no dependency file. Then this rule is used to exit the algorithm. 7. If there is no implicit rule, you can use, view ".default" rules, if there is, use, use the ".default" command to T. Once the rules are found, they will execute their quite commands, while this time, our automation variables will be generated. Update the library file with the make ----------- The library file is the package file for the Object file (intermediate file compiled). Under UNIX, it is generally made by the command "AR" to complete the package. First, a function library file for the function library file consists of multiple files. You can specify a library file and its composition in the following format: Archive (Member) This is not a command, and a target and dependence definition. In general, this usage is basically to serve "AR" commands. Such as: fooLib (Hack.o): Hack.o Ar Cr Foolib Hack.o If you want to specify multiple Member, you are separated by space, such as Foolib (Hack.o Kludge.O) equivalent: FOOLIB (HACK .o) FOOLIB (Kludge.O) You can also use the shell's file wildcard to define, such as foolib (*. o) Second, the implicit rule of the function library member When you search for an implicit rule of a goal, a special The characteristic is that if this goal is "A (m)" form, it will turn the target "(m)". So, if our member is "% .o" mode definition, and if we use "make foo.a" to call Makefile form, the implicit rule will go to "bar.o" rules. If there is no rule of bar.o, then the internal implicit rules take effect. Make will go to Bar.c file to generate bar.o. If you find it, the command executed by the make is as follows: cc -c bar.c -o bar.o ar r foo.a bar.o rm -f bar.o has a variable to pay attention to "$%", this is an automated variable for exclusive library files, and see "Automated variables" "one period. Third, the suffix rule of the library file You can use the Suffix Rules and "Include Rules" to generate a function library package file, such as: .ca: $ (cc) $ (cflags) $ (cppflags) -c $ O $ *. O $ (ar) R $ @ $ *. o $ (rm) $ *. o It is equivalent to: (% .o):% .C $ (cc) $ (cflags) $ (cppflags) -C $ <-O $ *. O $ (ar) R $ @ $ *. o $ () $ *. O III. Precautions When the library package file is generated, be careful to use the Make's parallel mechanism ( "-j" parameter). If multiple ar commands run on the same function library package at the same time, you can damage this library file. Therefore, in the future version of the Make, a mechanism should be provided to avoid parallel operations to occur on a function package file. But as far, you should not try not to use the "-j" parameter as much as possible. Subsequential - finally went to the end of the language, the above basically is all the details of the GNU Make's makefile. The Make's Make is basically like this, no matter what kind of make, it is based on the dependence of documents. It is basically following a standard. 80% of the technical details in this document apply to any make, I guess the content of the "function" may not be supported by other make, and I think different makers will have different implementations. I have no energy to view the GNU's make and VC's nmake, BCB Make, or what difference is made under other Unix, one is not enough, the second is because I basically use it under UNIX. Make, previously in Sco Unix and IBM AIX, now in Linux, Solaris, HP-UX, AIX, and Alpha, LINUX and Solaris are more. However, I can be sure that Make under UNIX, whether it is a platform, almost all the Make and CC / GCC compilers developed by Richard Stallman, and basically all GNU Make (all The UNIX machine is installed on the GNU, so there are more programs that use the GNU). The GNU's thing is still very good, especially after use, more and more sense of the power of the GNU software, and more and more feel that GNU is "killed" in the operating system (mainly Unix or even windows). For all the details of all the makers, we can not only use the Make tool to compile our programs, but also use Make to complete other work, because the commands in the rules can be under any shell, so in Unix You don't necessarily just use the compiler of the program language, you can also write other commands in Makefile, such as: Tar, AWK, Mail, Sed, CVS, Compress, LS, RM, YACC, RPM, FTP ..., etc. , Etc., to complete the function, file operation, file management, file operation, file management, file operation, and file management, such as "Program Packaging", "Program Backup", "Production Program Installation Pack", "Submit Code", "User Template", "Merge File", etc. Programming development design, or some other whimsical things. For example, when you write a bank trading process, because the bank's trading procedure is basically the same, you will see some general program templates for some transactions, and write some network communication, database operation, business operation. In one file, in these files, in these files, such as "@@ n, ### n" strange string labeled some locations, then write a transaction, just writing a specific process according to a specific rule, and finally When Make, use awk and sed to replace the "@@ n, ### n" in the template to a specific program, form a C file, and then compile. This action is very similar to the "extended C" language of the database (ie, "Exec SQL" in the C language executes the SQL statement. Before compiling CC / GCC, you need to use "extended C" translation, such as CPRE, It translates into standard C). If you have some more wonderful methods when using Make, please remember to tell me. Looking back, look at the whole document, I don't think I have just started to develop in Unix a few years ago, someone asked if I would not write Makefile, I didn't know what to say. At first, I saw that someone turned "! Make" after writing the program in the VI, I thought it was the function of VI. Later, I learned that there was a makefile in my monster, so I checked it. At that time, I didn't want to read English, I found it. Introducing Makefile if there is no Chinese documentation, I have to see Makefile written by others, I have accumulated a little knowledge, but in many places, I don't know if I don't know. Later, I started working on UNIX product software. I saw a 400-year-old year, nearly 2,000 lines of code, I found that it is necessary to compile such a huge thing. If there is no Makefile, how horror is the same. So I came to my heart, I read a bunch of English documents, I feel that I have mastered it. But it is found that the article is still so pitiful, so I want to write such an article, share it for everyone, I hope to help you. Now I finally finished, I saw the creation time of the document, and this technical document has also been written for more than two months. I found that I know it is a matter, I have to write down, telling others is another thing, and now there is no time to study technology details, so when I write, it is difficult to explain some details. Doing rigorous and refined, and telling what you are telling what you first say, it is still referring to some foreign sites, and the language style of some technical books is completed. The outline of the entire document is written by the Outline of the GNU-based Makefile Technical Manual and combines its own work experience and its own learning. Because there is never written such a long, such a thin document, there will be many places where there is a problem, language ambiguity or error. Because of some, I am in urgent to wait to give me an indication and suggestion, as well as any feedback. Finally, use this in this back, introduce yourself. I have currently engaged in software development under all UNIX platforms, mainly to do distributed computing / grid computing system product software, and I am very interested in the next-generation computer revolution - grid computing, for distributed calculations , P2P, Web Service, J2EE technical direction is also very interesting, and at the same time, for project implementation, team management, project management is also small, I hope to fight the young generation on the "technology and management of" technology and management ", A lot of exchanges with me. My MSN is: haoel@hotmail.com (common), QQ is: 753640 (not common). (Note: Do not give me MSN's mailbox, because Hotmail's spam causes me to refuse this mailbox, I welcome any form of communication, whether discussing technology or management, or other hairdry southern. I don't care about politics and entertainment news, other things I am welcome! In the end, I also want to introduce the design and developer of the Make program. The first rush is: Richard Stallman Open source software leaders and pioneers have never received a day of salary, never used a Windows operating system. For his deeds and his software and his thoughts, I don't have to say too much, I believe that everyone is not strange to this person, this is his home page: http://www.stallman.org/. Only a recent photo is posted here: Computer, music, butterfly is his favorite The second is: Roland McGrath Personal Person: http://www.frob.com/~roland/, below is some of his deeds: 1) Cooperation and maintain GNU Make. 2) Write GNU Hurd with Thomas Bushnell. 3) Write and maintain GNU C Library. 4) Cooperation and maintain part of GNU Emacs. Here, the fighter of the two open source projects is the most authentic tribute. (Full text)