GNU Make Guide

xiaoxiao2021-03-06  66

GNU Make Guide Translation: Ha Shado Press: This article is an article introducing GNU Make. After reading, readers should basically master the use of Make. Make is a tool that you want to program on UNIX (of course also include Linux) systems. If you don't use Make in the program you write, you will explain that the program you write is just a personal exercise program, does not have any practical value. Perhaps this is a bit of a bit of being biased, but make it really uses in any slightly larger program. I hope this article can provide a good useful information for China's UNIX programming beginners. In addition to installing red hats, China Linux users should try to write some useful procedures. Personal idea, everyone reference. C-Scene title # 2 multi-file project and GNU Make tool Author: Qiaozhi Fu special (Goerge Foot) e-mail: george.foot@merton.ox.ac.uk Occupation: Student at Merton College, Oxford University, England Occupation: Student , Merton College, Oxford City University, England IRC Anonymous: GFOOT Refused Commitment: All damage caused by anything (you have or don't have actual, abstract, or virtual). All damage is your own responsibility, but nothing to do with me. Ownership: The "Multi-File Project" part belongs to the author's property, copyright belongs to Georget Fug, from May to July, 1997. Other part belongs to CScene property, copyright CScene in 1997, all copyrights. The distribution, part or all of this CScene article shall be handled in accordance with all other CSCENE articles. 0) Introduction ~~~~~~~~~~~~~~ This article will first introduce why you want to separate your C source code into several reasonable independent files, what time you need, how can you be better. Then I will tell you how GNU Make automates your compilation and connection steps. For users of other Make tools, although appropriate adjustments are made when using other similar tools, the content of this article is still very useful. If you have doubts about your own programming tool, you can try it in actually, but please read the user manual first. 1) Multi-file item ~~~~~~~~~~~~~~~~~~~~ What do you use? First, there is a multi-file project? They seem to make things more complicated. Also wants the header file, but also the extern declaration, and if you need to find a file, you have to search in more files. But in fact, we have a strong reason to support us to break up a project into small pieces. When you change a line of code, the compiler needs to be re-compiled to generate a new executable. But if your project is separated in a few small files, when you change one of the files, the object file of the other source files already exists, so there is no reason to recompile them. What you need to do is to reproduce the file that is changed, and then reacts all the target files. In a large project, this means that it is a simple adjustment from a long (minutes from a few hours).

As long as the basic planning, a project is broken down into multiple small files to make it easier to find a code. Very simple, you decompose your code into a different file according to the role of the code. When you want to see a code, you can know accurately in that file to look for it. Generating a package from a lot of target files (library) is much better than from a single big target file. Of course, this is actually a advantage is determined by the system you use. However, when a program is connected to a program using GCC / LD (a GNU C Compilation / Connector), in the process of the connection, it will try to not connect the part of the part. But each time you can only remove a complete target file from the package. So if you refer to any of the symbols in a single target file, then this target file will be connected in. If a package is very fully decomposed, then after the connection, the obtained executable is much smaller than the files connected to the package consisting of a large target file. Because your program is very modular, the sharing part between files is minimized, then there are many benefits - it can be easily tracked into bugs, which often can be used in other projects, At the same time, others can easily understand what your code is doing. Of course, there are many other benefits ... 1.2 When you decompose your project, it is unreasonable to decompose anything is unreasonable. Simple programs like "World, you are good" are not divided, because there is nothing to be able to divide. Decompose the decomposition of small procedures for testing is also meaningless. But in general, when the decomposition project helps layout, development and readability, I will take it. In most cases, this is suitable. (The so-called "world, you are good", both 'Hello World', just a sample program that introduces a programming language, which will display a line 'Hello World' on the screen.) If you need Develop a considerable project, before the start, consider how you will implement it and generate a few files (with the appropriate name) to put your code. Of course, in the process of your project development, you can build new files, but if you do this, you may change the original idea, you should think about whether it needs to be adjusted for the overall structure. For medium-sized projects, you can of course use the above techniques, but you can just enter your code, when your code is more difficult to manage, decompose them into different files. But in my experience, the beginning of the mind form a probably scheme and try to follow it, or during the development process, as the needs of the program will make the development easier. 1.3 How to Decompose the project first instructions, which is all my personal opinions, you can (maybe you really will?) Do in other ways. This will touch the problem of coding style, and everyone has never stopped the debate on this issue. Here I just give me my favorite approach (while giving this reason): i) Do not point to multiple source files (exception: the header file of the package). The way to define a source code file is more efficient and easier to find. Otherwise, changing the structure of a source file (and its header file) must recompile several files.

II) If you can, you can use more than one header file to point to the same source code file. Sometimes the function prototype, type definition, and so on, which cannot be invoked, and it is very useful from their C source file files. Using a Header file to install public symbols, use another private symbol that if you change the internal structure of this source file, you can just recompile it without having to recompile other source files that use its public header file. . III) Do not repeat the definition information in multiple header files. If necessary, in one of the header files #include one, but do not repeat the same Header information twice. The reason is if you change this information later, you only need to change it once, do not search and change another repetition. IV) In each source file, #include states all Header files that declare the symbols in the source file file. In this way, the contradictions you make in some functions in the source file and the Header file can be discovered by the compiler. 1.4 Reviews for common errors a) Conversation (Identifier) ​​In the source file: In C, the default state of variables and functions is public. Therefore, any C source file file can reference universal (GLOBAL) functions and general variables existing in other source code archives, making this file without the declaration or prototype of the variable or function. So you must guarantee that you can't use the same symbol name in different two files, otherwise there will be an incorrect connection or a warning when compiling. A method of avoiding such an error is to add a prefix with its source file before the public symbol. For example: All functions in GFX.c are plus prefix "GFX_". If you are very careful to decompose your program, use meaningful function names, and not excessive common variables, of course, this is not a problem. To prevent a symbol from being seen outside of its defined source file, you can add keyword "static" before it definition. This is useful to use only simple functions that other files use only in one file. B) Multi-defined symbols: The Header file will be replaced with the location of the #include in your source file. Therefore, if the Header file is included in #include to more than one source file, all definitions in this header file will appear in each related source code file. This will cause the symbols in which they are defined over, thus connecting the connection error (see). Workaround: Do not define variables in the HEADER file. You only need to declare them in the Header file and then define them in the appropriate C source file (should be included in the Header file). For beginners, definitions and statements are easily confused. The role of the declaration is to tell the compiler that the symbols they have declared should exist and have the type specified. However, it does not make the compiler allocates storage space. The definition is required to require a compiler to allocate storage space. When making a statement instead of being defined, put a keyword "extern" before the declaration. For example, we have a variable called "counter". If we want it to become public, we define it in a source code (in one inside): "int counter;", then in the relevant header file declaration It: "Extern Int Counter;".

The function prototype is implied with Extern, so you don't need to worry about this problem. c) Repeat definition, repeat declaration, contradictory type: Please consider if there are two files in the #include in a C source file, and the AH is also #include BH file (the reason is that the BH file defines some ah needs type) What happens? At this time, the C source code file #include has b.h twice. So each of the #define in B.H has occurred twice, and each declaration has occurred twice, and so on. In theory, because they are exactly the same copy, there should be no problems, but in practical applications, this is not conforming to C's grammar, which may occur when compiling, or at least warning. The solution is to determine that every Header file is only included in any source file file. We generally use preprocessors to achieve this purpose. When we enter every Header file, we have a giant command for this Header file #define. We really use the body file of the Header file only if this giant intention is not defined. In practical applications, we only need to put the following one code in the start of each Header file: #ifndef filename_h #define filename_h then put the following code in the last: #ENDIF with the Header file file (capital) instead FileName_h, use the bottom line instead of the point in the file. Some people like to make comments in #ENDIF to remind them that this #ndif refers to what. For example: #ENDIF / * #ifndef filename_h * / I personally there is no such habit, because this is actually very obvious. Of course, this is only different in the style of each person, and there is no harm. You only need to add this skill in the header file with compilation errors, but there is no loss in all HEADER files, which is a good habit. 1.5 Re-compiling a multi-file project clear distinct compilation and connection is important. The compiler uses the source code file to generate some form of destination file (Object Files). During this process, the external symbol reference is not explained or replaced. Then we use the connector to connect these object files and some standard package plus your specified package, and finally connect to generate an executable. At this stage, the reference to the symbols in other files is interpreted in a target file, and the reference that cannot be interpreted is generally reported in the form of error information. Basic steps should be, put your source file into a form of a target file, and finally connect all the target files to an executable file. How to do it is determined by your compiler. Here I only give the relevant commands of the GCC (GNU C compiler), which may also apply to your non-GCC compiler. GCC is a multi-objective tool. It calls other components (pre-processing programs, compilers, combination programs, connector) when needed. Which components of specific components are called depends on the type of input file and the switch you pass to it.

In general, if you only give it C source file file, it will preprocess, compile, combine all files, and then connect the resulting target file into an executable file (generally generated file is named A.out). Of course you can do this, but this will destroy a lot of benefits we have decomposed into multiple files. If you give it a -C switch, GCC only compiles its file into a target file, named the file name of the source file but the suffix is ​​".c" or ".cc" becomes ".o". If you give it a list of target files, GCC will connect them into executables, the default file name is A.out. You can change the default name, with the file name you specified by the switch-O. Therefore, after you change a source code file, you need to recompile it: 'gcc -c filename.c' then reconnect your item: 'gcc -o exec_filename * .o'. If you change a Header file, you need to recompile all #include's source files for this file, you can use 'gcc -c file1.c file2.c file3.c' and then connect it as above. Of course, this is very cumbersome, fortunately, we have some tools to make this step simple. The second part of this article is to introduce one of the tools: GNU Make tool. (Good guy, now I started to see the true chapter. You have learned something?) 2) GNU Make Tool ~~~~~~~~~~~~~~~~ 2. The basic Makefile structure Gnu make's main job is Read into a text file, makefile. This file is mainly related to which files ('target' destination file) is from which other files ('DependenCIES' relying on files), what commands are used for this process. With this information, Make will check the file on the disk, if the timestamp of the destination file (the time when this file is generated or changed), Make performs the corresponding command to update Purpose file. (The destination file is not necessarily the final executable, which can be any file.) Makefile is typically called "makefile" or "makefile". Of course, you can specify other file names at the Make command line. If you don't specify, it will find "makefile" or "makefile", so use these two names is the simplest.

A Makefile mainly contains a range of rules, as follows: ... (tab)................................. o bar.o -o myprog foo.o: foo.c foo.h bar.h gcc -c foo.c -o foo.o bar.o: bar.c bar.h gcc -c bar.c-c bar .o === makefile end === This is a very basic makefile - make from the top, put the top first destination, 'myprog', as its main goal (one it needs to guarantee it always The latest ultimate goal). The rules given instructions As long as the file 'myprog' is more old than any of the file 'foo.o' or 'bar.o', the next line will be executed. However, before checking the timestamp of the file foo.o and bar.o, it will look down the rules that make foo.o or bar.o as the target file. It found about foo.o rules that rely on files foo.c, foo.h and bar.h. It can't find a rule that generates these relying on files from below, it starts to check the timestamp of these dependencies on the disk. If any of the timestamps in these files are more than foo.o, the command 'gcc -o foo.o foo.c' will be executed, so that the file foo.o is updated. Next, a similar inspection is made to the file bar., and the file is here is the file bar.c and bar.h. Now, make back to 'myprog' rules. If any one of the two rules is executed, myProg needs to be rebuilt (because one of them. "New than 'myprog', the connection command will be executed. I hope that you can see the benefits of using the Make tool to create a program - all cumbersome inspection steps in the previous chapter are made by Make: Check the timestamp. A simple change in your source file will cause that file being recompiled (because the .o file rely on .c file), the executable file is reconnected (because .o file is changed). In fact, the real benefits are when you change a Header file - you no longer need to remember that source file rely on it, because all the information is in makefile. Make will easily recompile all the source code files that have changed since this Header file, if necessary, re-connect. Of course, you have to make sure that the rules you write in makefile are correct, only listing the Header files of #include in the source file ... 2.2 Writing the Make rule (Rules) is most obvious (also the simplest) The method of writing rules is a view of the source code file that makes its target file as a purpose, while the C source file and the Header file of #include are relying on files.

But you also have to list other Header files of these Header files #include as relying on files, as well as files included in the files included ... Then you will find more and more files, then Your hair begins to fall off, your temper begins to get bad, your face turns into a dish, you start to collide with the electric wire on the road, and finally you smash your computer monitor, stop programming. Is there any way to have some way? Of course! To the compiler! When compiling each source file, it should be found to include what kinder files should be included. When using GCC, use the -m switch, which will output a rule for each of your C file, make the target file as a purpose, and this C file and all Header files whose #include should be used as a file. . Note that this rule will join all Header files, including the files surrounded by cornence brackets (`<',`>') and dual quotation marks (`"). In fact, we can quite certainly determine the system Header file (such as stdio.h, stdlib .h, etc.) Will not be changed by us, if you use -mm instead to pass to GCC, the Header file surrounded by the corner parentheses will not be included. (This saves some compile time) by GCC output The rule does not contain a command section; you can write your command or not write, let Make use its implicit rules (refer to the following 2.4). 2.3 Makefile variables mentioned in Makefiles mainly included some Rules. The other things they contain are variable definitions. The variables in the makefile are like an environment variable. In fact, environmental variables are interpreted as Make's variables in the Make process. These variables are sensitive, Usually use uppercase letters. They can be referenced almost anywhere, or they can be used to do a lot of things, such as: i), store a file name list. In the above example, the rules that generate executables include some target file names It is dependent. In this rule, the same files are delivered to the GCC as a command parameter. If you use a variable to store all the target file names, add a new target file to become simple and easier Error. II) Store the executable file name. If your project is used in a non-GCC system, or if you want to use a different compiler, you must change all the places using the compiler into new compilation The name of the name. But if you use a variable instead of the compiler name, you only need to change a place, the command names of all other places have changed. III) Store the compiler flag. Suppose you want to give you all your compile commands Pass one set of options (for example, -wall -o -g); if you put this set of options into a variable, you can put this variable in all call compilers. And when you want to change the option You only need to change this variable in one place. To set a variable, you only need to write the name of this variable in a line, followed by one = number, followed by the value of this variable you want to set. In the future, you have to reference this variable, write a $ symbol, followed by the variable name surrounded in parentheses.

For example, in the following, we use the previous makefile to rewrite the variables again: === Makefile start === Objs = foo.o bar.o cc = GCC cflags = -wall -o -g myprog: $ (OBJS) $ ( CC) $ (objs) -o myprog foo.o: foo.c foo.h bar.h $ (cc) $ (cflags) -c foo.c -o foo.o bar.o: bar.c bar.h $ (Cc) $ (cflags) -c bar.c -o bar.o === makefile ends === There are also some set internal variables, which are defined according to each rule content. Three more useful variables are $ @, $

Its command uses some variables, so you can set it according to your ideas: it uses the variable CC as a compiler (like our example), and transmits variable cflags (for C compiler, C compiler) CXXFLAGS, CPPFLAGS (C pre-regulator flag), target_arch (now don't consider this), then add the flag '-C', back with the variable $ <(first rely), then the flag '- o 'Call with variable $ @ (destination file name). A concrete command of a CC will be: $ (cc) $ (cflags) $ (target_arch) -c $ - o $ @ Of course you can define these variables in your own needs. This is why the code output with the -m or -mm switch with GCC can be used directly in a Makefile. 2.5 PHONY TARGETS, assuming that one of your projects will eventually generate two executable files. Your main goal is to generate two executable files, but these two files are independent of each other - if a file needs to be rebuilt, does not affect the other. You can use the "Imaginary Purpose" to achieve this effect. A illusion is almost the same as a normal purpose, but this destination file does not exist. Therefore, Make always assume that it needs to be generated. When it is updated, it will execute the command line in its rule. If you start at our makefile: All: Exec1 exec2 where Exec1 and Exec2 are two executables we are as a purpose. Make put this 'all' as its main purpose, try to update 'all' every time you execute. But since this line is in this line rule, there is no actual file called 'all' (in fact ALL does not actually be generated on the disk), so this rule does not really change the status of 'all'. Since this file does not exist, Make will try to update the all rule, so check it to rely on Exec1, if EXEC2 needs to be updated, if necessary, reach our purpose. Illustrative purposes can also be used to describe a set of non-preset actions. For example, you want to delete all files generated by makefile, you can set up such rules in Makefile: VeryProg Prerequisite is that there is no other rule depending on this 'Veryclean' purpose, it will never be carried out. However, if your clear use of the command 'make verycleclean', Make will use this purpose as its primary goal, perform those RM commands. What happens if there is a virtual file on your disk? At this time, this destination file must be the latest in this rule (all relying on files are already the latest), so they don't make the user clearly command Make to re-generate it. things happen.

The solution is to mark all the ingredients (with .phony), telling make not to check if they exist on the disk, nor to find any implicit rules, directly assume that the specified purpose needs to be updated. Add the following line to the Makefile to include the rules of the above rules: .phony: VeryClean is OK. Note that this is a special Make rule, make know .phony is a special purpose, of course, you can join any illusion you want to use in its relying on it, and Make knows that they are ingredients. 2.6 Functions Makefile The function is similar to its variables - when you use, you use a $ symbol with the bracket, the function name, and the space is followed by the comma-separated parameters, and finally use the brackets. For example, there is a function called 'Wildcard' in GNU Make, which has a parameter, which is to expand into a list of file names that are described by its parameters, and the file is spaced apart. You can use this command below: Sources = $ (Wildcard * .c) This line generates a list of all files ending with '.c', and then stores into the variable Sources. Of course, you don't need to store the results into a variable. Another useful function is the PATSUBST (Patten Substitude, the abbreviation of matching replacement) functions. It requires three parameters - the first is a model that needs to match, the second means to replace it, the third is a word that needs to be processed by the space separated by the space. For example, dealing with variables after the above definition, OBJS = $ (PatSubst% .c,%. O, $ (Sources)) This line will process all words in the Sources list (a column file name) if it ends Is '.c', use '.o' to replace '.c'. Note that the% symbols here will match one or more characters, and it is called a 'handle' each time the string is called. In the second parameter, the% is interpreted as the handle that matches the first parameter. 2.7 A more effective makefile takes us now, we can build a quite effective Makefile. This makefile can complete most of our needs, you can use it directly in most projects without doing too much change. First we need a basic Makefile to build our program. We can let it search for the current directory, find the source file, and assume that they belong to our item, put it into a variable called Sources. Here, if all * .cc files are also included, it may be more insurance because the source code file may be a C code. Sources = $ (Wildcard * .c * .cc) Using PATSUBST, we can generate the target file name by the source file name, we need to compile these target files.

If our source code file has both .c files, there are also .cc files, we need to use the embedded PATSUBST function call: OBJS = $ (PatSubst% .c,%. O, $ (PatSubst% .cc,%. O, $ (SOURCES))) The most inside of the PATSUBST called the .cc file suffixed replacement, the resulting result is replaced by the outer PATSUBST call processing, which is replaced with the .c file suffix. Now we can set up a rule to build an executable: MyProg: $ (objs) gcc -o myprog $ (objs) further rules do not necessarily need, GCC already knows how to generate the target file (Object Files). Below we can set rules that have relying on information: Depends: $ (SOURCES) GCC -M $ (Sources)> Depends here If a file called 'Depends' does not exist, or any source file is longer than an existing Depends This file is new, then a Depends file will be generated. The Depends file will contain rules for the source code file generated by GCC (Note -M Switch). Now let's let Make make these rules as part of the Makefile file. The techniques used here are like the #include system in the C language - we ask Make to include this file inClude to makefile, as follows: Include Depends gnu make, check whether the 'Depends' is updated, if not, it is used We re-produced the Depends file. It will then contain this set (new) rule into in and continue to handle the final target 'myprog'. When you see rules about MyProg, it checks if all target files are updated - using the rules in the Depends file, of course these rules are now updated. This system is actually a low efficiency, because whenever a source code file is changed, all source files must be preproced to generate a new 'Depends' file. And it is not 100% security, because when a Header file is changed, relying on information is not updated. But on the basic work, it is also quite useful. 2.8 A better makefile This is a Makefile I have designed for my most items. It should be able to do not need to modify it in most items. I mainly use it on DJGPP, which is a DOS version of the GCC compiler. So you can see the executed command name, 'alleg' package, and RM -F variables reflect this.

=== Makefile start === ####################### # # # gener makefile # By George Foot # email: George.foot@meton.ox.ac.uk # # Copyright (c) 1997 George Foot # all rights reserved. # 保 all copyright # # no warranty, no liability; # you us this at Your Own Risk. # 不 保, is not responsible # 你 你用 这个用 你 风 风 # # you are free to modify and # distribute this without giving # credit to the original author. # You can change and distribute this file # And no need to give the original author. # (How is your meaning?) # ################################################################################################################################################################################################################################################################################################ user setting # # Adjust the following if necessary; EXECUTABLE is the target # executable's filename, and LIBS is a list of libraries to link in # (eg alleg, stdcx, iostr, etc) You can override these on make's # command line. The following things are adjusted if needed, if needed. Executable is the target's executable file name, libs # is a list of packages that require a connection (such as Alleg, Stdcx, iostr, etc.). Of course, you can overwrite them on the command line of make, you are willing to have no problem.

# Executable: = Mushroom.exe Libs: = alleg # now alter any implicit rules' variables if you like, eg: # # Now change the variables in the implicit rules you want to change, such as cflags: = -g -wall -O3 -m486 cxxflags: = $ (cflags) # The next bit checks to seehther rm is in your djgpp bin # Directory; if not it Uses del instead, but this can cause (harmless) # `File Not find 'Error Messages . If you are not usning dos at all, # set the variable to something # files. # # Let's check if there is any rm command in your DJGPP command directory, if not, we use the # del command instead, But it is possible to give us 'File Not Found' this error message, this is not # 什么 #. If you are not using DOS, set it into a command that deletes files and unused. # (In fact, this step is redundant on the UNIX class, just convenient DOS users. UNIX # users can delete this 5 line command.) IFNEQ ($ (Wildcard $ (DJDIR) /bin/rm.exe),) RM -F: = rm -f else rm-f: = del endif # You shop Below this point. # # From here, you should do not need to change anything.

(I am not trustful, too NB!) Source: = $ (Wildcard * .c) $ (Wildcard * .cc) Objs: = $ (PatSubst% .c,%. O, $ (PatSubst% .cc, % .o, $ (Source))) DEPS: = $ (PatSubst% .o,%. D, $ (OBJS)) missing_deps: = $ (Filter-Out $ (Wildcard $ (DEPS)), $ (DEPS) Missing_Deps_sources: = $ (Wildcard $ (PatSubst% .d,%. C, $ (Missing_DEPS)) / $ (PatSubst% .d,%. CC, $ (Missing_DEPS))) CPPFLAGS = -Md .phony: Everything DEPS OBJS CLEAN VERYCLEAN REBUILD EVERYTHING: $ (Executable) DEP: $ (DEPS) OBJS: $ (OBJS) Clean: @ $ (rm-f) * .o @ $ (rm-f) * .d verycleclean: clean @ $ (RM-F) $ (Executable) Rebuild: Veryclean Everything IFNEQ ($ (missing_deps),) $ (Missing_Deps): @ $ (r-) $ (PATSUBST% .D,%. O, $ @) endif -Include $ (DEPS) $ (Executable): $ (OBJS) GCC -O $ (Executable) $ (OBJS) $ (Addprefix -l, $ (LIBS)) === Makefile ends === There are several places worth explaining of. First, when I define most of the variables, I use: = instead of = symbol. Its role is to immediately expand the functions and variables referred to in the definition. If you use =, the function and variable reference will remain in that child, that is, the value of changing a variable can cause the value of other variables to be changed. For example: a = foo b = $ (a) # now B is $ (a), and $ (a) is 'foo'. A = BAR # now B is still $ (a), but its value has become 'bar'. B: = $ (a) # The value of B is 'bar'. The value of a = foo # b is still 'bar'. Make will ignore all the text behind the # symbol until the end of the line. Ifneg ... Else ... Endif System is a failure / effective tool that makes a certain part of the code in your Makefile.

IFEQ uses two parameters if they are the same, it is added until Else (or ENDIF, if there is no else), if the ELSE is added; if different, add a piece of ELSE to ENDIF to makefile (if there is ELSE). The use of IFNEQ is just the opposite. The 'filter-out' function uses two lists separated by spaces, which deletes the items existing in the second list in the first list. I use it to handle the DEPS list, delete all existing projects, but only those missing. I have said before, CPPFlags has some flags for passing to the pre-processor for implicit rules. The -md switch is similar to the -m switch, but the file name formed from the source file .c or .CC is the use of the suffix. D.D (this explains the steps I form a DEPS variable). The file mentioned in DEPS later added with '-include' to make the makefile, which hides all the error messages generated due to the fault. If any relying on the file does not exist, makefile will remove the corresponding .o file from the disk to make Make rebuild it. Because cppflags specifies -md, it is also re-generated. Finally, 'addprefix' functions put the first parameter value of each of the second parameter list. The purpose of this makefile is (these purposes can be transmitted to the command line of Make): everything: (Preset) Update the primary executable, and generate or update a '.d' file for each source file. One '.o' file. DEPS: just generates or updates a '.d' file for each source code program. Objs: Generate or update the '.d' file and target file for each source code program. Clean: Delete all an intermediary / dependent file (* .d and * .o). Veryclean: Make `Clean 'and delete executables. Rebuild: Do `Veryclean 'and` everything'; it is completely reconstructed. In addition to preset EVERYTHING, only Clean, Veryclean, and Rebuild are meaningful to users. I haven't found a directory for a source code file, this makefile will fail, unless the file is disabled. If this messy situation occurs, just enter `make Clean ', all target files and dependent files will be deleted, and the problem should be solved. Of course, it is best not to mess with them. If you find that this makefile file cannot complete its work in some case, please tell me, I will take it better. 3 Summary ~~~~~~~~~~~~~~~ I hope this article is enough to explain how the multi-file project works, and it means how security is reasonable. At this point, you should easily use the GNU Make tool to manage small projects, if you fully understand the back of several parts, these are not difficult for you. GNU Make is a powerful tool, although it is mainly used to build a program, there are still many other uses.

转载请注明原文地址:https://www.9cbs.com/read-113559.html

New Post(0)