1

I've noticed a lot of questions about people having the message "make: Nothing to be done for 'all'.", however my problem is the opposite. Here is my makefile:

#################
##  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

The makefile works perfectly fine. It takes every .c in the different directories, creates an object directory, build/ if the library is static and dyn_build/ if it is dynamic, put the object files inside said directory and compile the library from them.

My issue is that if I run make twice in a row, nothing should be done the second time as the object files and the library are still there and up to date. But, somehow doing make twice in a row results in the second make repeating the operation.

What is causing this and is there a way to fix it?

Jon Nimrod
  • 335
  • 1
  • 2
  • 12
  • Try `make --trace` or use [`remake`](http://bashdb.sourceforge.net/remake/) with `-x` to understand more what is happening – Basile Starynkevitch Nov 18 '17 at 11:20
  • I see where that's coming from now, thank you! – Jon Nimrod Nov 18 '17 at 12:50
  • `$(OBJDIR)$(notdir $@)` and `$(DYN_OBJDIR)$(notdir $@)` break the second rule [here](http://make.mad-scientist.net/papers/rules-of-makefiles/), the recipes for your object files don't create the files you're specifying in the rules. – user657267 Nov 18 '17 at 12:51
  • The problem is that $(OBJDIR)%.o outputs to ./build/.//, I've tried many changes but can't manage to rename the rule to something that would output ./build/. $(OBJDIR)$(notdir %.o) doesn't work. What's the correct syntax? – Jon Nimrod Nov 18 '17 at 15:53
  • Welcome to Stack Overflow. Please take a look at our [help section](https://stackoverflow.com/help), with special attention to the page on [minimal complete examples](https://stackoverflow.com/help/mcve). – Beta Nov 19 '17 at 02:44

1 Answers1

1

Your problem can be reduced to this:

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) ...

So Make runs the last rule with e.g. build/./add/ft_strsplit.o as the target, and add/ft_strsplit.c as the prerequisite. The question is how to write the recipe so as to build build/ft_strsplit.o.

As @user657267 has pointed out, it is a mistake to have a (non-PHONY) rule that does not build a file whose name is the target of the rule. So let's first ask Make for the files we actually want:

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

So far so good, but now how can Make find the sources? When we ask Make to build ./build/ft_strsplit.o, how can it know where ft_strsplit.c is?

We use vpath:

vpath %.c add bonus

Now the makefile works correctly. And to write that vpath line automatically, we can just pull the directory names out of the assignments:

#   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)
...
Beta
  • 96,650
  • 16
  • 149
  • 150