I have these files in the same folder:
a.c
b.c
common.c
liba.mk
libb.mk
"liba.mk" is designated to compile "a.c" and "common.c" and archive the object files. "libb.mk" is doing similar works on "b.c" and "common.c"
My problem is, "common.c" appears at both makefile. How to add dependency rules on this? I expect that when I make "liba.mk" and then make "libb.mk", "libb.mk" would re-compile "common.c".
Here is my content on liba.mk:
SRC_C = a.c common.c
SRC_O = $(patsubst %.c,%.o,$(SRC_C))
OBJ_LIST = $(addprefix liba/,$(patsubst %.c,%.o,$(SRC_C)))
DEPENDENCY_LIST = $(addprefix liba/,$(patsubst %.c,%.d,$(SRC_C)))
all: pre_action liba
.PHONY: pre_action
pre_action:
mkdir liba
.PHONY: liba
liba: $(SRC_O)
$(AR) rvs liba/liba.a $(OBJ_LIST)
$(SRC_O): %.o : %.c
$(CC) -DLIBA -c $< -o $#
$(CC) -DLIBA -c $< -MM -MT $# -MF liba/$(patsubst %.o,%.d,$#)
cp $# liba/$(notdir $#)
-include $(DEPENDENCY_LIST)
.PHONY: clean
clean:
rm -rf liba
rm -f $(SRC_O)
And libb.mk has similar content:
SRC_C = b.c common.c
SRC_O = $(patsubst %.c,%.o,$(SRC_C))
OBJ_LIST = $(addprefix libb/,$(patsubst %.c,%.o,$(SRC_C)))
DEPENDENCY_LIST = $(addprefix libb/,$(patsubst %.c,%.d,$(SRC_C)))
all: pre_action libb
.PHONY: pre_action
pre_action:
mkdir libb
.PHONY: libb
libb: $(SRC_O)
$(AR) rvs libb/libb.a $(OBJ_LIST)
$(SRC_O): %.o : %.c
$(CC) -DLIBB -c $< -o $#
$(CC) -DLIBB -c $< -MM -MT $# -MF libb/$(patsubst %.o,%.d,$#)
cp $# libb/$(notdir $#)
-include $(DEPENDENCY_LIST)
.PHONY: clean
clean:
rm -rf libb
rm -f $(SRC_O)
I guess that I need to append extra dependency item when generating dependency file. But it seems silly to perform file processing on dependency file. Is there any better solution for this?
From your comment I now understand that you MUST recompile common.c because it uses different compiler flags (-DLIBB vs. -DLIBA) and, since the dependencies of common.o (i.e. common.c and possibly header files) did not change it did not recompile common.c.
To achieve that you could use:
pre_action:
rm common.o
mkdir libb # or liba
My make is a bit rusty but I believe this will always compile common.c.
Related
So, I decided to learn make as my first step into large projects, and I have to say that it is not that hard if you are just doing simple tasks and got addicted to it.
However I usually work with a scheme for my directories:
.
├── build
├── include
│ └── func.h
├── lib
│ └── func.c
├── Makefile
└── src
└── main.c
I usually have all my object files spread in the build directory. However, I could only map the source files to the build folder (like ./build/src/main.o where I prefer ./build/main.o).
I Tried Reading The Documentation to no avail!
this is what I came up with so far:
# C Compiler
CC = gcc
#------------- Directories
SOURCE_DIR = src lib
OBJECTS_DIR = build
INCLUDE_DIR = . ./include
#----------------------------
VPATH = $(SOURCE_DIR)
#------------- Files
SOURCE = $(foreach dir, $(SOURCE_DIR), $(wildcard $(dir)/*.c))
# Fake Objects (Just so I can map them to c files)
FOBJECTS = $(addprefix $(OBJECTS_DIR)/, $(SOURCE:.c=.o))
OBJECTS = $(addprefix $(OBJECTS_DIR)/, $(notdir $(FOBJECTS)))
DEPS = $(foreach dir, $(INCLUDE_DIR), $(wildcard $(dir)/*.h))
#----------------------------
#------------- Flags
OPT = -O0
IFLAGS = $(foreach dir, $(INCLUDE_DIR), -I$(dir))
LFLAGS = -lm
CFLAGS = -Wall
FLAGS = $(OPT) $(IFLAGS) $(LFLAGS) $(CFLAGS)
#----------------------------
BINARY = bin
all : $(BINARY)
$(BINARY) : $(OBJECTS)
$(CC) -o $# $(OBJECTS)
$(OBJECTS) : $(FOBJECTS)
mv -t $(OBJECTS_DIR) $(FOBJECTS)
rm -rf -- $(OBJECTS_DIR)/*/
$(OBJECTS_DIR)/%.o : %.c $(DEPS)
$(CC) $(FLAGS) -c -o $# $<
exec : $(BINARY)
#./$(BINARY)
clean :
rm -rf $(OBJECTS) $(BINARY)
I keep getting this error:
gcc -O0 -I. -I./include -lm -Wall -c -o build/src/main.o src/main.c
Assembler messages:
Fatal error: can't create build/src/main.o: No such file or directory
make: *** [Makefile:39: build/src/main.o] Error 1
I know the reason is the Fake Objects I created but creating the perfect rule for this is hard
As I said, you probably do not want to put all .o in the same directory because comingling .o files from unrelated projects isn't the best organization. If the .o files were related, you'd probably put the .c files in the same subdir.
But, if you did want all .o in a single build directory, one way is to create the build/* subdirs:
# C Compiler
CC = gcc
#------------- Directories
SOURCE_DIR = src lib
OBJECTS_DIR = build
INCLUDE_DIR = . ./include
OBJ_MK = $(addprefix $(OBJECTS_DIR)/, $(SOURCE_DIR))
#----------------------------
VPATH = $(SOURCE_DIR)
#------------- Files
SOURCE = $(foreach dir, $(SOURCE_DIR), $(wildcard $(dir)/*.c))
# Fake Objects (Just so I can map them to c files)
FOBJECTS = $(addprefix $(OBJECTS_DIR)/, $(SOURCE:.c=.o))
OBJECTS = $(addprefix $(OBJECTS_DIR)/, $(notdir $(FOBJECTS)))
DEPS = $(foreach dir, $(INCLUDE_DIR), $(wildcard $(dir)/*.h))
#----------------------------
#------------- Flags
OPT = -O0
IFLAGS = $(foreach dir, $(INCLUDE_DIR), -I$(dir))
LFLAGS = -lm
CFLAGS = -Wall
FLAGS = $(OPT) $(IFLAGS) $(LFLAGS) $(CFLAGS)
#----------------------------
BINARY = bin
all : $(OBJ_MK) $(BINARY)
$(BINARY) : $(OBJECTS)
$(CC) -o $# $(OBJECTS)
$(OBJECTS) : $(FOBJECTS)
mv -t $(OBJECTS_DIR) $(FOBJECTS)
rm -rf -- $(OBJECTS_DIR)/*/
$(OBJECTS_DIR)/%.o : %.c $(DEPS)
$(CC) $(FLAGS) -c -o $# $<
exec : $(BINARY)
#./$(BINARY)
clean :
rm -rf $(OBJECTS) $(BINARY)
rm -rf $(OBJ_MK)
$(OBJ_MK):
mkdir $#
The make output is:
mkdir build/src
mkdir build/lib
gcc -O0 -I. -I./include -lm -Wall -c -o build/src/main.o src/main.c
gcc -O0 -I. -I./include -lm -Wall -c -o build/lib/func.o lib/func.c
mv -t build build/src/main.o build/lib/func.o
rm -rf -- build/*/
gcc -o bin build/main.o build/func.o
However, the above actually makes the build more complex because its "natural" tendency was to create the subdirs. To override that required extra mv and rm commands.
To use the subdirectory method, the build is actually simpler, and we can do:
# C Compiler
CC = gcc
#------------- Directories
SOURCE_DIR = src lib
OBJECTS_DIR = build
INCLUDE_DIR = . ./include
OBJ_MK = $(addprefix $(OBJECTS_DIR)/, $(SOURCE_DIR))
#----------------------------
VPATH = $(SOURCE_DIR)
#------------- Files
SOURCE = $(foreach dir, $(SOURCE_DIR), $(wildcard $(dir)/*.c))
# Fake Objects (Just so I can map them to c files)
OBJECTS = $(addprefix $(OBJECTS_DIR)/, $(SOURCE:.c=.o))
DEPS = $(foreach dir, $(INCLUDE_DIR), $(wildcard $(dir)/*.h))
#----------------------------
#------------- Flags
OPT = -O0
IFLAGS = $(foreach dir, $(INCLUDE_DIR), -I$(dir))
LFLAGS = -lm
CFLAGS = -Wall
FLAGS = $(OPT) $(IFLAGS) $(LFLAGS) $(CFLAGS)
#----------------------------
BINARY = bin
all : $(OBJ_MK) $(BINARY)
$(BINARY) : $(OBJECTS)
$(CC) -o $# $(OBJECTS)
$(OBJECTS_DIR)/%.o : %.c $(DEPS)
$(CC) $(FLAGS) -c -o $# $<
exec : $(BINARY)
#./$(BINARY)
clean :
rm -rf $(OBJECTS) $(BINARY)
rm -rf $(OBJ_MK)
$(OBJ_MK):
mkdir $#
The make output is:
mkdir build/src
mkdir build/lib
gcc -O0 -I. -I./include -lm -Wall -c -o build/src/main.o src/main.c
gcc -O0 -I. -I./include -lm -Wall -c -o build/lib/func.o lib/func.c
gcc -o bin build/src/main.o build/lib/func.o
If you really want all the objects in a single directory, you almost have it right but you added some very strange rules that I don't understand; what is this for:
$(OBJECTS) : $(FOBJECTS)
mv -t $(OBJECTS_DIR) $(FOBJECTS)
rm -rf -- $(OBJECTS_DIR)/*/
? This is what's causing your problem. You're saying that every individual object file depends on all the "intermediate" object files, so then make tries to build these "intermediate" object files. The only way it knows to do that is with the pattern rule you provided, but that doesn't build those files.
Remove that rule altogether and it will probably work. You just want:
VPATH = $(SOURCE_DIR)
OBJECTS = $(addprefix $(OBJECTS_DIR)/, $(notdir $(SOURCE:.c=.o)))
all : $(BINARY)
$(BINARY) : $(OBJECTS)
$(CC) -o $# $(OBJECTS)
$(OBJECTS_DIR)/%.o : %.c $(DEPS)
$(CC) $(FLAGS) -c -o $# $<
etc. The compiler will build the object files directly into their final destination. You don't need the FOBJECTS thing or the rule that uses it.
I've been trying for some time to separate the source files of my project from the generated object files.
Indeed, I would like my project to be structured this way:
obj/
main.o
src1.o
[...]
src/
main.c
src1.c
[...]
Makefile
The Makefile I currently have is as follows:
NAME = a.out
OBJ_DIR = "obj"
SRC_DIR = "src"
MAIN_SRC = main.c
PROJ_SRC = src1.c \
src2.c \
src3.c
MAIN_OBJ = $(MAIN_SRC:%.c=%.o)
PROJ_OBJ = $(PROJ_SRC:%.c=%.o)
CC = gcc
RM = rm -rf
$(NAME): $(MAIN_OBJ) $(PROJ_OBJ)
$(CC) $(MAIN_OBJ) $(PROJ_OBJ) -o $(NAME)
all: $(NAME)
clean:
$(RM) $(MAIN_OBJ) $(PROJ_OBJ)
fclean: clean
$(RM) $(NAME)
I tried to use pattern rules, without success.
MAIN_OBJ = $(MAIN_SRC:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
PROJ_OBJ = $(PROJ_SRC:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
[...]
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
$(CC) $(CFLAGS) -c $< -o $#
Does anyone have a solution to my problem?
MAIN_SRC and PROJ_OBJ do not have directory prefix, so that expressions
$(MAIN_SRC:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
$(PROJ_SRC:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
do not replace anything.
Fix:
MAIN_OBJ := $(MAIN_SRC:%.c=$(OBJ_DIR)/%.o)
PROJ_OBJ := $(PROJ_SRC:%.c=$(OBJ_DIR)/%.o)
And then your pattern rule should work.
You may like to have make create that $(OBJ_DIR) for you:
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(OBJ_DIR)
$(CC) $(CFLAGS) -c -o $# $<
$(OBJ_DIR) :
mkdir -p $#
A more advanced example for you with automatic header dependency generation.
bro!
If your project "main" 's architecture is just liking this:
main
|
|__Makefile
|__obj
|__src
|__main.c
|__src1.c
|__src2.c
[...]
Just add this to your "Makefile" to store your object out of source files directory:
# Object files
# String substituion for every C/C++ file
# e.g: ./src/src1.cpp turns into ./obj/src1.o
OBJS := $(patsubst %.c, ${OBJ_DIR}/%.o, $(notdir $(SRC_DIR)))
And just add this to your "Makefile" to compile:
# Compile: Generate object files from source files
# $# := {NAME}
# $< := THE first file
# $^ all the dependency
# C Sources
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
$(CC) $(C_FLAGS) -c $< -o $#
END!
I installed a real-time library libre from brew install libre in my macOS. It is located in the directory /usr/local/Cellar/libre/0.5.7. I am trying to explicitly add this path in Makefile so I declare RT_LIBS_PATH=-L/usr/local/Cellar/libre/0.5.7. The entire makefile looks like this:
TARGET = run
LIBS = -O2 -lm
CC = gcc-7
CFLAGS = -fopenmp
RT_LIBS_PATH=-L/usr/local/Cellar/libre/0.5.7/lib
.PHONY: default all clean
all: $(TARGET)
OBJECTS = $(patsubst %.c, %.o, $(wildcard *.c))
HEADERS = $(wildcard *.h)
%.o: %.c $(HEADERS)
#$(CC) $(CFLAGS) $(RT_LIBS_PATH) -c $< -o $#
.PRECIOUS: $(TARGET) $(OBJECTS)
$(TARGET): $(OBJECTS)
#$(CC) $(OBJECTS) $(CFLAGS) $(LIBS) -o $#
clean:
-rm -f *.o
-rm -f $(TARGET)
However, it seems makefile does not recognize the libre, thus I assume I use RT_LIBS_PATH=-L/usr/local/Cellar/libre/0.5.7/lib in a wrong way. Kindly, is there something wrong in this way?
You have to specified library path when you are creating .o, you have to specify it when link all objs into executable
$(TARGET): $(OBJECTS)
#$(CC) $(OBJECTS) $(CFLAGS) $(RT_LIBS_PATH) $(LIBS) -o $#
I have a C project with a bunch of source files and their headers:
one.c
one.h
two.c
two.h
I also have a main.c, but that has no .h file with it:
main.c
I have this in my Makefile:
# Use gcc to make object files from C files.
_build/%.o: %.c %.h
#mkdir -p _build
#echo
#echo Compiling $<
$(CC) $(CFLAGS) $< -o $#
This is fine for one.o and two.o. But it's no good for main.o, which does not have a main.h on which to depend. Make then throws this error.
make: *** No rule to make target `_build/main.o', needed by `all'. Stop.
How can I best treat main.c specially?
Add a separate static pattern rule
_build/%.o: %.c
#mkdir -p _build
#echo
#echo Compiling $<
$(CC) $(CFLAGS) $< -o $#
_build/one.o _build/two.o: _build/%.o: %.h
Even better, use dependency generation
OBJS := $(addprefix _build/,main.o one.o two.o)
DEPS := $(OBJS:.o=.d)
CPPFLAGS := -MMD -MP
.PHONY: all clean
all: $(OBJS)
$(OBJS): _build/%.o: %.c | _build
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $# $<
_build: ; mkdir -p $#
clean: ; $(RM) -r _build
-include $(DEPS)
I was given two .o files with corresponding .h files to use for an assignment, but I do not know how to get the compiler to use the .o files. This is the Makefile I am currently using:
TARGET = prog
LIBS = -lm
CC = gcc
CFLAGS = -g -Wall
.PHONY: default all clean
default: $(TARGET)
all: default
OBJECTS = $(patsubst %.c, %.o, $(wildcard *.c))
HEADERS = $(wildcard *.h)
%.o: %.c $(HEADERS)
$(CC) $(CFLAGS) -c $< -o $#
.PRECIOUS: $(TARGET) $(OBJECTS)
$(TARGET): $(OBJECTS)
$(CC) $(OBJECTS) -Wall $(LIBS) -o $#
clean:
-rm -f *.o
-rm -f $(TARGET)
I believe I need to add the file1.o and file2.o at the end, but I am not sure if that is right. I do have the .h files in the C source files when appropriate, so the only reason that I can think of for the compilation error is that the .o files are not being compiled with my code.
Add a define for the provided .o's (e.g.):
PREBUILT_O = fludger.o ramble.o plexor.o
Change your target rule to:
$(TARGET): $(OBJECTS) $(PREBUILT_O)
$(CC) $(OBJECTS) $(PREBUILT_O) $(LIBS) -o $#
The compiler doesn't use your .o files. The linker does.
Your link step needs to be
$(TARGET) : $(OBJECTS)
$(LD) $(OBJECTS) $(LIBS) -o $#
(Very possibly missing some other linker flags, but that's the crux of your problem)
Also, you probably don't want the clean step to delete all the .o files since you're provided with at least two of them.