How to include a static library inside my static library with makefile? - makefile

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

Related

Why is Makefile relinking?

I was trying to make a more complex Makefile with a src dir and a obj dir.
But doing that the Makefile is now relinking, and I don't understand why.
NAME = program
SRC = main.cpp
SRC_DIR = src/
OBJ = $(SRC:.cpp=.o)
OBJ_DIR = obj/
CC = c++
CFLAGS = -Wall -Werror -Wextra -std=c++98 -fsanitize=address
all: $(NAME)
$(OBJ): $(OBJ_DIR)
$(CC) $(CFLAGS) -c $(SRC_DIR)$(SRC) -o $(OBJ_DIR)$(OBJ)
$(OBJ_DIR):
mkdir $(OBJ_DIR)
$(NAME): $(OBJ)
$(CC) $(CFLAGS) $(OBJ_DIR)$(OBJ) -o $(NAME)
clean:
rm -rf $(OBJ_DIR)
fclean: clean
rm -f $(NAME)
re: fclean all
.PHONY: all clean fclean re
OBJ = $(SRC:.cpp=.o)
This becomes main.o
$(OBJ): $(OBJ_DIR)
$(CC) $(CFLAGS) -c $(SRC_DIR)$(SRC) -o $(OBJ_DIR)$(OBJ)
and this becomes:
main.o: obj/
c++ [options] -o obj/main.o
This will result in the compiler creating obj/main.o. main.o still does not exist. So, on the next make run, make will valiantly try to build it, with the same results (not to mention that an explicit dependency on a directory will create its own set of problems, too).

I dont understand why my makefile is relinking

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

Makefile doesn't recompile when linker script changes

I have a Makefile as follows. make doesn't recompile the program when the linker script riscv32i.ld changes. What do I need to do to add a dependency on that file?
AS=riscv32-unknown-elf-as
CC=riscv32-unknown-elf-gcc
OC=riscv32-unknown-elf-objcopy
CFLAGS=-nostdlib -T riscv32i.ld
MAKEFLAGS += --silent
SOURCES=$(wildcard *.asm)
OBJ=$(patsubst %.asm,%.o, $(SOURCES))
ELF=$(patsubst %.asm,%.elf, $(SOURCES))
HEX=$(patsubst %.asm,%.hex, $(SOURCES))
.PHONY: all clean
all: $(HEX)
$(HEX): %.hex: %.elf
$(OC) -O binary $< $#
$(ELF): %.elf: %.o
$(CC) $(CFLAGS) -o $# $<
$(OBJ): %.o: %.asm
$(AS) -o $# $<
clean:
rm -f *.o *.elf *.hex
Okay I'm an idiot. Just adding riscv32i.ld as a prerequisite to $(ELF) works:
AS=riscv32-unknown-elf-as
CC=riscv32-unknown-elf-gcc
OC=riscv32-unknown-elf-objcopy
CFLAGS=-nostdlib -T riscv32i.ld
MAKEFLAGS += --silent
SOURCES=$(wildcard *.asm)
OBJ=$(patsubst %.asm,%.o, $(SOURCES))
ELF=$(patsubst %.asm,%.elf, $(SOURCES))
HEX=$(patsubst %.asm,%.hex, $(SOURCES))
.PHONY: all clean
all: $(HEX)
$(HEX): %.hex: %.elf
$(OC) -O binary $< $#
$(ELF): %.elf: %.o riscv32i.ld
$(CC) $(CFLAGS) -o $# $<
$(OBJ): %.o: %.asm
$(AS) -o $# $<
clean:
rm -f *.o *.elf *.hex

How to avoid my makefile to relink

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!

How to move .o on project folder?

I wrote this Makefile to move all .o of the project inside a directory 'obj' in the main folder.
Directories
.:
actor/ lib/ Controller.cpp Controller.h Controller.o doc.txt main.cpp main.o Makefile uno VRP*
./actor:
Customer.cpp Customer.h Customer.o Depot.cpp Depot.h Depot.o Route.cpp Route.h Route.o Vehicle.cpp Vehicle.h Vehicle.o
./lib:
Search.cpp Search.h Search.o Utils.cpp Utils.h Utils.o VRP.cpp VRP.h VRP.o
Makefile
CXX=g++
RM=rm -rf
BIN_NAME=VRP
CPPFLAGS=-s -O2 -std=gnu++11 -Wall
SRCS=$(wildcard *.cpp actor/*.cpp lib/*.cpp)
OBJS=$(subst .cpp,.o,$(SRCS))
all: $(OBJS_DIR) $(BIN_NAME)
$(OBJS_DIR):
mkdir $(OBJS_DIR)
$OBJS_DIR)/%.o : $(SRCS)
$(CXX) $(CPPFLAGS) -c $< -o $#
$(BIN_NAME) : $(OBJS)
$(CXX) -o $# $^
debug:
$(CXX) -g $(CPPFLAGS) -o $(BIN_NAME) $(OBJS)
.PHONY : all clean
clean:
$(RM) $(OBJS) $(OBJS_DIR)
dist-clean: clean
$(RM) $(BIN_NAME)
How can I make it works?
This line $OBJS_DIR)/%.o : $(SRCS) sets the prerequisites of every file that matches $OBJS_DIR)/%.o to all the files in $(SRCS) that's not even close to what you want. (It is also a typo. You are missing the opening ().
You can't write a single rule for what you are trying to do here you need three pattern rules (or one with a vpath/VPATH setup).
$(OBJS_DIR)/%.o: %.cpp
$(CXX) $(CPPFLAGS) -c $< -o $#
$(OBJS_DIR)/%.o: actor/%.cpp
$(CXX) $(CPPFLAGS) -c $< -o $#
$(OBJS_DIR)/%.o: lib/%.cpp
$(CXX) $(CPPFLAGS) -c $< -o $#
That being said you don't actually have any targets that match $(OBJS_DIR)/%.o since the value of $(OBJS) is Controller.o ... actor/Customer.o ... lib/Search.o. To fix that you also need:
OBJS=$(addprefix $(OBJS_DIR)/,$(patsubst %.cpp,%.o,$(notdir $(SRCS))))
$(notdir) to get just the filename from the source files.
$(patsubst) instead of $(subst) just for correctness (subst would have modified a Bar.cpp.cpp file to Bar.o.o).
$(addprefix) to add the $(OBJS_DIR) prefix to the bare object file names.

Resources