Makefile to convert all *.c to *.o - c

I am writing a Makefile for compiling all *.c files in a directory into
*.o . There are many *.c files so I don't want to do it on individual basis,
I tried
%.o: %.c
$(CC) -c $(CFLAGS) $(CPPFLAGS) -o $# $<
but this isn't working ... please help me understand what's going wrong here ...

You told make how to generate a *.o out of a corresponding *.c file. (Not that you needed to, because make already knows as much, at least as long as you don't try anything more specific than what you wrote in your rule.)
You didn't tell make you wanted any specific foo.o or bar.o, so make does nothing.
Either add a list of object files you want generated to the Makefile, or call make foo.o specifically.
----
For what it's worth, have a look at this... there are some tricks and lessons in there, which I trust your curiosity will find out about. Most importantly, it adds compiler warnings, and automated header dependency handling.
This is assuming GNU make for e.g. patsubst, the existence of find, and GCC (for the dependency handling via -MMD -MP). If you want to go cross-platform, I'd suggest a meta-build system like CMake, which I am using myself.
PROJNAME := MyProject
PROJDIRS := subdir1 subdir2
SRCFILES := $(shell find $(PROJDIRS) -type f -name "\*.c")
OBJFILES := $(patsubst %.c,%.o,$(SRCFILES))
DEPFILES := $(patsubst %.c,%.d,$(SRCFILES))
WARNINGS := -Wall -Wextra -pedantic -Wshadow -Wpointer-arith -Wcast-align \
-Wwrite-strings -Wmissing-prototypes -Wmissing-declarations \
-Wredundant-decls -Wnested-externs -Winline \
-Wuninitialized -Wconversion -Wstrict-prototypes
CFLAGS := -g -std=c99 $(WARNINGS)
.PHONY: all clean
all: $(PROJNAME)
clean:
-#$(RM) $(wildcard $(OBJFILES) $(DEPFILES) $(PROJNAME))
-include $(DEPFILES)
$(PROJNAME): $(OBJFILES)
#$(CC) $(LDFLAGS) $^
%.o: %.c Makefile
#$(CC) $(CFLAGS) -MMD -MP -c $< -o $#

Your rule maps a single .c file to a single .o, and mirrors an existing implicit rule.
In order to generate all the .o files corresponding to a set of .c files, you can create a list of object file names from the list of .c files, and then make a target that depends on that list:
SRC = $(wildcard *.c) # list of source files
OBJS = $(patsubst %.c, %.o, $(SRC)) # list of object files
objs : $(OBJS) # target
Then generate the object files with
make objs
This will build a .o file for each .c one.

You can add a rule OBJS, it will do it for you
OBJS = $(SRCS:.c=.o)
With you .c files in the SRCS, and if they are too many do:
SRCS = $(wildcard *.c)
Then add it when you'll run make
$(NAME) : $(OBJS)
[...]

Related

How to execute a generic target in a C makefile?

I want to create a Makefile, which compiles each .c file in the the directory to a .o file with the same name.
But for some reason, it does not work. I am not sure if I "call" the generic target properly. Can you help me?
CC = clang
CFLAGS = -std=c11 -pedantic -Wall -Wextra
.PHONY: clean all
all: *.o
clean:
rm -f *.o
%.o: %.c
$(CC) $(CFLAGS) -c -o $# $<
Greetings
As others commented, this line:
all: *.o
expands the right side just to the existing files.
You can use these functions to "collect" all C sources, and exchange the extension:
all: $(patsubst %.c, %.o, $(wildcard *.c))
However, not every make will support these functions.
(Note: Why can't you explicitly list the object files you want generated?)

Makefile Stops Building Files After First .o In Out-of-Source Build

I have a bit of a huge Makefile that basically works as I want it to.
Issue: The problem I'm having is that the makefile only checks if the first .o needs updating and not if any others do. I'm not sure what part of my makefile is in error.
Context: I have project structure like this:
quendor
src
main.c
options.c
quendor.h
Makefile
When my Makefile builds, it constructs a build directory and things look as follows:
quendor
build
src
main.d
main.o
options.d
options.o
src
main.c
options.c
quendor.h
Makefile
To See the Problem: Now let's say I don't change my main.c but I do change my options.c file. In that case, when I run make again I get this:
make: 'build/./src/main.o' is up to date.
I'm not sure if this is because it's building into a build/src directory rather than just build as I intended.
Here is the full Makefile and I'm including all of it just because I'm not sure what might be a problem and I don't want to make unwarranted assumptions.
.PHONY : all clean
NAME := quendor
PLATFORM := windows
CC := gcc
LINK := gcc
BUILD_DIR ?= ./build
SRC_DIR ?= ./src
ifeq ($(PLATFORM), windows)
TARGET ?= quendor.exe
else
TARGET ?= quendor
endif
ifeq ($(CC), gcc)
CFLAGS += -std=c11 -Wall -Wextra -Wpedantic -Wconversion -Wmissing-prototypes -Wshadow -MMD -MP
LDFLAGS +=
OPT +=
endif
SRCS := $(wildcard $(SRC_DIR)/*.c)
OBJS := $(SRCS:%.c=$(BUILD_DIR)/%.o)
DEPS := $(OBJS:%.o=%.d)
MKDIR_P ?= #mkdir -p $(dir $#)
-include $(DEPS)
all : $(TARGET)
#echo "Building $(TARGET)"
$(TARGET) : $(OBJS)
$(LINK) $(OPT) -o $# $^ $(LDFLAGS)
$(BUILD_DIR)/%.o : %.c
$(MKDIR_P)
$(CC) $(CFLAGS) -c $< -o $#
clean:
$(RM) $(TARGET) -r $(BUILD_DIR)
This may be an artifact of how StackOverflow is parsing my Makfile but I do notice that it's showing different syntax highlighting after this line:
SRCS := $(wildcard $(SRC_DIR)/*.c)
The problem is that you are including the dependencies before you define the all rule:
-include $(DEPS)
all : $(TARGET)
If you don't specify a particular target to build on the command line (e.g., if you don't run make all) then make chooses the first explicit target in the makefile (and any included makefiles!!) as the target to build.
I assume that the dependency definitions in the $(DEPS) variable define main.o as a target and since that comes before all, it's the only thing that's run by default.
Move the -include statement later in the makefile (I typically put these all at the end of the makefile) and it will work.

How to have gnu make treat intermediate files as out of date

I've been following http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/#combine to create a Makefile that will generate a dependency list too, so the list of header files a .o target depends on (from the related .c file) is automatically generated.
The Makefile I have ended up with is
DEPDIR := .deps
$(shell mkdir -p $(DEPDIR))
DEPFLAGS = -MT $# -MMD -MP -MF $(DEPDIR)/$*.Td
INCDIR = ../includes
CFLAGS = -I$(INCDIR)
CC = gcc
SRCS = main.c chunk.c memory.c
COMPILE.c = $(CC) $(DEPFLAGS) $(CFLAGS) $(TARGET_ARCH) -c
POSTCOMPILE = mv -f $(DEPDIR)/$*.Td $(DEPDIR)/$*.d && touch $#
%.o: %.c
%.o: %.c $(DEPDIR)/%.d
$(COMPILE.c) $(OUTPUT_OPTION) $<
$(POSTCOMPILE)
$(DEPDIR)/%.d: ;
.PRECIOUS: $(DEPDIR)/%.d
include $(wildcard $(patsubst %,$(DEPDIR)/%.d,$(basename $(SRCS))))
running make main.o generates main.o and .deps/main.d as expected, and changing one of the header files included in main.c causes main.o to be out of date and regenerated as desired.
However, main.o should also be out of date if .deps/main.d does not exist, but deleting .deps/main.d doesn't cause make to see main.o as out of date.
What needs to be changed to make deleting .deps/main.d cause make to see main.o as out of date?
I've been meaning to update my blog post. You need to ensure that the dependency files are listed as prerequisites somewhere so they're not considered intermediate. Change this line:
include $(wildcard $(patsubst %,$(DEPDIR)/%.d,$(basename $(SRCS))))
to something like:
ALLDEPS := $(patsubst %,$(DEPDIR)/%.d,$(basename $(SRCS)))
build-deps: $(ALLDEPS)
.PHONY: build-deps
include $(wildcard $(ALLDEPS))
I'm not 100% sure why these are considered intermediate and yet make doesn't delete them; I'll have to look into it more closely.

Circular dependency dropped: make, fortran and c building static library

I am trying to build a static library with mixed c and fortran code. When building the fortran files, I receive this error for each of my fortran files, but not the c files.
make: Circular file0.F90 <- file0.F90.o dependency dropped.
mpif90 -c -O2 -o "file0.F90.o" "file0.F90"
The Makefile I am using is below. My rule for F90 files is the same as for c files, so I am not sure why it should have this behaviour?
CC = mpicc
FC = mpif90
TARGET=libpxn
FCFLAGS = -O2 -fPIC
CFLAGS = -O2 -fPIC -lm -Wall
CPPFLAGS = $(CFLAGS)
SRCS = $(wildcard *.F90) $(wildcard *.c)
OBJS = $(patsubst %, %.o, $(SRCS))
# Rules
all: static
static: $(OBJS)
ar rcs $(TARGET).a $(OBJS)
%.c.o: %.c
$(CC) -c $(CFLAGS) -o "$#" "$<"
%.F90.o: %.F90
$(FC) -c $(FCFLAGS) -o "$#" "$<"
clean:
#printf "Cleaning: \n"
#find . -type f -name '*.o' -print0 | xargs -0 -I % sh -c 'printf "% "; rm -f %'
rm -f $(TARGET).so $(TARGET).a
I tried also with gnu compilers with the same result. Any ideas why this is happening?
.c is a built-in suffix, meaning at the very least there is one built-in rule defined as %.c: which will stop make from applying match anything rules (%:) to files ending with .c.
Make has no idea about .F90 on the other hand, so when it reaches the prerequisites of your %.F90.o rule, it will try to apply the match anything rule %: %.o which results in file0.F90: file0.F90.o, and a circular dependency.
The quick and dirty solution is to simply add an empty pattern rule for .F90
%.F90:
The "correct" way (IMHO) to handle this would be to rewrite your makefile to conform to the built-in implicit rules
TARGET := libpxn.a
CC := mpicc
FC := mpif90
FFLAGS := -O2 -fPIC
CFLAGS := -O2 -fPIC -Wall
ARFLAGS := rcs
CSRCS := $(wildcard *.c)
FSRCS := $(wildcard *.F90)
OBJS := $(CSRCS:.c=.o) $(FSRCS:.F90=.o)
.PHONY: all clean
all: $(TARGET)($(OBJS))
%.o: %.F90
$(COMPILE.F) $(OUPUT_OPTION) $<
%.F90:
clean:
$(info "Cleaning:")
$(RM) $(TARGET)
Make has a built-in rule for archives so you can just specify ARFLAGS and use libname(objects) as a prerequisite (IIRC if you're using GNU ar you don't need s as it'll always make an index).
The F90 recipe is copied from make's built-in rule for .F, in fact if you use .F as a fortran suffix instead of .F90 you won't even need this rule.
If you have two source files with the same stem (say foo.c and foo.F90) you'll either have to split the sources into two subdirectories (recommended), or go back to your original plan of the double suffix (you'll need to provide both rules again in that case).
I've rewritten clean as the objects are intermediate files now and will be deleted automatically after they are added to the archive.

Makefile: wildcard and patsubst does not change file source names

I am trying to write a Makefile for my project, all the *.c and *.h files are in a folder called src, and the Makefile looks like this --
CC := gcc
CFLAGS := -g -Wall -ansi -pedantic -std=gnu99
LDFLAGS := -lm
INCLUDES := $(wildcard src/*.h)
IFLAGS := $(addprefix -I/,$(INCLUDES))
SRC := $(wildcard src/*.c)
OBJS := $(patsubst %.c, %.o, $(SRC))
APP := app
all: $(OBJS)
$(APP): $(OBJS)
$(CC) $(CFLAGS) $< -o $# $(LDFLAGS)
$(OBJS): $(SRC) $(INCLUDES)
$(CC) $(CFLAGS) $(IFLAGS) -c $< -o $#
clean:
rm -rf $(OBJS)
rm -rf *.out
rm -f $(APP)
At this point I am not building the executable, just trying to compile them to object files, so when I run, I am getting this output --
gcc -g -Wall -ansi -pedantic -std=gnu99 -I/src/structure.h -I/src/rng.h -c src/allocate.c -o src/allocate.o
gcc -g -Wall -ansi -pedantic -std=gnu99 -I/src/structure.h -I/src/rng.h -c src/allocate.c -o src/auxiliary.o
gcc -g -Wall -ansi -pedantic -std=gnu99 -I/src/structure.h -I/src/rng.h -c src/allocate.c -o src/decode.o
gcc -g -Wall -ansi -pedantic -std=gnu99 -I/src/structure.h -I/src/rng.h -c src/allocate.c -o src/display.o
You can see that in each gcc invocation, the source file names do not change, they are all always src/allocate.c why ? However, the object names are correctly expanded like src/allocate.o, src/auxiliary.o and src/decode.oetc.
It seems you've mixed up some things here.
They are basically two type of rules you need to use here, and they both share the same syntax:
targets : prerequisites
recipe
When you write this:
$(APP): $(OBJS)
$(CC) $(CFLAGS) $< -o $# $(LDFLAGS)
You're saying to make that you want to create $(APP), and to do that you need $(OBJS) to exist or to be created.
Now when you write this:
$(OBJS): $(SRC) $(INCLUDES)
$(CC) $(CFLAGS) $(IFLAGS) -c $< -o $#
You're telling make you want to create a list of .o files, and for each individual file that you need all $(SRC) and $(INCLUDES).
Since in the recipe you're using $<, which is a shortcut for the first entry in the prerequisites list, you always end up with the same source file being compiled.
To do what you want, you must abstract things a little bit and tell make "Here is how I want you to build any .o file that depends on a corresponding .c". That is the job of pattern rules:
%.o: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -o $# -c $<
Ultimately, your Makefile should look like this:
APP := app
SRC := $(wildcard src/*.c)
OBJ := $(SRC:.c=.o)
CFLAGS := -W -Wall -g -std=c99 -pedantic
LDLIBS := -lm
all: $(OBJS)
$(APP): $(OBJ)
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $#
clean:
$(RM) $(APP) $(OBJ)
Note another couple of things here that you missed:
The -I preprocessor flag (that should be placed in the CPPFLAGS variable) accept a directory, not a file.
The -ansi compiler flag is a synonym of -std=c89. You're using -std=gnu99 right after so that one will be picked ultimately
You don't need to list your header files at all. Don't bother.
Don't use the -r flag of the rm command without care, you'll end up removing folders. It is not used to remove multiple files but to remove recursively, read up your man.
You used $< instead of $^ at the linking phase, so your executable will miss many object files.
To address the comments:
GNU make has a lot of predefined rules, functions and variables that you should be using before rolling your own. It has basic rules for compiling and linking C and C++ programs, among other, this is why your Makefile does not need te redefine the %.o: %c rule that already exists.
You can see all of these by typing this in your favorite shell:
$ make -p > predefined.mk
$(RM), $(CC) are one of these predefined variables, you can see by yourself what they actually contain.
Now, as many users are concerned with header files dependencies, let's adress this issue. You won't have to manually do that, modern compilers like GCC and Clang do this for you once you set them up.
The dependencies for each .c file will be generated in a .d file that must be included in the Makefile.
To tell the compiler to generate these files while compiling, you need to pass a preprocessor flag:
CPPFLAGS := -MMD
Now the dependencies are auto-generated, we need to include them:
DEP := $(OBJ:.o=.d)
-include $(DEP)
You'd also want to clean them:
clean:
$(RM) $(APP) $(OBJ) $(DEP)
Now your Makefile looks like this:
APP := app
SRC := $(wildcard src/*.c)
OBJ := $(SRC:.c=.o)
DEP := $(OBJ:.o=.d)
CPPFLAGS := -MMD
CFLAGS := -W -Wall -g -std=c99 -pedantic
LDLIBS := -lm
all: $(OBJS)
$(APP): $(OBJ)
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $#
clean:
$(RM) $(APP) $(OBJ) $(DEP)
-include $(DEP)
Last point: the syntax $(SRC:.c=.o) is a shortcut for $(SRC:%.c=%.o) which is also a shortcut for $(patsubst %.c,%.o,$(SRC)).

Resources