C Makefile linker error - - c

I'v written the Makefile below. I'm getting the following error during compilation. I'm not sure what IBS is? Is it missing the L from LIBS or something?
Follow on question:
This is the directory structure.
.
├── Makefile
└── src
├── include
│ └── utils.h
├── main.c
└── utils.c
However, when I run make, this is the output. It doesn't seem to be picking up and building the file utils.c?
cc -I./src -I./src/include -I/usr/local/include/upm -MMD -MP -c
src/main.c -o build/./src/main.c.o.o
TARGET_EXEC ?= app.out
BUILD_DIR ?= ./build
SRC_DIRS ?= ./src
SRCS := $(shell find $(SRC_DIRS) -name *.cpp -or -name *.c -or -name *.s)
OBJS := $(SRCS:%=$(BUILD_DIR)/%.o)
DEPS := $(OBJS:.o=.d)
INC_DIRS := $(shell find $(SRC_DIRS) -type d)
INC_FLAGS := $(addprefix -I,$(INC_DIRS)) -I/usr/local/include/upm
CPPFLAGS ?= $(INC_FLAGS) -MMD -MP
$(BUILD_DIR)/$(TARGET_EXEC): $(OBJS)
$(CC) $(OBJS) -o $# $(LDFLAGS)
LD_FLAGS = -L/usr/local/lib/upm -L/usr/lib/rabbitmq
LIBS = -lrabbitmq -lupmc-rn2483 -lupmc-rn2903 -lupmc-utilities
# c source
$(BUILD_DIR)/%.c.o: %.c
$(MKDIR_P) $(dir $#)
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $#.o
$(CC) $(LD_FLAGS) $#.o -o $# $LIBS
.PHONY: clean
clean:
$(RM) -r $(BUILD_DIR)
-include $(DEPS)
MKDIR_P ?= mkdir -p

$(CC) $(LD_FLAGS) $#.o -o $# $LIBS
# wrong ^^^^^
is wrong. Makefile variables need parenthesis: $(LIBS) and your $LIBS is understood as $(L)IBS and you don't have any L variable (so $LIBS expands to IBS since $L expands to nothing)
BTW, you could have used make --trace or remake with -x to find that bug
Regarding the edited question, I believe that you might be wrong in having such a complex source tree for such a small program (generally speaking, small programs of less than a few dozen thousands lines are simpler to deal in a flat source tree, that is a single directory containing both *.c and *.h source files). However, you might consider
INC_DIRS = $(wildcard */include)

Related

Is there a way to have all my object files in the same directory using Make?

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.

Makefile error when including dependency files generated from another Makefile

I have the current structures of directories:
./myFolder/
Makefile
main.c
./common/
Makefile
error.c
error.h
./build/
/common/
/myFolder/
/build/common contains the object and dependency files obtained from the compilation of the folder common and the equivalent for build/myFolder.
Basically /myFolder/ contains a programme that requires some function contained in common. Thus, the /myFolder/Makefile calls also the /common/Makefile to compile.
./common/Makefile is the following:
CC = gcc
CURRENT_DIR := $(shell basename $(CURDIR))
SOURCEDIR := ./
SOURCES := $(wildcard $(SOURCEDIR)/*.c)
OBJDIR := ../build/$(CURRENT_DIR)
OBJECTS := $(patsubst $(SOURCEDIR)/%.c,$(OBJDIR)/%.o, $(SOURCES))
DEPENDS := $(patsubst $(SOURCEDIR)/%.c,$(OBJDIR)/%.d, $(SOURCES))
# ADD MORE WARNINGS!
WARNING := -Wall -Wextra
all: $(OBJECTS)
clean:
$(RM) $(OBJECTS) $(DEPENDS) $(EXECUTABLE)
-include $(DEPENDS)
$(OBJDIR)/%.o: $(SOURCEDIR)/%.c Makefile | $(OBJDIR)
$(CC) $(WARNING) -MMD -MP -c $< -o $#
$(OBJDIR):
mkdir -p $(OBJDIR)
and ./myFolder/Makefile is the following:
CC = gcc
INC_PATH := -I../common/
BUILD_DIR_NAME := build
BUILDDIR := ../$(BUILD_DIR_NAME)
CURR_DIR_NAME := $(shell basename $(CURDIR))
SOURCEDIR := ./
SOURCES := $(wildcard $(SOURCEDIR)/*.c)
OBJDIR := $(BUILDDIR)/$(CURR_DIR_NAME)
OBJECTS := $(patsubst $(SOURCEDIR)/%.c,$(OBJDIR)/%.o, $(SOURCES))
DEPENDS := $(patsubst $(SOURCEDIR)/%.c,$(OBJDIR)/%.d, $(SOURCES))
COMMONDIR_NAME := common
COMMONDIR := ../$(COMMONDIR_NAME)
SOURCESCOMMON := $(wildcard $(COMMONDIR)/*.c)
OBJDIRCOMMON := $(BUILDDIR)/$(COMMONDIR_NAME)
OBJECTSCOMMON := $(patsubst $(COMMONDIR)/%.c,$(OBJDIRCOMMON)/%.o, $(SOURCESCOMMON))
DEPENDSCOMMON := $(patsubst $(COMMONDIR)/%.c,$(OBJDIRCOMMON)/%.d, $(SOURCESCOMMON))
# ADD MORE WARNINGS!
WARNING := -Wall -Wextra
EXECUTABLE := ../out_file
# .PHONY means these rules get executed even if
# files of those names exist.
.PHONY: all clean
# The first rule is the default, ie. "make",
# "make all" and "make parking" mean the same
all: $(EXECUTABLE)
clean:
$(RM) $(OBJECTS) $(DEPENDS) $(EXECUTABLE)
+$(MAKE) -C $(COMMONDIR) clean
# Linking the executable from the object files
# $^ # "src.c src.h" (all prerequisites)
$(EXECUTABLE): $(OBJECTS) $(OBJECTSCOMMON)
$(CC) $(WARNING) $^ -o $#
-include $(DEPENDS) $(DEPENDSCOMMON)
$(OBJDIR):
mkdir -p $(OBJDIR)
$(OBJDIR)/%.o: $(SOURCEDIR)/%.c Makefile | $(OBJDIR)
$(CC) $(WARNING) -MMD -MP -c $(INC_PATH) $< -o $#
$(OBJDIRCOMMON):
mkdir -p $(OBJDIRCOMMON)
$(OBJDIRCOMMON)/%.o: $(COMMONDIR)/%.c $(COMMONDIR)/Makefile| $(OBJDIRCOMMON)
+$(MAKE) -C $(COMMONDIR)
If I step into the folder myFolder and compile with make for the first time, everything is ok.
If then I try again I get the following error:
make: *** No rule to make target `error.c', needed by `../build/common/error.o'. Stop.
If I do make clean and then make it works.
The line causing the problem is the following:
-include $(DEPENDS) $(DEPENDSCOMMON)
particularly $(DEPENDSCOMMON). With -include $(DEPENDS) instead of it, it works perfectly.
Now, - tells the Makefile not to complain if the files do not exist. If they exist they will be included and recompile your sources properly according to the dependencies. For this reason I would expect not to compile at the first attempt, but if it compiles at the first attempt, also to not generate such error (since all files exist).
Can someone please tell me what I am missing?
For completeness here are the other files which are just examples:
main.c
#include "../common/error.h"
#include <stdio.h>
int main(int argc, char *argv[])
{
if (argc<1) err_sys("some error");
printf("Hello world\n");
return 0;
}
error.c
#include <stdio.h>
void err_sys(const char *fmt, ...)
{
printf("some err\n");
}
error.h
#ifndef _ERROR_H_
#define _ERROR_H_
#endif
/*Fatal error related to a system cal1.
* Print a message and terminate*/
void err_sys(const char *fmt,...);
The error is related to your Makefile structure.
The main problem is that you generate the dependencies in common/Makefile and use it in myFolder/Makefile. The dependencies are generated for $(SOURCEDIR)/%.c, e.g. ./somefile.c which is valid only in common, not in myFolder
A related problem is that you duplicate many parts from common/Makefile in myFolder/Makefile. It doesn't make much sense to have a separate Makefile in this situation.
One way to solve this would be to build a library from the files in common and reference only the library from myFolder/Makefile. This avoids duplicating information from common/Makefile to myFolder/Makefile.
I changed your Makefiles to work this way. (There might be room for improvement, I only wanted to make it work.)
common/Makefile:
CC = gcc
CURRENT_DIR := $(shell basename $(CURDIR))
SOURCEDIR := ./
SOURCES := $(wildcard $(SOURCEDIR)/*.c)
OBJDIR := ../build/$(CURRENT_DIR)
LIBNAME=libcommon.a
COMMONLIB = $(OBJDIR)/$(LIBNAME)
OBJECTS := $(patsubst $(SOURCEDIR)/%.c,$(OBJDIR)/%.o, $(SOURCES))
DEPENDS := $(patsubst $(SOURCEDIR)/%.c,$(OBJDIR)/%.d, $(SOURCES))
.PHONY: all clean
# ADD MORE WARNINGS!
WARNING := -Wall -Wextra
all: $(COMMONLIB)
clean:
$(RM) $(OBJECTS) $(DEPENDS) $(COMMONLIB)
-include $(DEPENDS)
$(OBJDIR)/%.o: $(SOURCEDIR)/%.c Makefile | $(OBJDIR)
$(CC) $(WARNING) -MMD -MP -c $< -o $#
$(OBJDIR):
mkdir -p $(OBJDIR)
$(COMMONLIB): $(OBJECTS)
$(AR) $(ARFLAGS) $# $^
myFolder/Makefile:
CC = gcc
INC_PATH := -I../common/
BUILD_DIR_NAME := build
BUILDDIR := ../$(BUILD_DIR_NAME)
CURR_DIR_NAME := $(shell basename $(CURDIR))
SOURCEDIR := ./
SOURCES := $(wildcard $(SOURCEDIR)/*.c)
OBJDIR := $(BUILDDIR)/$(CURR_DIR_NAME)
OBJECTS := $(patsubst $(SOURCEDIR)/%.c,$(OBJDIR)/%.o, $(SOURCES))
DEPENDS := $(patsubst $(SOURCEDIR)/%.c,$(OBJDIR)/%.d, $(SOURCES))
COMMONDIR_NAME := common
COMMONDIR := ../$(COMMONDIR_NAME)
OBJDIRCOMMON := $(BUILDDIR)/$(COMMONDIR_NAME)
LIBNAME=libcommon.a
COMMONLIB = $(OBJDIRCOMMON)/$(LIBNAME)
.PHONY: buildlib clean all
# ADD MORE WARNINGS!
WARNING := -Wall -Wextra
EXECUTABLE := ../out_file
# .PHONY means these rules get executed even if
# files of those names exist.
.PHONY: all clean
# The first rule is the default, ie. "make",
# "make all" and "make parking" mean the same
all: $(EXECUTABLE)
clean:
$(RM) $(OBJECTS) $(DEPENDS) $(EXECUTABLE)
+$(MAKE) -C $(COMMONDIR) clean
# Linking the executable from the object files
# $^ # "src.c src.h" (all prerequisites)
$(EXECUTABLE): $(OBJECTS) $(COMMONLIB)
$(CC) $(WARNING) $^ -o $#
-include $(DEPENDS)
$(OBJDIR):
mkdir -p $(OBJDIR)
$(OBJDIR)/%.o: $(SOURCEDIR)/%.c Makefile | $(OBJDIR)
$(CC) $(WARNING) -MMD -MP -c $(INC_PATH) $< -o $#
$(COMMONLIB): FORCE
+$(MAKE) -C $(COMMONDIR)
FORCE:
Note: I used the target FORCE with no rule as a dependency instead of declaring $(COMMONLIB) as .PHONY to force running the recursive make. When I tried with .PHONY, the executable was re-built every time without checking the time stamp of the library file.
Another option would be to throw away the Makefile in common and replace the recursive make call in myFolder/Makefile with the corresponding compile command.
$(OBJDIRCOMMON)/%.o: $(COMMONDIR)/%.c Makefile| $(OBJDIRCOMMON)
$(CC) $(WARNING) -MMD -MP -c $< -o $#
Notes
You don't need to use the relative path ../common in the #include directive when you specify this as an include directory with option -I.
I added .PHONY to declare your phony targets as such.
For automatic dependency generation and general recommendations about Makefiles I recommend to read the papers at http://make.mad-scientist.net/papers/.
You might also consider using a Makefile generator like cmake.
If you copy&paste the Makefile code from here, make sure to replace the spaces at the beginning of the lines with a tab.

Unexpected prerequisite skip in GNU Make 4.2.1

I'm trying to create a generic Makefile to use with most of my projects. It should work as follows: only rebuild and link those .o files whose .c or .h dependency has changed. The .o and .d files are stored in a separate directory called 'build'.
With the help of the official GNU Make manual and some googling I've managed to achieve the desired behavior except for one thing: when I run make re I get the error:
Assembler messages: Fatal error: can't create build/ft_build_buffer.o: No such file or directory — the reason for this is that the 'build' directory only gets created whenever the .d files are generated, but for some reason the re rule simply skips this step and goes on to compile .o files straight away! Note: if I run make clean && make fclean && make all (which should be the exact same thing) everything works fine.
A few other things: I've tried using the -MMD option to generate dependencies on the fly but on my machine that causes the .d files to only contain .c dependencies. Of course I could just make all .c files depend on all .h files but that seems like a very sloppy solution.
Feel free to share any other advice/improvements that will make this file more clean and readable, thanks! :)
# Define the C compiler to use.
CC := gcc
# Define any compile-time flags.
CFLAGS := -I./include -Wall -Wextra -Werror -g
#CFLAGS := -I./include -march=native -O2 -pipe
# Define the executable file.
BIN := ft_hexdump
# Define build directory.
BUILD_DIR := build
# Define source files directory.
SRC_DIR := src
# Define the C source files.
SRCS := $(wildcard $(SRC_DIR)/*.c)
# Define the C object files.
OBJS := $(SRCS:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o)
# Define the prerequisite files.
DEPS := $(OBJS:%.o=%.d)
.PHONY: all clean fclean re
.DELETE_ON_ERROR:
all: $(BIN)
-include $(DEPS)
$(BIN): $(OBJS)
$(CC) $(CFLAGS) $^ -o $#
$(BUILD_DIR)/%.o: $(BUILD_DIR)/%.d
$(CC) $(CFLAGS) -c $(SRC_DIR)/$*.c -o $#
$(BUILD_DIR)/%.d: $(SRC_DIR)/%.c
#mkdir -p $(#D)
#set -e; rm -f $#; \
$(CC) $(CFLAGS) $(INCLUDE) -MM $< > $#.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $# : ,g' < $#.$$$$ > $#; \
rm -f $#.$$$$
clean:
-rm -rf $(BUILD_DIR)
fclean: clean
-rm -f $(BIN)
re: fclean all
Here is the modified working version as suggested by #M.M
# Define the C compiler to use.
CC := gcc
# Define any compile-time flags.
CFLAGS := -I./include -Wall -Wextra -Werror -g
#CFLAGS := -I./include -march=native -O2 -pipe
# Define the executable file.
BIN := ft_hexdump
# Define build directory.
BUILD_DIR := build
# Define source files directory.
SRC_DIR := src
# Define the C source files.
SRCS := $(wildcard $(SRC_DIR)/*.c)
# Define the C object files.
OBJS := $(SRCS:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o)
# Define the prerequisite files.
DEPS := $(OBJS:%.o=%.d)
.PHONY: all clean fclean re
.DELETE_ON_ERROR:
all: $(BIN)
-include $(DEPS)
$(BIN): $(OBJS)
$(CC) $(CFLAGS) $^ -o $#
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c
#mkdir -p $(#D)
$(CC) $(CFLAGS) -MMD -c $(SRC_DIR)/$*.c -o $#
clean:
-rm -rf $(BUILD_DIR)
fclean: clean
-rm -f $(BIN)
re:
$(MAKE) fclean
$(MAKE) all

Not able to include folder for C compilation

Everything compile if the C is in outer folder, but when lib.c is in [lib] folder, it gives an error: make: *** No rule to make target 'obj/lib.o', needed by 'run'. Stop.
How should the makefile be corrected to make sure the compilation is successful?
What is the correct way to emend the makefile?
The tree is such:
├── inc
│   └── main.h
├── lib
│   └── lib.c
├── main.c
├── main_functions.sh
├── Makefile
└── test_usages.c
The makefile:
# IDIR =../include \
This is a makefile \
IDIR =./inc
CC=gcc
ODIR=obj
# LIB_SRC_DIR =./lib
LDIR =./lib
CFLAGS=-I $(IDIR) $(LDIR) ## added $(LDIR)
# header files required
_DEPS = *.h
DEPS = $(patsubst %,$(IDIR)/%,$(_DEPS))
_DEP_LIB = *.c ##
DEPS_LIB = $(patsubst %,$(LDIR)/%,$(_DEP_LIB)) ##
_OBJ = lib.o main.o test_usages.o
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
$(ODIR)/%.o: %.c $(DEPS) $(DEPS_LIB) ## added $(DEPS_LIB)
$(CC) -c -o $# $< $(CFLAGS)
#%.o: %.c
# $(CC) $(CFLAGS) $(INCLUDES) -c $(input) -o $(output)
# make commands options: make <options>, e.g. make hello_make
# executable name
hello_make: $(OBJ)
gcc -o $# $^ $(CFLAGS)
run: $(OBJ)
gcc -o $# $^ $(CFLAGS)
echo "=========================================================="
./run
echo "=========================================================="
.PHONY: clean
clean:
echo "cleaning ...." $(ODIR)/*.o
rm -f $(ODIR)/*.o *~ core $(INCDIR)/*~ ./*.exe
Thanks in advance for the advice.
There are some quirks in your Makefile, but here is how I got it to work:
Remove trailing blank in the line LDIR =./lib
Insert VPATH=$(LDIR) at some convenient place
Now make -n run shows (but doesn't run) all expected command lines:
gcc -c -o obj/lib.o ./lib/lib.c -I ./inc ./lib
gcc -c -o obj/main.o main.c -I ./inc ./lib
gcc -c -o obj/test_usages.o test_usages.c -I ./inc ./lib
gcc -o run obj/lib.o obj/main.o obj/test_usages.o -I ./inc ./lib
echo "=========================================================="
./run
echo "=========================================================="
BTW, you could use these options to debug your Makefile:
make -npr run print all variables, rules and so on, but not the built-ins.
make -nd run print all decisions, a lot of them.

How to write a good and efficient makefile

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.

Resources