如何避免这个递归的Makefile重新链接?

时间:2015-03-20 12:43:36

标签: makefile

今天我要求你提供关于Makefile让我发疯的帮助。那是:

# Executable name
NAME = libft.a

# Compiler and archive linker settings
CC = gcc
AR = ar
CFLAGS = -Wall -Wextra -Werror -O3 -g3
ARFLAGS = -rsc
IFLAGS = -I./includes/

# Project layout
SRC_DIR = ./src/
INC_DIR = ./inc/
OBJ_DIR = ./obj/

OBJ = $(shell grep -r .o ./obj | awk '{print $$3}' | tr '\n' ' ')

.PHONY: all clean fclean re

#------------------------------------------------------------------------------#

all: $(OBJ_DIR) $(NAME)

$(OBJ_DIR):
    mkdir -p $(OBJ_DIR)

$(NAME): compile $(OBJ) $(INC_DIR)libft.h
    @echo "Linking library $(NAME).\n"
    @$(AR) $(ARFLAGS) $(NAME) $(OBJ)
    @echo "  ✧ $(AR) $(ARFLAGS) $(NAME) object files: OK! √\n"

compile:
    make -C src/io
    make -C src/lists
    make -C src/memory
    make -C src/strings
    make -C src/tests

我尝试了多种依赖关系,规则等组合,但我还是没有得到它。有时我会让它停止重新链接,但在这种情况下它不会重新编译目标文件,因为$(OBJ)是空的,并且在我运行编译后没有更新。

这个版本差不多好,但是每次我运行make它都会执行配方$(NAME)并执行ar -rsc %(OBJ) ..我怎样才能将它们放在{{1}的依赖项中}

2 个答案:

答案 0 :(得分:2)

嗯,基本上你的整个方法都不会成功。仅举一个例子:您正在尝试使用grep找到目标文件(老实说,我根本不理解shell命令;从{{1}的输出中打印$3字是什么你不是这里只是grep -r吗?)这将扩展到子目录中的所有目标文件。但是,当您的顶级makefile被解析时,该shell命令会运行,并且在 make运行任何规则之前解析 ...所以,还没有构建任何目标文件!所以,这个目标不依赖于任何东西。即使在构建了一些目标文件之后,它也只依赖于已存在的目标文件,而不依赖于构建期间创建的目标文件。

如果我是你,我会完全不同地做到这一点。但是,使makefile正常工作的最简单方法是使用递归make来构建find $(OBJ_DIR) -name \*.o;像这样更改你的makefile:

$(NAME)

此处all: compile $(NAME): $(OBJ) $(INC_DIR)libft.h @echo "Linking library $(NAME).\n" @$(AR) $(ARFLAGS) $@ $^ @echo " ✧ $(AR) $(ARFLAGS) $@ object files: OK! √\n" compile: mkdir -p $(OBJ_DIR) $(MAKE) -C src/io $(MAKE) -C src/lists $(MAKE) -C src/memory $(MAKE) -C src/strings $(MAKE) -C src/tests $(MAKE) $(NAME) 不依赖all;相反,$(NAME)步骤首先构建所有内容,然后在结束时递归调用自身构建compile;在这一点上,我们知道一切都是最新的,我们可以依赖于现有的目标文件。

其他事项:注意我在这里使用自动变量$(NAME)而不是$^;该变量是一个运行shell脚本的简单变量:它很昂贵!每次展开$(OBJ)变量时,您都需要支付该费用,因此您只需要这样做一次。或者,您可以使用$(OBJ)来设置:=,这样每个make实例只调用一次OBJS。这仍然是你需要的时间,但避免这将是痛苦的。

我还将mkdir移到了compile规则中。它比all的先决条件更清洁。

最后,您不应该直接使用make命令调用子品牌。始终使用$(MAKE)变量,否则各种操作都无法正常工作。

答案 1 :(得分:0)

上一篇文章明显解决了这个问题。

您需要使用$(MAKE)变量以$(NAME)规则递归调用您的make文件,而不是将$(NAME)作为all依赖项,后续调用您的基础Makefile再次使用$(MAKE)变量。