c - "make all"连续两次不 't return "使 : Nothing to be done for 'all' . "

标签 c makefile libraries

我注意到很多关于人们收到消息“make: Nothing to be done for 'all'.”的问题,但我的问题恰恰相反。 这是我的生成文件:

#################
##  VARIABLES  ##
#################

#   Environment
OS :=                       $(shell uname)

#   Output
NAME :=                     libft.a
DYNAMIC_NAME :=             ${NAME:a=so}

#   Compiler
CC :=                       gcc

ifneq ($(OS), Linux)
    FLAGS +=                -Wall -Wextra -Werror
endif

DYN_FLAG :=                 -shared
HEADERS :=                  -I ./includes/
O_FLAG :=                   -O2

#   Directories
ADDITIONAL_FUNCTIONS =      $(addprefix ./additional_functions/, $(ADDITIONAL))
BONUS_FUNCTIONS =           $(addprefix ./bonus_functions/, $(BONUS))
LIBC_FUNCTIONS =            $(addprefix ./libc_functions/, $(LIBC))
PERSONAL_FUNCTIONS =        $(addprefix ./personal_functions/, $(PERSONAL))

DYN_OBJDIR =                dyn_build/
OBJDIR :=                   build/

#   Sources
ADDITIONAL +=               ft_itoa.c
ADDITIONAL +=               ft_memalloc.c ft_memdel.c
ADDITIONAL +=               ft_putchar.c ft_putchar_fd.c
ADDITIONAL +=               ft_putendl.c ft_putendl_fd.c
ADDITIONAL +=               ft_putnbr.c ft_putnbr_fd.c
ADDITIONAL +=               ft_putstr.c ft_putstr_fd.c
ADDITIONAL +=               ft_strclr.c ft_strdel.c
ADDITIONAL +=               ft_strnew.c ft_strjoin.c
ADDITIONAL +=               ft_strequ.c ft_strnequ.c
ADDITIONAL +=               ft_striter.c ft_striteri.c
ADDITIONAL +=               ft_strmap.c ft_strmapi.c
ADDITIONAL +=               ft_strsplit.c ft_strsub.c ft_strtrim.c
BONUS +=                    ft_lstadd.c ft_lstnew.c
BONUS +=                    ft_lstdel.c ft_lstdelone.c
BONUS +=                    ft_lstiter.c ft_lstmap.c
LIBC +=                     ft_atoi.c
LIBC +=                     ft_isalnum.c ft_isalpha.c ft_isascii.c
LIBC +=                     ft_isdigit.c ft_isprint.c
LIBC +=                     ft_memcpy.c ft_memccpy.c ft_memchr.c ft_memcmp.c
LIBC +=                     ft_bzero.c ft_memmove.c ft_memset.c
LIBC +=                     ft_strcat.c ft_strlcat.c ft_strncat.c
LIBC +=                     ft_strchr.c ft_strrchr.c
LIBC +=                     ft_strcmp.c ft_strncmp.c
LIBC +=                     ft_strcpy.c ft_strncpy.c ft_strdup.c
LIBC +=                     ft_strlen.c
LIBC +=                     ft_strstr.c ft_strnstr.c
LIBC +=                     ft_tolower.c ft_toupper.c
PERSONAL +=                 ft_intlen.c
PERSONAL +=                 ft_invert.c ft_islower.c ft_isupper.c
PERSONAL +=                 ft_lstgetnode.c ft_lstsize.c
PERSONAL +=                 ft_kill.c ft_putuchar.c ft_putuchar_fd.c
PERSONAL +=                 ft_strrev.c ft_strrevcpy.c
PERSONAL +=                 get_next_line.c

DYN_OBJECTS =               $(patsubst %.c,$(DYN_OBJDIR)%.o,$(SRCS))
OBJECTS =                   $(patsubst %.c,$(OBJDIR)%.o,$(SRCS))

SRCS +=                     $(ADDITIONAL_FUNCTIONS)
SRCS +=                     $(BONUS_FUNCTIONS)
SRCS +=                     $(LIBC_FUNCTIONS)
SRCS +=                     $(PERSONAL_FUNCTIONS)

#################
##    RULES    ##
#################

all: $(NAME)

$(NAME): $(OBJECTS)
    @ar rcs $@ $(patsubst %.c,$(OBJDIR)%.o,$(notdir $(SRCS)))
    ranlib $@
    @echo "Static library created."

$(OBJECTS): | $(OBJDIR)

$(OBJDIR):
    @mkdir -p $@

$(OBJDIR)%.o: %.c
    $(CC) $(FLAGS) $(O_FLAG) -c $< $(HEADERS) -o $(OBJDIR)$(notdir $@)

$(DYN_OBJECTS): | $(DYN_OBJDIR)

$(DYN_OBJDIR):
    @mkdir -p $@

$(DYN_OBJDIR)%.o: %.c
    $(CC) $(FLAGS) $(O_FLAG) -c $< $(HEADERS) -fpic -o $(DYN_OBJDIR)$(notdir $@)

clean:
    @/bin/rm -rfv $(OBJDIR)
    @/bin/rm -rfv $(DYN_OBJDIR)

fclean: clean
    @/bin/rm -fv $(NAME)
    @/bin/rm -fv $(DYNAMIC_NAME)

re: fclean all

so: $(DYN_OBJECTS)
        @$(CC) $(DYN_FLAG) -o $(DYNAMIC_NAME) $(patsubst %.c,$(DYN_OBJDIR)%.o,$(notdir $(SRCS)))
    @echo "Dynamic library created."

.PHONY: all build clean dynbuild fclean re so

makefile 工作得很好。它获取不同目录中的每个 .c,创建一个对象目录,如果库是静态的则为 build/,如果库是动态的则为 dyn_build/,将目标文件放入所述目录并从中编译库。

我的问题是,如果我连续运行两次 make,则第二次不应执行任何操作,因为目标文件和库仍然存在并且是最新的。但是,不知何故,连续两次 make 会导致第二次 make 重复该操作。

是什么原因造成的,是否有解决方法?

最佳答案

你的问题可以简化为:

ADDITIONAL +=          ft_strsplit.c 
BONUS +=               ft_lstadd.c

ADDITIONAL_FUNCTIONS = $(addprefix ./add/, $(ADDITIONAL))
BONUS_FUNCTIONS =      $(addprefix ./bonus/, $(BONUS))

SRCS +=                $(ADDITIONAL_FUNCTIONS)
SRCS +=                $(BONUS_FUNCTIONS)

OBJECTS =              $(patsubst %.c,./build/%.o,$(SRCS))

# OBJECTS contains ./build/./add/ft_strsplit.o and ./build/./bonus/ft_lstadd.o

all: $(OBJECTS)

$(OBJDIR)%.o: %.c
     $(CC) ...

因此 Make 运行最后一条规则,例如build/./add/ft_strsplit.o 作为目标,add/ft_strsplit.c 作为先决条件。问题是如何编写配方以构建build/ft_strsplit.o

正如@user657267 所指出的,拥有一个不构建名称为规则目标的文件的(非 PHONY)规则是错误的。所以让我们首先向 Make 询问我们真正想要的文件:

ADDITIONAL += ft_strsplit.c
BONUS +=      ft_lstadd.c

SRCS +=       $(ADDITIONAL)
SRCS +=       $(BONUS)

OBJECTS =     $(patsubst %.c,./build/%.o,$(SRCS))
# OBJECTS contains ./build/ft_strsplit.o and ./build/ft_lstadd.o

到目前为止一切顺利,但现在 Make 如何找到源代码?当我们要求 Make 构建 ./build/ft_strsplit.o 时,它如何知道 ft_strsplit.c 在哪里?

我们使用 vpath :

vpath %.c add bonus

现在 makefile 可以正常工作了。要自动编写 vpath 行,我们只需从分配中提取目录名称即可:

#   Directories
ADDITIONAL_DIR := ./additional_functions
BONUS_DIR :=      ./bonus_functions
...

ADDITIONAL_FUNCTIONS = $(addprefix $(ADDITIONAL_DIR)/, $(ADDITIONAL))
BONUS_FUNCTIONS =      $(addprefix $(BONUS_DIR)/, $(BONUS))
...

vpath %.c $(ADDITIONAL_DIR)
vpath %.c $(BONUS_DIR)
...

关于c - "make all"连续两次不 't return "使 : Nothing to be done for 'all' . ",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47365294/

相关文章:

c - 编译时出错E2040

c - 为什么 WH_MOUSE 钩子(Hook)不再是全局的?

c++ - Makefile 构建共享库

perl - 如何使用 makefile/autoconf 制作可安装的 Perl 程序?

azure - 无法在 azure synapse Analytics Spark 池上上传工作区包和requirement.txt 文件

c - 如何有效地多线程算法?

c - C 编程参数有不完整类型错误

shell - 将环境变量导出到 Makefile shell

java - 替换 fragment 时出错

php - CodeIgniter 和 Javascript/Jquery 库