由于这里不重要的原因,我有一个源代码,我会自动逐个文件地处理源代码,并以系统的方式重命名处理后的源文件。例如,我从名为的文件开始
fun1.c fun2.c
并最终得到文件
fun1_a.c fun2_a.c
我也希望 Makefile 能够自动调整。 Makefile 的基本版本是
SRC= fun1.c fun2.c
%.o: $.c
$(CC) $(CFLAGS) -c $< -o $@
OBJ= $(SRC:.c=.o)
fun2.o: fun1.o
如何最好地处理文件,以便根据需要更改源文件和依赖项定义中的每个条目,但模式规则保持不变?换句话说,我需要的是:
SRC= fun1_a.c fun2_a.c
%.o: $.c
$(CC) $(CFLAGS) -c $< -o $@
OBJ= $(SRC:.c=.o)
fun2_a.o: fun1_a.o
我认为这是微不足道的,但我的脚本编写能力,尤其是sed
和perl
是有限的。
编辑:请注意,在实践中,并非所有文件都会被调用,funx.c
其中x
是整数,因此我正在寻找一种适用于任何文件名的解决方案。
答案1
我建议创建整个源代码树的副本,然后修改副本目录中的文件而不重命名它们。这样你就不需要修改makefile。作为奖励,您只需通过比较目录即可了解更改的概述。
而不是这个
project
fun1.c
fun1_mod.c
fun2.c
fun2_mod.c
Makefile
Makefile_mod
你有这个
project
fun1.c
fun2.c
Makefile
project_mod
fun1.c
fun2.c
Makefile
阐述
如果 makefile 非常简单,就像您的示例一样,您可能可以使用 sed 修改 makefile 中的文件名。但 makefile 是神秘的野兽。具有大量隐式规则和多级变量扩展。
即使在简单的 makefile 中,修改文件名也是很常见的情况。甚至你的 makefile 也有一些文件名修改 ( OBJ= $(SRC:.c=.o)
)。这能如果使用 sed 更改某些内容,会得到意想不到的结果。
像这样的常见通配符*.c
很容易最终收集比预期更多的文件。尝试编写通配符来排除或包含后缀就像放牧猫一样。
如果原始源文件和修改后的源文件位于同一目录中,您永远无法确定原始源文件是否是由修改后的 makefile 无意中编译的,反之亦然。
而且,我预感到,你不会只有一项修改。你会有很多。所以不仅仅是fun1_mod.c
“fun2_mod.c
但是”_mod1
_mod2
_mod3
_mod3butpartmod1
等等。
您将永远头痛于弄清楚哪个二进制文件是从哪个 modset 编译出来的。
因此,为每次修改创建整个源代码树的副本。修改各个目录下的源码。保持文件名相同。保持 makefile 相同。
这样你就进入一个目录并编译。转到其他目录并编译。总是相同的 makefile。并且始终确定将编译哪些文件。 (除非 makefile 从父目录和同级目录中获取源文件,但这不是常见的做法,并且在 makefile 社区中是不受欢迎的。)
奖金:
您可以使用您喜欢的目录比较工具轻松查看一个 modset 与另一个 modset 之间的区别。
您可以将修改保留在源代码管理中,例如 git。每个模组一个分支。您可以在主分支中进行更改并将其传播到其他分支。你可以挑选周围的变化。你可以向同事推拉。
答案2
假设原始文件名是静态的,只有重命名操作的结果是不可预测的。重命名文件时,会生成一个附加文件,其中包含原始文件名到新名称的映射,例如:
fun1.c=fun1_a.c
fun2.c=fun2_a.c
假设生成的映射文件名为rename.mk
,可以Makefile
通过以下方式修改:
include rename.mk
SRC= $(fun1.c) $(fun2.c)
%.o: $.c
$(CC) $(CFLAGS) -c $< -o $@
OBJ= $(SRC:.c=.o)
$(fun2.c:.c=.o): $(fun1.c:.c=.o)
文件名已成为变量名,并用于通过rename.mk
.