如何使用一个 Makefile 高效地构建组件的不同版本

发布于 2024-07-05 10:31:05 字数 2306 浏览 5 评论 0原文

我希望我没有把自己逼到墙角。 我已经通过实现 Makefile 获得了大部分内容,但我无法让最后一点工作。 我希望这里有人可以建议一种技术来完成我想做的事情。

我在源存储库中的版本控制文件中拥有所谓的“物料清单”,我构建了类似的内容:

make VER=x

我希望我的 Makefile 使用 $(VER) 作为标记从存储库中检索 BOM,生成依赖项文件以包含在 Makefile 中,重新扫描包含该依赖项,然后构建产品。

更一般地说,我的 Makefile 可能有多个目标——A、B、C 等——并且我可以构建每个目标的不同版本,因此我可能会这样做:

make A VER=x
make B VER=y
make C VER=z

依赖文件包含有关所有三个目标的信息。

但是,创建依赖项文件有点昂贵,因此如果我这样做:

make A VER=x
...make source (not BOM) changes...
make A VER=x

我真的希望 Makefile 不重新生成依赖项。 为了使事情尽可能复杂,我可能会这样做:

make A VER=x
.. change version x of A's BOM and check it in
make A VER=x

所以我需要重新生成对第二个构建的依赖关系。

签出会弄乱用于重新生成依赖项的时间戳,因此我认为我需要一种方法使依赖项文件不依赖于 BOM,而是依赖于 BOM 更改的某些指示。

我所要做的就是使 BOM 签出发生在 .PHONY 目标中(因此它总是被签出),并跟踪“.sig”文件中最后一次签出的内容(如果签名文件丢失或内容与新文件的签名不同,然后 BOM 发生更改),并且依赖项生成依赖于签名)。 在我的 Makefile 的顶部,我有一些设置:

BOMS = $(addsuffix .bom,$(MAKECMDGOALS)
SIGS = $(subst .bom,.sig,$(BOMS))

DEP = include.d
-include $(DEP)

似乎我总是需要做:

.PHONY: $(BOMS)

$(BOMS):
     ...checkout TAG=$(VER) $@

但是,如上所述,如果我这样做,并继续:

$(DEP) : $(BOMS)
     ... recreate dependency

那么每次调用 make 时依赖项都会更新。 所以我尝试:

$(DEP) : $(SIGS)
     ... recreate dependency

并且

$(BOMS):
     ...checkout TAG=$(VER) $@
     ...if $(subst .bom,.sig,$@) doesn't exist
     ...  create signature file
     ...else
     ...  if new signature is different from file contents
     ...    update signature file
     ...  endif
     ...endif

但是当签名更改时,依赖项生成不会被触发。 我认为这是因为 $(SIGS) 不是目标,所以 make 不会注意到 $(BOMS) 规则何时更新签名。

我尝试创建 .sig:.bom 规则并通过触摸管理签出的 BOM 的时间戳,但这不起作用。

有人提出这样的建议:

$(DEP) : $(SIGS)
    ... recreate dependency
$(BOMS) : $(SIGS)
    ...checkout TAG=$(VER) $@
$(SIGS) :
    ...if $(subst .bom,.sig,$(BOMS)) doesn't exist
    ...  create it
    ...else
    ...  if new signature is different from file contents
    ...    update signature file
    ...  endif
    ...endif

但是当从 BOM 创建 SIG 时,BOM 如何依赖于 SIG? 正如我所读到的,“从 BOM 创建 SIG,如果 SIG 比 BOM 新,则检查 BOM”。 我如何引导该过程? 第一个BOM从哪里来?

I hope I haven't painted myself into a corner. I've gotten what seems to be most of the way through implementing a Makefile and I can't get the last bit to work. I hope someone here can suggest a technique to do what I'm trying to do.

I have what I'll call "bills of materials" in version controlled files in a source repository and I build something like:

make VER=x

I want my Makefile to use $(VER) as a tag to retrieve a BOM from the repository, generate a dependency file to include in the Makefile, rescan including that dependency, and then build the product.

More generally, my Makefile may have several targets -- A, B, C, etc. -- and I can build different versions of each so I might do:

make A VER=x
make B VER=y
make C VER=z

and the dependency file includes information about all three targets.

However, creating the dependency file is somewhat expensive so if I do:

make A VER=x
...make source (not BOM) changes...
make A VER=x

I'd really like the Makefile to not regenerate the dependency. And just to make things as complicated as possible, I might do:

make A VER=x
.. change version x of A's BOM and check it in
make A VER=x

so I need to regenerate the dependency on the second build.

The check out messes up the timestamps used to regenerate the dependencies so I think I need a way for the dependency file to depend not on the BOM but on some indication that the BOM changed.

What I've come to is making the BOM checkout happen in a .PHONY target (so it always gets checked out) and keeping track of the contents of the last checkout in a ".sig" file (if the signature file is missing or the contents are different than the signature of the new file, then the BOM changed), and having the dependency generation depend on the signatures). At the top of my Makefile, I have some setup:

BOMS = $(addsuffix .bom,$(MAKECMDGOALS)
SIGS = $(subst .bom,.sig,$(BOMS))

DEP = include.d
-include $(DEP)

And it seems I always need to do:

.PHONY: $(BOMS)

$(BOMS):
     ...checkout TAG=$(VER) $@

But, as noted above, if i do just that, and continue:

$(DEP) : $(BOMS)
     ... recreate dependency

Then the dependency gets updated every time I invoke make. So I try:

$(DEP) : $(SIGS)
     ... recreate dependency

and

$(BOMS):
     ...checkout TAG=$(VER) $@
     ...if $(subst .bom,.sig,$@) doesn't exist
     ...  create signature file
     ...else
     ...  if new signature is different from file contents
     ...    update signature file
     ...  endif
     ...endif

But the dependency generation doesn't get tripped when the signature changes. I think it's because because $(SIGS) isn't a target, so make doesn't notice when the $(BOMS) rule updates a signature.

I tried creating a .sig:.bom rule and managing the timestamps of the checked out BOM with touch but that didn't work.

Someone suggested something like:

$(DEP) : $(SIGS)
    ... recreate dependency
$(BOMS) : $(SIGS)
    ...checkout TAG=$(VER) $@
$(SIGS) :
    ...if $(subst .bom,.sig,$(BOMS)) doesn't exist
    ...  create it
    ...else
    ...  if new signature is different from file contents
    ...    update signature file
    ...  endif
    ...endif

but how can the BOM depend on the SIG when the SIG is created from the BOM? As I read that it says, "create the SIG from the BOM and if the SIG is newer than the BOM then checkout the BOM". How do I bootstrap that process? Where does the first BOM come from?

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

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

发布评论

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

评论(2

你的他你的她 2024-07-12 10:31:05

我不是 make 专家,但我会尝试让 $(BOMS) 依赖于 $(SIGS),并使 $(SIGS) 目标执行当前在 $(BOMS) 目标下拥有的 if/else 规则。

$(DEP) : $(SIGS)
    ... recreate dependency
$(BOMS) : $(SIGS)
    ...checkout TAG=$(VER) $@
$(SIGS) :
    ...if $(subst .bom,.sig,$(BOMS)) doesn't exist
    ...  create it
    ...else
    ...  if new signature is different from file contents
    ...    update signature file
    ...  endif
    ...endif

编辑:你是对的,当然,你不能让 $(BOM) 依赖于 $(SIGS)。 但为了重新创建 $(DEP),您需要将 $(SIG) 作为目标。 也许有一个依赖于 $(BOM) 和 $(SIG) 的中间目标。

$(DEP) : $(SIGS)
    ... recreate dependency
$(NEWTARGET) : $(BOMS) $(SIGS)
$(BOMS) : 
    ...checkout TAG=$(VER) $@
$(SIGS) :
    ...if $(subst .bom,.sig,$(BOMS)) doesn't exist
    ...  create it
    ...else
    ...  if new signature is different from file contents
    ...    update signature file
    ...  endif
    ...endif

$(SIGS) 可能还需要依赖于 $(BOMS),我会用它来看看。

I'm not a make expert, but I would try have $(BOMS) depend on $(SIGS), and making the $(SIGS) target execute the if/else rules that you currently have under the $(BOMS) target.

$(DEP) : $(SIGS)
    ... recreate dependency
$(BOMS) : $(SIGS)
    ...checkout TAG=$(VER) $@
$(SIGS) :
    ...if $(subst .bom,.sig,$(BOMS)) doesn't exist
    ...  create it
    ...else
    ...  if new signature is different from file contents
    ...    update signature file
    ...  endif
    ...endif

EDIT: You're right, of course, you can't have $(BOM) depend on $(SIGS). But in order to have $(DEP) recreate, you need to have $(SIG) as a target. Maybe have an intermediate target that depends on both $(BOM) and $(SIG).

$(DEP) : $(SIGS)
    ... recreate dependency
$(NEWTARGET) : $(BOMS) $(SIGS)
$(BOMS) : 
    ...checkout TAG=$(VER) $@
$(SIGS) :
    ...if $(subst .bom,.sig,$(BOMS)) doesn't exist
    ...  create it
    ...else
    ...  if new signature is different from file contents
    ...    update signature file
    ...  endif
    ...endif

$(SIGS) might also need to depend on $(BOMS), I would play with that and see.

凉城凉梦凉人心 2024-07-12 10:31:05

Make 非常不擅长检测实际的文件更改,而不是仅检测更新的时间戳。

在我看来,问题的根源在于 bom-checkout 总是修改 bom 的时间戳,导致依赖项重新生成。 我可能会尝试解决这个问题——尝试在不弄乱时间戳的情况下检查 bom。 围绕结帐工具的包装脚本可能会解决问题; 首先将 bom 签出到临时文件,将其与已签出的版本进行比较,仅当新版本不同时才替换它。

如果您没有严格限制使用 make,那么还有其他工具可以更好地检测实际文件更改(例如 SCons)。

Make is very bad at being able to detect actual file changes, as opposed to just updated timestamps.

It sounds to me that the root of the problem is that the bom-checkout always modifies the timestamp of the bom, causing the dependencies to be regenerated. I would probably try to solve this problem instead -- try to checkout the bom without messing up the timestamp. A wrapper script around the checkout tool might do the trick; first checkout the bom to a temporary file, compare it to the already checked out version, and replace it only if the new one is different.

If you're not strictly bound to using make, there are other tools which are much better at detecting actual file changes (SCons, for example).

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