我有一个Makefile,其中单个目标依赖于多个文件 – 每个文件必须单独处理(不提供中间输出文件).我的具体情况更复杂:
我有C源,我想从中提取枚举定义.有一些皱纹我无法改变:
>编译器不是GCC – 它是由Cosmic Software制作的自定义编译器.
>除了编译器,我可以自己运行解析器(让我们称之为parser.exe),它有选项(-e)在STDOUT上输出预处理源.
> make实际上是PTC Integrity软件包附带的专有版本.它不支持循环 – 如果我想使用循环,我必须做Windows批处理脚本.
>这一切都在Windows上运行
我编写了一个实用程序(使用C#和ANTLR),我们称之为ExtractEnums.exe,它从C源中提取枚举(并计算表达式),只要该源已经过预处理.整个预处理源的重量超过30 MB.我没有使用Cosmic解析器将预处理的源写入磁盘,而是选择将其传输到ExtractEnums.exe.因为我需要为每个源文件调用解析器,所以我需要使用命名管道而不仅仅是管道(|)运算符.在Windows上,命名管道不会获得真正的文件名,这就是为什么你会看到ExtractEnums.exe -client写入管道和后台进程ExtractEnums.exe -server,它在下面的例子中从管道中读取.
############################################################################
# Dummy files - these will never exist
#
D_FILES = $(SRCS:.c=.dummy) # All dummy files
server :
cmd /c start /B ExtractEnums.exe -server > temp.pipe
%.dummy : %.c server
cmd /c parser.exe $(DEFINES_AND_OPTS) -e $^ | cmd /c ExtractEnums.exe -client
# Extract enums from all the preprocessed source:
%.enums : $(D_FILES)
cmd /c echo ;;exit;; | cmd /c ExtractEnums.exe -client
cmd /c move temp.pipe $@
如果我调用make product_name.enums,这一切都会运行. SRCS是所有源文件的列表. ;;出口;;是一个特殊的字符串,我发送到ExtractEnums.exe -server告诉它退出.这是问题所在:
为了遍历所有源并将它们提供给预处理器,我制作了一个永远不存在的.dummy文件列表.由于它们永远不存在,因此目标总是过时的.这意味着即使源未更改,调用make product_name.enums也将始终通过预处理器运行所有源.
我意识到我已经提出了一个复杂的解决方案.如果你有一个更简单的方法来解决这个问题,我愿意接受建议 – 在这种情况下,我会编辑这个问题的名称是合适的.
最佳答案 在解决类似的问题时,我遇到了这个老问题.只需将“虚拟”文件转换为实际(空)文件即可跟踪上次处理源文件的时间.在下面我将它们分组在一个子目录(虚拟对象)中,这样它们就不会对源树产生太多干扰:
D_DIR = dummies
D_FILES = $(patsubst %.c,$(D_DIR)/%.dummy,$(SRCS)) # All dummy files
$(D_DIR)/%.dummy : %.c
[ -f server ] || { cmd /c start /B ExtractEnums.exe -server > temp.pipe && touch server; }
cmd /c parser.exe $(DEFINES_AND_OPTS) -e $^ | cmd /c ExtractEnums.exe -client
mkdir -p $(dir $@) # create dummy's directory if it does not exist
touch $@ # create dummy
# Extract enums from all the preprocessed source:
%.enums : $(D_FILES)
cmd /c echo ;;exit;; | cmd /c ExtractEnums.exe -client
rm -f server
cmd /c move temp.pipe $@
注意:我还使用空虚拟文件(服务器)将服务器标记为正在运行,并仅在虚拟配方中需要时启动它.这避免了将其作为每个虚拟对象的先决条件并重新构建虚拟对象,如果其对应的源文件未更改但服务器未运行.