使用 GNU Make 同时构建调试和发布目标

发布于 2024-09-29 18:43:12 字数 1364 浏览 4 评论 0原文

我正在开发一个中型项目,其中包含几个具有相互依赖关系的库,我最近将其转换为使用非递归 makefile 进行构建。我的下一个目标是能够同时从同一源代码树构建调试和发布版本(make debug;make release)。我的第一步是制作包含正确构建标志的调试和发布目标。我使用目标特定变量来做到这一点,如下所示: CXXFLAGS=-Wall -Wextra -Werror -DLINUX

CXX_DEBUG_FLAGS=-g3 -DDEBUG_ALL
CXX_RELEASE_FLAGS=-O3

.PHONY: debug 
debug: CXXFLAGS+=$(CXX_DEBUG_FLAGS) 
debug: build

.PHONY: release 
release: CXXFLAGS+=$(CXX_RELEASE_FLAGS) 
release: build

这工作正常,但您只能构建调试或发布,而不能同时构建两者。同时,我并不是指在同一个构建期间,我的意思是在同一源代码树中连续进行(进行调试;进行发布)。为了做到这一点,我需要将对象文件放置在调试/发布特定的目录中,这样它们就不会互相覆盖,并且我需要用“D”来破坏调试目标二进制文件名称。我认为这很容易,因为我可以再次使用目标特定变量,如下所示: CXXFLAGS=-Wall -Wextra -Werror -DLINUX

CXX_DEBUG_FLAGS=-g3 -DDEBUG_ALL
CXX_RELEASE_FLAGS=-O3

.PHONY: debug 
debug: CXXFLAGS+=$(CXX_DEBUG_FLAGS) 
debug: MODULE_BLD_TYPE=D
debug: OUT_DIR=debug_obj
debug: build

.PHONY: release 
release: CXXFLAGS+=$(CXX_RELEASE_FLAGS) 
release: MODULE_BLD_TYPE:=
release: OUT_DIR=release_obj
release: build

.PHONY: build
build: TARGET_NAME=HelloWorld$(MODULE_BLD_TYPE)
build: TARGET_BUILD_DIR=$(PROJECT_ROOT_DIR)/$(OUT_DIR)
build: TARGET_BUILD_OBJS=$(addprefix $(TARGET_BUILD_DIR)/,$(SOURCES:.cpp=.o))
build: $(TARGET_NAME)

您让阅读本文的专家已经知道这不起作用,因为您无法使用目标特定变量来创建实际目标。它们对于我的 CXXFLAGS var 效果很好,因为该变量未在目标名称中使用。

是否有使用非递归 makefile 管理调试/发布版本的设计模式和/或最佳实践?具体来说,如何构建目标文件目录路径和目标名称(基于目标构建目标)?

I'm working on a medium sized project which contains several libraries with interdependence's which I've recently converted over to build using a non-recursive makefile. My next goal is to enable building of both debug and release builds out of the same source tree at the same time (make debug;make release). My first step was to make debug and release targets which contained the correct build flags. I did this using target specific variables, like this:
CXXFLAGS=-Wall -Wextra -Werror -DLINUX

CXX_DEBUG_FLAGS=-g3 -DDEBUG_ALL
CXX_RELEASE_FLAGS=-O3

.PHONY: debug 
debug: CXXFLAGS+=$(CXX_DEBUG_FLAGS) 
debug: build

.PHONY: release 
release: CXXFLAGS+=$(CXX_RELEASE_FLAGS) 
release: build

This worked fine, but you could only build debug, or release, not both at the same time. And by same time, I don't mean during the same build I mean back to back in the same source tree (make debug;make release). In order to do this I need to place the object files in a debug/release specific directory so they don't overwrite each other and I need to mangle the debug target binary name with a 'D'. I though this would be easy as I could just use target specific variables again, like this:
CXXFLAGS=-Wall -Wextra -Werror -DLINUX

CXX_DEBUG_FLAGS=-g3 -DDEBUG_ALL
CXX_RELEASE_FLAGS=-O3

.PHONY: debug 
debug: CXXFLAGS+=$(CXX_DEBUG_FLAGS) 
debug: MODULE_BLD_TYPE=D
debug: OUT_DIR=debug_obj
debug: build

.PHONY: release 
release: CXXFLAGS+=$(CXX_RELEASE_FLAGS) 
release: MODULE_BLD_TYPE:=
release: OUT_DIR=release_obj
release: build

.PHONY: build
build: TARGET_NAME=HelloWorld$(MODULE_BLD_TYPE)
build: TARGET_BUILD_DIR=$(PROJECT_ROOT_DIR)/$(OUT_DIR)
build: TARGET_BUILD_OBJS=$(addprefix $(TARGET_BUILD_DIR)/,$(SOURCES:.cpp=.o))
build: $(TARGET_NAME)

You make experts reading this already know this won't work because you can't use target specific variables to create actual targets. They worked fine for my CXXFLAGS var because the variable wasn't used in a target name.

Is there a design pattern and or best practice to managing debug/release builds using non-recursive makefiles? Specificly, how do I build the object file directory path and target name (build a target based on a target)?

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

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

发布评论

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

评论(2

ゃ人海孤独症 2024-10-06 18:43:12

Make 最持久的问题之一是它无法一次处理多个通配符。没有真正干净的方法来做你所要求的事情(不诉诸递归,我认为这并不是那么糟糕)。这是一个合理的方法:

CXXFLAGS=-Wall -Wextra -Werror -DLINUX
CXX_DEBUG_FLAGS=-g3 -DDEBUG_ALL 
CXX_RELEASE_FLAGS=-O3 

.PHONY: debug  
debug: CXXFLAGS+=$(CXX_DEBUG_FLAGS)  
debug: HelloWorldD

.PHONY: release  
release: CXXFLAGS+=$(CXX_RELEASE_FLAGS)
release: HelloWorld

DEBUG_OBJECTS = $(addprefix $(PROJECT_ROOT_DIR)/debug_obj/,$(SOURCES:.cpp=.o))
RELEASE_OBJECTS = $(addprefix $(PROJECT_ROOT_DIR)/release_obj/,$(SOURCES:.cpp=.o))

HelloWorldD: $(DEBUG_OBJECTS)
HelloWorld: $(RELEASE_OBJECTS)

# And let's add three lines just to ensure that the flags will be correct in case
# someone tries to make an object without going through "debug" or "release":

CXX_BASE_FLAGS=-Wall -Wextra -Werror -DLINUX
$(DEBUG_OBJECTS): CXXFLAGS=$(CXX_BASE_FLAGS) $(CXX_DEBUG_FLAGS)
$(RELEASE_OBJECTS): CXXFLAGS=$(CXX_BASE_FLAGS) $(CXX_RELEASE_FLAGS)

One of the most persistent problems with Make is its inability to handle more than one wildcard at a time. There is no really clean way to do what you ask (without resorting to recursion, which I don't think is really so bad). Here is a reasonable approach:

CXXFLAGS=-Wall -Wextra -Werror -DLINUX
CXX_DEBUG_FLAGS=-g3 -DDEBUG_ALL 
CXX_RELEASE_FLAGS=-O3 

.PHONY: debug  
debug: CXXFLAGS+=$(CXX_DEBUG_FLAGS)  
debug: HelloWorldD

.PHONY: release  
release: CXXFLAGS+=$(CXX_RELEASE_FLAGS)
release: HelloWorld

DEBUG_OBJECTS = $(addprefix $(PROJECT_ROOT_DIR)/debug_obj/,$(SOURCES:.cpp=.o))
RELEASE_OBJECTS = $(addprefix $(PROJECT_ROOT_DIR)/release_obj/,$(SOURCES:.cpp=.o))

HelloWorldD: $(DEBUG_OBJECTS)
HelloWorld: $(RELEASE_OBJECTS)

# And let's add three lines just to ensure that the flags will be correct in case
# someone tries to make an object without going through "debug" or "release":

CXX_BASE_FLAGS=-Wall -Wextra -Werror -DLINUX
$(DEBUG_OBJECTS): CXXFLAGS=$(CXX_BASE_FLAGS) $(CXX_DEBUG_FLAGS)
$(RELEASE_OBJECTS): CXXFLAGS=$(CXX_BASE_FLAGS) $(CXX_RELEASE_FLAGS)
夜灵血窟げ 2024-10-06 18:43:12

使用 VPATH 进行调试和发布构建使用同一组源文件。调试和发布版本可以有自己的目录,这意味着它们的目标文件是分开的。

或者,使用原生支持源外构建的构建工具,例如 automake 或(呃)cmake。

如果启用 automake 选项 subdir-objects(如 AM_INIT_AUTOMAKE([foreign subdir-objects])),您可以编写非递归 Makefile.am

Use VPATH to make debug and release builds use the same set of source files. The debug and release build can have their own directory, which means they'll have their object files separated.

Alternatively, use a build tool that supports out-of-source builds natively, like automake or (ugh) cmake.

If you enable the automake option subdir-objects (as in AM_INIT_AUTOMAKE([foreign subdir-objects])), you can write a non-recursive Makefile.am.

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