Makefile 包含基于 Debug / Release 目标的依赖项

Posted

技术标签:

【中文标题】Makefile 包含基于 Debug / Release 目标的依赖项【英文标题】:Makefile include dependencies based on Debug / Release target 【发布时间】:2017-08-03 21:25:04 【问题描述】:

我正在尝试创建一个 Makefile 来编译我的 C 程序。我正在尝试使用以下目录结构生成调试和发布版本:

helloworld/
├── Debug/
│   ├── bin/
│   ├── depends/
│   └── obj/
├── Release/
│   ├── bin/
│   ├── depends/
│   └── obj/
├── mylib/
│   ├── bar.c
│   ├── bar.h
│   ├── foo.c
│   └── foo.h
└── main.c

我想要做的是让 Makefile 包含基于目标的不同依赖文件(调试与发布)。我现在的makefile是这样的:

CC = clang

CFLAGS = -c -g -Wall -Wextra -pedantic

SOURCES = main.c foo.c bar.c

OBJECTS = $(SOURCES:%.c=Debug/obj/%.o)
INCLUDE = -Imylib/
VPATH   =   mylib

.PHONY: debug

debug: Debug/bin/main

Debug/bin/main: $(OBJECTS)
    $(CC) $^ -o -g $@

Debug/obj/%.o: %.c | Debug
    $(CC) $(CFLAGS) $< -o $@ -MMD -MP -MF Debug/depends/$(@F:.o=.d) $(INCLUDE)

-include $(SOURCES:%.c=Debug/depends/%.d)

Debug:
    -mkdir Debug
    -mkdir Debug/bin
    -mkdir Debug/depends
    -mkdir Debug/obj

clean:
    rm -rf Debug
    rm -rf Release

这对于调试非常有用。但是当我尝试为 Debug 和 Release 创建单独的目标时,我很困惑如何修改 -include $(SOURCES:%.c=Debug/depends/%.d)

CC = clang

CFLAGS = -c -g -Wall -Wextra -pedantic

SOURCES = main.c foo.c bar.c
DEBUG_OBJECTS = $(SOURCES:%.c=Release/obj/%.o)
RELEASE_OBJECTS = $(SOURCES:%.c=Debug/obj/%.o)
INCLUDE = -Imylib/
VPATH   =   mylib

.PHONY: all debug release

all: release debug
release: Release/bin/main
debug: Debug/bin/main

Release/bin/main: $(RELEASE_OBJECTS)
    $(CC) $^ -o $@

Release/obj/%.o: %.c | Release
    $(CC) $(CFLAGS) $< -o $@ -MMD -MP -MF Release/depends/$(@F:.o=.d) $(INCLUDE)

Debug/bin/main: $(DEBUG_OBJECTS)
    $(CC) $^ -o -g $@

Debug/obj/%.o: %.c | Debug
    $(CC) $(CFLAGS) $< -o $@ -MMD -MP -MF Debug/depends/$(@F:.o=.d) $(INCLUDE)

# -------------------------------------------------------
# -include $(SOURCES:%.c=Debug/depends/%.d) What do I do?
# -------------------------------------------------------

Release:
    -mkdir Release
    -mkdir Release/bin
    -mkdir Release/depends
    -mkdir Release/obj

Debug:
    -mkdir Debug
    -mkdir Debug/bin
    -mkdir Debug/depends
    -mkdir Debug/obj

clean:
    rm -rf Debug
    rm -rf Release

问题

    如何根据目标有条件地包含依赖文件?

    有没有更好的项目组织结构?

    我对 makefile 非常陌生。以前我只是依靠我的 IDE 来管理构建和配置。还有其他提示可以帮助改进这个 makefile 吗?

【问题讨论】:

当您使用make debug release(或make all)调用它时,您是否已经知道要做什么?应该包含哪些依赖文件? 我的意图是,只要构建调试可执行文件,就会包含 Debug/depends,而只要构建发布可执行文件,就会包含 Release/depends。甚至可以在创建配方的过程中切换包含吗?如果没有,我会很高兴放弃make all 并只使用make debugmake release 一个文件是否包含在内,这不能依赖于当前构建的目标。否则,每次 make 调用只能构建一个目标,这真的很可惜。你会接受基于递归make(即make调用make)的解决方案吗?关于这是好事还是坏事存在争议(像往常一样,当它有帮助时它是好的,当它使事情变得更糟时是坏的)。 我没有考虑递归 make 但在这种情况下它看起来可以解决问题。 【参考方案1】:

好的,我想我已经找到了一种可能的解决方案:使用两个 makefile。第一个 makefile 创建目标文件并创建最终的可执行文件。第二个 makefile 使用不同的变量调用第一个 makefile。

制作文件

export CC := gcc
export SOURCES  := main.c bar.c foo.c
export VPATH    := mylib/
export INCLUDES := $(VPATH:%=-I%)
export DBGFLAGS := -g -c -Wall -Wextra -pedantic
export RELFLAGS :=    -c -Wall -Wextra -pedantic -Os

.PHONY: all debug release

all: debug release

release:
    make -f target.mk TARGET=Release CFLAGS='$(RELFLAGS)'

debug:
    make -f target.mk TARGET=Debug CFLAGS='$(DBGFLAGS)'

clean:
    make -f target.mk clean TARGET=Debug
    make -f target.mk clean TARGET=Release

target.mk

$(TARGET)/bin/main.out: $(SOURCES:%.c=$(TARGET)/obj/%.o)
    $(CC) $^ -o $@

$(TARGET)/obj/%.o: %.c | $(TARGET)
    $(CC) $(CFLAGS) $< -o $@ -MMD -MP -MF $(TARGET)/depends/$(@F:.o=.d) $(INCLUDES)

$(TARGET):
    -mkdir $(TARGET)
    -mkdir $(TARGET)/bin
    -mkdir $(TARGET)/depends
    -mkdir $(TARGET)/obj

clean:
    rm -rf $(TARGET)

-include $(SOURCES:%.c=$(TARGET)/depends/%.d)

【讨论】:

以上是关于Makefile 包含基于 Debug / Release 目标的依赖项的主要内容,如果未能解决你的问题,请参考以下文章

将atollic项目导出为基于makefile的项目

在 makefile 中构建 RELEASE 和 DEBUG

如何调试makefile

使用Makefile编译多个c源代码的方法

learning makefile set debug level and build command

Makefile 多目录自动编译