Make: *.h no such file or directory - c

My project has the following directory structure:
main.cu
FA_kernels/*.cu
FD_kernels/*.cu
MEM_kernels/*.cu
MOD_kernels/*.cu
headers/*.h
Where *.extension means a bunch of files with that extension. I can't seem to get the makefile to work correctly. The error I'm getting is:
FA_kernels/FA_SFD.cu:2:20: fatal error: FA_SFD.h: No such file or directory
#include "FA_SFD.h"
^
My intent was for -I headers to be specified to the compiler, thereby making the headers directory available for searching. Clearly this has not worked. Here is the makefile:
CC := nvcc
LD := nvcc
MODULES := FA_kernels FD_kernels MEM_kernels MOD_kernels .
SRC_DIR := $(MODULES)
BUILD_DIR := $(addprefix build/,$(MODULES))
SRC := $(foreach sdir,$(SRC_DIR),$(wildcard $(sdir)/*.cu))
OBJ := $(patsubst src/%.cu,build/%.o,$(SRC))
INCLUDES := $(addprefix -I,headers)
vpath %.cu $(SRC_DIR)
define make-goal
$1/%.o: %.cu
$(CC) $(INCLUDES) -c $$< -o $$#
endef
.PHONY: all checkdirs clean
all: checkdirs build/lem
build/lem: $(OBJ)
$(LD) $^ -o $#
checkdirs: $(BUILD_DIR)
$(BUILD_DIR):
#mkdir -p $#
clean:
#rm -rf build
$(foreach bdir,$(BUILD_DIR),$(eval $(call make-goal,$(bdir))))
Any ideas?
UPDATE: Here is the full console output from running make
nvcc FA_kernels/FA_SFD.cu FA_kernels/partition.cu FA_kernels/contribA.cu FA_kernels/parallel-SFD-List.cu FD_kernels/SFD.cu FD_kernels/flow_routines.cu FD_kernels/floodingDriver.cu FD_kernels/watershed.cu MEM_kernels/memory_dev.cu MEM_kernels/Data.cu MEM_kernels/MapInfo.cu MEM_kernels/memory.cu MOD_kernels/erosion.cu MOD_kernels/eroincidep.cu MOD_kernels/updates.cu MOD_kernels/runoffweight.cu MOD_kernels/depo-List.cu lem.cu -o build/lem
FA_kernels/FA_SFD.cu:2:20: fatal error: FA_SFD.h: No such file or directory
#include "FA_SFD.h"
^
compilation terminated.
Makefile:24: recipe for target 'build/lem' failed
make: *** [build/lem] Error 1

From your output, apparently patsubst in OBJ was not successful at all. From the way you define SRC, I assume makefile is directly under src/, then you should change src/%.cu to %.cu in the definition of OBJ as such:
OBJ := $(patsubst %.cu,build/%.o,$(SRC))
Also, if I understand you correctly, you were trying to create a folder structure under build/ that is identical to the folder structure under src/. So, for instance, /src/abc.cu will generate /src/build/abc.o, then you don't need to define functions to get these rules, simply do:
build/%.o: %.cu
$(CC) $(INCLUDES) -c $< -o $#
and you are good to go.
If instead you wish to create build/ on the same level as src/. i.e. XXX/src/abc.cu -> XXX/build/abc.o. Then simply replace all occurrences of build in your makefile with ../build.
If you would rather put makefile at the same level as src/, then you should edit SRC to reflect that:
SRC := $(foreach sdir,$(SRC_DIR),$(wildcard src/$(sdir)/*.cpp))
and change the target to:
build/%.o: src/%.cpp
$(CC) $(INCLUDES) -c $< -o $#
Now you can safely remove vapth ... and the last line $foreach in your makefile.
EDIT: This is what your makefile will look like. I can't test it right now so there may be some mistakes in it, but hopefully it makes you understand the general idea.
CC := nvcc
LD := nvcc
MODULES := FA_kernels FD_kernels MEM_kernels MOD_kernels .
SRC_DIR := $(MODULES)
BUILD_DIR := $(addprefix build/,$(MODULES))
SRC := $(foreach sdir,$(SRC_DIR),$(wildcard $(sdir)/*.cu))
OBJ := $(patsubst %.cu,build/%.o,$(SRC))
INCLUDES := $(addprefix -I,headers)
# vpath %.cu $(SRC_DIR)
#define make-goal
build/%.o: %.cu
$(CC) $(INCLUDES) -c $< -o $#
#endef
.PHONY: all checkdirs clean
all: checkdirs build/lem
build/lem: $(OBJ)
$(LD) $^ -o $#
checkdirs: $(BUILD_DIR)
$(BUILD_DIR):
#mkdir -p $#
clean:
#rm -rf build
#$(foreach bdir,$(BUILD_DIR),$(eval $(call make-goal,$(bdir))))

Related

How to generate object files in the build directory?

I am currently working on a C project to implement a Linux userspace application.
I wrote this Makefile, which allows me to compile :
PROJ_DIR := ../
SRC_DIR := $(PROJ_DIR)/src
BUILD_DIR := $(PROJ_DIR)/build
# define the executable file
TARGET := tcp_proxy
# include paths list
INC_DIRS := $(SRC_DIR)
INC_DIRS += $(SRC_DIR)/rpmsg
INC_DIRS += $(SRC_DIR)/rpmsg/rx
INC_DIRS += $(SRC_DIR)/rpmsg/tx
INC_DIRS += $(SRC_DIR)/tcp
INC_DIRS += $(SRC_DIR)/tcp/rx
INC_DIRS += $(SRC_DIR)/tcp/tx
INC_FLAGS := $(addprefix -I,$(INC_DIRS))
# source file list
SRCS := $(shell find $(SRC_DIR) -name *.c)
# object file list
OBJS := $(SRCS:.c=.o)
LDFLAGS := -pthread
all: tcp_proxy
tcp_proxy: $(OBJS)
$(CC) $(CFLAGS) $(INC_FLAGS) -o $(TARGET) $(OBJS) $(LDFLAGS)
%.o: %.c
$(CC) $(CFLAGS) $(INC_FLAGS) -c $< -o $#
.PHONY: clean
clean:
$(RM) *.o *~ $(TARGET)
However, the object files are generated in the same place as the source files.
So I would like to know how to duplicate the folders under "src" in a "build" directory and generate inside this directory the object files and the executable.
I would also like, when I do a make clean, to be able to delete all the object files and the executable.
My project :
Searching would definitely find you a lot of examples and information on this.
First tell make what objects you want to build; change your setting of OBJS to this:
# object file list
OBJS := $(SRCS:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
Then tell make how to build it; change your pattern rule for building objects to this:
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
#mkdir -p $(#D)
$(CC) $(CFLAGS) $(INC_FLAGS) -c $< -o $#

How to Compile Object files into an Archive using Make

Problem
I'm writing a B-tree in c and it's getting pretty big. I have a struct for the tree, one for the nodes, and one for the items (key/value). I'd like to compile the object files from all three header files into an archive (.a) using make. Whenever I try to compile using make it uses the archive without every building the objects. Any idea why?
include/
btree.h
item.h
node.h
src/
btree_attach.c
btree_create.c
btree_destructor.c
btree_disk.c
btree_find.c
btree_get_node.c
btree_insert.c
btree_key_size.c
item_compare_item.c
item_compare_item_qsort.c
item_print_item.c
node_create_.c
node_destructor.c
node_find.c
node_flush_node.c
node_insert.c
node_print_node.c
node_split_node.c
# Generic makefile
# VAriables:
src := $(wildcard *.c)
obj := $(obj:.c=.o)
dep := $(dep:.o=.d)
CFLAGS := -g
INCLUDE = -Iinclude
all: lib/btree.a\
clean:
rm -f a.out obj/* bin/*
# ---------------
# Object files
$(obj): $(src) $(dep)
$(CC) $(CFLAGS) $(INCLUDE) $# $^
#Archive file
.PHONY: lib/btree.a
lib/btree.a: $(obj) $(dep)
ar -rv $# $^
Update
I changed the make file to the following:
# VAriables:
src := $(wildcard src/*.c)
obj := $(src:.c=.o)
dep := $(obj:.o=.d)
CFLAGS := -g
INCLUDE = -include
print:
$(src)\
$(obj)\
$(dep)
all: lib/btree.a
# ---------------
# Object files
$(obj): $(src)
$(CC) $(CFLAGS) $(INCLUDE) $# $^
#Archive file
lib/btree.a: $(obj)
ar -rv $# $^
The printout has the following
src/b_util.c src/item_compare_item.c src/b_tree.c src/item_print_item.c src/random_tester_2.c src/node_attach.c src/node_find.c src/node_create_.c src/btree_disk.c src/node_insert.c src/tnode.c src/btree_create.c src/node_unattach.c src/b_tree_test.c src/node_split_node.c src/node_print_node.c src/random_tester_1.c src/node_destructor.c src/btree_insert.c src/item.c src/btree_attach.c src/item_compare_item_qsort.c src/node_flush_node.c src/jdisk.c src/btree_find.c src/btree_destructor.c src/btree_get_node.c src/jdisk_test.c src/btree_key_size.c\
src/b_util.o src/item_compare_item.o src/b_tree.o src/item_print_item.o src/random_tester_2.o src/node_attach.o src/node_find.o src/node_create_.o src/btree_disk.o src/node_insert.o src/tnode.o src/btree_create.o src/node_unattach.o src/b_tree_test.o src/node_split_node.o src/node_print_node.o src/random_tester_1.o src/node_destructor.o src/btree_insert.o src/item.o src/btree_attach.o src/item_compare_item_qsort.o src/node_flush_node.o src/jdisk.o src/btree_find.o src/btree_destructor.o src/btree_get_node.o src/jdisk_test.o src/btree_key_size.o\
src/b_util.d src/item_compare_item.d src/b_tree.d src/item_print_item.d src/random_tester_2.d src/node_attach.d src/node_find.d src/node_create_.d src/btree_disk.d src/node_insert.d src/tnode.d src/btree_create.d src/node_unattach.d src/b_tree_test.d src/node_split_node.d src/node_print_node.d src/random_tester_1.d src/node_destructor.d src/btree_insert.d src/item.d src/btree_attach.d src/item_compare_item_qsort.d src/node_flush_node.d src/jdisk.d src/btree_find.d src/btree_destructor.d src/btree_get_node.d src/jdisk_test.d src/btree_key_size.d
Essentially they all went to the src dir but I'd like them to be seperated into (see below). Why is it putting everything in src?
obj/*.o
dep/*.d
src/*.c
Most likely because your sources variable src is empty. Which means your objects list variable obj is empty. Which means that your library lib/btree.a doesn't depend on anything, so make doesn't build anything.
This is most likely because this:
src := $(wildcard *.c)
obj := $(obj:.c=.o)
dep := $(dep:.o=.d)
should instead be:
src := $(wildcard src/*.c)
obj := $(src:.c=.o)
dep := $(obj:.o=.d)
It would be more clear if you showed us where your makefile was, and what directory you invoking make from.
You have a lot of other issues as well; for example this:
$(obj): $(src) $(dep)
$(CC) $(CFLAGS) $(INCLUDE) $# $^
is quite wrong. This says "each object file depends on ALL the source files and ALL the dependency files", and "to build a single object file, you compile ALL the source files".

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

Makefile: Separated sources and objects

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!

Resources