使用自动变量编译 Makefile

Posted

技术标签:

【中文标题】使用自动变量编译 Makefile【英文标题】:Makefile Compilation using Automatic Variables 【发布时间】:2016-10-18 11:50:17 【问题描述】:

我在 makefile 中尝试简单的事情,但无法使其工作。以下是与我的要求相关的示例文件:

生成文件:

OBJDIR=obj

dummy_build_folder := $(shell mkdir -p $(OBJDIR))

CC = gcc

SRCS =  1/print.c \
        2/add.c

INCLUDE =   -I "./1/" \
          -I "./2/" \

OBJS = $(addprefix $(OBJDIR)/,$(patsubst %.c,%.o,$(notdir $(SRCS))))

$(OBJDIR)/%.o: %.c
  @-if not exist $(OBJDIR) mkdir $(OBJDIR) 1>NUL 2>NUL  
  $(CC) -c $(INCLUDE) $< -o $@

all: $(OBJS)
  @-if not exist $(OBJDIR) mkdir $(OBJDIR) 1>NUL 2>NUL
  @echo $(OBJS)

.PHONY : clean

clean:
    rm $(OBJS)

当我尝试运行相同的程序时,出现以下错误: "make: *** 没有规则来制作目标 'obj/print.o','all' 需要。停止。"

我也尝试使用“$(OBJDIR)/%.o: $(SRCS)”,但这里 $

gcc -c -I "./1/" -I "./2/"  1/print.c -o obj/print.o

gcc -c -I "./1/" -I "./2/"  1/print.c -o obj/add.o

我的目录结构是:

RootFolder:

    1/print.c

    2/add.c

    3/xyz.c (Don't want to compile this file)

    Makefile

另外,我想将所有 .o 文件保存在上述位置的不同文件夹 (./obj/*o) 中。

【问题讨论】:

格式化您的代码。 【参考方案1】:

.o 文件与对应的.c 文件之间没有依赖关系,也没有匹配规则,这是make 通过make: *** No rule to make target 'obj/print.o', needed by 'all'. Stop. 告诉你的。

模式规则$(OBJDIR)/%.o : %.c 无法将.c 匹配到.o,因为目标文件在.c 的路径中不存在目录级别。该目录级别被 $(notdir ...) 调用删除。

模式规则中的%(词干)部分必须匹配。例如。在$(OBJDIR)/1/print.o : 1/print.c 中,词干是1/print。而 $(OBJDIR)/print.o : 1/print.c print1/print 不匹配。

避免此问题的一个好方法是为输出文件构建与源文件相同的目录结构。

固定Makefile:

OBJDIR := obj
CC := gcc

SRCS := 1/print.c 2/add.c

INCLUDE := -I "./1/" -I "./2/"

OBJS := $(patsubst %.c,$OBJDIR/%.o,$SRCS)
DEPS := $(patsubst %.c,$OBJDIR/%.d,$SRCS)

all: $(OBJS)
    @echo "Object files are $(OBJS)"

.SECONDEXPANSION:

# This rule creates the object file and its directory.
$(OBJS) : $OBJDIR/%.o : %.c | $$(dir $$@)
    $(CC) -c $(INCLUDE) $< -MD -MP -o $@

$OBJDIR/%.d : ;

$OBJDIR/% :
    mkdir -p $@

clean :
    rm -rf $OBJDIR

.PHONY: all clean

-include $DEPS

示例用法:

$ mkdir 1 2
$ touch 1/print.c 2/add.c
$ make
mkdir -p obj/1/
gcc -c -I "./1/" -I "./2/" 1/print.c -MD -MP -o obj/1/print.o
mkdir -p obj/2/
gcc -c -I "./1/" -I "./2/" 2/add.c -MD -MP -o obj/2/add.o
Object files are obj/1/print.o obj/2/add.o

注意事项:

    使用纯订单依赖项| $$(dir $$@) 自动为您创建输出目录。 使用 -MD -MP-include $DEPS 位会自动为您创建头文件依赖项。

【讨论】:

感谢您的回复,提供的解决方案对我有用。只是出于好奇,我们可以用任何其他方式来做吗,我的意思是不使用 .SECONDEXPANSION 吗?也请你解释一下|的意思吗?这里的符号 "| $$(dir $$@)" ,我得到了我们试图传递目录路径并搜索该目录中所有 .c 文件的上下文。 @Dipanshu | $$(dir $$@) 表示目标文件$$@ 依赖于其目录$$(dir ...)。作为order only依赖|,即目录必须存在,但忽略其时间戳 @Dipanshu 请参阅order-only-prerequisites 和secondary expansion。 @Dipanshu 没有.SECONDEXPANSION make 无法自动添加对目录的依赖并自动创建。

以上是关于使用自动变量编译 Makefile的主要内容,如果未能解决你的问题,请参考以下文章

makefile

Linux项目自动化构建工具-make/Makefile

Makefile学习

Makefile

MakefileMakefile 中 LINUXINCLUDE 的作用

MakefileMakefile 中 LINUXINCLUDE 的作用