makefile 中的预构建步骤

发布于 2024-08-08 21:19:02 字数 389 浏览 6 评论 0原文

如何运行必须在所有其他 makefile 命令之前执行的脚本?如果没有要构建的内容,则不执行脚本会很好(但不是强制性的)。

我搜索过 SO 和 Google,但找不到任何东西。

我有一个解决方法:

# myscript.bat output is empty
CHEAT_ARGUMENT = (shell myscript.bat)
CFLAGS += -DCHEAT_ARGUMENT=$(CHEAT_ARGUMENT)
AFLAGS += -DCHEAT_ARGUMENT=$(CHEAT_ARGUMENT)

但它非常丑陋。还有其他方法可以在 ma​​kefile 中运行“预构建步骤”吗?

How can I run a script, which must execute before all other makefile commands? And it will be nice (but not mandatory) to the script is not executed if there is nothing to build.

I've searched SO and Google, but can't find anything.

I have this workaround:

# myscript.bat output is empty
CHEAT_ARGUMENT = (shell myscript.bat)
CFLAGS += -DCHEAT_ARGUMENT=$(CHEAT_ARGUMENT)
AFLAGS += -DCHEAT_ARGUMENT=$(CHEAT_ARGUMENT)

But it's very ugly. Is there other way to run "pre-build step" in makefile?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

马蹄踏│碎落叶 2024-08-15 21:19:02

我提出两种解决方案。第一个模仿 NetBeans IDE 生成的内容:

CC=gcc

.PHONY: all clean

all: post-build

pre-build:
    @echo PRE

post-build: main-build
    @echo POST

main-build: pre-build
    @$(MAKE) --no-print-directory target

target: $(OBJS)
    $(CC) -o $@ $(OBJS)

clean:
    rm -f $(OBJS) target

第二个受 Eclipse IDE 生成的内容启发:

CC=gcc

.PHONY: all clean
.SECONDARY: main-build

all: pre-build main-build

pre-build:
    @echo PRE

post-build:
    @echo POST

main-build: target

target: $(OBJS)
    $(CC) -o $@ $(OBJS)
    @$(MAKE) --no-print-directory post-build

clean:
    rm -f $(OBJS) target

请注意,在第一个中,无论主构建是否确定为最新,总是调用预构建和后构建。

在第二个中,如果主构建的状态是最新的,则不会执行构建后步骤。而预构建步骤始终在两者中执行。

I propose two solutions. The first mimics what NetBeans IDE generates:

CC=gcc

.PHONY: all clean

all: post-build

pre-build:
    @echo PRE

post-build: main-build
    @echo POST

main-build: pre-build
    @$(MAKE) --no-print-directory target

target: $(OBJS)
    $(CC) -o $@ $(OBJS)

clean:
    rm -f $(OBJS) target

The second one is inpired by what Eclipse IDE generates:

CC=gcc

.PHONY: all clean
.SECONDARY: main-build

all: pre-build main-build

pre-build:
    @echo PRE

post-build:
    @echo POST

main-build: target

target: $(OBJS)
    $(CC) -o $@ $(OBJS)
    @$(MAKE) --no-print-directory post-build

clean:
    rm -f $(OBJS) target

Note that in the first one, pre and post builds are always called regardless of whether the main build is determined to be up to date or not.

In the second one, the post-build step is not executed if the state of the main build is up to date. While the pre-build step is always executed in both.

送君千里 2024-08-15 21:19:02

根据您的 make 版本,如果 CFLAGS 和 AFLAGS 被评估数十次,类似下面的内容应该至少避免运行数十次:

CHEAT_ARG := $(shell myscript)

注意冒号。

这仅运行一次。绝不会超过一次,但也绝不会少于一次。选择你自己的权衡。

更新 对于 GNU make 3.80 或更高版本,延迟简单变量扩展可能有助于执行脚本零次(如果不需要)或一次(如果需要一次或多次)。该实现涉及一些重要的技巧,链接的文章对此进行了全面的描述。 TLDR,适用于这个问题的示例:

CHEAT_ARG = $(eval CHEAT_ARG := $(shell myscript))$(CHEAT_ARG)

Depending on your make version, something like the following should at least avoid running dozens of times if CFLAGS and AFLAGS are evaluated dozens of times:

CHEAT_ARG := $(shell myscript)

Note the colon.

This runs exactly once. Never more than once, but also never less than once. Choose your own tradeoffs.

Update For GNU make 3.80 or above, deferred simple variable expansion might be helpful to execute the script zero times (if it is not needed) or one time (if it is needed one or more times). The implementation involves some non-trivial trickery, which the linked article describes comprehensively. TLDR, adapted for this question's example:

CHEAT_ARG = $(eval CHEAT_ARG := $(shell myscript))$(CHEAT_ARG)
虫児飞 2024-08-15 21:19:02

您可以向 Makefile 添加一个特殊目标,并使所有构建规则都依赖于此:

run-script:
    myscript

.o.c: run-script
     $(CC) $(CFLAGS) -o $@ 
lt;

.o.S: run-script
     $(AS) $(AFLAGS) -o $@ 
lt;

根据您的脚本实际执行的操作,将其在 Makefile 之前的阶段(autoconf 术语中的配置阶段)运行一次可能更有意义(并且减少工作量)。

You could add a special target to your Makefile and have all your build rules depend on that:

run-script:
    myscript

.o.c: run-script
     $(CC) $(CFLAGS) -o $@ 
lt;

.o.S: run-script
     $(AS) $(AFLAGS) -o $@ 
lt;

Depending on what your script actually does, putting it to run once in a stage before the Makefile (configure stage in autoconf terms) could make even more sense (and be less work).

一刻暧昧 2024-08-15 21:19:02

你的提议似乎有点“不合时宜”。为什么不直接在您需要它之前运行的任何 makefile 目标中运行该命令呢?

例如,如果您需要它在链接 foo 之前运行:

foo: ${OBJS}
    my-command-goes-here
    ${CC} -o $@ ${OBJS} ${LIBS}

What you are proposing seems a bit "un-make-like". Why not just run the command in whatever makefile target you need it to go before?

Example, if you need it to run before linking foo:

foo: ${OBJS}
    my-command-goes-here
    ${CC} -o $@ ${OBJS} ${LIBS}
噩梦成真你也成魔 2024-08-15 21:19:02

谢谢您的回答。 ndim对我帮助很大,asveikau。最终文件是一个二进制可执行文件,因此我现在可以使用如下内容:

run-script:
    myscript
$(AXF_FILE): run-script $(OBJ_DIRS) $(OBJ_FILES)
    $(LINK) #......

它将运行 myscript 一次。 {AXF_FILE} 值取决于 myscript,我必须之前运行它。在这种情况下,myscript 始终运行,而不仅仅是在需要重建时才运行。
之后,我想到了最简单的答案

all: run-script $(AXF_FILE)

那就是全部;)(当然,可以使用任何目标而不是“全部”)


编辑:此方法也在计算$(AXF_FILE)后执行脚本。因此可能会得到错误的 AXF_FILE 值。
现在只有 ndim 的第一个答案可以满足我的需要。

Thank you for answers. ndim helped me much, asveikau. The final file is one binary executable, so I can use now something like this:

run-script:
    myscript
$(AXF_FILE): run-script $(OBJ_DIRS) $(OBJ_FILES)
    $(LINK) #......

It will run myscript once. {AXF_FILE} value depends on myscript and I must run it before. And in this case myscript runs always, not only when rebuild is needed.
After, The Simplest Answer came to my mind:

all: run-script $(AXF_FILE)

That's all ;) (Of course, any target can be used instead of "all")


Edit: this method execute script after $(AXF_FILE) is calculated too. So it's possible to get wrong value of AXF_FILE.
Now only the first answer by ndim works as I need.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文