Reprinted on http://blog.9cbs.net/haoel/ Write Makefile Chen Hao with me - 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 program compilation and link ---------- Here, I think more about the specifications and methods of the program compilation. In general, whether C, C , or PAS, first of all to put the source file Compiled into an intermediate code file, it is .Obj file under Windows, UNIX is .o file, ie 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. Hello, the return of the gnu is a lot of content, how to get less, let us start. Makefile Presentation ------- Make Commands When you execute, 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. 1. Makefile's 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 depend on the file in Preequisites, 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 slowly come to you later. The content is more. :) Second, one example is as mentioned earlier, if a project has 3 head files, and 8 C files, in order to complete the three rules mentioned earlier, our makefile should be the following. 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 - Command.c Display.o: display.c defs.h buffer.h cc - Cd 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 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 syntax is: include
Include and
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. Writing rules ---- Rule contains two parts, one is dependency, one is a way to generate the target. In Makefile, the order of the rules is very important, because only one ultimate goal is in Makefile, other goals are coming from this target, so be sure to let Make know what your ultimate goal is. In general, it may be a lot of targets defined in makefile, but the target in the first rule will be established as the final goal. If there are many objectives in the first rule, then the first goal will become the final goal. This goal is made by Make. Ok, let's take a look at how to write rules. First, the rules example foo.O: foo.c defs.h # foo module cc -c -g foo.c See this example, you should not be very strange, and I have said before, foo.o is our goal. , Foo.c and defs.h are the source files dependent on the target, and only one command "cc -c -g foo.c" (starting with the Tab). This rule tells us two things: 1, the dependency of the file, foo.o relies on the file of foo.c and defs.h, if foo.c and defs.h's file date is newer than the foo.o file date Or foo.o does not exist, then dependence occurs. 2. Generate (or update) the foo.o file. That is the CC command, which explains how to generate foo.o file. (Of course, foo.c files) DEFS.H files) Second, the syntax of the rules Targets: prerequisites command ... or this: targets: prerequisites; command command ... targets is a file name, separated by space, you can use wildcard . In general, our goal is basically a file, but it may be multiple files. Command is a command line if it is not with "Target: prerequisites", then, must start with the [Tab key], if Prerequisites are in one line, then the semicolon is separated by sections. (See) prerequisites is the file (or dependent target) that is dependent on the target. If a file is to be new than the target file, then the goal is considered "Out of", it is considered to be reborn. This has been told in front. If the command is too long, you can use a backslash box ('/') as a newline. Make has no restrictions on how many characters on a line. The rule tells make two things, dependencies, and how to become a target file. In general, Make will execute commands with UNIX standard shell, that is, / bin / sh. Third, using wildcards in rules If we want to define a series of similar files, we naturally remember to use wildcards. Make supports three wildcards: "*", "?" and "[...].
This is the same as UNIX's B-shell. Wave number ("~") characters also have a relatively special purpose in the file name. If it is "~ / test", this means the TEST directory under the $ HOME directory of the current user. And "~ hchen / test" represents the Test directory under the host directory of the user's hCHEN. (These are small knowledge under UNIX, Make also supports) and under Windows or MS-DOS, the user does not have a host directory, then the directory referred to by the Wave is determined according to the environment variable "home". Wildcard replaces your series of files, such as "* .c" means that the suffix is C. One requires us to pay attention, if there is a wildcard in our file name, such as "*", you can use the escape character "/", such as "*" to represent the true "*" character, not any length String. Ok, or let's take a few examples: Clean: rm -f * .o, I don't say much, this is the wildcard support supported by the operating system shell. This is a wildcard in the command. Print: * .c lpr -p $? Touch Print The above example illustrates that wildcards can also be in our rules, the target print relies on all [.c] files. Where "$?" Is an automated variable, I will tell you later. Objects = * .o above this example, indicating that the harness can also be used in the variable. Not to say [* .o] will start, no! The value of Objects is "* .o". The variable in makefile is actually a macro in C / C . If you want a wildcard to expand in the variable, that is, the value of Objects is all the collection of file names of [.o], then you can: Objects: = $ (Wildcard * .o) This method of use by keyword "Wildcard" pointed out that we will discuss later about Makefile's keywords. Fourth, the file search is in some major projects, with a large number of source files, our usual practice is to classify this many source files and store them in different directories. So, when Make needs to find the dependencies of the document, you can add a path before the file, but the best way is to tell Make with a path, let Make go automatically. The special variable "vpath" in the makefile file is to complete this feature. If this variable is not specified, Make will only find dependencies and destination files in the current directory. If this variable is defined, Make will find a file in the specified directory when the current directory is not found. VPATH = src: ../ Headers The above definition specifies two directories, "src" and "../headers", make will search in this order. The directory is separated by a "colon". (Of course, the current directory is always the highest priority search) Another way to search the file is the use of the "vPath" keyword (note, it is not a variable, this is a key " Word, this is similar to the VPath variable mentioned above, but it is more flexible. It can specify different files in different search directories. This is a very flexible function. Its usage is three: 1, vpath
2, vPath
One example is that if your makefile needs to generate a number of executable files, you just want to simply knock an opportunity, and all the target files are written in a makefile, then you can use "PseudoT" This feature: All: PROG1 PROG2 PROG3.PHONY: ALL PROG1: PROG1.O Utils.o cc -o prog1 prog1.o utils.o prog2: prog2.o cc -o prog2.o prog3: prog3.o sort.o Utils.o cc -o prog3 prog3.o sort.o utils.o We know that the first goal in makefile will be used as its default target. We declare a "all" pseudo-target that relies on the other three goals. Since the characteristics of the pseudo objective are always being executed, the three goals depending on the dependence are always like "all". Therefore, the rules of the other three goals will always be resolution. Just achieve the goal of us to generate multiple goals. ".Phony: all" declares that "all" is "pseudo-target". Just mention, from the above example we can see that the goal can also be dependent. Therefore, the pseudo target can also be dependent. Look at the following example: .phony: CleanAll Cleanobj CleanObj Cleanall: Cleanobj: rm * .o cleandiff: rm * .diff "make clean" will clear all files to be cleared. "Cleanobj" and "Cleandiff" are a bit like "subroutine". We can enter the "make cleanl" and "make clean cleanobj" and "make cleandiff" commands to achieve the purpose of clearing different kinds of files. 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 syntax:
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
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
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:
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 are:
The first is what we have seen in front of our "IFEQ" IFEQ (
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 call, very like variables, is also identified by "$", its syntax is as follows: $ (
Function: Find words in
Example: Sourcees: = foo.c bar.c Baz.s Ugh.h foo: $ (Sources) CC $ (Filter% .C%. S, $ (Sources)) -O foo $ (file% .c%. S, $ (Sources)) The value returned is "foo.c bar.c baz.s". $ (Filter-Out ) Name: Sort Function - Sort. Function: Sort by words in string
(ascending). Returns: Returns the sorted string. Example: $ (Sort Foo Bar LOSE) Returns "Bar Foo Lose". Note: The Sort function removes the same words in
. $ (Word
, to and to is larger than the number of words in start, to
$ (Firstword
$ (Addsuffix
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 , ,
This function means that the words in the parameter are taken out one by one on the variable specified by the parameter , and then the expression included in
Therefore, is preferably a variable name, can be an expression, and in is usually enumerated in ["words in [TEXT". 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 parameters in Foreach are a temporary local variable. After the foreach function is executed, the variables of parameter 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
The return value of the IF function is if
Therefore, 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 performs this function, the variables in the 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 the order, 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 that "Undefined" If If "Environment" If File If "Command Line" If "OVERRIDE" If Automatic " If 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 Generate a fatal error, 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 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 Implicit rules ---- When we use Makefile, there are some frequent uses, and how often is very high, for example, we compile the C / C source program for intermediate target files (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 the following Makefile: foo: foo.o bar.o cc -o foo foo.o bar.o $ (cflags) $ (ldflags) We can notice that this makefile does not write how to generate foo .o and bar.o Rules and commands of these two goals. 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 the following two rules: foo.o: foo.c cc 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. As such a rule (no command): foo.o: foo.p Dependent file "foo.p" (source file of the Pascal program) is 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 " This rule is just converting the Ratfor or has a pre-processed Fortran program to a standard Fortran program. The commands used are: ".f" "$ (fc) -f $ (cppflags) $ (fflags)" ".r" "$ (fc) -f $ (fflags) $ (rflags)" 6, compile MODULA The implicit rules of the program. The dependent target of " The same rule is also the same for " 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. You can also prevent Make automatically delete the intermediate target. To do this, you can use the pseudo-target ". Secondary" to force the declaration (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. Implicit rules ---- When we use Makefile, there are some frequent uses, and how often is very high, for example, we compile the C / C source program for intermediate target files (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 the following Makefile: foo: foo.o bar.o cc -o foo foo.o bar.o $ (cflags) $ (ldflags) We can notice that this makefile does not write how to generate foo .o and bar.o Rules and commands of these two goals. 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 the following two rules: foo.o: foo.c cc 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. As such a rule (no command): foo.o: foo.p Dependent file "foo.p" (source file of the Pascal program) is 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 " This rule is just converting the Ratfor or has a pre-processed Fortran program to a standard Fortran program. The commands used are: ".f" "$ (fc) -f $ (cppflags) $ (fflags)" ".r" "$ (fc) -f $ (fflags) $ (rflags)" 6, compile MODULA The implicit rules of the program. The dependent target of " The same rule is also the same for " 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. You can also prevent Make automatically delete the intermediate target. To do this, you can use the pseudo-target ". Secondary" to force the declaration (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. 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 Homepage is: 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)