如何动态包含makefile?

发布于 2024-09-30 15:10:42 字数 777 浏览 10 评论 0原文

是否可以动态包含 Makefile?例如取决于某些环境变量?我有以下 Makefile:

makefile
app1.1.mak
app1.2.mak

并且有一个环境变量 APP_VER 可以设置为 1.1.0.1、1.1.0.2、1.2.0.1、1.2.0.2。
但是 1.1 和 1.2 行只有两个不同的 makefile。

我尝试编写以下 Makefile:

MAK_VER=$$(echo $(APP_VER) | sed -e 's/^\([0-9]*\.[0-9]*\).*$$/\1/')  
include makefile$(MAK_VER).mak  

all: PROD  
        echo MAK_VER=$(MAK_VER)  

但它不起作用:

$ make all
"makefile$(echo", line 0: make: Cannot open makefile$(echo
make: Fatal errors encountered -- cannot continue.

更新:

据我了解 make 在计算宏之前包含文件。
这就是为什么它尝试执行以下语句

include makefile.mak

而不是

include makefile1.1.mak

Is it possible to include Makefiles dynamically? For example depending on some environment variable? I have the following Makefiles:

makefile
app1.1.mak
app1.2.mak

And there is an environment variable APP_VER which could be set to 1.1.0.1, 1.1.0.2, 1.2.0.1, 1.2.0.2.
But there will be only two different makefiles for 1.1 and 1.2 lines.

I have tried to write the following Makefile:

MAK_VER=$(echo $(APP_VER) | sed -e 's/^\([0-9]*\.[0-9]*\).*$/\1/')  
include makefile$(MAK_VER).mak  

all: PROD  
        echo MAK_VER=$(MAK_VER)  

But it does not work:

$ make all
"makefile$(echo", line 0: make: Cannot open makefile$(echo
make: Fatal errors encountered -- cannot continue.

UPDATE:

As far as I understand make includes files before it calculates macros.
That's why it tries to execute the following statement

include makefile.mak

instead of

include makefile1.1.mak

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

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

发布评论

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

评论(3

一生独一 2024-10-07 15:10:42

您有两个问题:您获取版本的方法太复杂,并且您的 include 行有缺陷。试试这个:

include app$(APP_VER).mak

如果 APP_VER 是一个环境变量,那么这将起作用。如果您还想包含名为 makefile 的 makefile(即,如果 makefile 不是我们正在编写的文件),请尝试以下操作:

include makefile app$(APP_VER).mak

请注意,这被视为一个坏主意。如果 makefile 依赖于环境变量,则它将对某些用户起作用,而对其他用户不起作用,这被认为是不良行为。

编辑:

这应该可以做到:

MAK_VER := $(subst ., ,$(APP_VER))
MAK_VER := $(word 1, $(MAK_VER)).$(word 2, $(MAK_VER))

include makefile app$(MAK_VER).mak

You have two problems: your method of obtaining the version is too complicated, and your include line has a flaw. Try this:

include app$(APP_VER).mak

If APP_VER is an environmental variable, then this will work. If you also want to include the makefile called makefile (that is, if makefile is not the one we're writing), then try this:

include makefile app$(APP_VER).mak

Please note that this is considered a bad idea. If the makefile depends on environmental variables, it will work for some users and not others, which is considered bad behavior.

EDIT:

This should do it:

MAK_VER := $(subst ., ,$(APP_VER))
MAK_VER := $(word 1, $(MAK_VER)).$(word 2, $(MAK_VER))

include makefile app$(MAK_VER).mak
疏忽 2024-10-07 15:10:42

试试这个:

MAK_VER=$(shell echo $(APP_VER) | sed -e 's/^\([0-9]*\.[0-9]*\).*$/\1/')
MAK_FILE=makefile$(MAK_VER).mak

include $(MAK_FILE)

all:
    echo $(MAK_VER)
    echo $(MAK_FILE)

Try this:

MAK_VER=$(shell echo $(APP_VER) | sed -e 's/^\([0-9]*\.[0-9]*\).*$/\1/')
MAK_FILE=makefile$(MAK_VER).mak

include $(MAK_FILE)

all:
    echo $(MAK_VER)
    echo $(MAK_FILE)
给不了的爱 2024-10-07 15:10:42

修改大纲解决方案

有四个 makefile:

  • makefile
  • app1.1.mak
  • app1.2.mak
  • appdummy.mak

app.dummy.mak makefile 可以为空 - 如果您愿意,可以为 /dev/null 的符号链接。 app.1.1.mak 和 app.1.2.mak 均与当前内容相同。

主 makefile 略有变化:

MAK_VER = dummy
include makefile$(MAK_VER).mak  

dummy:  
        ${MAKE} MAK_VER=$(echo $(APP_VER) | sed -e 's/^\([0-9]*\.[0-9]*\).*$/\1/') all

all: PROD
        ...as now...

如果您输入 make,它将读取(空)虚拟 makefile,然后尝试构建 dummy 目标,因为它首先出现。 ,它将再次运行 make,并在命令行上使用 APP_VER=1.1APP_VER=1.2

make APP_VER=1.1 all

要构建虚拟目标 无法在 makefile 中更改命令行,因此这会覆盖 makefile 中的行。因此,第二次调用 make 将读取正确的版本特定 makefile,然后构建 all

这种技术有局限性,最明显的是,安排每个目标都这样对待是很繁琐的。有很多方法可以解决这个问题,但通常不值得。


项目组织

更严重的是,我认为您需要全面审查您正在做的事情。您可能正在使用版本控制系统 (VCS) 来管理源代码。另外,1.1 版和 1.2 版源代码之间可能存在一些(显着)差异。因此,为了能够构建 1.1 版本,您必须从 1.1 版本维护分支切换到 1.2 版本开发分支,或者类似的操作。那么,为什么 makefile 不只是版本为 1.1 或 1.2 呢?如果在版本之间切换,则需要清除可能使用错误源构建的所有派生文件(目标文件、库、可执行文件等)。你必须把源代码改过来。那么为什么不改变 makefile 呢?

调用 make 的构建脚本

我还观察到,由于您有环境变量 APP_VER 驱动您的进程,因此您可以通过需要一个标准化的“make 调用程序”来解决问题,该标准化的“make 调用程序”会整理 APP_VER 值并调用 make 。 > 正确。假设该脚本名为 build

#!/bin/sh
: ${APP_VER:=1.2.0.1}  # Latest version is default
case $APP_VER in
[0-9].[0-9].*)
    MAK_VER=`echo $APP_VER | sed -e 's/^\(...\).*/\1/'`
    ;;
*)  echo "`basename $0 .sh`: APP_VER ($APP_VER) should start with two digits followed by dots" 1>&2;
    exit 1;;
esac
exec make MAK_VER=$MAK_VER "$@"

该脚本验证 APP_VER 是否已设置,如果未设置,则给出适当的默认值。然后,它处理该值以导出 MAK_VER(如果不正确则出错)。当然,您需要在达到版本 10 后修改该测试,因为您计划取得成功,以便在适当的时候达到两位数的版本号。

给定正确的版本信息,您现在可以使用任何命令行参数调用 makefile。

makefile 可以非常简单:

MAK_VER = dummy

include app$(MAK_VER).mak  

all: PROD
        ...as now...

appdummy.mak 文件现在包含一条规则:

error:
        echo "You must invoke this makefile via the build script" 1>&2
        exit 1

它只是指出进行构建的正确方法。

请注意,如果将 VCS 下的产品版本号保存在文件中,然后脚本从该文件中读取版本号,则可以避免使用 APP_VER 环境变量。该脚本还可以完成各种其他工作,确保安装正确的工具、设置其他环境变量等等。

Modifying the outline solution

Have four makefiles:

  • makefile
  • app1.1.mak
  • app1.2.mak
  • appdummy.mak

The app.dummy.mak makefile can be empty - a symlink to /dev/null if you like. Both app.1.1.mak and app.1.2.mak are unchanged from their current content.

The main makefile changes a little:

MAK_VER = dummy
include makefile$(MAK_VER).mak  

dummy:  
        ${MAKE} MAK_VER=$(echo $(APP_VER) | sed -e 's/^\([0-9]*\.[0-9]*\).*$/\1/') all

all: PROD
        ...as now...

If you type make, it will read the (empty) dummy makefile, and then try to build the dummy target because it appears first. To build the dummy target, it will run make again, with APP_VER=1.1 or APP_VER=1.2 on the command line:

make APP_VER=1.1 all

Macros set on the command line cannot be changed within the makefile, so this overrides the line in the makefile. The second invocation of make, therefore, will read the correct version-specific makefile, and then build all.

This technique has limitations, most noticeably that it is fiddly to arrange for each and every target to be treated like this. There are ways around it, but usually not worth it.


Project organization

More seriously, I think you need to review what you're doing altogether. You are, presumably, using a version control system (VCS) to manage the source code. Also, presumably, there are some (significant) differences between the version 1.1 and 1.2 source code. So, to be able to do a build for version 1.1, you have to switch from the version 1.1 maintenance branch to the version 1.2 development branch, or something along those lines. So, why isn't the makefile just versioned for 1.1 or 1.2? If you switch between versions, you need to clean out all the derived files (object files, libraries, executables, etc) that may have been built with the wrong source. You have to change the source code over. So why not change the makefile too?

A build script to invoke make

I also observe that since you have the environment variable APP_VER driving your process, that you can finesse the problem by requiring a standardized 'make invoker' that sorts out the APP_VER value and invokes make correctly. Imagine that the script is called build:

#!/bin/sh
: ${APP_VER:=1.2.0.1}  # Latest version is default
case $APP_VER in
[0-9].[0-9].*)
    MAK_VER=`echo $APP_VER | sed -e 's/^\(...\).*/\1/'`
    ;;
*)  echo "`basename $0 .sh`: APP_VER ($APP_VER) should start with two digits followed by dots" 1>&2;
    exit 1;;
esac
exec make MAK_VER=$MAK_VER "$@"

This script validates that APP_VER is set, giving an appropriate default if it is not. It then processes that value to derive the MAK_VER (or errors out if it is incorrect). You'd need to modify that test after you reach version 10, of course, since you are planning to be so successful that you will reach double-digit version numbers in due course.

Given the correct version information, you can now invoke your makefile with any command line arguments.

The makefile can be quite simple:

MAK_VER = dummy

include app$(MAK_VER).mak  

all: PROD
        ...as now...

The appdummy.mak file now contains a rule:

error:
        echo "You must invoke this makefile via the build script" 1>&2
        exit 1

It simply points out the correct way to do the build.

Note that you can avoid the APP_VER environment variable if you keep the product version number under the VCS in a file, and the script then reads the version number from the file. And there could be all sorts of other work done by the script, ensuring that correct tools are installed, other environment variables are set, and so on.

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