首页 > 解决方案 > sed 的表达式在 Makefile 中做了什么

问题描述

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

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

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

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

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

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

注意:这sparc-elf-gcc是用于 sparcV8 架构的特殊交叉编译器。

标签: makefilesparc

解决方案


里面发生了很多事情:

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

让我们分解一下。

  1. sed命令本身:sed 's,^\(.*\)\.o[ :]*,$(@D)/\1.o $(@D)/\1.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,使其发出有关标头依赖项的信息。这些被捕获在一个文件中,例如objdir/src.d.12345,然后在您调用的部分中,该文件被重定向到sed,输出到最终目标,例如objdir/src.d,之后中间文件被删除。

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

objdir/tasks/t1.o : my_header.h

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

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

简而言之,就是说它修改了计算出的依赖关系列表,以使作为规则列表本身目标的依赖文件依赖于相应目标文件所做的所有相同文件。


推荐阅读