Generic `make` rule for generating object files from source files - makefile

I have all my source files in a directory called src and I would like all object files to be placed in a directory obj. It is possible to write a generic make rule (that preferably also works with nmake) that will generate the object file corresponding to the source file and place it in the correct directory?

With nmake, you can use an inference rule with paths:
{src\}.c{obj\}.obj:
$(CC) $(CFLAGS) -c -o $# $<

For GNU make you can use pattern rules, like so:
SRCDIR = src
OBJDIR = obj
$(OBJDIR)/%.o : $(SRCDIR)/%.c
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $# $<

Related

Using GNU Make to compile non-existent object files

I've been learning C++ for a few months now by just using an editor and my terminal to compile and run my programs. But I saw a need to be a bit more formal with my projects, so I'm trying to learn how to build a proper project file structure and also how to use Make.
Currently, I am using GNU Make 4.1. But I am having trouble to creating object files with Make, receiving the error:
make: *** No rule to make target 'build/%.o', needed by 'main'. Stop.
I've been looking all over for a solution, but none have worked so far.
Here is my makefile:
# Specify compiler
CC=gcc
# Specify linker
LINK=gcc
# Specify flags
CPPFLAGS = -Wall -g
# Specify directories
SRCDIR = ./src
OBJDIR = ./build
# Compile object files
$(OBJDIR)/%.o : $(SRCDIR)/%.cpp
$(CC) -c -o $# $< $(CPPFLAGS)
# Compile object files into binary
main : $(OBJDIR)/%.o
$(CC) -o $# $^
Consider the final rule...
# Compile object files into binary
main : $(OBJDIR)/%.o
$(CC) -o $# $^
Unfortunately $(OBJDIR)/%.o isn't expanded in the way in which you require. Assuming all of your source files are in $(SRCDIR) you can create a variable containing their names...
SRCFILES := $(wildcard $(SRCDIR)/*.cpp)
Now create a variable containing the corresponding object file paths...
OBJFILES := $(patsubst $(SRCDIR)/%.cpp,$(OBJDIR)/%.o,$(SRCFILES))
Now $(OBJFILES) should contain the list of object file paths on which main is dependent. So the final rule becomes...
main: $(OBJFILES)
$(CC) -o $# $^

Create object files in one folder from different source folders

I am creating a Makefile of a Keil based project. I have a working Makefile now, but I have manually written rules for all the source files, something like this:
out/abc.o: ../../../src/modules/abc.c
ARMCC -o $# $(FLAGS) $^
out/def.o: ../../../src/utilities/def.c
ARMCC -o $# $(FLAGS) $^
out/xyz.o: src/xyz.c
ARMCC -o $# $(FLAGS) $^
which has become kinda long. The object files need to be in one directory(/out), but the source files are in different levels and in various folders like utilities, modules etc. Is there a way to shorten my Makefile so that it scans these different levels of source files and creates the object files?
EDIT:
A follow-up question to the answer. My linker rule is something like this, along with the VPATH addition. I added one directory to VPATH and others are still explicitly compiled.
OBJECT_FILES=out/abc.o out/def.o out/xyz.o
out/binary.axf: $(OBJECT_FILES)
ARMLINK $(MANY_FLAGS) $^ -o $#
VPATH=../a/b/c/module
out/%.o : %.c
$(CC) $(C_FLAGS) $(INCLUDE_PATH) -o $# --depend out/%.d $<
I now get an error that there is no rule for abc.o. abc.c which is present in the directory specified in VPATH under module
*** No rule to make target `out/abc.o', needed by `out/binary.axf'. Stop.
You can use VPATH for this. It can search a list of directories for source files. Assuming you can come up with the list of directories:
VPATH = ../../../src src
CC = ARMCC
out/%.o : %.c
$(CC) -o $# $(CFLAGS) -c $<

Including generated files in Makefile dependencies

I have a set of files that get generated.
GENERATED = log/loga.c log/logb.h include/loga.h
My target below initproc depends on GENERATED above. But I can't included $(GENERATED) below like $(INIT_OBJS). It says
fatal error: include/loga.h: No such file or directory when I do make initproc
initproc: $(INIT_OBJS) log/loga.o init/initb.o settings/settingc.o
$(CXX) $(CXXFLAGS) $(LDFLAGS) $^ $(LDLIBSXX) -o $#
How do I include the dependency above ?
You have to add a $(GENERATED) target with some rules to explain how to generate this files. Moreover you have to manage header, source and object files by using some patsusbt and filter functions. Something like that should be working:
# All the generated files (source and header files)
GENERATED := log/loga.c log/logb.h include/loga.h
# The rules to generate this files
$(GENERATED):
<some commands to generate the files ...>
# The rules to generate object files from the generated source files
# This could be merge with another rule from your Makefile
GENERATED_SRC := $(filter %.c,$(GENERATED))
GENERATED_OBJ := $(patsubst %.c,%.o,$(GENERATED_SRC))
$(GENERATED_OBJ): $(GENERATED_SRC)
$(CXX) $(CXXFLAGS) -c $^ -o $#
# The final target depends on the generated object files
initproc: $(INIT_OBJS) <other objects ...> $(GENERATED_OBJ)
$(CXX) $(CXXFLAGS) $(LDFLAGS) $^ $(LDLIBSXX) -o $#

generic make rule assitance when placing files into different folders

I have a make rule like this. I want it to define a generic rule that describes transformation of any C file into compiled Object file. It works fine, but i want to keep my C files in one folder and output files in another.
Here is the relevant snippet from Makefile itself:
.SUFFIXES .c .o
.c.o :
$(GCC) -c $(CFLAGS) $< -o $#
I want to modify this makefile rule to tell make to find the source (C) files in one folder, let's say $(C_DIR), run GCC and then and put OBJ files into $(O_DIR) ?
You cannot do that with suffix rules. In order to do that you'll have to use non-POSIX-standard make features. GNU make (the standard make on GNU/Linux systems for example, and available for pretty much any other platform) provides pattern rules that can do this:
SRCS = foo.c bar.c baz.c
OBJS = $(addprefix $(O_DIR)/,$(SRCS))
all: $(OBJS)
$(O_DIR)/%.o : $(C_DIR)/%.c
$(CC) -c $(CPPFLAGS) $(CFLAGS) -o $# $<

Passing target name to a dependency in makefile

If I have the following rule in a makefile:
$(OBJ)/%.o: $(SRC)/%.c
$(CC) -c -o $# $< $(CFLAGS)
Every file matching the prefix ./obj/ and sufix .o will have its stem passed to %, so I can provide some dependencies based on its name.
But, suppose I have this kind of rule, which I specify one by one the targets I want:
OBJECTS=abc.o bca.o cba.o
$(OBJECTS): $(SRC)/%.c
$(CC) -c -o $# $< $(CFLAGS)
How do I make the % stem actually work for the current target name make is executing? Just using % doesn't work, neither $#.
Note that I'm trying to write the actual target name to its own dependency. For example, when make is executing the rule for abc.o, it would include $(SRC)/abc.c and just it (something like $(patsubst %.o, $(SRC)/%.c, MAGIC_TARGET_NAME_VARIABLE)).
You can just replace this rule:
$(OBJECTS): $(SRC)/%.c
with:
$(OBJECTS) : %.o : $(SRC)/%.c
You will need to add the $(OBJ) to the -o part of the recipe if you still want them built there:
$(OBJECTS) : %.o : $(SRC)/%.c
$(CC) -c -o $(OBJ)/$# $< $(CFLAGS)
I’m not completely clear on what you’re asking, but I think this accomplishes what you’re trying to do:
OBJECTS=abc.o bca.o cba.o
.PHONY: all
all: $(OBJECTS:%=obj/%)
$(OBJ)/%.o: $(SRC)/%.c
echo $(CC) -c -o $# $< $(CFLAGS)
All .o files are built; each .o file is built using only the .c file corresponding to it; and if you want to refer to the list of all object files or source files in the command for compiling a .o file, then you can reference ${OBJECTS} directly.
If this isn’t what you’re trying to do, you’ll be able to get a better answer by listing the input files you have, the output files you want to make, the input dependencies of each output file, and what compilation command you want to execute for each output file.

Resources