Я заметил много вопросов о людях, у которых есть сообщение «сделать: ничего не поделаешь для« всех »», однако моя проблема в другом. Вот мой make-файл:

#################
##  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 повторяет операцию.

Что вызывает это и есть ли способ исправить?

1
Jon Nimrod 18 Ноя 2017 в 14:03

1 ответ

Лучший ответ

Ваша проблема может быть сведена к этому:

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

Теперь make-файл работает правильно. И чтобы написать эту строку 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)
...
1
Beta 19 Ноя 2017 в 02:41