Linux Makefile and Shell

  • 2020-05-15 02:43:32
  • OfStack

Probably anyone who knows Makefile knows that Makefile can call Shell scripts. But when it comes to actual use, it's not that simple, and ambiguity can drive you crazy. If you don't believe me, you can look at a couple of examples, imagine 1 what these examples are going to print, write down the results of your imagination, and then run the examples on your computer, compare them to 1.

Example 1:


if [ "$(BUILD)" = "debug" ]; then  echo "build debug"; else echo "build release"; fi
all:
    echo "done"

Example 2:

all:
    @CC=arm-linux-gcc
    @echo $(CC)

Example 3:

CC=arm-linux-gcc
all:
    @echo $(CC)

Example 4:

SUBDIR=src example
all:
    @for subdir in $(SUBDIR); \
    do\
        echo "building " $(subdir); \
    done


Description:
1. The Shell script is only valid in target; everything else is ignored. So in example 1, strings like "build debug" don't print at all. The correct way to write example 1 is:

Example 1:


all:
    if [ "$(BUILD)" = "debug" ]; then  echo "build debug"; else echo "build release"; fi
    echo "done"

2. make treats each line of the Shell script as a separate unit that runs in a separate process. In example 2, the two-line Shell script runs in two unrelated processes. The first process sets CC to arm-linux-gcc. The second process is not aware of arm-linux-gcc, so the printed result is not arm-linux-gcc. The correct way to write example 2 is:

Example 2:


all:
    @CC=arm-linux-gcc; echo $(CC)

Or:

all:
@CC=arm-linux-gcc; \
echo $(CC)

3. make preprocesses all variables and functions of Makefile before calling Shell. These variables and functions all start with $. In example 3, the script that Shell took was actually echo arm-linux-gcc, so it printed correctly.
4. When preprocessing make, it will not miss anything starting with $. To reference Shell's own variables, start with $$. Also note that Shell's own variables do not need parentheses. The correct way to write example 4 is:

Example 4:


SUBDIR=src example
all:
    @for subdir in $(SUBDIR); \
    do\
        echo "building " $$subdir; \
    done


Related articles: