makefile basic rules

    A makefile contains a set of rules for compiling an application. The first rule that the make command sees is used as the default rule. A rule can be divided into three parts: the work target (target), its prerequisites (prerequisites) and the command to be executed (command).
# Note: When the necessary conditions are not specified, the update will only be made if the file represented by the work target does not exist.
target1 [target2...]: [prereq1 prereq2...]
    command1
    command2
    ...

    Among them, the work target (target) is a file that must be built or something to be done; the necessary conditions or dependencies are those files that must exist before the working directory is created; and the command to be executed is when the necessary conditions are met. Those shell commands that create work targets. All three parts support shell wildcard patterns, but when the pattern appears in a job target or prerequisite, the wildcard expansion is performed by make, and when the pattern appears in a command, it is expanded by subshell.
    When make processes a rule, it first finds the files specified in the prerequisites and work targets. If there are files related to other rules in the necessary conditions, make will first complete the update action of the corresponding rules. If a file with a timestamp after the work target exists in the prerequisites, make executes the command to recreate the work target. Scripts are passed to the shell and run in its subshell.
    Example:
count_words: count_words.o lexer.o -lfl
        gcc count_words.o lexer.o -lfl -o count_words
count_words.o: count_words.c
        gcc -c count_words.c
lexer.c: lexer.l
        flex -t lexer.l > lexer.c

    But when you execute the make command, you will see output like this:
$ make
gcc -c count_words.c
flex -t lexer.l > lexer.c
gcc -c lexer.c
gcc count_words.o lexer.o -lfl -o count_words

    It can be seen that make first completes the necessary conditions before realizing the final work goal. Note that the lexer.c file here is generated by the flex program. The "-lfl" parameter is specified here, and the "-l" parameter requires gcc to link the system library it specifies into the application, where the actual library name is libfl.a. According to GNU make: when the necessary conditions of the form -l<NAME> are found, make will search for files of the form libNAME.so; if not found, make will then search for files of the form libNAME.a.
    If you want to update another (or more) different working target, you should specify it explicitly on the command line, eg:
        $ make lexer.c
    make provides many command line options, one of the more useful ones is "--just -print/-n" to ask make to display the commands it will execute for a particular job target, but not to actually execute them.
    Additionally, sometimes we may wish to provide hypothetical work goals like the following:
...
clean:
        rm -f *.o lexer.c

    Because most hypothetical work targets do not specify necessary conditions, and make cannot distinguish between work targets in the form of files and hypothetical work targets, if a file with the same name as the hypothetical work target happens to appear in the current directory, make will display it in the attached drawing. The relationship between the file and the hypothetical work target may be established in the file, which may cause the corresponding work target to always be regarded as updated, and the corresponding command will never be executed again.
    To avoid this problem, GNU make provides a special job target ".PHONY", which is used to indicate that the job target is not a real file, and always marks the job target as not yet updated. When you want to declare a hypothetical work goal, just specify the work goal as a necessary condition of ".PHONY":
...
.PHONY: clean
clean:
        rm -f *.o lexer.c

    It doesn't seem to make sense to have the hypothetical work target as a requirement of the actual document, because the hypothetical work target is always not updated, which will always cause the actual document (the work target) to be recreated. But it's somewhat useful to have it as a sine qua non for a hypothetical work goal. For example, the all job target is often used to specify a list of programs to compile:
...
.PHONY: all
all: bash bashbug

    This way, the all job target will create bash and bashbug (a bug reporting tool).
    In addition, hypothetical work targets can be used as shell scripts built into the makefile, allowing make to invoke the script represented by the hypothetical work target before proceeding to the actual work target. For example, if we care about disk space usage and want to show how much disk space is available before doing disk-intensive work, we can write:
...
.PHONY: make-documentation
make-documentation: df
        javadoc ...
.PHONY: df
df:
        df -k . | awk 'NR == 2 {printf("%d available\n", $$4)}'

    The use of variables is supported in makefiles. The reference form is $(varaible_name) or ${varaible-name}. When the variable name has only one character, parentheses can be omitted, and the variable name can contain most characters (including punctuation). In order to facilitate access to the work target and elements in the necessary conditions, make will set automatic variables when the rule matches (and thus only apply to the command script part of the rule). Here are a few commonly used automatic variables:
automatic variable describe
$@ The filename of the job target
$% The file name element in the archive file member structure, you can specify a member named member in the archive file archive with the syntax archive(member)
$< The filename of the first prerequisite
$? All prerequisites with a timestamp after the job target, separated by spaces
$^ All necessary file names, separated by spaces, and duplicate files are removed
$+ Same as $^, but will contain duplicate filenames.
$* The main filename of the job target (i.e. without the extension part). Not recommended for use outside of pattern rules

    Also, for compatibility with other make versions, these variables have two variants. One of the directory parts that only returns the value is realized by appending the letter D after the original symbol, such as $(@D); the other file part that only returns the value is realized by appending the letter F, such as $ (@F).
    The previous makefile can now be written as:
count_words: count_words.o lexer.o -lfl
        gcc $^ -o $@
count_words.o: count_words.c
        gcc -c $<
lexer.c: lexer.l
        flex -t $< > $@

    By default, make will only look for working targets and prerequisites in the current directory. Therefore, when the required files appear in multiple directories, other means are needed. At this point, consider using the VPATH variable and the vpath directive.
    The contents of the VPATH variable is a directory listing. Make searches this directory listing for files it cannot find in the current directory. Its definition format is:
        VPATH = dir1 [dir2 ...]
    but make only takes the first file found, so it may surprise us when there are files with the same name in multiple directories. At this point, the vpath instruction can be used, and its syntax is as follows:
        vpath pattern directory-list
    For example, assuming that the header files we need are in the ./include/ directory, and the source files are in the ./src/ directory, we will A makefile can be written like this, using vpath to tell make to search the src directory for ".c" and ".l" files, and the include directory for ".h" files:
# VPATH = src include # This is the case when using the VPATH variable
# CPPFLAGS = -I include # Specify implicit compilation rules
vpath %.l %.c src
vpath %.h include
count_words: count_words.o counter.o lexer.o -lfl
        gcc $^ -o $@
count_words.o: count_words.c counter.h
        gcc -c $<
lexer.c: lexer.l
        flex -t $< > $@

    Note that pattern rules are used in "%.c", etc. The "%" in this rule is roughly equivalent to "*" in the shell, which can represent any number of characters. "%" can be placed anywhere in the filename, but only once. In addition, you may also use a pattern with only one "%", which is usually used to denote an executable program, since executable files on Unix generally do not need an extension.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326065843&siteId=291194637