I'm building a project have tree as following:
.
├── build
├── inc
│ └── log.h
├── Makefile
└── src
└── ota.c
"src" directory contain source files .c;
"inc" contain header files .h;
"build" will contain object files .o and execute file.
Makefile details:
vpath %.h inc
vpath %.c src
RED = \033[1;31m
GREEN = \033[1;32m
YELLOW = \033[1;33m
BLUE = \033[1;34m
RESET = \033[1;0m
INC_DIR = inc
SRC_DIR = src
BUILD_DIR = build
CC = gcc
CFLAGS = -Wall -I$(INC_DIR)
RM = rm -rf
SRCS = $(wildcard */*.c)
INCS = $(wildcard */*.h)
OBJS = $(patsubst %,$(BUILD_DIR)/%,$(patsubst
%.c,%.o,$(notdir $(SRCS))))
TARGET = OTA
$(BUILD_DIR)/$(TARGET): $(OBJS)
#echo "$(YELLOW)Linking ...$(RESET)"
$(CC) $(CFLAGS) -o $# $^
#echo Finished!
$(BUILD_DIR)/%.o: %.c %.h
#echo "$(GREEN)Compiling objects ...$(RESET)"
$(CC) $(CFLAGS) -c $< -o $#
.PHONY: clean
clean:
#echo "$(RED)$(OBJS) $(SRCS) $(INCS) $(RESET)"
$(RM) $(BUILD_DIR)/*
When I run make by terminal on Ubuntu 20.04 then encouter an error as below:
minh#Minh:~/Workspaces/OTA-tool$ make
make: *** No rule to make target 'build/ota.o', needed by 'build/OTA'. Stop.
Please, tell me why error and help me fix it. Thanks
The basic problem is this:
OBJS = $(patsubst %,$(BUILD_DIR)/%,$(patsubst %.c,%.o,$(notdir $(SRCS))))
By setting OBJS to a value without the pathname, now make can no longer match up the object filename to the source filename.
So for example if you have src/foo.c, then OBJ will be build/foo.o. Then this pattern rule:
$(BUILD_DIR)/%.o: %.c %.h
does not match, because the % in the target matches foo, which means make will be looking for foo.c (which doesn't exist, it's src/foo.c) and foo.h (which also doesn't exist).
Since the prerequisites don't match, this pattern rule doesn't match. And since no other pattern rules match, make says it doesn't have any rule which knows how to create the target build/foo.o.
One way to solve this is to add the directories on the prerequisite as well:
$(BUILD_DIR)/%.o: src/%.c inc/%.h
Now make will look for src/foo.c and inc/foo.h.
Related
I have three directories obj/, inc/ and src/ . The directories inc/ and src/ contains all the .c files. I would like to redirect all the .o files generated in src/ and inc/ to obj/
This is a simple example of my makefile
NAME = push_swap
SRC = $(wildcard ./src/*c)
INC = $(wildcard ./inc/*c)
OBJ1 = $(SRC:.c=.o)
OBJ2 = $(INC:.c=.o)
CC = gcc
CFLAGS = -Wall -Werror -Wextra
$(NAME): $(OBJ1) $(OBJ2)
$(CC) $(CFLAGS) $(OBJ1) $(OBJ2) -o $#
all: $(NAME)
clean:
rm -f */*.o
fclean: clean
rm -f $(NAME)
re: fclean all
The makefile works perfectly, but all the object files are generetad in its src folder, making hard to search for .c files and debbug the code.
By default, Make will build the object file in the directory where it finds the source. If you want the object file to be built somewhere else, there is more than one way to do it.
You could write a rule for Make to use instead of the default:
obj/%.o: src/%.c
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $#
And another for source files in inc/, if you want to keep source files there.
Or you could write a more general rule, and use 'vpath` to find the sources:
vpath %.c src inc
obj/%.o: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $#
EDIT: Did you remember to change the names of the files you ask Make to build (as #MadScientist pointed out in his comment (and as I ought to have pointed out in my Answer))?
Try this:
SRC = $(wildcard ./src/*c)
OBJ1 = $(patsubst ./src/%.c, ./obj/%.o, $(SRC))
CC = gcc
CFLAGS = -Wall -Werror -Wextra
vpath %.c src
obj/%.o: %.c
$(CC) $(CFLAGS) -c -o $# $<
all: $(OBJ1)
Program tree:
├── Makefile
├── foo
├── lib
│ └── foo.h
└── src
└── foo.c
I am wondering if there are proper ways to write the Makefile to compile a C program like this structure? Like putting all .c files inside src folder whilst keeping all header files in lib folder.
Tried to write Makefile for it but it did not work as expected... And also, I was trying to make .o files in build folder but I'm not sure how to do that. If I have many files from both src and lib folder, what's the proper way to link them together?
My Makefile:
CC := gcc
CFLAGS := -std=c99 -Werror -Wall
TARGET := foo
LIBDIR := lib
SRCDIR := src
BUILDDIR := build
LIBS = -Ilib
.PHONY: all
.PHONY: clean
all: ${TARGET}
$(TARGET): $(TARGET).c,$(wildcard $(LIBDIR)/ *.h)
${CC} ${CFLAGS} ${LIBS} ${SRCDIR}/${TARGET}.c
clean:
rm -rf $(TARGET)
Showing up errors when I do make
make: *** No rule to make target 'foo.c,lib/foo.h', needed by 'foo'. Stop.
To fix the issue, you need to replace the comma with a space in $(TARGET): what,ever
The best way to make these applications would be to add instructions on compiling for each object or library you introduce
Such as adding files.o
files.o: files.c files.h
// Compile command
Thanks for the useful advice! I ended up with writing the part like this:
%.o: ${LIBDIR}/%.h
mkdir ${BUILDDIR}
${CC} ${CFLAGS} -c ${LIBDIR}/${TARGET}.h -o ${BUILDDIR}/${TARGET}.o
$(TARGET): $(TARGET).o
${CC} ${CFLAGS} ${LIBS} ${SRCDIR}/${TARGET}.c -o $(TARGET)
I'm trying to write a Makefile that when I add some deps in my application I just have to change DEPS_NAME variable, but something is wrong and I can't figure out what. I know that this is not the only problem with this Makefile, I just started to study this technology.
This is my project structure
application/
├── deps/
│ ├── buffer/
│ │ ├── buffer.c
│ │ └── buffer.h
│ └── other/
│ ├── other.c
│ └── other.h
├── objs/
├── application.c
└── Makefile
This is my Makefile
CC = gcc
APP_NAME = application
OBJS_PATH = objs
DEPS_PATH = deps
DEPS_NAME = buffer other
DEPS = $(patsubst %,$(OBJS_PATH)/%.o,$(DEPS_NAME))
$(OBJS_PATH)/%.o: $(DEPS_PATH)/%/%.c
$(CC) -o $# -c $^
$(APP_NAME): $(DEPS)
$(CC) -o $# $#.c $^
all: $(APP_NAME)
This is the error when i type make:
make: *** No rule to make target `objs/buffer.o', needed by `application'. Stop.
until you have determined the root cause of the problem, suggest a separate target for each *.c to *.o compile step.
you want the 'all' target to be the first target in the makefile.
(that is what a 'all' target is for, so can call the makefile with:
make
without specifying a target in the make file
Note: 'all' is a phony target (produces no file named 'all')
so should be written similar to:
.PHONY: all
all : $(app_name) $(DEPS)
When make performs the compile step(s)
It needs to know how to find the header files.
and since the header files are scattered,
it may be advisable to either 1) list all the paths/*.h files in the compile rule (simple but can result in unneeded compiles) or 2) generate dependancy files.(difficult, but best as the file count grows) or 3) write a separate compile rule for each source file. (least flexable, but easy for those new to make)
the compile rule needs to have parameters indicating where to find the header files. (in gcc, use '-I./other/.' and '-I./buffer/.)
I have never seen multiple stem references. Looks like it badly confuses the parser.
On a bright side it seems that
$(OBJS_PATH)/%.o: $($(DEPS_PATH)/%/%.c)
does the trick. Don't ask me why.
Putting the object files in the same directory of the source files I solved the problem with this Makefile
CC = gcc
CFLAGS = -Ideps
APP_NAME = application
DEPS_SOURCE = $(wildcard deps/*/*.c)
DEPS_OBJECT = $(DEPS_SOURCE:.c=.o)
all: $(APP_NAME)
$(APP_NAME): $(DEPS_OBJECT)
$(CC) $#.c -o $# $(DEPS_OBJECT) $(CFLAGS)
%.o: %.c
$(CC) -o $# -c $^
clean:
rm -f $(DEPS_OBJECT) $(APP_NAME)
.PHONY: all clean
Whit this solution I don't have to change the Makefile when I add other deps in the project.
I am trying to follow this tutorial:
http://www.cs.colby.edu/maxwell/courses/tutorials/maketutor/
When I am at the last makefile (#5), the "make" can't proceed becasue (error prompt) No rule to make target "obj/hellomake.o", needed by "hellomake". This piece of code tries to compile the sources files and put libs, srcs, objs into respective folders.
IDIR =../include
CC=gcc
CFLAGS=-I$(IDIR)
ODIR=obj
LDIR =../lib
LIBS=-lm
_DEPS = hellomake.h
DEPS = $(patsubst %,$(IDIR)/%,$(_DEPS))
_OBJ = hellomake.o hellofunc.o
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
$(ODIR)/%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
hellomake: $(OBJ)
gcc -o $# $^ $(CFLAGS) $(LIBS)
.PHONY: clean
clean:
rm -f $(ODIR)/*.o *~ core $(INCDIR)/*~
I have been staring at it for an hour already, it's not a complex piece of code but I couldn't eyeball the problem. I suspect the problem happens here:
$(ODIR)/%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
hellomake: $(OBJ)
gcc -o $# $^ $(CFLAGS) $(LIBS)
I just don't see anything wrong with it. Please help.
Their script is fine! Just do this:
1°) Create directory "include" and "src"
mkdir include; mkdir src
2°) Create an "obj" folder inside "src"
mkdir obj
3°) Your directory tree should look like this:
$:~/parentDir$ tree
.
├── include
│ └── hellomake.h
└── src
├── hellofunc.c
├── hellomake
├── hellomake.c
├── Makefile
└── obj
├── hellofunc.o
└── hellomake.o
4°) Now just use make command inside src directory.
:D
If you do not have a source file named hellomake.c, make does not know how to make obj/hellomake.o. You should also create the obj directory yourself since you do not have a command to do so in the Makefile, but its absence would not cause the error you report.
You probably know better and the explanation may be more subtle:
I suspect there is a missing TAB character at the beginning of this line:
$(CC) -c -o $# $< $(CFLAGS)
Commands are introduced by TAB characters in Makefiles, not spaces. It is unfortunate, but nobody seems to want to fix this.
I remember meeting Stuart Feldman at Bell Labs in 1984: He was introduced to me as the inventor of make. Before I could say anything, he promptly apologized this way: I know, sorry about he TABs!
I have following folder structure:
TOPDIR
|
├── a
│ ├── a.c
│ ├── a.h
│ └── a.mk
├── b
│ ├── b.c
│ ├── b.h
│ └── b.mk
├── c
│ ├── c.c
│ ├── c.h
│ └── c.mk
├── include
│ └── common.h
├── root
│ ├── main.c
│ └── root.mk
└── Makefile
per-condition
My target is to write main Makefile under TOPDIR and sub-makefile, *.mk in sub folder, the include folder contain some common defines. root folder contain my main file(main function located here). Meanwhile, in main.c, it will call function from a.c and b.c, c.c is driver related, and will be called from a.c and b.c
Problem
I wrote sub-makefile like(I use one a.mk for example, others are same, ONLY root.mk has little different):
#MODULE will be modified for each sub folder
MODULE = a
LIB = $(MAKE_DIR)/libs/lib$(MODULE).a
SRCS = $(wildcard *.c)
OBJS = $(patsubst %.c, %.o, $(SRCS))
#generate lib file from obj file
$(LIB): $(OBJS)
#mkdir -p ../libs
#$(AR) cr $# $^
#echo " Archive $(notdir $#)"
#compile obj file from source file
$(OBJS): $(SRCS)
#$(CC) $(CFLAGS) -c $^
#echo " CC $(OBJS)"
.PHONY: clean
clean:
#$(RM) -f $(LIB) $(OBJS)
#$(RM) -f *.expand
#echo " Remove Objects: $(OBJS)"
#echo " Remove Libraries: $(notdir $(LIB))"
I wrote root.mk like:
PROG = ../prog/DEMO
SRCS = $(wildcard *.c)
OBJS = $(patsubst %.c, %.o, $(SRCS))
#generate finial target file for run
$(PROG): $(SRCS)
#mkdir -p ../prog
#$(CC) $^ $(CFLAGS) -Wl,-Map=$(PROG).map $(LIBS) -o $#
#echo " Generate Program $(notdir $(PROG)) from $^"
.PHONY: clean
clean:
#$(RM) -f $(OBJS) $(PROG)
#$(RM) -f *.expand
#$(RM) -rf ../prog ../libs
#echo " Remove Objects: $(OBJS)"
#echo " Remove Libraries: $(notdir $(PROG))"
I wrote main Makefile like:
MAKE_DIR = $(PWD)
ROOT_DIR := $(MAKE_DIR)/root
DRV_DIR := $(MAKE_DIR)/driver
INCLUDE_DIR := $(MAKE_DIR)/include
DEBUG_DIR := $(MAKE_DIR)/debug
INC_SRCH_PATH :=
INC_SRCH_PATH += -I$(ROOT_DIR)
INC_SRCH_PATH += -I$(DRV_DIR)
INC_SRCH_PATH += -I$(INCLUDE_DIR)
INC_SRCH_PATH += -I$(DEBUG_DIR)
LIB_SRCH_PATH :=
LIB_SRCH_PATH += -L$(MAKE_DIR)/libs
CC = gcc
LD = ld
#problem happan here, if I change the sequence of LIB,
#during the finial link, it will find some function un-referenced,
#why can I put liba first?
LIBS := -lc -lb -la
CFLAGS :=
CFLAGS += $(INC_SRCH_PATH) $(LIB_SRCH_PATH)
CFLAGS += -Wall -O -ggdb
CFLAGS += -DDEBUG -D_REENTRANT
LDFLAGS :=
export MAKE_DIR CC LD CFLAGS LDFLAGS LIBS LINT INC_SRCH_PATH
all:
#$(MAKE) -C a -f a.mk
#$(MAKE) -C b -f b.mk
#$(MAKE) -C c -f c.mk
#$(MAKE) -C root -f root.mk
.PHONY: clean
clean:
#$(MAKE) -C debug -f debug.mk clean
#$(MAKE) -C driver -f driver.mk clean
#$(MAKE) -C mw -f mw.mk clean
#$(MAKE) -C root -f root.mk clean
Question
In main Makefile, I define which LIB file I will use, if need move it to root.mk for better?
In sub-makefile, I did NOT use -MM to generate depend file, if this cause the problem I can NOT change the sequence of my lib*, which I also described in Makefile comments.
Seems my makefile system can NOT detect I update some head file, for example, I first compiled whole code, and then, I modified one head file, when I try to re-compile, none of source is compiled
if:
#Automatic dependency magic:
%.d: src/%.c
$(CC) -MM -o$# $<
-include (MYPROG_OBJECTS:%.o=%.d)
need add into each sub-makefile?
This rule is definitely wrong:
$(OBJS): $(SRCS)
#$(CC) $(CFLAGS) -c $^
#echo " CC $(OBJS)"
The target line will expand to something like:
a.o b.o c.o d.o : a.c b.c c.c d.c
That's not right. It is identical to writing this:
a.o : a.c b.c c.c d.c
...
b.o : a.c b.c c.c d.c
...
c.o : a.c b.c c.c d.c
...
d.o : a.c b.c c.c d.c
...
This means that whenever you change any source file, ALL the object files will be rebuilt. You should use a pattern rule here:
%.o : %.c
#$(CC) $(CFLAGS) -o $# -c $<
#echo " CC $#"
to compile the object files one at a time.
As far as your questions go, I don't understand question #1.
Questions #2 and #3 (if I understand correctly) are the same thing: the reason for #3 (no files are recompiled when you change a header file) is that you're not declaring any prerequisites on header files. Make doesn't have any built-in support for this, so you either have to do it by hand (add a.o : a.c b.h c.h g.h to your makefiles) or else automatically generate the dependencies.
The dependency generation will typically use the -MM or similar flags, assuming your compiler supports these flags.