Makefile : Automatically compile all c files, keeping .o files in separate folder - c

What I have is a directory with 3 sub-directories. src/ for .c and .h files, bin/ where the compiled executable is supposed to go and obj/ where I want the .obj files to go.
Now I want the makefile to compile every .c file from src (without me having to list them all in the makefile) and put the .o files in obj and the executable built from foo.c saved as bin/foo.
Can someone help me out? Whenever I use wildcards, make complains about rules not being there and when I use implicit rules, it doesn't put the object files in a separate folder.

To build foo.o from foo.c, locally:
foo.o: foo.c
$(CC) -c $< -o $#
To do the same, but with any needed header files in src/:
SRC := src
foo.o: foo.c
$(CC) -I$(SRC) -c $< -o $#
To do the same, but with the source file in src/:
SRC := src
foo.o: $(SRC)/foo.c
$(CC) -I$(SRC) -c $< -o $#
To do that, but put the object file in obj/:
SRC := src
OBJ := obj
$(OBJ)/foo.o: $(SRC)/foo.c
$(CC) -I$(SRC) -c $< -o $#
A pattern rule that will do that for any such object file (obj/foo.o, obj/bar.o, ...):
SRC := src
OBJ := obj
$(OBJ)/%.o: $(SRC)/%.c
$(CC) -I$(SRC) -c $< -o $#
To create the list of desired objects:
SOURCES := $(wildcard $(SRC)/*.c)
OBJECTS := $(patsubst $(SRC)/%.c, $(OBJ)/%.o, $(SOURCES))
And a rule to cover them all:
all: $(OBJECTS)
Putting it all together:
SRC := src
OBJ := obj
SOURCES := $(wildcard $(SRC)/*.c)
OBJECTS := $(patsubst $(SRC)/%.c, $(OBJ)/%.o, $(SOURCES))
all: $(OBJECTS)
$(CC) $^ -o $#
$(OBJ)/%.o: $(SRC)/%.c
$(CC) -I$(SRC) -c $< -o $#
Note that this has one big shortcoming: is does not track dependencies on header files. This can be done automatically, but it's a subtle trick; it can wait until you've mastered this much.

Related

How to redirect the output of object files to another directory?

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)

Compiling lot of .c files to .o files using makefile

I want to compile all .c files to .o files except some of them. Any help?
Currently my commands are looking like this:
%.o: %.c
$(CC) -C -o $(CFLAGS) $# $^
but I made a
EXCEPTIONS2 = testadmin.c testclient.c testserver.c server_comm.c client_comm.c
TO_COMPILE = $(filter-out $(EXCEPTIONS2), $(wildcard *.c))
But i dont know how to put them together, any idea?
You need to add a target that depends on those files. You can, for example, get all files in a directory like
SOURCEDIR := Some/Directory/You/Like
SOURCES := $(shell find $(SOURCEDIR) -name '*.c')
EXCEPTIONS2 = testadmin.c testclient.c testserver.c server_comm.c client_comm.c
TO_COMPILE = $(filter-out $(EXCEPTIONS2), $(SOURCES))
and then do something like:
%.o: %.c
$(CC) -C -o $(CFLAGS) $# $^
all: $(TO_COMPILE:%.c=%.o)
Just add a target that depends on the object files you want to be created:
.PHONY: all
all: $(TO_COMPILE:%.c=%.o)
and that's all.

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 executes the command only once

I am using the Makefile of MinGW (Windows 8.1, GCC 7.3.0) to build a medium-sized project automatically detecting all source files under the folder src and compiling all object files into the obj folder, but unfortunately it is only executing the command over the first detected file and stops there.
This is the first time I write a Makefile script for anything beyond one source file and maybe I am getting some rule wrongly. Thanks in advance!
CC := gcc
SRC := src
OBJ := obj
MAIN := main
PACK := libbundle
SOURCES := $(wildcard $(SRC)/*.c)
OBJECTS := $(patsubst $(SRC)/%.c,$(OBJ)/%.o, $(SOURCES))
CFLAGS := -I$(SRC)
$(OBJECTS): $(SOURCES)
$(CC) $(CFLAGS) -c $< -o $#
# build:
# ar rcs $(PACK).a $(OBJECTS)
# $(CC) -shared -o $(PACK).so $(OBJECTS)
# $(CC) -o $(MAIN).c $(PACK).so
Output:
gcc -Isrc -c src/firstsource.c -o obj/firstsource.o
...and stops there!
Problem - rule with multiple targets
Your rule
$(OBJECTS): $(SOURCES)
$(CC) $(CFLAGS) -c $< -o $#
has multiple targets. I don't believe this is appropriate here. See discussion here of where rules with multiple targets are useful.
Also, this rule specifies multiple prerequisites - but $< represents only the first prerequisite. You can use $+ to capture all prerequisites - but then you lose the ability to use the -o option. See below if you want to use multiple prerequisites.
What $(OBJECTS): $(SOURCES) means in detail
Suppose, for example, that your src/ directory contains firstsource.c and secondsource.c. Then your variables become
$(SOURCES) -> src/firstsource.c src/secondsource.c
$(OBJECTS) -> obj/firstsource.o obj/secondsource.o
(Actually - and somewhat non-intuitively - firstsource will be placed after secondsource, but let's ignore that for simplicity's sake.)
So the rule
$(OBJECTS): $(SOURCES)
$(CC) $(CFLAGS) -c $< -o $#
is equivalent to
obj/firstsource.o obj/secondsource.o: src/firstsource.c src/secondsource.c
$(CC) $(CFLAGS) -c $< -o $#
This rule, in turn, is equivalent to two rules (since it has multiple targets) - each with the same prerequisites:
obj/firstsource.o: src/firstsource.c src/secondsource.c
$(CC) $(CFLAGS) -c $< -o $#
obj/secondsource.o: src/firstsource.c src/secondsource.c
$(CC) $(CFLAGS) -c $< -o $#
Can you see the problem here?
Since $< represents only the first prerequisite, the recipe for the first rule becomes
gcc -Isrc -c src/firstsource.c -o obj/firstsource.o
which is fine for the first rule, but for the second rule it won't work
gcc -Isrc -c src/firstsource.c -o obj/secondsource.o
because you are using the wrong input file.
By the way ... You mentioned that
unfortunately it [i.e. make] is only executing the command over the first detected file and stops there.
This is because - when you invoke make without any arguments - it calls the first rule in the file and no more.
Option 1: Use multiple rules
What is more suitable here are multiple rules - each with only a single target. So try replacing the above with the following.
$(OBJ)/%.o: $(SRC)/%.c
$(CC) $(CFLAGS) -c $< -o $#
compile-only: $(OBJECTS)
You could invoke make on this modified Makefile as
make -B compile-only
Option 2: Single target with multiple prerequisites
If you have multiple prerequisites in your target, you can refer to them in your recipe using the special variable $+. However, you can not use the -o option in this case - so will not be able to specify the output directory for the object files. (To work around this, you could cd to the obj directory before compiling - but then you will need to tweak the SOURCES variable.)
CC := gcc
CFLAGS := -Isrc
SRC := src
SOURCES := $(wildcard $(SRC)/*.c)
myobjs: $(SOURCES)
$(CC) $(CFLAGS) -c $+
This will place all the object files in the top-level directory. As mentioned, you can tweak SOURCES and cd the obj directory if you must place the object files in a separate directory.
Aside - pre-defined recipes for pattern rules
I understand the rationale in placing the build output in a separate directory as you have done, but - if you were willing to place the build output in the same directory as the source files - you could simplify your Makefile using make's predefined pattern rules.
SOURCES := $(wildcard $(SRC)/*.c)
OBJECTS := $(SOURCES:.c=.o)
compile: $(OBJECTS)
You should use standard targets in your Makefile, the most important one being "all". And it should be the first target in the Makefile so that make and make all do the same thing.
all: $(OBJECTS)
With $(OBJECTS): $(SOURCES) you are telling make that each file in $(OBJECTS) depends on every file in $(SOURCES) and will execute the commands below as any of the objects fails the test of being newer than any of the sources. The command will be executed only once and stop.
What you need is to specify that each object file depends on its correspondient source file. As I see you are using GMAKE syntax, I'll show you the GNU make syntax for such a rule:
$(OBJECTS): obj/%.o: src/%.c
$(CC) $(CFLAGS) -c $< -o $#
this is as if you had a rule for each .o file that says how to compile it from its proper source file.
you will also need to say which files are your default targets, with something like:
.PHONY: all
all: $(OBJECTS)
clean:
$(RM) $(TOCLEAN)
put that rule the first one, so it will be selected by default.
This will make all your default target. It will explode into all your object files, and for each object you have a rule that says how to compile it (not neccessary, as gnu make already know how to compile a C program, but repeating it here doesn't hurt)
your final Makefile is:
CC := gcc
SRC := src
OBJ := obj
MAIN := main
PACK := libbundle
CFLAGS := -I$(SRC)
PICFLAGS := -fPIC
SOURCES := $(wildcard $(SRC)/*.c)
OBJECTS := $(patsubst $(SRC)/%.c, $(OBJ)/%.o, $(SOURCES))
TOCLEAN += $(OBJECTS)
PICOBJECTS := $(patsubst $(OBJ)/%.o, $(OBJ)/%.pic, $(OBJECTS))
TOCLEAN += $(PICOBJECTS)
.PHONY: all
.SUFFIXES: .c .o .pic
all: $(PACK).a $(MAIN)
clean:
$(RM) $(TOCLEAN)
$(MAIN): $(MAIN).o $(PACK).so
$(CC) $(LDFLAGS) -o $# $+
TOCLEAN += $(MAIN)
$(PACK).a: $(OBJECTS)
ar r $(PACK).a $(OBJECTS)
TOCLEAN += $(PACK).a
$(PACK).so: $(PICOBJECTS)
$(LD) $(LDFLAGS) -shared -o $(PACK).so $(PICOBJECTS)
TOCLEAN += $(PACK).so
# this to create a normal .o file in $(OBJ) directory.
$(OBJECTS): $(OBJ)/%.o: $(SRC)/%.c
$(CC) $(CFLAGS) -o $# -c $<
# this to create a PIC (Position Independent Code) .pic object in $(OBJ) directory.
# (REQUIRED FOR .so SHARED OBJECT)
$(PICOBJECTS): $(OBJ)/%.pic: $(SRC)/%.c
$(CC) $(CFLAGS) $(PICFLAGS) -o $# -c $<

Makefile can't find linux/ library

I'm attempting to build a loadable kernel module dependent on several source files, but I'm getting this error:
/home/.../Uart.h:3:28: fatal error: linux/spinlock.h: No such file or directory
#include <linux/spinlock.h>
^
The main module code is all in one file (call it "xdev.c"). The dependencies are mostly functions that I need to call in the module and are included by their header files. I have the files organized like this:
./
bin/
This is where I want the compiled dependencies (.o files to go)
src/
My dependencies .c and .h files
...
Uart.h # Error is in this file
Uart.c
Crc8.h
Crc8.c
...
xdev.c # This file include <linux/...> files with no trouble
Makefile
I'm new to using make files, but based on tutorials and questions here, primarily this one, I created this make file:
TARGET = xdev
LINKER = gcc
# None of the compiler or linker flags I have tried worked, so I removed them
LFLAGS =
CFLAGS =
KERN_DIR = /lib/modules/$(shell uname -r)/build/
MOD_SRC = $(shell pwd)
INC_DIR = $(MOD_SRC)/src
SRC_DIR = $(MOD_SRC)/src
BIN_DIR = $(MOD_SRC)/bin
RM = rm -f
SOURCES = $(wildcard $(SRC_DIR)/*.c)
INCLUDES = $(wildcard $(INC_DIR)/*.h)
OBJECTS = $(SOURCES:$(SRC_DIR)/%.c=$(BIN_DIR)/%.o)
$(TARGET): $(OBJECTS)
#$(LINKER) $(OBJECTS) $(LFLAGS) -o $#
$(OBJECTS): $(BIN_DIR)/%.o : $(SRC_DIR)/%.c
#$(CC) $(CFLAGS) -c $< -o $#
obj-m += $(TARGET).o
$(TARGET)-objs := $(OBJECTS)
all:
+make -C $(KERN_DIR) M=$(MOD_SRC) modules
clean:
+make -C $(KERN_DIR) M=$(MOD_SRC) clean
$(RM) $(OBJECTS)
My understanding of what it does is:
make a list of all .c files and the corresponding location for the .o file
OBJECTS = $(SOURCES:$(SRC_DIR)/%.c=$(BIN_DIR)/%.o)
compile the .c files to create the .o files
$(OBJECTS): $(BIN_DIR)/%.o : $(SRC_DIR)/%.c
#$(CC) $(CFLAGS) -c $< -o $#`
link to the .o files so the program knows what the functions defined in the .h files are
$(TARGET): $(OBJECTS)
#$(LINKER) $(OBJECTS) $(LFLAGS) -o $#
add the .o files as objects of the module $(TARGET)-objs := $(OBJECTS)
The command I'm using to make is
sudo make -j4
Try, maybe, to tell your compiler where to look for header files:
$(OBJECTS): $(BIN_DIR)/%.o : $(SRC_DIR)/%.c
#$(CC) $(CFLAGS) -I$(INC_DIR) -I<kernel-folder>/include -c $< -o $#

Resources