sed 的表达式在 Makefile 中做什么

What does sed 's expression do in a Makefile

我有一个旧项目的 Makefile,我必须针对新系统对其进行修改。它的源文件和目标文件具有以下全局定义:

SRCFILES = $(wildcard *.c) $(wildcard tasks/*.c) 
SRCDIR = .
OBJDIR = objdir
OBJFILES = $(SRCFILES:%.c=${OBJDIR}/%.o)

Makefile 是一团糟,我不得不大量修改它。我设法编译代码并从 .c 源代码生成 .o 文件。预期的 .elf 文件也已正确编译。

问题是我无法理解以下几行中的代码在做什么我搜索了很多网站但没有运气。有什么想法吗?

 sed 's,^\(.*\)\.o[ :]*,$(@D)/.o $(@D)/.d : ,g' < $@.$$$$ > $@; \
 rm -f $@.$$$$

makefile如下

lwip.elf: build_echo $(OBJFILES)
 @set -e; echo Linking the object files...; \
 sparc-elf-gcc $(OBJFILES) -o $@;
 @echo Successfully linked the files
 @echo lwip.elf file ready to load...

build_echo: httpserver_raw/fsdata.c
 @echo Building the source files first...
 @echo The Modified or New source code to be build are :

clean:
 - rm -f lwip.elf 

$(OBJDIR)/%.o: $(SRCDIR)/%.c
 @set -e; echo '    $<'; \
 sparc-elf-gcc-4.4.2 -Wall -O2 -g -msoft-float -mcpu=v8 -c -o $@ $(CFLAGS) -I. -I lwip/include -I lwip/include/ipv4 -I lwip/leon3 $<

$(OBJDIR)/%.d: $(SRCDIR)/%.c
 @set -e; rm -f $@; mkdir -p $(@D); \
 sparc-elf-gcc -MM -I. -I lwip/include -I lwip/include/ipv4 -I lwip/leon3 $< > $@.$$$$; \
 sed 's,^\(.*\)\.o[ :]*,$(@D)/.o $(@D)/.d : ,g' < $@.$$$$ > $@; \
 rm -f $@.$$$$

-include $(patsubst %.c,$(OBJDIR)/%.d,$(SRCFILES))

注:sparc-elf-gcc是sparcV8架构专用的交叉编译器

里面发生了很多事情:

sed 's,^\(.*\)\.o[ :]*,$(@D)/.o $(@D)/.d : ,g' < $@.$$$$ > $@; \
 rm -f $@.$$$$

让我们分解一下。

  1. sed 命令本身:sed 's,^\(.*\)\.o[ :]*,$(@D)/.o $(@D)/.d : ,g',
  2. 其输入从 @.$$$$ 指定的文件重定向 (<),并且
  3. 其输出被重定向(>)到$@指定的文件,然后
  4. 有一个第二个命令,rm -f $@.$$$$

此外,这是在更大的命令列表的上下文中,它使用

进行设置
@set -e; rm -f $@; mkdir -p $(@D); \
 sparc-elf-gcc -MM -I. -I lwip/include -I lwip/include/ipv4 -I lwip/leon3 $< > $@.$$$$;

在解释它时,您必须首先识别几个 make 隐含变量:

  • $@,表示规则的目标名称
  • $(@D),表示目标名称的目录(目标的dirname
  • $<,代表第一个先决条件

接下来,您需要认识到美元符号对 make 具有特殊含义,因此如果您想要文字 $,则需要将其加倍。 $$$$ 简单地重复这个,所以传递给 shell 的只是两个美元符号 ($$)。 shell 反过来用它自己的进程 ID 替换它——这是一种相对常见(但仍然不安全)的用于生成唯一文件名的习惯用法。

因此,您从标注中省略的命令部分确保目标的目标目录存在,然后运行一个(交叉?)带有标志的 gcc,使其发出有关 header 依赖项的信息.这些被捕获在一个文件中,例如 objdir/src.d.12345,然后在您调用的部分中,该文件被重定向到 sed,输出到最终目标,例如 objdir/src.d ,之后删除中间文件。

sed 命令本身正在对所有行执行替换 (s),将模式 ^\(.*\)\.o[ :]* 的每个出现 (g) 替换为替换我马上回来。首先是图案。 ^ 将模式锚定到一行的开头。 \(\) 是分隔捕获组的元字符,里面的 .* 匹配任意数量的任意字符。紧随其后的必须是文字小数点、\.o 和零次或多次出现或 space 和冒号字符 ([ :]*)。例如,这将匹配此,直到但不包括 header 名称:

objdir/tasks/t1.o : my_header.h

替换使用前面提到的 $(@D) -- 它由 make 扩展,而不是 shell 或 sed -- 和 </code>,其中 <code>sed 扩展为与第一个捕获组匹配的文本。因此,这会将上面的示例行转换为:

objdir/tasks/t1.o objdir/tasks/t1.d : my_header.h

简而言之,所有这一切都是说它对计算出的依赖项列表进行处理,使作为规则列表本身目标的依赖项文件依赖于相应 object 的所有相同文件文件确实如此。