Makefile writing commands (3)

The commands in each rule are consistent with the command line of the operating system shell. make will execute the commands one by one in order. The beginning of each command must start with the [Tab] key, unless the command is followed by a semicolon after the dependency rule. Spaces or blank lines between command lines are ignored, but if the space or blank line begins with the Tab key, then make considers it an empty command.

We may use different shells under UNIX, but the make command is interpreted and executed by "/bin/sh" - the standard shell of UNIX by default. Unless you specify a different Shell. In Makefile, "#" is a comment, much like "//" in C/C++, and the following characters are commented.

1. Display command

Normally, make prints the command line it wants to execute to the screen before the command is executed. When we use the "@" character in front of the command line, then this command will not be displayed by make. The most representative example is that we use this function to display some information on the screen. Such as:

    @echo is compiling XXX modules...

When make is executed, it will output the string "Compiling XXX module...", but not the command. If there is no "@", then make will output:

    echo Compiling XXX module...
    Compiling XXX module...

If make is executed with the make parameter "-n" or "--just-print", it will only display the command, but will not execute the command. This function is very helpful for us to debug our Makefile and see what we wrote. How the commands are executed or in what order.

The make parameter "-s" or "--slient" completely prohibits the display of commands.

 

2. Command execution

When the dependent target is newer than the target, that is, when the target of the rule needs to be updated, make will execute the following commands one by one. It should be noted that if you want to apply the result of the previous command to the next command, you should separate the two commands with a semicolon. For example, your first command is the cd command, and you want the second command to run on the basis of cd, then you can't write these two commands on two lines, but should write these two commands in on a line, separated by semicolons. Such as:

    Example 1:
        exec:
                cd /home/hchen
                pwd

    Example 2:
        exec:
                cd /home/hchen; pwd

When we execute "make exec", cd in the first example has no effect, pwd will print out the current Makefile directory, while in the second example, cd will work, pwd will print out "/home/hchen ".

make generally uses the system shell defined in the environment variable SHELL to execute commands. By default, it uses the UNIX standard shell-/bin/sh to execute commands. 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 a UNIX-style directory format, first, make will look for the command interpreter in the path specified by SHELL. If it can't find it, it will look in the current directory in the current drive letter. If it can't find it again, It will look in all paths defined in the PATH environment variable. In MS-DOS, if the command interpreter you defined is not found, it will add suffixes such as ".exe", ".com", ".bat", ".sh" to your command interpreter.



3. Command error

After each command is run, make will check the return code of each command. If the command returns successfully, make will execute the next command. When all the commands in the rule return successfully, the rule is considered to be completed successfully. If a command in a rule fails (command exit code is non-zero), then make will terminate execution of the current rule, which will potentially terminate execution of all rules.

Sometimes, the wrong command does not mean that it is wrong. For example, in the mkdir command, we must create a directory. If the directory does not exist, then mkdir is successfully executed, and everything is fine. If the directory exists, then an error occurs. The reason why we use mkdir means that there must be such a directory, so we don't want mkdir to fail and terminate the operation of the rule.

In order to do this, and ignore errors in the command, we can prepend a minus sign "-" (after the Tab key) to the Makefile's command line to mark the command as a success regardless of the error. Such as:

   clean:
            -rm -f *.o

There is also a global way to add the "-i" or "--ignore-errors" parameter to make, then all commands in the Makefile will ignore errors. And if a rule targets ".IGNORE", then all commands in that rule will ignore errors. These are different levels of error prevention for commands, which you can set to your liking.

Another make parameter to be mentioned is "-k" or "--keep-going". This parameter means that if the command in a rule is wrong, then the execution of the rule will be terminated. But continue with the other rules.



4. Nested execution of make

In some large projects, we will put our source files of different modules or different functions in different directories. We can write a Makefile of this directory in each directory, which is beneficial to make our Makefile change. It should be more concise, instead of writing everything in one Makefile, which will make it difficult to maintain our Makefile. This technology is very beneficial for our module compilation and segmented compilation.

For example, we have a subdirectory called subdir, and there is a Makefile in this directory to specify the compilation rules for files in this directory. Then our general Makefile can be written like this:

    subsystem:
            cd subdir && $(MAKE)

It is equivalent to:

    subsystem:
            $(MAKE) -C subdir

Defining the $(MAKE) macro variable means that maybe our make needs some parameters, so defining it as a variable is more conducive to maintenance. The meaning of both examples is to first enter the "subdir" directory, and then execute the make command.

We call this Makefile the "Master Makefile". The variables of the master Makefile can be passed to the lower Makefile (if you declare it explicitly), but will not overwrite the variables defined in the lower Makefile unless "-e is specified. "parameter.

If you want to pass variables to lower Makefiles, then you can use a declaration like this:

    export <variable ...>

If you don't want certain variables to be passed to the lower Makefile, then you can declare it like this:

    unexport <variable ...>

Such as:
   
    Example 1:

        export variable = value

        It is equivalent to:

        variable = value
        export variable

        It is equivalent to:

        export variable := value

        It is equivalent to:

        variable := value
        export variable

    Example two:

        export variable += value

        It is equivalent to:

        variable += value
        export variable

If you want to pass all variables, then just one export will do. There is nothing after it, which means that all variables are passed.

It should be noted that there are two variables, one is SHELL and the other is MAKEFLAGS. Whether you export or not, these two variables are always passed to the lower Makefile, especially the MAKEFILES variable, which contains the parameter information of make, If we execute the "Master Makefile" with make parameters or define this variable in the upper Makefile, the MAKEFILES variable will be these parameters and will be passed to the lower Makefile, which is a system-level environment variable.

But there are several parameters in the make command that are not passed down, they are "-C", "-f", "-h", "-o" and "-W" (details about Makefile parameters will be explained later ), if you don't want to pass parameters to the lower layer, then you can do it like this:

    subsystem:
            cd subdir && $(MAKE) MAKEFLAGS=

If you define the environment variable MAKEFLAGS, then you have to be sure that the options in it are used by everyone. If there are "-t", "-n", and "-q" parameters, then there will be unexpected The result may make you panic abnormally.

There is also a useful parameter in "nested execution", "-w" or "--print-directory" will output some information during the make process, allowing you to see the current working directory. For example, if our subordinate make directory is "/home/hchen/gnu/make", if we use "make -w" to execute, then when entering this directory, we will see:

    make: Entering directory `/home/hchen/gnu/make'.

And when we leave the directory after finishing the lower level make, we see:

    make: Leaving directory `/home/hchen/gnu/make'

When you use the "-C" parameter to specify the lower Makefile of make, "-w" will be automatically turned on. If there is "-s" ("--slient") or "--no-print-directory" in the parameter, then "-w" is always invalid.



Five, define the command package

If some identical command sequences appear in the Makefile, then we can define a variable for these identical command sequences. The syntax for defining such a sequence of commands starts with "define" and ends with "endef", as in:

    define run-yacc
    yacc $(firstword $^)
    mv y.tab.c $@
    endef

Here, "run-yacc" is the name of the command package, which should not have the same name as the variable in the Makefile. The two lines in "define" and "endef" are the command sequences. The first command in this command package is to run the Yacc program, because the Yacc program always generates the "y.tab.c" file, so the second line of the command is to change the name of this file. Let's take a look at this command package into an example.

    foo.c : foo.y
            $(run-yacc)

As we can see, to use this command package, we use it as if we were using variables. In the use of this command package, "$^" in the command package "run-yacc" is "foo.y", and "$@" is "foo.c" (for this special variable starting with "$" , we will introduce it later), when make executes the command package, each command in the command package will be executed independently in turn.

< -Previous Next- > 

Guess you like

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