What is makefile? What is makefile? Maybe many winodws programmers do not know this, because the windows ide has done this job for you, But I think makefile should be understood as a good and professional programmer. It seems that there are so many HTML editors, but if you want to be a professional, you still need to understand the meaning of HTML tags. Especially for software compilation in UNIX, you can't help writing makefile by yourself. If you want to write makefile, it shows whether a person can complete large-scale engineering. Because makefile is related to the compilation rules of the entire project. The source files in a project are not counted. They are stored in several directories by type, function, and module. makefile defines a series of rules to specify which files need to be compiled first, which files need post-compilation, which need to be re-compiled, or even perform more complex functional operations, because makefile is like a shell script and can also execute operating system commands. The benefit of makefile is "automatic compilation". Once written, only one make command is required, and the entire project is fully automatically compiled, which greatly improves the efficiency of software development. Make is a command tool that explains commands in makefile. Generally, most ides use this command, such as make in Delphi and nmake in Visual C ++, GNU make in Linux. It can be seen that makefile is a compilation method in Engineering. There are few articles about How to Write makefile. This is why I want to write this article. Of course, the make statements of different manufacturers are different and have different syntaxes, but they are all written in "file dependency". Here, I only talk about GNU make, my environment is RedHat Linux 8.0, and the make version is 3.80. This make is the most widely used and used. It also complies with the IEEE 1003.2-1992 standard (posix.2 ). In this document, we will use the C/C ++ source code as our basis, so it will inevitably involve some knowledge about C/C ++ compilation and relevant content, you can also view the relevant compiler documentation. The default compiler here is GCC and CC in UNIX. Compilation and link of Programs ---------- Here, I would like to talk about some of the program compilation Specifications and methods. Generally, whether it is C, C ++, or pas, you must first compile the source file into an intermediate code file, in Windows, that is. OBJ file, which is in UNIX format. o file, that is, object file. This action is called compile ). Then merge a large number of object files into the execution file. This action is called Link ). During compilation, the compiler requires correct syntax and correct declaration of functions and variables. For the latter, you usually need to tell the compiler where the header file is located (the header file should only be declared, 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 ). The links are mainly linked functions and global variables. Therefore, we can use these intermediate target files (O files or OBJ files) to link our applications. The linker does not care about the source file where the function is located, but only about the intermediate target file of the function. In most cases, due to too many source files, too many intermediate target files are generated during compilation, during the link, you need to clearly specify the intermediate target file name, which is inconvenient for compilation. Therefore, we need to pack the intermediate target file, in Windows, this package is called "library file", that is. lib file. In UNIX, it is an archive file, that is. file. To sum up, the source file will first generate the intermediate target file, and then the intermediate target file will generate the execution file. During compilation, the compiler only checks program syntax, and whether functions and variables are declared. If the function is not declared, the compiler will give a warning, but the object file can be generated. When linking a program, the linker will find the function implementation in all object files. If it cannot be found, it will report the Link error code (linker error). In VC, this error is generally caused by a link 2001 error, which means that the linker cannot find the function implementation. You need to specify the object file of the function. Well, let's get down to the truth. GNU make has a lot of content, so we can start with it. Makefile Introduction ------- When executing the make command, you need a MAKEFILE file to tell the make command how to compile and link the program. First, we use an example to describe the writing rules of makefile. In order to give everyone a sense. This example is from the GNU make user manual. In this example, our project contains 8 C files and 3 header files, we need to write a makefile to tell the make command how to compile and link these files. Our rules are: 1) if this project has not been compiled, all our c files must be compiled and linked. 2) if several C files of this project are modified, We will compile only the modified C files and link them to the target program. 3) if the header file of this project has been changed, we need to compile the C files that reference these header files and link them to the target program. As long as our makefile is well written, we can use only one make command to complete all this, the make command automatically and intelligently determines which files need to be re-compiled based on the current file modification, so as to compile the required files and link the target program. I. makefile rules Before talking about this makefile, let's take a rough look at the makefile rules. Target...: prerequisites... Command ... ... Target is a target file, which can be an object file or an execution file. It can also be a label. For the label feature, it will be described in the subsequent "pseudo-target" chapter. Prerequisites is the file or target required to generate the target. Command is the command to be executed by make. (Any shell command) This is the dependency of a file. That is to say, one or more target files depend on the files in prerequisites, and their generation rules are defined in command. To put it bluntly, if more than one prerequisites file is newer than the target file, the command defined by command will be executed. This is the makefile rule. That is, the core content in makefile. In the end, makefile is like this, as if my document should be over. Haha. This is the main line and core of makefile, but it is not enough to write a makefile. I will give you some experience in the future. There are plenty of contents. :) Ii. Example As mentioned above, if a project has three header files and eight C files, we want to complete the three rules described above, our makefile should look like 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-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 A backslash (/) indicates a line break. This makes it easier to read makefile. We can save this content in a file named "makefile" or "makefile", and then directly enter the command "make" in this directory to generate the execution file edit. If you want to delete the execution file and all the intermediate target files, simply execute "make clean. In this makefile, the target file contains the execution file edit and intermediate target file (*. o), the dependent files (Prerequisites) are the ones after the colon. c file and. h file. Each. o file has a set of dependent files, and these. O files are dependent files of the execution file edit. The dependency essentially describes the files generated by the target file, in other words, the files updated by the target file. After the dependency is defined, the subsequent line defines how to generate the operating system commands for the target file, which must start with a tab key. Remember, make does not care about how the command works. It only executes the defined command. Make will compare the modification date of the targets file and the prerequisites file. If the date of the prerequisites file is newer than the date of the targets file, or the target does not exist, then, make will execute subsequent defined commands. It should be noted that clean is not a file, it is just an action name, a bit like lable in C language, and there is nothing after the colon, so, make will not automatically find the dependency of the file, and will not automatically execute the subsequent commands. To execute the subsequent command, you must clearly name the lable after the make command. This method is very useful. We can define unnecessary compilation or compilation-independent commands in a makefile, such as program packaging, program backup, and so on. 3. How does make work? By default, we only enter the make command. So, 1. Make will find the file named "makefile" or "makefile" in the current directory. 2. If it is found, it will find the first target file (target) in the file. In the above example, it will find the file "edit, and use this file as the final target file. 3. If the edit file does not exist or is later than the edit file. O if the file modification time of the file is newer than that of the edit file, the file will be generated by executing the command defined later. 4. If. o file also exists, so make will find the target in the current file. o file dependency. If found, it will be generated based on that rule. o file. (This is a bit like a stack process) 5. Of course, your c files and H files exist, so make will generate. o file, and then use. o The ultimate task of file life make, that is, execution file edit. This is the dependency of the entire make. Make will find the dependency of the file layer after layer until the first target file is finally compiled. In the process of searching, if an error occurs, for example, if the dependent file cannot be found, make will exit directly and report an error. For the defined command error, or the compilation fails. Make does not care. Make only depends on the file dependency, that is, if the file after the colon is still not found after I find the dependency, I am sorry, I will not work. Through the above analysis, we know that such commands as clean are not directly or indirectly associated with the first target file, and the commands defined after it will not be automatically executed. However, we can show that you want to execute make. That is, the command -- "make clean" to clear all target files for re-compilation. So in our programming, if this project has been compiled, when we modify one of the source files, such as file. c. Then, based on our dependencies, our target file. O will be re-compiled (that is, the command defined after this dependency), so file. O files are also up-to-date, so file. the file modification time of O is newer than that of edit, so edit will be relinked (For details, refer to the Command defined after the target file of Edit ). If we change "command. H", KDB. O, command. O, and files. O will be recompiled, and edit will be relinked. 4. Use variables in makefile In the above example, let's take a look at the edit rules: 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 [. o] the file string is repeated twice. If our project needs to add a new [. o] file, so we need to add it in two places (three places, and one place in clean ). Of course, our makefile is not complex, so we are not tired of adding it in two places. However, if makefile becomes complex, we may forget a place to be added, leading to compilation failure. Therefore, variables can be used in makefile to facilitate maintenance of makefile. The makefile variable is a string, which may be better understood as a macro in C language. For example, we declare a variable named objects, objects, objs, objs, OBJ, or obj. Whatever it is, you just need to be able to represent the OBJ file. We defined this at the beginning of makefile: Objects = Main. o kbd. O command. O display. O/ Insert. O search. O files. O utils. o Therefore, we can easily use this variable in the "$ (objects)" method in our makefile, so our improved makefile will look like 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-C command. c Display. O: Display. c defs. h buffer. h CC-C display. c Insert. O: insert. c defs. h buffer. h CC-C insert. c Search. O: search. c defs. h buffer. h CC-C search. c Files. O: files. c defs. h buffer. H command. h CC-C files. c Utils. O: utils. c defs. h CC-C utils. c Clean: Rm edit $ (objects) So if a new. o file is added, you only need to modify the objects variable. I will give you more things about variables in the future. V. Make auto-Derivation GNU make is very powerful. It can automatically deduce the commands behind the file and file dependency, so we do not need to go to every [. o] The files are all written with similar commands, because our make will automatically identify and deduce the commands by ourselves. As long as make sees [. o] file, it will automatically [. c] Add the file to the dependency. If make finds a whatever. o, then whatever. c, it will be whatever. o. And CC-C whatever. C will also be deduced, so our makefile no longer needs to be written so complicated. Our new makefile is released again. Objects = Main. o kbd. O command. O display. O/ Insert. O search. O files. O utils. o Edit: $ (objects) CC-O edit $ (objects) Main. O: defs. h KBD. O: defs. H command. h Command. O: defs. H command. h Display. O: defs. h 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 called "concealed rules" of make ". In the above file content, ". Phony" indicates that clean is a pseudo-target file. For more detailed "concealed rules" and "pseudo-target files", I will give you one by one in the future. 6. Alternative makefile Now that our make command can be automatically deduced, I can see the heap [. o] and [. h] dependencies are a little uncomfortable, so many repeated [. h]. can I collect it together? Well, no problem. This is very easy for make. Who calls it to provide the function of automatically deriving commands and files? Let's take a look at the latest makefile style. Objects = Main. o kbd. O command. O display. O/ Insert. O search. O files. O utils. o Edit: $ (objects) CC-O edit $ (objects) $ (Objects): defs. h KBD. O command. O files. O: Command. h Display. O insert. O search. O files. O: Buffer. h . Phony: clean Clean: Rm edit $ (objects) This style makes our makefile very simple, but our file dependency is a bit messy. The fish and the bear's paw cannot have both. It also shows your preferences. I don't like this style. First, the dependency between files is unclear. Second, if there are more files and a few new. O files need to be added, it's hard to understand. VII. Rules for clearing the target file Each makefile should write a rule to clear the target file (. O and execution file), which not only facilitates re-compilation, but also facilitates file cleaning. This is a "Cultivation" (Oh, remember my "programming Cultivation ). The general style is: Clean: Rm edit $ (objects) A more robust approach is: . Phony: clean Clean: -RM edit $ (objects) As mentioned earlier,. Phony indicates that clean is a "pseudo target ",. The addition of a small minus sign in front of the RM command means that some files may have problems, but don't worry, continue to do the following. Of course, the clean rule should not be placed at the beginning of the file. Otherwise, it will become the default goal of make. I believe no one would like this. The unwritten rule is: "clean is always placed at the end of the file ". The above is an overview of makefile, which is also the basis of makefile. There are still many details about makefile. Are you ready? If you are ready, come. Makefile Overview ------- I. What is in makefile? Makefile contains five main items: explicit rules, concealed rules, variable definitions, file instructions, and annotations. 1. explicit rules. Explicit rules demonstrate how to generate one or more target files. This is clearly pointed out by makefile writers that the files to be generated, the dependent files of the files, and the generated commands. 2. Concealed rules. Since make has the function of automatic derivation, obscure rules allow us to write makefile roughly, which is supported by make. 3. variable definition. In makefile, we need to define a series of variables, which are generally strings. This is a bit of a macro in your c language. When makefile is executed, all the variables are extended to the corresponding reference location. 4. File instructions. It consists of three parts: one is to reference another makefile in a makefile, just like the include in C; the other is to specify the valid part of The makefile according to some situations, just like pre-compiled # If in C; there is also the definition of a multi-line command. I will discuss this part in the subsequent sections. 5. comment. Makefile only contains line comments. Like a Unix shell script, the comments use the "#" character, which is like "//" in C/C ++. If you want to use the "#" character in your makefile, you can escape it by using the reversed box, for example, "/#". Finally, it is worth mentioning that the command in makefile must start with the [Tab] key. Ii. MAKEFILE file name By default, the make command searches for files named "gnumakefile", "makefile", and "makefile" in sequence in the current directory and finds the file to be interpreted. Among the three file names, it is best to use the "makefile" file name, because the first character of the file name is in upper case, so there is a clear sense of purpose. It is best not to use "gnumakefile", which is identified by GNU make. Some other make files are only sensitive to all lowercase "makefile" file names, but basically, most make files support "makefile" and "makefile" default file names. Of course, you can use other file names to write makefile, such as: "Make. linux "," make. solaris "," Make. if you want to specify a specific makefile, you can use the "-F" and "-- file" parameters of make, such as make-F make. linux or make -- file make. aix. 3. Reference other makefiles You can use the include keyword in makefile to include other makefiles, which is similar to the # I nclude in C language. The contained files are stored in the original mode of the current file. The include syntax is: Include <FILENAME> Filename can be the file mode of the current operating system shell (including paths and wildcards) There may be some null characters before include, but it must not start with the [Tab] key. Include and <FILENAME> can be separated by one or more spaces. For example, you have several makefiles:. MK, B. MK, C. MK, there is also a file named Foo. make, and a variable $ (bar), which contains e. MK and F. MK, then, the following statement: Include Foo. Make *. mk $ (bar) It is equivalent: Include Foo. Make a. mk B. mk C. mk E. mk F. mk When the make command starts, it searches for other makefiles specified by include and places the files in the current location. It is like the # I nclude command of C/C ++. If no absolute or relative path is specified for the file, make will first search for it in the current directory. If no absolute or relative path is found in the current directory, make will also find it in the following directories: 1. If the "-I" or "-- include-Dir" parameter exists during make execution, make will search for it in the directory specified by this parameter. 2. If the directory <prefix>/include (generally:/usr/local/bin or/usr/include) exists, make will also find it. If a file is not found, make generates a warning message without a fatal error. It will continue to load other files. Once the makefile is read, make will retry the unfound or unreadable files. If it still does not work, make will produce a fatal message. If you want make to ignore unreadable files and continue execution, you can add a minus sign "-" before include. For example: -Include <FILENAME> It indicates that no errors occur during the include process. The commands related to make compatibility with other versions are sinclude, which serves the same purpose as this one. Iv. environment variables makefiles If your current environment defines the environment variable makefiles, make will perform an Include-like action on the value of this variable. The values in this variable are other makefiles separated by spaces. However, unlike include, the "target" of the makefile introduced in this environment change does not work. If an error is found in the file defined in the environment variable, make will ignore it. However, we recommend that you do not use this environment variable here, because as long as this variable is defined, all makefiles will be affected when you use make, this is not what you want to see. This is just to tell you that there may be some strange things in your makefile, so you can check whether the variable is defined in the current environment. V. How make works The execution steps of GNU make are as follows: (similar to other make statements) 1. Read all makefiles. 2. Read Other makefiles to be included. 3. initialize the variables in the file. 4. Deduce hidden rules and analyze all rules. 5. create dependency links for all target files. 6. Determine the targets to be regenerated Based on the dependency. 7. Run the generated command. Step 1-5 is the first stage, and step 6-7 is the second stage. In the first phase, if the defined variable is used, make will expand it to the position in use. But make will not be fully expanded immediately. Make uses the procrastination strategy. If the variable appears in the dependency rule, it will only be used when the dependency is determined, variable is expanded within it. Of course, you do not have to be clear about this method, but you will be more familiar with make. With this foundation, the subsequent sections will be easy to understand. |