Simple Non-recursive Makefile with object files in separate directory - c

I have searched and tried a few examples to get a simple project done using non-recursive makefiles. In the past, I had used simple single directory codebase but now I am putting together an environment for more than one engineer :-)
+--app
| +-- obj/
| +-- Makefile
| +-- first.c
| +-- second.c
|
+--lib1
| +-- obj/
| +-- Makefile
| +-- foo.c
| +-- bar.c
|
+--lib2
| +-- obj/
| +-- Makefile
| +-- sample.c
Nothing fancy- just two directories (maybe a third later) with library code and multiple applications all in the "app" directory. I want to keep the .o and .d files in a separate obj/ directory for cleanliness.
I would like to be able to do a "make" in each of the sub-directories like lib1 and lib2 to verify the libraries. They will produce libabc.a and libxyz.a respectively.
I wrote some simple Makefile but my rules don't work and I tried to understand the GNU make manual but am getting lost.
lib1/Makefile:
lib_src = foo.c bar.c
lib_obj = $(patsubst %.c,obj/%.o,$(lib_src))
libabc.a: $(lib_obj)
#echo [Archive... $(#F)]
#$(AR) -cr libabc.a $^
obj/%.c : %.c
$(CC) $(CFLAGS) -c -o $# $<
app/Makefile:
ALL_APP = first second
% : %.c libabc.a libxyz.a
$(CC) $(CLFAGS) $^ -o $#
include ../lib1/Makefile
include ../lib2/Makefile
Now, I have trouble defining the same target in each Makefile (obviously). Like I couldn't define a clean in lib1/Makefile and app/Makefile because lib1 is included there. Makes sense though I was hoping that I could do a make clean in lib1 alone.
now when I do a make in "app", there is no rule to make obj/foo.o. I guess because the paths are all bogus. "obj/" refers to the lib1/obj/ but as the Makefile got included, that is all lost.
What am I doing wrong and can I get my project built using really simple Makefiles like I have above. Most examples online are fairly complex since they try to achieve more (I believe).
Thanks in advance (and sorry for a topic that has been discussed many times). I would rather not learn automake and cmake right now, if I can avoid it. I am hoping that my project is simple enough to not warrant use of these powerful tools.
Best regards,

Let's start with lib1/Makefile:
lib_src = foo.c bar.c
lib_obj = $(patsubst %.c,obj/%.o,$(lib_src))
libabc.a: $(lib_obj)
#echo [Archive... $(#F)]
#$(AR) -cr libabc.a $^
obj/%.c : %.c
$(CC) $(CFLAGS) -c -o $# $<
We introduce the variable HERE, and make a couple of small changes:
HERE := ../lib1
lib_src := foo.c bar.c
lib_obj := $(patsubst %.c,$(HERE)/obj/%.o,$(lib_src))
$(HERE)/libabc.a: $(lib_obj)
#echo [Archive... $(#F)]
#$(AR) -cr $# $^
$(HERE)/obj/%.c : $(HERE)/%.c
$(CC) $(CFLAGS) -c -o $# $<
This makefile will still work just as before when invoked from within lib1/. But once we make corresponding changes to lib2/Makefile, we can change app/Makefile:
ALL_APP = first second
% : %.c ../lib1/libabc.a ../lib2/libxyz.a
$(CC) $(CLFAGS) $^ -o $#
include ../lib1/Makefile
include ../lib2/Makefile
Now for the clean rule. We rename lib1/Makefile => lib1/lib1.mak and lib2/Makefile => lib2/lib2.mak, write a new lib1/Makefile:
include lib1.mak
clean:
#rm -f lib*.a obj/*
do the same in lib2/, and modify app/Makefile:
...
include ../lib1/lib1.mak
include ../lib1/lib1.mak
clean:
#rm -f $(ALL_APP)
#$(MAKE) -C ../lib1 clean
#$(MAKE) -C ../lib2 clean
(We could do it without recursion, but it would be more complicated, and there's really nothing wrong with using recursive Make in this way.)
Some further refinements are possible. For instance, it's not good to have paths hard-coded into lib1/lib1.mak and lib2/lib2.mak this way, and that can be fixed. But this is enough for one day.

Related

Makefile: Need help to build source files from different directories to a specific object directory [duplicate]

This question already has an answer here:
Makefile to put object files from source files different directories into a single, separate directory?
(1 answer)
Closed 4 months ago.
I'm writing a Makefile for my project. The project is something like this:
config.mk - variables like CC, CFLAGS, PREFIX, etc.
obj
src
|--- include
|--- foo1
| |--- 1.c
| |--- 2.c
| L--- unwanted1.c
L--- foo2
|--- bar1
| |---3.c
| |---4.c
| |---unwanted2.c
| L---unwanted3.c
|--- bar2
|---5.c
L---6.c
I wanted to exclude the unwanted .c files (they were used in a different part of the build process), build them then put the created object files in obj. But I don't know how to build them yet.
This is what I've been able to write (and worked):
# Compiler setting are defined here:
include config.mk
SRCS = src/foo1/1.c src/foo1/2.c \
src/foo2/bar1/3.c src/foo2/bar1/4.c \
src/foo2/bar2/5.c src/foo2/bar2/5.c
OBJS = $(addprefix obj/,$(notdir $(SRCS:.c=.o)))
But I don't know how to write the building part. Answers I've found used %.c and %.o, which is impossible in this case.
I tried writing it like this:
$(OBJS): $(SRCS)
${CC} -fPIC -c -Isrc/include ${CFLAGS} -o $# $<
lib: $(OBJS)
${CC} -shared -o lib.so -Wl,-soname="lib.so" $(OBJS)
But it didn't work.
make: *** No rule to make target 'obj/bar1.o', needed by 'lib'. Stop.
How can I rewrite the building part to make it work?
Thanks in advance.
Your current attempt can't work because it expands to:
obj/1.o obj/2.o ... : src/foo1/1.c src/foo1/2.c ...
and make parses this exactly as if you'd written:
obj/1.o : src/foo1/1.c src/foo1/2.c ...
obj/2.o : src/foo1/1.c src/foo1/2.c ...
...
which not only will do the wrong thing (because $< is always the same file: src/foo1/1.c so you'll always compile the same file) but will rebuild all the object files whenever any object file changes.
First let me say, it's a bad idea to dump all your object files into a single directory. What if you have src/foo1/1.c and then you also create src/foo2/bar1/1.c? You're basically saying, yes I have a complex data structure for all my sources, but even so they all must have unique names. A better idea is to mirror the source structure in the object directory, then you just need this:
OBJS = $(patsubst %.c,obj/%.o,$(SRCS))
obj/%.o: %.c
#mkdir -p $(#D)
${CC} -fPIC -c -Isrc/include ${CFLAGS} -o $# $<
If you really, really want to put all .o's into a single directory the best way to do it is with VPATH:
VPATH = $(sort $(dir $(SRCS)))
OBJS = $(addprefix obj/,$(notdir $(SRCS:.c=.o)))
obj/%.o: %.c
${CC} -fPIC -c -Isrc/include ${CFLAGS} -o $# $<

Makefile with arbitrarily many mains. How to compile all mains with one command?

I am still newish to makefile patterns. I have been working on a project based on a template makefile and project structure, however I have a good sense of what all the makefile instructions are doing.
I would like to modify this so that all the .c files in /src/mains, each with a different main call gets compiled to its own executable.
The original template had no /src/mains folder, and only one file in the /src could contain a main function call.
First the project structure
root
|
|------ Makefile
|
|------ build
| |
| |--- apps
| | |--- prog
| | |--- hello
| |
| |---- objects
| |--- *.o
|
|----- include
| |--- *.h
|
|------ src
|--- *.c // for each .h (no main calls)
|--- mains
|--- prog.c (call to main)
|--- hello.c (call to different main)
Current Makefile
Without manually writing new linking rules for each make, I found no success. I am just going to leave the cleaner, unmodified makefile here, I'd like to change this so that it automatically builds all the files in mains to /build/apps
As of right now it makes an executable called prog in /build/apps, using a main function call from within /src
CXX := gcc
CXXFLAGS := -pedantic-errors -Wall -Wextra -Werror
LDFLAGS := -lm
BUILD := ./build
OBJ_DIR := $(BUILD)/objects
APP_DIR := $(BUILD)/apps
TARGET := prog # OP: this probably needs to become a wildcard, right?
INCLUDE := -Iinclude/
SRC := $(wildcard src/*.c)
OFLAGS := -O1 -flto
OBJECTS := $(SRC:%.c=$(OBJ_DIR)/%.o)
DEPENDENCIES := $(OBJECTS:.o=.d)
all: build $(APP_DIR)/$(TARGET)
$(OBJ_DIR)/%.o: %.c
#mkdir -p $(#D)
$(CXX) $(CXXFLAGS) $(INCLUDE) -c $< -MMD -o $# $(OFLAGS)
$(APP_DIR)/$(TARGET): $(OBJECTS)
#mkdir -p $(#D)
$(CXX) $(CXXFLAGS) -o $(APP_DIR)/$(TARGET) $^ $(LDFLAGS)
-include $(DEPENDENCIES)
build:
#mkdir -p $(APP_DIR)
#mkdir -p $(OBJ_DIR)
clean:
-#rm -rvf $(OBJ_DIR)/*
-#rm -rvf $(APP_DIR)/*
If you could modify the Makefile outright that would be great, I would also appreciate any explanation so I don't need a template next time.
Also more generally, How do you like to structure your projects?
Thanks!
Make has no knowledge of programming languages at all. It is simply a tool that receives your set of rules and dependency trees.
So create a target that has all your programs as dependencies. Add it to the .PHONY target, as it is not a real file.
Also write your rules so that each program can be built independently from the others. You can have synergies, if your programs are built with common modules.
The options -p, -n and -d are helpful to debug the Makefile. Reading the manual and tutorials is a must, as always.

About generating makefile prerequisites automatically

I'm working on Stanford CS107 assignment 3, in which we implement a C version "vector". In the end I have some files in my directory,
.
├── Makefile
├── bool.h
├── vector.c
├── vector.h
└── vectortest.c
My question is about the handout Makefile, which looks like that,
CC = gcc
CFLAGS = -g -Wall -std=gnu11 -Wpointer-arith
LDFLAGS =
VECTOR_SRCS = vector.c
VECTOR_HDRS = $(VECTOR_SRCS:.c=.h)
VECTOR_TEST_SRCS = vectortest.c $(VECTOR_SRCS)
VECTOR_TEST_OBJS = $(VECTOR_TEST_SRCS:.c=.o)
SRCS = $(VECTOR_SRCS) vectortest.c
HDRS = $(VECTOR_HDRS)
EXECUTABLES = vector-test
default: $(EXECUTABLES)
vector-test: Makefile.dependencies $(VECTOR_TEST_OBJS)
$(CC) $(CFLAGS) -o $# $(VECTOR_TEST_OBJS) $(LDFLAGS)
# The dependencies below make use of make's default rules,
# under which a .o automatically depends on its .c and
# the action taken uses the $(CC) and $(CFLAGS) variables.
# These lines describe a few extra dependencies involved.
Makefile.dependencies:: $(SRCS) $(HDRS)
$(CC) $(CFLAGS) -MM $(SRCS) > Makefile.dependencies
-include Makefile.dependencies
.PHONY: clean
clean:
-rm -fr $(EXECUTABLES) *.o core Makefile.dependencies
When I run make vector-test, a file Makefile.dependencies was generated, in which lies some "default rules" of make,
vector.o: vector.c vector.h bool.h
vectortest.o: vectortest.c vector.h bool.h
My question is: professor keep the result of preprocess in another file is just to show us what the "default rules" is, or it's for some efficiency reason? For example GNU-GCC-3.22 Using Precompiled Headers can save times by preventing compile from processing header files over and over again? Because normally we don't have to list all .h files, and simply do gcc -c vector.c, or leave everything to the implicit rules. Am I right?
Another question is why he use :: instead of : here? I didn't find some useful information online talking about that. Thanks guys!
professor keep the result of preprocess in another file
Not true. According to your makefile, preprocessing result is not stored in any files. Preprocessing is a result of running preprocessor on your source files, i.e. it will substitute the contents of header files in place of #include directives and evaluate and substitute macros.
Instead, in your makefile, a header dependency rules are generated and stored in Makefile.dependencies. The -MM key of gcc generates header dependency rules, so that in case you edit one of the header files on which your source files depend, those source files will be recompiled next time you invoke make.
In your makefile you then include the generated dependency rules with -include Makefile.dependencies, so that make picks up header dependency rules generated by previous make invocation.
The contents of Makefile.dependencies, as you have noticed, are a valid makefile syntax.
See https://www.gnu.org/software/make/manual/html_node/Automatic-Prerequisites.html for more info.
So, this is kind of efficiency reasons, so that you can avoid rebuilding all, by cleaning first in case some of the header files are edited. But also, it is a convenience reason, that you don't have to worry about remembering to clean and rebuild all in case you have edited some of the header files. The make utility will rebuild only affected source files.
Precomiled headers is not related to that.
Thanks #igagis and #MadScientist for following great references:
Mad-Scientist.net - Auto-Dependency Generation
GNU - Generating Prerequisites Automatically
GNU - How Makefiles Are Remade
The follow content is just a simple conclusion of Mad-Scientist.net - Auto-Dependency Generation, for more information please check the original link.
In short, there are two conventional practices to generate prerequisites automatically,
Old-school way is to use gcc -MM to create a single dependencies file.
vector.o: vector.c vector.h bool.h
vectortest.o: vectortest.c vector.h bool.h
The code snippet looks like,
depend:: $(SRCS) $(HDRS)
$(CC) $(CFLAGS) -MM $(SRCS) $(LDFLAGS) > $(DEP_FILE)
-include $(DEP_FILE)
This practice has two main problems:
You have to explicitly run make depend to keep dependencies file up to date.
It is inefficient to rebuild all dependencies if any tiny change is made in source code, especially when you have a large scale project to manage.
A second modern way solves above problems by separating each dependency rule into one .d file.
In vector.d:
vector.o vector.d: vector.c vector.h bool.h
In vectortest.d
vectortest.o vectortest.d: vectortest.c vector.h bool.h
The point here is that when make read the above rule in .d file, before it does anything, it will try to rebuild included .d file automatically, and that makes the difference. People don't have to explicitly run make depend.
The following snippet is not the final version but to give you a little taste about what the code looks like. There are some little tricks hiding behind, check the references above for complete solution.
%.d: %.c
#set -e; rm -f $#; \
$(CC) -M $(CPPFLAGS) $< > $#.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $# : ,g' < $#.$$$$ > $#; \
rm -f $#.$$$$
-include $(wildcard $(SRCS:.c=.d))
Currently I feel comfortable with the first practice, because it's quite simple and good enough for most of my personal use case. And here is the complete Makefile for this assignment.
# 1. C11 is the newest version of C language
# 2. -Wpointer-arith request a warning when addtion and subtraction are done
# on pointers to void and to functions, which is supported in GNU C.
CC = gcc
CFLAGS = -g -Wall -std=gnu11 -Wpointer-arith
LDFLAGS =
VECTOR_SRCS = vector.c
VECTOR_HDRS = $(VECTOR_SRCS:.c=.h)
VECTOR_OBJS = $(VECTOR_SRCS:.c=.o)
VECTOR_TEST_SRCS = vectortest.c $(VECTOR_SRCS)
VECTOR_TEST_OBJS = $(VECTOR_TEST_SRCS:.c=.o)
SRCS = $(VECTOR_SRCS) vectortest.c
HDRS = $(VECTOR_HDRS)
OBJS = $(SRCS:.c=.o)
EXES = vectortest
DEP_DIR = ./deps
DEP_FILE = $(DEP_DIR)/Makefile.dependencies
.PHONY: default depend clean
default: $(EXES)
# 1. The dependencies below make use of make's default rules,
# under which a .o automatically depends on its .c and
# the action taken uses the $(CC) and $(CFLAGS) variables.
# These lines describe a few extra dependencies involved.
#
# 2. -MMD means write a dependencies file containing user headers.
# -MM likes -MMD, but also implies -E only do preprocess,
# and write to stand out by default.
depend:: $(SRCS) $(HDRS)
$(CC) $(CFLAGS) -MM $(SRCS) $(LDFLAGS) > $(DEP_FILE)
-include $(DEP_FILE)
vectortest: $(VECTOR_TEST_OBJS) depend
$(CC) $(CFLAGS) -o $# $(VECTOR_TEST_OBJS) $(LDFLAGS)
clean:
-rm -f *.o $(EXES) $(DEP_FILE)

Compiling all C files and creating executable with Makefile

I have a C project, which has the following file structure:
Makefile
src
|-utils
| |--vic.c
| |--vic.h
|-mod
| |--type.c
| |--type.h
|-bb.c
|-bb.h
|-main.c
So, at the root directory I have the actual Makefile and the src directory, which includes the source files. Inside the src directory there are multiple .c and .h files along with the main.c file, and there are other directories which also contain other .c and .h files. Please note that the above shown file structure is kept short for brevity. I want to create a Makefile that will automatically compile everything and generate an executable main program, and also delete the object files generated during the compilation. Currently, I have something like this:
CC=gcc
CFLAGS=
RM=rm -rf
OUT=main
SRC=src
OBJ=obj
SOURCES=$(wildcard $(SRC)/*.c)
OBJECTS=$(patsubst $(SRC)/%.c, $(OBJ)/%.o, $(SOURCES))
all: build
build: $(OBJECTS)
$(CC) $(CFLAGS) $^ -o $#
$(RM) $(OBJ)
$(OBJ)/%.o: $(SRC)/%.c
$(CC) $(CFLAGS) -I$(SRC) -c $< -o $#
debug: CFLAGS+=-DDEBUG
debug: build
.PHONY: clean
clean:
$(RM) $(OBJ) $(OUT)
But that doesn't seem to work as expected, as when I issue make command, it returns the following error message:
Assembler messages: Fatal error: can't create obj/main.o: No such file
or directory
Any ideas how to achieve what I want?
It seems you rm -rf obj/ after each step, but there's no mkdir -p obj/ to replace it.
Since GNU make will, itself, remove intermediate targets, I don't see why you would do $(RM) $(OBJ), but your %.o target could have a line like
mkdir -p "$(shell dirname "$#")"
… to ensure that the destination directory exists.
PS: your output is named build rather than main because that's the name you gave it …

makefile within non-standard directory layout

A very similar question, but not exact to those asked frequently; my project has the following layout (cross-platform, hence different IDEs, etc.)
[Project]
|
|--- codeblocks
| |- obj
|--- src
|--- visual_studio
Essentially, I'm trying to get my makefile (located in the codeblocks directory), to compile the files contained within src, and have the object files put into the obj directory.
The compilation side I can acheive with no problem, but I can't for the life of me figure out how to tell make to use this alternative directory as the default location for the object files; moving them afterwards I can do, but means I have to recompile the entire application each time I do a build, which defeats the object of the makefile.
Reading through the make documentation (yes, I did try first, and learnt some extra things on the way!), I came across some examples, such as
$(OBJDIR)/%.o: %.c, but make is unable to find the rule to utilize it, and I am nowhere near experienced enough to work it out for myself :(
Can anyone point me in the right direction or provide some suitable hints?
Here is a simple example Makefile demonstrating how to do this.
SOURCES = $(wildcard src/*.c)
OBJECTS = $(SOURCES:src/%.c=obj/%.o)
obj/%.o: src/%.c
$(CC) $(CFLAGS) -c -o $# $<
target.exe: $(OBJECTS)
$(CC) -o $# $^ $(LDFLAGS) $(LDLIBS)
The directory structure and files needed by the Makefile are:
project/
project/Makefile
project/src/*.c
project/obj
I tested this on my machine and it ran correctly:
$ make
cc -c -o obj/main.o src/main.c
cc -o target.exe obj/main.o
If you are using GNU make, you can use the extended pattern rules like you describe. You can then have a rule
$(OBJDIR)/%.o: $(SRCDIR)/%.c
$(CC) $(CFLAGS) -c -o $# $^
To compile the source files. The additional complication is that you linking rule needs to also specify $(OBJDIR) for all the object files. You can use something like
SOURCES = $(wildcard $(SRCDIR)/*.c)
OBJECTS = $(SOURCES:$(SRCDIR)/%.c=$(OBJDIR)/%.o)
$(TARGET): $(OBJECTS)
$(CC) -o $# $^ $(LDFLAGS) $(LDLIBS)
Alternately, you can use VPATH to avoid the need for $(SRCDIR) in all these places.

Resources