I have the following files:
Makefile
libft.h
ft_atoi.c
ft_itoa.c
...
And the following Makefile:
SRC_FILES:=$(wildcard *.c)
NAME=libft.a
LIBSO=libft.so
CC=gcc
CFLAGS=-Wall -Wextra -Werror -g
OBJ_DIR=obj/
HDR_NAME=libft.h
SRC_NAMES=${SRC_FILES:.c=.o}
SRC_NAMES_O=$(addprefix $(OBJ_DIR), $(SRC_NAMES))
all: $(NAME)
$(NAME): $(OBJ_DIR) $(SRC_NAMES)
ar -rc $# $(SRC_NAMES_O)
ranlib $#
$(OBJ_DIR):
mkdir $#
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $(OBJ_DIR)$#
clean:
rm -rf $(OBJ_DIR)
sclean: clean
rm -rf $(NAME) $(LIBSO)
fclean: clean
rm -f $(NAME)
re: fclean all
so:
$(CC) -nostartfiles -fPIC $(CFLAGS) $(SRC_FILES) $(BONUS_FILES)
gcc -nostartfiles -shared -o libft.so $(SRC_FILES) $(BONUS_FILES)
.PHONY: all bonus clean sclean fclean re so
But it is relinking. What did I do Wrong? I feel like it should run but it keeps recompiling everything each time I run make.
By code-review-only, I suspect that the culprit is the following line:
$(NAME): $(OBJ_DIR) $(SRC_NAMES)
ar -rc $# $(SRC_NAMES_O)
ranlib $#
Namely, $(OBJ_DIR) is a normal prerequisite of $(NAME), so each time a file (or subdirectory) in the obj/ directory is created, renamed, or deleted, the timestamp of obj changes, and thereby triggers a rebuild of the make all target.
To avoid this, you may want to replace this target with:
$(NAME): $(SRC_NAMES) | $(OBJ_DIR)
ar -rc $# $(SRC_NAMES_O)
ranlib $#
The underlying concept of GNU Make is called order-only prerequisite:
Occasionally (…) you have a situation where you want to impose a specific ordering on the rules to be invoked without forcing the target to be updated if one of those rules is executed. In that case, you want to define order-only prerequisites. Order-only prerequisites can be specified by placing a pipe symbol (|) in the prerequisites list: any prerequisites to the left of the pipe symbol are normal; any prerequisites to the right are order-only:
targets : normal-prerequisites | order-only-prerequisites
The normal prerequisites section may of course be empty. (…)
Related
I have the following subdirectories:
libftprintf/
-Makefile(1)
-ft_printf.h
-ft_printf.c
-ft_printf_source1.c
-ft_printf_source2.c
-libft/
-Makefile(2)
-ft_atoi.c
-ft_itoa.c
-...
And what I want is to call makefile(2) (which gives me a libft.a file) from makefile(1) and add all under the same libftprintf.a file.
How do I go about to do this?
My makefile:
SRC_FILES:=$(wildcard *.c)
NAME=libftprintf.a
CC=gcc
CFLAGS=-Wall -Wextra -Werror
OBJ_DIR=obj
HDR=ft_printf.h
SRC_NAMES=$(patsubst %.c,%.o,$(SRC_FILES))
SRC_NAMES_O=$(addprefix $(OBJ_DIR)/, $(SRC_NAMES))
$(OBJ_DIR):
mkdir $#
%.o: %.c $(HDR) $(OBJ_DIR)
$(CC) $(CFLAGS) -c $< -o $(OBJ_DIR)/$#
$(NAME): $(OBJ_DIR) $(SRC_NAMES)
ar -rc $# $(SRC_NAMES_O)
ranlib $#
all: $(NAME)
bonus: all
clean:
rm -rf obj/
sclean: clean
fclean: clean
re: sclean all
.PHONY: all clean fclean re so
It is not possible to combine two static libraries together into a single static library, directly. It's just not something that's supported by the toolchain.
If you are determined to do it the only way is to write a little script that will extract every object file from one of the libraries using ar x and add each one into the other library with ar r.
I fixed it by copying the first library libft.a and renaming it libftprintf.a and then ar -rcs it with the object files.
My Makefile:
SRC_FILES:=$(wildcard *.c)
NAME=libftprintf.a
LIBFT=libft/libft.a
CC=gcc
CFLAGS=-Wall -Wextra -Werror
OBJ_DIR=obj
HDR=ft_printf.h
SRC_NAMES=$(patsubst %.c,%.o,$(SRC_FILES))
SRC_NAMES_O=$(addprefix $(OBJ_DIR)/, $(SRC_NAMES))
$(OBJ_DIR):
mkdir $#
%.o: %.c $(HDR) $(OBJ_DIR)
$(CC) $(CFLAGS) -c $< -o $(OBJ_DIR)/$#
$(LIBFT):
make -C libft
$(NAME): $(LIBFT) $(OBJ_DIR) $(SRC_NAMES)
cp libft/libft.a $#
ar -rcs $# $(SRC_NAMES_O)
all: $(NAME)
bonus: all
clean:
rm -rf obj/
make -C libft $#
fclean: clean
rm -f libftprintf.a
make -C libft $#
re: fclean all
.PHONY: all clean fclean re so
My project's directory is mounted via NFS. From the directory under which it is mounted, I call make -f msh/Makefile cd=msh. (msh is my mount.) cd is a variable in the Makefile that is prepended to source files. This works fine with source files directly under cd. However, if the source files are under a subdirectory within cd, Make fails, saying that there is no rule to make that target. It does not fail if I call Make from within my mount.
This is my Makefile.
CC?=gcc
CFLAGS:=-Wall -Werror -D_POSIX_C_SOURCE=200112L $(CFLAGS)
cd?=.
objects_nix=if/tty.o
objects:=sub.o if.o $(objects_nix)
ifdef SO
CFLAGS+=-fPIC
bin=libmsh.so
else
bin=libmsh.a
endif
.PHONY : clean
$(bin) :
libmsh.a : $(objects)
$(AR) -r -c -s $# $(objects)
libmsh.so : $(objects)
#echo
#echo If you have resumed compilation after not having used the SO flag,
#echo you should run make clean.
#echo
$(LD) $(LDFLAGS) -shared -o $# $(objects)
test : $(cd)/test.c $(bin)
ifdef SO
$(CC) $(CFLAGS) -I$(cd) $(LDFLAGS) -L. -lmsh -Wl,-rpath,. -o $# $(cd)/test.c
else
$(CC) $(CFLAGS) -I$(cd) $(LDFLAGS) -o $# $(cd)/test.c $(bin)
endif
%.o : $(cd)/%.c
$(CC) $(CFLAGS) -c -o $# $<
clean :
rm -f libmsh.so libmsh.a
rm -f $(objects)
rm -f test.o test
I have tried creating another rule for the subdirectory, and this works. But I'd like it to work with only the one rule.
You have told Make how to make a .o file from .c file in $(cd). It does not know how to make a .o file if the .c file in some other directory. You can solve this in various ways, such as:
Add an explicit rule for all directories. You have already done that.
Use VPATH.
Create a Makefile for each directory.
My Makefile is relinking and I can't find why.
I'm not sure why malloc assume that $(NAME) have to be executed. Is the $(SRC:.c=.o) macro changing the timestamps of the .o files or something like that ?
CC = gcc
NAME = app
#
CFLAGS = -Wall -Werror -Wextra -pedantic -pedantic-errors
INCLUDES = -I ./includes
#
DIRSRC = srcs/
DIROBJ = objs/
SRC += main.c
SRC += malloc.c
OBJ = $(SRC:.c=.o)
DIROBJS = $(addprefix $(DIROBJ), $(OBJ))
#
LIBS_PATH = ./libs
LIBFT_PATH = $(LIBS_PATH)/libft
LIBFT_INCLUDES = -I $(LIBFT_PATH)
LIBFT = -L $(LIBFT_PATH) -lft
#
COMPILE = $(CC) $(CFLAGS) $(INCLUDES)
#
all: $(NAME)
$(NAME): configure libs $(DIROBJS)
$(COMPILE) $(LIBFT) $(DIROBJS) -o $(NAME)
$(DIROBJ)%.o: $(DIRSRC)%.c
#echo Compiling: $<
$(COMPILE) $(LIBS_INCLUDES) -c $< -o $#
clean:
#rm -rf $(DIROBJ)
fclean: clean
#rm -rf $(NAME)
re: fclean all
#
configure:
#mkdir -p $(DIROBJ)
#
libs:
#$(MAKE) -C $(LIBS)
.PHONY: all configure clean fclean re libs cleanlibs fcleanlibs relibs
It always relink because the configure rule will always run. So Make believes one of the dependencies changed, and it reevaluates the rule.
The way I would solve this would be to get rid of the configure rule and to move the #mkdir -p $(DIROBJS) in the rule that builds your object files:
$(DIROBJ)%.o: $(DIRSRC)%.c
#mkdir -p $(DIROBJS)
#echo Compiling: $<
$(COMPILE) $(LIBS_INCLUDES) -c $< -o $#
There might be more reasons (that could be related to the library you're also building), I don't know. Let us know if this solves it entirely.
#rtur's answer works, however I should mention another alternative. You could do:
$(DIROBJ):
mkdir $#
$(DIROBJ)/%.o: $(DIRSRC)/%.c | $(DIROBJ)
#echo Compiling: $<
$(COMPILE) $(LIBS_INCLUDES) -c $< -o $#
That way, it only makes the directory if it doesn't already exist. One thing to notice is the | symbol. This makes $(DIROBJ) an order-only prerequisite. This means if it's newer than the target, it will not cause the the target to rebuild. This is really important for directories, as the timestamp of a directory is the date the last item in it was added/deleted/modified, and your target would always be out of date without that symbol. This is considered cleaner, as you have less invocations of mkdir this way.
Also, as a style note, you usually, you don't include the trailing / at the end of directory names. $(OBJ_DIR)/%.o looks nicer than $(OBJ_DIR)%.o. Of course, that could just be my opinion :-)
I'm 42 network student.
I had this problem quite often as well.
Moving the .o files into a folder usually causes the Makefile to relink since that directory is not a 'dependency'.
Here's an example:
NAME = lib.a
INC = lib.h
FLAGS = -Wall -Wextra -Werror
LIB = function1.c function2.c function3.c function4.c
OBJ = $(SRC:%.c=%.o)
all: $(NAME) clear
$(NAME): $(OBJ)
#$(AR) rcs $# $^
#ranlib $(NAME)
%.o: %.c
#$(CC) $(FLAGS) -I $(INC) -c $< -o $#
clear:
#mkdir -p obj
#mv $(OBJ) obj
clean:
#$(RM) $(OBJ)
fclean: clean
#$(RM) $(NAME)
re: fclean all
The existence $(OBJ) are going to be checked when making $(NAME), not the 'obj' folder.
Solution:
NAME = lib.a
INC = lib.h
FLAGS = -Wall -Wextra -Werror
SRC = function1.c function2.c function3.c function4.c
DIR_OBJ = obj/
OBJ = $(SRC:%.c=$(DIR_OBJ)%.o)
all: $(NAME)
$(NAME): $(OBJ)
#$(AR) rcs $# $^
#ranlib $(NAME)
$(DIR_OBJ)%.o:%.c
#mkdir -p $(dir $#)
#$(CC) $(FLAGS) -I $(INC) -c $< -o $#
clean:
#$(RM) -rf $(DIR_OBJ)
fclean: clean
#$(RM) $(NAME)
re: fclean all
I think I covered it with this example, let me know if I missed a detail.
Good luck with your projects!
I have a makefile that works that looks like this:
TARGET:=prog
SOURCES:=a.c b.c
CFLAGS:=-Wall -g -O2
OBJECTS:=$(SOURCES:%.c=%.o)
$(TARGET): $(OBJECTS)
gcc -o $# $^
%.o: %.c
gcc $(CFLAGS) -c -o $# $<
clean:
rm -f $(TARGET) $(OBJECTS)
The only variables that the user needs to change are the target name and the sources required to build it. The objects that need to be generated are automatically determined from the sources. I would like to extend this to support multiple targets, each with its own list of sources. I'm having trouble getting the syntax right, though. This is the general idea:
TARGETS:=prog1 prog2
SOURCES_prog1:=a.c b.c
SOURCES_prog2:=a.c c.c
CFLAGS:=-Wall -g -O2
OBJECTS_$#=$(SOURCES_$#:%.c=%.o)
$(TARGETS): $(OBJECTS_$#)
gcc -o $# $^
%.o: %.c
gcc $(CFLAGS) -c -o $# $<
clean:
rm -f $(TARGET) $(OBJECTS)
But I can't get the object list to be generated correctly. I'm also unsure how to write the clean rule to clean all of the objects. Is this possible?
There are two primary ways that I see to do this.
The first involves dynamically creating the target/prerequisite mappings using the $(eval) function.
TARGETS:=prog1 prog2
SOURCES_prog1:=a.c b.c
SOURCES_prog2:=a.c c.c
CFLAGS:=-Wall -g -O2
$(TARGETS):
gcc -o $# $^
$(foreach t,$(TARGETS),$(eval OBJECTS_$t := $(SOURCES_$t:.c=.o))$(eval $t: $(OBJECTS_$t)))
The second involves using Secondary Expansion.
TARGETS:=prog1 prog2
SOURCES_prog1:=a.c b.c
SOURCES_prog2:=a.c c.c
CFLAGS:=-Wall -g -O2
.SECONDEXPANSION:
$(TARGETS): $$(OBJECTS_$$#)
gcc -o $# $^
$(foreach t,$(TARGETS),$(eval OBJECTS_$t := $(SOURCES_$t:.c=.o)))
In either case the clean target becomes:
clean:
rm -f $(TARGETS) $(foreach t,$(TARGETS),$(OBJECTS_$t))
When I call the clean rule with make clean all objects are correctly deleted. However if just after I call the all rule with make it recompiles all the objects again, even if the target is already there.
As far as I know, it should not recompile the objects beacuse the $(NAME) dependecy in the all rule is already satisfied. Indeed make clean erase just the object and not the program target too.
Somebody can explain me how to avoid recompiling after a make clean call? Thank you.
Here is the makefile:
NAME = myprogram
CC = clang++
CFLAGS = -Werror -Wextra -Wall -O3 -std=c++11
DIR_SRCS = srcs/
DIR_OBJS = objs/
DIR_INCS = incs/
FILES = main.cpp \
file1.cpp \
files2.cpp \
file3.cpp \
OBJS = $(addprefix $(DIR_OBJS), $(notdir $(addprefix $(DIR_SRCS), $(FILES:.cpp=.o))))
all: $(NAME)
$(NAME): $(OBJS)
$(CC) $(OBJS) $(CFLAGS) -I$(DIR_INCS) -o $(NAME)
$(DIR_OBJS)%.o: $(DIR_SRCS)%.cpp
mkdir -p $(DIR_OBJS)
$(CC) $(CFLAGS) -I$(DIR_INCS) -c $< -o $#
clean:
rm -rf $(DIR_OBJS)
fclean: clean
rm -f $(NAME)
re: fclean all
.PHONY: all clean fclean re
The $(NAME) dependecy in the all rule is NOT satisfied, because $(NAME) depends on $(OBJS) - and $(OBJS) does not exist (after make clean). This is how make works. If any dependencies don't exists or are newer than the target - the dependecies need to be regenerated (and in turn - the target).
For example: program --> program.o --> (program.c, program.h)
If program.c or program.h is newer than program.o : program.o needs to be regenerated (updated). This causes program.o to be newer than program - program needs to be relinked (using program.o).