如何使用Makefile将多个文件提供给后台进程

我有一个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 $@

注意:我还使用空虚拟文件(服务器)将服务器标记为正在运行,并仅在虚拟配方中需要时启动它.这避免了将其作为每个虚拟对象的先决条件并重新构建虚拟对象,如果其对应的源文件未更改但服务器未运行.

点赞