Makefile里调用shell注意点

Makefile中调用Shell的最佳实践
本文详细探讨了在Makefile中如何正确且高效地调用Shell命令,包括注意事项、常见陷阱及优化技巧,帮助你提升构建过程的稳定性和效率。


大家经常编写和使用Makefile, Makefile里面也经常用到shell, 但对其中一些需要注意的地方未必
会去留意, 这里列出几个来, 不知是否对大家有用。
1. 注意Makefile的变量和shell变量, 看如下示例:
 
  DIRS = src bin lib
   all:
    @for i in $(DIRS); /
     do /
         echo " " $$i; /
     done
   大家看出来了吗? DIRS是makefile变量,i是shell变量, 使用的时候:
   $(DIRS), $$i区别还是蛮大的。
  
2. 每一行的shell都是在独立的进程中运行的,如果你在上一行为一个变量赋值, 不要指望它在下一行有效, 比如:
  @CROSS_COMPILE=mipsel-linux-
   @echo $(CROSS_COMPILE)
 
   打印的结果不会是mipsel-linux-,如果你想得到所要的结果, 就并为一条shell吧:
   @CROSS_COMPILE=mipsel-linux- ; echo @echo $(CROSS_COMPILE)
    或者:
   @CROSS_COMPILE=mipsel-linux- ; /
    echo @echo$(CROSS_COMPILE)
   
3. shell一定要写在target里, 否则你写了也白费劲, 是会被make忽略掉的.
   @echo "Building all..."
   all:
    @echo "Begin"
   只会打印Begin.

Makefile调用 Shell 脚本是常见的需求,可以用于执行自动化构建、清理、部署等操作。Makefile 提供了多种方式来执行 Shell 命令,主要包括以下几种方法: ### 1. 使用 `$(shell ...)` 函数 `$(shell ...)` 是 GNU Make 提供的一个内置函数,用于在 Makefile 解析阶段执行 Shell 命令,并将其输出作为变量的值。这种方式适用于需要在 Makefile 中获取 Shell 命令结果的场景。 示例: ```makefile SRC_FILES := $(shell find . -name "*.c") OBJ_FILES := $(SRC_FILES:.c=.o) all: @echo "Object files: $(OBJ_FILES)" ``` 该示例中,`$(shell find . -name "*.c")` 会查找当前目录下所有的 `.c` 文件,并将其路径赋值给 `SRC_FILES` 变量[^2]。 ### 2. 在规则的动作部分直接执行 Shell 命令 在 Makefile 的规则中,可以使用 Shell 命令作为目标的动作。Make 默认会为每个动作启动一个新的 Shell 实例,因此多个命令之间如果需要共享上下文,应使用分号或反斜杠连接。 示例: ```makefile clean: rm -f *.o rm -f myprogram ``` 在 `clean` 目标中,`rm -f *.o` 和 `rm -f myprogram` 是两个独立的 Shell 命令,分别由不同的 Shell 实例执行。 如果希望在同一个 Shell 上下文中执行多个命令,可以使用如下方式: ```makefile setup: cd /tmp && mkdir -p testdir && touch testdir/file.txt ``` 这 `cd`、`mkdir` 和 `touch` 都在同一个 Shell 实例中运行,因此能正确创建目录并生成文件。 ### 3. 使用 `eval` 和 `shell` 函数组合 `$(eval ...)` 函数可以动态定义变量或规则,结合 `$(shell ...)` 可以实现更复杂的逻辑。 示例: ```makefile define RUN_SCRIPT $(shell echo "Running script for target: $1") $(shell ./scripts/$1.sh) endef test_script: $(call RUN_SCRIPT,test) ``` 此示例定义了一个宏 `RUN_SCRIPT`,它接受一个参数 `$1` 并调用对应的 Shell 脚本 `scripts/$1.sh`。 ### 4. 使用 `MAKE_SHELL` 或自定义 SHELL 默认情况下,Make 使用 `/bin/sh` 来执行命令。可以通过 `SHELL` 变量指定不同的 Shell 解释器,例如 `bash`,以支持更高级的 Shell 特性。 示例: ```makefile SHELL := /bin/bash use_bash: @echo "Current shell is: $SHELL" @echo "Using Bash-specific features: $(BASH_VERSION)" ``` 通过设置 `SHELL` 变量为 `/bin/bash`,可以在规则中使用 Bash 的特性(如数组、条件表达式等)[^4]。 ### 5. 使用 `subshell` 和 `export` 控制 Shell 行为 由于 Make 为每个动作启动一个新的 Shell 实例,因此如果需要在多个动作之间共享状态,可以使用 `export` 导出变量,或在同一个动作中执行多个命令。 示例: ```makefile export VAR = value share_state: echo "VAR is $$VAR" ``` 这 `VAR` 被导出为环境变量,可以在 Shell 中通过 `$VAR` 访问。 ### 6. 使用 `:=` 或 `=` 控制变量展开时机 Makefile 中的变量定义可以使用 `=` 或 `:=`。`=` 表示递归展开变量,而 `:=` 表示立即展开变量。在调用 Shell 命令时,推荐使用 `:=` 以避免变量在后续展开时导致意外行为。 示例: ```makefile VAR1 = $(shell echo "This is VAR1") VAR2 := $(shell echo "This is VAR2") print_vars: @echo "VAR1: $(VAR1)" @echo "VAR2: $(VAR2)" ``` 由于 `VAR1` 使用 `=` 定义,其值在使用时才会展开;而 `VAR2` 使用 `:=` 定义,其值在定义时就已经展开[^2]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值