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

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.

Related

Discovering STM32: Writing a makefile to create src inc (etc) directories

I'm an electrical engineer who's gotten into embedded C at a beginner/intermediate level. I've found Geoffery Brown's "Discovering the STM32 Microcontroller" to be an excellent beginner embedded resource after having gone through Steve Oualline's Practical C Programming. I very much recommend that path to anyone wanting to learn embedded C.
To my question: The author of Discovering STM32 provides a Makefile scheme that includes a project-specific Makefile as well as a Makefile common (Makefile.common) to all project directories that gets included. I really want to organize my code into src, inc, obj and bin directories but the author did not provide this functionality in the makefile templates. After reading up on Makefiles and trying a few things out, I'm at a loss as to how to do it with the author-provided structure. My goal is to retain the same Makefile/Makefile.common scheme while having my code be organized into separate bin, src, inc and obj directories within my project subfolder after my .elf is built.
More simply, I want my directory structure / folders to look like :
DiscoveringSTM32
Makefile.common
ProjectA
src
main.c
stuff.c
whateverelse.c
Makefile
inc
stuff.h
whateverelse.h
bin
ProjectA.elf
obj
stuff.o
whateverelse.o
Context / what I'm working with:
FWIW, my full DiscoveringSTM32 repo is here.
The project-specific (e.g. "ProjectA") author provided Makefile looks like this:
TEMPLATEROOT = ..
# compilation flags for gdb
CFLAGS = -O1 -g
ASFLAGS = -g
LDLIBS += -lm
# object files
OBJS = $(STARTUP) main.o
OBJS += foo.o bar.o
OBJS += baz.o fee.o
OBJS += fo.o fum.o
# include common make file
include $(TEMPLATEROOT)/Makefile.common
While the author provided Makefile.common looks like
# name of executable
ELF=$(notdir $(CURDIR)).elf
# Tool path
TOOLROOT="C:\Users\Robert\OneDrive\Documents\GNU_ARM_TOOLS\9-2020-q2-update\bin"
# Library path
LIBROOT="C:\Users\Robert\OneDrive\Documents\DiscoveringSTM32\STM32F10x_StdPeriph_Lib_V3.5.0"
# Tools
CC=$(TOOLROOT)/arm-none-eabi-gcc
LD=$(TOOLROOT)/arm-none-eabi-gcc
AR=$(TOOLROOT)/arm-none-eabi-ar
AS=$(TOOLROOT)/arm-none-eabi-as
# Code Paths
DEVICE=$(LIBROOT)/Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x
CORE=$(LIBROOT)/Libraries/CMSIS/CM3/CoreSupport
PERIPH=$(LIBROOT)/Libraries/STM32F10x_StdPeriph_Driver
# Search path for standard files
vpath %.c $(TEMPLATEROOT)
# Search path for perpheral library
vpath %.c $(CORE)
vpath %.c $(PERIPH)/src
vpath %.c $(DEVICE)
# Search path for Library
vpath %.c $(TEMPLATEROOT)/Library/ff9/src
vpath %.c $(TEMPLATEROOT)/Library/ff9/src/option
vpath %.c $(TEMPLATEROOT)/Library
# Processor specific
#PTYPE = STM32F10X_MD_VL
PTYPE = STM32F10X_MD #try this for blue pill
LDSCRIPT = $(TEMPLATEROOT)/stm32f100.ld
STARTUP= startup_stm32f10x.o system_stm32f10x.o
# Compilation Flags
FULLASSERT = -DUSE_FULL_ASSERT
LDFLAGS+= -T$(LDSCRIPT) -mthumb -mcpu=cortex-m3
CFLAGS+= -mcpu=cortex-m3 -mthumb
CFLAGS+= -I$(TEMPLATEROOT) -I$(DEVICE) -I$(CORE) -I$(PERIPH)/inc -I.
CFLAGS+= -D$(PTYPE) -DUSE_STDPERIPH_DRIVER $(FULLASSERT)
CFLAGS+= -I$(TEMPLATEROOT)/Library/ff9/src -I$(TEMPLATEROOT)/Library
# Build executable
$(ELF) : $(OBJS)
$(LD) $(LDFLAGS) -o $# $(OBJS) $(LDLIBS)
# compile and generate dependency info
%.o: %.c
$(CC) -c $(CFLAGS) $< -o $#
$(CC) -MM $(CFLAGS) $< > $*.d
%.o: %.s
$(CC) -c $(CFLAGS) $< -o $#
clean:
rm -f $(OBJS) $(OBJS:.o=.d) $(ELF) startup_stm32f* $(CLEANOTHER)
debug: $(ELF)
arm-none-eabi-gdb $(ELF)
# pull in dependencies
-include $(OBJS:.o=.d)
I think I understand the jist of what's going on here where we define our object files (i.e. main.o from main.c, foo.o from foo.c) and we have rules to create the object files from their dependencies, ultimately building my flashable ELF file.
Things I've tried
After some googling and reading some online tutorials I've tried defining my directories like so:
BINDIR = bin
SRCDIR = src
OBJDIR = obj
INCDIR = inc
and then wildcarding all my .c's and .o's
# name of executable
ELF:= $(BINDIR)/$(notdir $(CURDIR)).elf
SRC := $(wildcard $(SRCDIR)/*.c)
OBJ = $(SRC:$(SRCDIR)/%.c=$(OBJDIR)/%.o)
OBJ += $(STARTUP)
I +='d in $(STARTUP) and thus the associated files defined by STARTUP as I've run into "error: no rule to make target startup_stm32f10x.o".
The farthest I've got with this endeavor is successfully creating a bin directory with the .elf file in it in my specific project directory (e.g. Documents/DiscoveringStm32/projectA). Getting there involved keeping the author-provided += object file scheme and modifying the ELF definition in makefile.common to be:
ELF:= $(BINDIR)/$(notdir $(CURDIR)).elf
I tried doing:
$(ELF) : $(OBJDIR)/$(OBJS)
$(LD) $(LDFLAGS) -o $# $(OBJS) $(LDLIBS)
# compile and generate dependency info
$(OBJDIR)/%.o: $(SRCDIR)/%.c
$(CC) -c $(CFLAGS) $< -o $#
$(CC) -MM $(CFLAGS) $< > $*.d
%.o: %.s
$(CC) -c $(CFLAGS) $< -o $#
but this threw errors.
I've come to have an appreciation for the complexities of Makefiles through all this. I'm sure I'll have learned quite a bit more about writing them once this is figured out.
Thanks for the help in advance!
In order to allow the source files to reside in src, you can use VPATH = $(SRCDIR) along with your definition of SRCDIR.
To place the object files in obj, you have to add the directory to the filenames in OBJS, e. g. with OBJS := $(OBJS:%.o=$(OBJDIR)/%.o).
The compile rule head is then $(OBJDIR)/%.o: %.c.

how to use source files that are not in current directory in makefile?

I'm new to C, sorry if my question is basic, below is my makefile:
src = $(wildcard *.c)
obj = $(src:.c=.o)
LDFLAGS = -pthread
prog: $(obj)
$(CC) -o $# $^ $(LDFLAGS)
.PHONY: clean
clean:
rm -f $(obj) prog
but I have source files(let's myfunc.c) in other directory. I don't want to copy myfunc.c to every project then compile and link it, I only want to use a single source from that directory, how can I modify my makefile to reflect this?
You must tell Make two new things: That myfunc.o is needed, and where to find myfunc.c. (I'll assume some/dir/myfunc.c.)
There is more than one way to do it. A beginner should learn the simple way:
obj = $(src:.c=.o) myfunc.o
myfunc.o: some/dir/myfunc.c
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $#
Once you understand that, you can use vpath instead:
obj = $(src:.c=.o) myfunc.o
vpath %.c some/dir

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 : Automatically compile all c files, keeping .o files in separate folder

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.

How to make `make` make an a executable for each C file in a folder?

My question is deceptively simple, but I have lost several hours of study trying to get the solution. I'm trying to create a Makefile that builds an executable for each .c file in a directory.
I have tried the following:
CC = gcc
SRCS = $(wildcard *.c)
OBJS = $(patsubst %.c,%.o,$(SRCS))
all: $(OBJS)
$(CC) $< -o $#
%.o: %.c
$(CC) $(CPFLAGS) -c $<
but this way it is creating only .o files, and not any executables. I need a rule that makes an executable for each of these .o files. Something like the following:
gcc src.o -o src
rob's answer doesn't seem to work on my machine. Perhaps, as the complete Makefile:
SRCS = $(wildcard *.c)
all: $(SRCS:.c=)
.c:
gcc $(CPFLAGS) $< -o $#
(The last two lines, are on my machine, unnecessary, as the default rules are adequate.)
Your all is telling it just to build the object files. Add something like
EXEC = $(patsubst %.c,%,$(SRCS))
all: $(EXEC)
Try the following:
% : %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -o $# $<
all: $(basename $(wildcard *.c))
and you don't even need the first two lines, as make knows how to compile and link .c files into executables. Still, it is often necessary to change make's built-in recipes.
This is the Makefile I use to compile a bunch of scheme files.
SRCS = $(wildcard *.scm)
all: $(SRCS:.scm=)
%: %.scm
chicken-csc -o $# $<

Resources