How can I make a simple makefile to generate the object files and output binary in a bin directory from any number of c source and header files in a src directory? In this example structure, main includes module_a.h and module_b.h. module_a.h and module_b.h each only include stdio.h.
I can manage the clean rule, but do not know how to automatically generate the .o files and dependencies.
├── bin
├── makefile
├── README.md
└── src
├── main.c
├── module_a.c
├── module_a.h
├── module_b.c
└── module_b.h
This is a simple Makefile that I use. I'm not a Makefile guru so most likely it can be improved. But it should give you something to start with. The only tricky bit is the dependency handling. I am aware that there are other ways to do this. The example shows one way - generate .d files for each object file which lists the dependencies for that object file. Then include all the .d files into the Makefile to pick up all those dependency rules.
BIN := bin/my_binary
# Include all C files in the src directory
SRCS := $(shell find src -name '*.c')
# List of object files to link
OBJS := $(patsubst %.c,%.o,$(SRCS))
# Link rule
$(BIN): $(OBJS)
$(CC) -o $# $(OBJS)
# Include Dependency files
-include $(OBJS:.o=.d)
# Builds object file and generates dependency
%.o: %.c
$(CC) -c $(CFLAGS) $*.c -o $*.o
$(CC) -MM $(CFLAGS) $*.c > $*.d
mv -f $*.d $*.d.tmp
sed -e 's|.*:|$*.o:|' < $*.d.tmp > $*.d
rm $*.d.tmp
Related
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 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.
I'm trying to use out-of-source builds with a project using GNU bison & flex for parsing and lexing.
Build is managed by GNU Make, and everything went well until I separated the logic from the main .y file to a new .c file.
The Makefile is adopted from this post.
The main problem is that .tab.h is generated by bison, and it is generated inside a build directory: ./build/src/parser.tab.h.
I manged to solve this problem in an ad-hoc manner, by including the .tab.h using a relative path #include "../build/src/parser.tab.h" and adding .tab.c to the dependencies for C files.
Is this considered a good practice?
Is there a way to implicitly state this in Makefile and/or including the generated .tab.h file?
Here is my C file:
#include "../build/src/parser.tab.h"
int main(int argc, char *argv[])
{
yyparse();
return 0;
}
and Makefile:
TARGET_EXEC := parser
BUILD_DIR := ./build
SRC_DIRS := ./src
SRCS := $(shell find $(SRC_DIRS) -name *.c -or -name *.y -or -name *.l)
OBJS := $(SRCS:%=$(BUILD_DIR)/%.o)
DEPS := $(OBJS:.o=.d)
INC_DIRS := $(shell find $(SRC_DIRS) -type d)
INC_FLAGS := $(addprefix -I,$(INC_DIRS))
CC := gcc
CFLAGS := -O0 -Wall -Wextra -Wpedantic -std=c17
CPPFLAGS := $(INC_FLAGS) -MMD -MP
LDFLAGS := -ly -ll
YACC := bison
YFLAGS := -d
LEX := flex
LFLAGS :=
$(BUILD_DIR)/$(TARGET_EXEC): $(OBJS)
$(CC) $(OBJS) -o $# $(LDFLAGS)
$(BUILD_DIR)/%.c.o: %.c build/src/parser.tab.c
mkdir -p $(dir $#)
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $#
%.y.o: %.tab.c
mkdir -p $(dir $#)
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $#
%.l.o: %.yy.c
mkdir -p $(dir $#)
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $#
$(BUILD_DIR)/%.tab.c: %.y
mkdir -p $(dir $#)
$(YACC) $(YFLAGS) $< -o $#
$(BUILD_DIR)/%.yy.c: %.l
mkdir -p $(dir $#)
$(LEX) $(LFLAGS) -o $# $<
.PHONY: clean
clean:
rm -r $(BUILD_DIR)
-include $(DEPS)
Here are MWE lexer & parser:
%{
#include "parser.tab.h"
#include <stdio.h>
%}
ws [ \t]+
%%
{ws} { ; } // skip whitespaces
. { printf("unknown token %c\n", yytext[0]); }
%%
prgm: ;
Tree before & after:
.
├── Makefile
├── build
│ ├── parser
│ └── src
│ ├── lexer.l.d
│ ├── lexer.l.o
│ ├── lexer.yy.c
│ ├── main.c.d
│ ├── main.c.o
│ ├── parser.tab.h
│ ├── parser.y.d
│ └── parser.y.o
└── src
├── lexer.l
├── main.c
└── parser.y
.
├── Makefile
└── src
├── lexer.l
├── main.c
└── parser.y
First, your makefile is more confusing than it needs to be because you're using the $(BUILD_DIR) variable in some places and using a hardcoded build in other places: use the variable everywhere.
Second, no you should not include the path in your source file. That means whenever you change your makefile to move something you'll have to edit your source file as well.
Instead, just add the path to search for the header file to the compiler command line. You already have an INC_FLAGS variable that contains options to tell the compiler where to look for headers; just add a new one:
INC_FLAGS := $(addprefix -I,$(INC_DIRS)) -I$(BUILD_DIR)/src
Now you can just use #include "y.tab.h" in your source.
I'm working on a C project, and I decided to put the source code and its objects in different directories. The root directory has something like that:
SmartC ▶ tree -L 1
.
├── built
├── doc
├── Makefile
├── README.md
├── src
├── tests
└── trash
So, inside both src and built directories, I put two others Makefiles to do the compile and link jobs.
The src directory (where I put the source code) has the following structure:
src
├── graph.c
├── graph.h
├── list.c
├── list.h
├── main.c
├── Makefile
├── node.c
├── node.h
├── tree.c
├── tree.h
└── types
├── complex.c
├── complex.h
├── matrix.c
└── matrix.h
and the built has the same structure, but it is intended to store all objects made by compilation.
My question is about my src/Makefile:
BINDIR = ../built/src
CC = gcc
CFLAGS = -g -Wall -O3
OBJECTS = \
$(BINDIR)/main.o \
$(BINDIR)/node.o \
$(BINDIR)/list.o \
$(BINDIR)/graph.o \
$(BINDIR)/tree.o \
$(BINDIR)/types/complex.o \
$(BINDIR)/types/matrix.o \
compile: $(OBJECTS)
$(BINDIR)/%.o: %.c
$(CC) -c $< -o $# $(CFLAGS)
This Makefile creates all the objects of the source code, inside src directory, and move them to built/src. But, every time I create a new source code file (*.c), I have to put the name of its object in this makefile, so it can be compiled. I'd like to do an automatic search, inside the src directory, and fill the "OBJECTS" variable with this search.
Is anyone has some idea of how to accomplish this? I mean, automatic search for source code inside an specific directory?
I even accept any other strategy rather than what I'm making.
=========== Answer ===============
I got the tip (in comments) about wildcards. So I did. Here is the solution I found.
src/Makefile
BINDIR = ../built/src
CC = gcc
CFLAGS = -g -Wall -O3
OBJECTS := $(patsubst %.c,$(BINDIR)/%.o,$(wildcard *.c */*.c))
compile: $(OBJECTS)
$(BINDIR)/%.o: %.c
$(CC) -c $< -o $# $(CFLAGS)
EDIT [Solved]
I like to do the following.
Create Variables to Each Directory of the Project
SRCDIR = src
OBJDIR = obj
LIBDIR = lib
DOCDIR = doc
HDRDIR = include
CFLAGS = -g -Wall -O3
Get Only the Internal Structure of SRCDIR Recursively
STRUCTURE := $(shell find $(SRCDIR) -type d)
Get All Files inside the STRUCTURE Variable
CODEFILES := $(addsuffix /*,$(STRUCTURE))
CODEFILES := $(wildcard $(CODEFILES))
Filter Out Only Specific Files
# Filter Only Specific Files
SRCFILES := $(filter %.c,$(CODEFILES))
HDRFILES := $(filter %.h,$(CODEFILES))
OBJFILES := $(subst $(SRCDIR),$(OBJDIR),$(SRCFILES:%.c=%.o))
# Filter Out Function main for Libraries
LIBDEPS := $(filter-out $(OBJDIR)/main.o,$(OBJFILES))
Now it is Time to create the Rules
compile: $(OBJFILES)
$(OBJDIR)/%.o: $(addprefix $(SRCDIR)/,%.c %.h)
$(CC) -c $< -o $# $(CFLAGS)
With this approach, you can see that I'm using the STRUCTURE variable only to get the files inside the SRCDIR directory, but it can be used for others purposes as well, like mirror the SRCDIR inside OBJDIR once STRUCTURE stores only the internal sub-directories. It is quite useful after clean operations like:
clean:
-rm -r $(OBJDIR)/*
NOTE: The compile rule only works well if for each *.c there is the corresponding *.h file (with the same base name, I mean).
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.