Makefile 强制脚本在生成文件的开头运行,并显示其输出

Makefile 强制脚本在生成文件的开头运行,并显示其输出,makefile,gnu-make,Makefile,Gnu Make,我有一个脚本,它生成一个version.h文件,其中包含关于特定构建的各种详细信息 该脚本运行各种命令,例如: readonly VERSION=$(git describe --always --dirty --long --tags) readonly NUM_COMMITS=$(git rev-list HEAD | wc -l | bc) readonly BRANCH=$(git rev-parse --abbrev-ref HEAD) readonly AHEAD_BY=$(git

我有一个脚本,它生成一个
version.h
文件,其中包含关于特定构建的各种详细信息

该脚本运行各种命令,例如:

readonly VERSION=$(git describe --always --dirty --long --tags)
readonly NUM_COMMITS=$(git rev-list HEAD | wc -l | bc)
readonly BRANCH=$(git rev-parse --abbrev-ref HEAD)
readonly AHEAD_BY=$(git log --oneline origin/${BRANCH}..${BRANCH} | wc -l | bc)
readonly NUM_UNTRACKED=$(git ls-files --exclude-standard --others --full-name -- . | wc -l | bc)
readonly HOSTNAME=$(hostname)
然后,它写入一个临时文件,对照先前生成的文件进行检查,如果它们不同,则用新文件覆盖旧的
version.h

#pragma once

/*
 * Version information
 *
 * - This is a generated file - do not edit
 */

namespace foo { namespace app {

static const char VERSION[]       = "26b75cd";
static const char NUM_COMMITS[]   = "224";
static const char BRANCH[]        = "master";
static const char AHEAD_BY[]      = "0";
static const char NUM_UNTRACKED[] = "0";
static const char USER[]          = "steve";
static const char HOSTNAME[]      = "steve-linux";
static const char BUILD_VARIANT[] = "debug";
static const char BUILD_DATE[]    = __DATE__ " "  __TIME__;

}}
当文件更新时,它也会打印到标准输出

version updated: 26b75cd
版本脚本应该是运行的第一件事,并且应该在每次调用makefile时运行

目前,我通过在makefile中使用一个简单的扩展变量来实现这一点

new_ver := $(shell ./app/gen_version.sh $(BUILD))
它可以工作,但是脚本的任何输出都被捕获在
new\u var
中,我无法显示该输出

这是一个可以接受的权衡(不显示新版本),但在理想情况下,我希望显示脚本输出

我不确定添加到默认
all
目标中的
.PHONY
目标是否有效,因为每个应用程序都有自己的目标,因此您可以构建它

define do-make-bin
    binaries += $(addprefix $(BIN_DIR),$1)
    bin_sources += $2

    # a target so users can call 'make <bin-name>' and build only the bin and its dependencies
    $1: $(addprefix $(BIN_DIR),$1)

    # the target to build the actual binary
    $(addprefix $(BIN_DIR),$1): $(call src_to_obj,$2) $(addsuffix .so,$(addprefix $(LIB_DIR)lib,$3)) $(addsuffix .a,$(addprefix $(LIB_DIR)lib,$4))
    @$(CXX) $(call src_to_obj,$2) -L/usr/lib -L$(SDK_LIB_DIR) -L$(LIB_DIR) $(TARGET_LINK_FLAGS) -Wl$(,)-Bstatic $(addprefix -l,$4) $(addprefix -l,$6) -Wl$(,)-Bdynamic -Wl$(,)-rpath$(,)$(RPATH) $(linkpath) -L$(LIB_DIR) $(sdk_libs) $(tcmalloc_libs) -lpthread -lrt $(addprefix -l,$3) $(addprefix -l,$5) -rdynamic -o $$@
endef
define do make bin
二进制文件+=$(addprefix$(BIN_DIR),$1)
bin_来源+=$2
#一个目标,以便用户可以调用“make”并仅构建bin及其依赖项
$1:$(addprefix$(BIN_DIR),$1)
#构建实际二进制文件的目标
$(addprefix$(BIN_DIR),$1:$(调用src_to_obj,$2)$(addsuffix.so,$(addprefix$(LIB_DIR)LIB,$3))$(addsuffix.a,$(addprefix$(LIB_DIR)LIB,$4))
@$(CXX)$(调用src_to_obj,$2)-L/usr/lib-L$(SDK_lib_DIR)-L$(lib_DIR)$(目标链接标志)-Wl$(,)-Bstatic$(addprefix-L,$4)$(addprefix-L,$6)-Wl$(,)-Bdynamic-Wl$(,)-rpath$(rpath)$(linkpath)-L$(lib DIR)$(sdkmallulibs)$(tcoc-libs)-thread-lrt(addprefix-L,$5)$(add-rdo)前缀,$$$@
恩德夫

调用
make foo
仍应检查当目标没有先决条件且存在时,是否需要更新
version.h

。您需要的是在创建临时文件时设置一个有条件的先决条件。您可以使用gnu/make的
通配符
功能

如果临时文件被调用为
version.new.h
,并假设脚本检查
version.h
version.new.h
之间的差异。如果它们相同,则会将其删除。然后,您可以使用以下内容:

version.h : $(wildcard version.new.h)
       mv -f version.new.h version.h
为了验证是否首先创建了.h版本,您应该拆分作业。 然后确保第一个作业首先运行。
Makefile
代码的示例如下:

all: version_h other_staff

.PHONY: version_h
version_h:
    ./app/gen_version.sh $(BUILD)
    $(MAKE) version.h

version.h : $(wildcard version.new.h)
    mv -f version.new.h version.h

other_staff: $(EXE) $(LIBS)

如果您限制自己使用普通的makefile方法,那么确保它在每个目标之前运行的唯一方法是将内容放入配方中,然后使构建该内容的目标成为makefile中每个目标的先决条件。虽然这可以通过这样一种方式来完成,它不会每次都导致所有的东西都重建,但这太糟糕了。另外,它不允许您将输出放入一个变量中,如
new\u ver
(您说您想显示它,但不说您是否也需要在变量中显示它)

但是,如果唯一的问题是您没有显示
new\u ver
的值,那么问题就简单地解决了:

new_ver := $(shell ./app/gen_version.sh $(BUILD))
$(info $(new_ver))

这是最简单的方法。我不知道你说“更优雅”是什么意思。@Madscietist抱歉,我已经编辑了这个问题。考虑到您的回复,我意识到我试图克服的问题是,在为响应分配感谢之后,我无法
echo$(新版本)
。将
version\u h
添加到
all
仅当我们正在构建的目标是
all
时有效。无论目标是什么,我如何让它运行?@SteveLorimer如果
all
是默认情况下它将工作的第一个目标。正如@MadScientist所提到的,最明显的反应是将其声明为每个目标的
先决条件。我以为你已经知道了,你不想做这件事,因为它的开销。因此,我提出了上述解决方法。无论如何,我会编辑完整的回复谢谢-太简单了,我现在感觉很蹩脚如果
$(新版本)
为非空,是否有方法仅调用
$(信息…
呢?更不用说-使用了
ifdef新版本
,效果非常好。再次感谢!