Makefile executes the command only once - c

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 $<

Related

How can I improve this Makefile to optimize the usage of the SRC and BIN folders?

This is my first attempt at making a Makefile after having gone through several tutorials and the gnu make manual. The Makefile works and creates the .o, .a and .exe files in the BIN folder. However, I have have added src\ and bin\ prefixes to all files. I know there must be a better way of addressing folder issues while using Makefiles. Only problem is, I am unable to figure it out after hours of editing and trying out different things, based on the tutorials. I find GNU make manual too overwhelming at this stage of my learning curve.
I am using MinGW GCC toolchain on Windows 7. I have copied mingw32-make.exe to make.exe for the purpose of trying out the tutorials and exampples I have been going through.
I would really appreciate any help on the subject. Thank you.
My Makefile is as follows:
CC = gcc
CFLAGS = -O3 -Wall -c
BIN = bin/
LDFLAGS = -L$(BIN) -lmyLib
all: test.exe
test.exe: test.o libmyLib.a
gcc bin\test.o -o bin\test.exe $(LDFLAGS)
test.o: src\test.c src\myLib.h
$(CC) $(CFLAGS) -o bin\test.o src\test.c
libmyLib.a: myLib.o
ar rcs bin\libmyLib.a bin\myLib.o
myLib.o: src\test.c src\myLib.h
$(CC) $(CFLAGS) -o bin\myLib.o src\myLib.c
clean:
del bin\*.* /Q
First, there are some issues with your Makefile, even if it apparently works. When you write:
myLib.o: src\test.c src\myLib.h
$(CC) $(CFLAGS) -o bin\myLib.o src\myLib.c
you are lying to make:
You tell it that the result of the rule is myLib.o while it is bin\myLib.o, that is, a different file.
You tell make that myLib.o depends on src\test.c while it in fact depends on src\myLib.c.
Same with your other rules as in:
libmyLib.a: myLib.o
ar rcs bin\libmyLib.a bin\myLib.o
You tell make that the rule shall be executed if myLib.o is newer than libmyLib.a while the real prerequisite is bin\myLib.o and the real target is bin\libmyLib.a.
By doing so you totally prevent make from doing what it is supposed to do: decide if a recipe must be executed or not, depending on the last modification times of target files and prerequisite files. Give it a try: run make twice and you'll see that it uselessly redoes what it did already. Never, never lie to make.
Second, you can improve your Makefile by using several advanced features like automatic ($#, $<, $^), standard (LDLIBS, AR, ARFLAGS) and regular (BIN, SRC) make variables. Here is an example of what you could try, after fixing the above mentioned issues and better using variables (plus adding the missing -I gcc option, and declaring all and clean as phony because these targets are not real files and we do not want to lie to make):
BIN = bin
SRC = src
CC = gcc
CFLAGS = -O3 -Wall -c -I$(SRC)
LDFLAGS = -L$(BIN)
LDLIBS = -lmyLib
AR = ar
ARFLAGS = rcs
.PHONY: all clean
all: $(BIN)/test.exe
$(BIN)/test.exe: $(BIN)/test.o $(BIN)/libmyLib.a
$(CC) $< -o $# $(LDFLAGS) $(LDLIBS)
$(BIN)/test.o: $(SRC)/test.c $(SRC)/myLib.h
$(CC) $(CFLAGS) -o $# $<
$(BIN)/libmyLib.a: $(BIN)/myLib.o
$(AR) $(ARFLAGS) $# $^
$(BIN)/myLib.o: $(SRC)/myLib.c $(SRC)/myLib.h
$(CC) $(CFLAGS) -o $# $<
clean:
del $(BIN)\*.* /Q
Now, all non-phony targets and prerequisites are regular files, the ones that are really involved in the rules. Again, give it a try and you'll see that make rebuilds only what is out of date and thus needs to be rebuilt.
If you want to get rid of the $(SRC)/ prefix you can use the vpath directive that tells make where to look for source files (I insist on source, many people try to use it for target files, this is not what it is intended for):
vpath %.h $(SRC)
vpath %.c $(SRC)
And then:
$(BIN)/test.o: test.c myLib.h
$(CC) $(CFLAGS) -o $# $<
$(BIN)/myLib.o: myLib.c myLib.h
$(CC) $(CFLAGS) -o $# $<
Note: you could also use the VPATH variable instead of the vpath directive.
Pattern rules are used to factor similar rules, like, for instance, your compilation rules that differ only by the names of the source file and object file:
$(BIN)/%.o: %.c myLib.h
$(CC) $(CFLAGS) -o $# $<
All in all:
BIN = bin
SRC = src
CC = gcc
CFLAGS = -O3 -Wall -c -I$(SRC)
LDFLAGS = -L$(BIN)
LDLIBS = -lmyLib
AR = ar
ARFLAGS = rcs
vpath %.h $(SRC)
vpath %.c $(SRC)
.PHONY: all clean
all: $(BIN)/test.exe
$(BIN)/test.exe: $(BIN)/test.o $(BIN)/libmyLib.a
$(CC) $< -o $# $(LDFLAGS) $(LDLIBS)
$(BIN)/%.o: %.c myLib.h
$(CC) $(CFLAGS) -o $# $<
$(BIN)/libmyLib.a: $(BIN)/myLib.o
$(AR) $(ARFLAGS) $# $^
clean:
del $(BIN)\*.* /Q
Finally, if you really want to avoid the $(BIN)/ prefix in your rules you will have to move to the $(BIN) directory and call make from there. You can leave the Makefile in the main directory and use the -f ../Makefile option, if you wish.
But of course this is less convenient that just typing make [goals] from the main directory. There are ways to let make test from where it has been called, and if it is not from the build directory, re-call itself with the -C and -f options such that it does its job from the build directory. But it is probably a bit too complicated if you are new to make.
If you are however interested have a look at this post that covers this topic (and more). If we simplify as much as possible what the post suggests and specialize it for your case, the final Makefile could be something like:
# here starts the black magic that makes it possible
.SUFFIXES:
BIN := bin
SRC := src
ifneq ($(notdir $(CURDIR)),$(BIN))
.PHONY: $(BIN) clean
$(BIN):
#$(MAKE) --no-print-directory -C $# -f ../Makefile SRC=$(CURDIR)/$(SRC) $(MAKECMDGOALS)
Makefile: ;
% :: $(BIN) ; :
clean:
del $(BIN)\*.* /Q
else
# here ends the black magic that makes it possible
# here starts the Makefile you would really like to write
CC := gcc
CFLAGS := -O3 -Wall -c -I$(SRC)
LDFLAGS := -L.
LDLIBS := -lmyLib
AR := ar
ARFLAGS := rcs
vpath %.h $(SRC)
vpath %.c $(SRC)
.PHONY: all
all: test.exe
test.exe: test.o libmyLib.a
$(CC) $< -o $# $(LDFLAGS) $(LDLIBS)
%.o: %.c myLib.h
$(CC) $(CFLAGS) -o $# $<
libmyLib.a: myLib.o
$(AR) $(ARFLAGS) $# $^
# here ends the Makefile you would really like to write
# a last bit of black magic
endif
The Makefile you would really like to write is what you would write if your source files and target files were all in the source directory. No prefixes any more; vpath takes care of the $(SRC)/ prefix and $(BIN)/ is useless because when this part of the Makefile is used we are already inside $(BIN).
Note: I know nothing about Windows and its various command line interfaces so there are probably some things to adapt (backslashes instead of slashes for instance).

How to use filter with *F in Makefile?

There is this line in my Makefile:
$(CC) $(CFLAGS) -o $# -c $(filter %$(*F).cpp, $(SOURCES))
Suppose I have 2 cpp file like "docinfo.cpp" and "info.cpp", when g++ build "docinfo.cpp" to "docinfo.o", it works.
g++ -I ... -o docinfo.o -c docinfo.cpp
But when g++ build "info.cpp" to "info.o", it has an error.
g++ -I ... -o info.o -c docinfo.cpp info.cpp
How do I make it work?
This is my Makefile:
CC := gcc
RM := rm -rf
WORKSPACE := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
TARGET := $(WORKSPACE)test.so
SOURCES := $(foreach dir,$(WORKSPACE),$(wildcard $(dir)source/*.c))
INCLUDE := -I$(WORKSPACE)include/
CFLAGS := $(INCLUDE) -O0 -Wall -fPIC
#CFLAGS += -g
#CFLAGS += -D__DEBUG__
OBJS := $(notdir $(SOURCES:.c=.o))
OBJ_PATH := $(WORKSPACE)object/
OBJS_O := $(addprefix $(OBJ_PATH), $(OBJS))
LIB_PATH := $(WORKSPACE)lib
LIBS := -ldl -shared
.PHONY: all clean
all: $(OBJ_PATH) $(LIB_TAG) $(TARGET)
$(OBJ_PATH):
mkdir -p $#
$(TARGET): $(OBJS_O)
$(CC) $(CFLAGS) -o $# $^ -L$(LIB_PATH) $(LIBS)
#echo "$#"
$(OBJS_O): $(SOURCES)
$(CC) $(CFLAGS) -o $# -c $(filter %$(*F).c,$(SOURCES))
clean:
-$(RM) $(OBJS_O) $(OBJ_PATH) $(TARGET)
First, why don't you just use $< rather than trying to filter out something from $(SOURCES)?
$(CC) $(CFLAGS) -o $# -c $<
If, for some weird reason, you do need the filter, then if you don't want to return a match for any value ending with $(*F).cpp, then just don't prefix it with the pattern match character (%):
$(CC) $(CFLAGS) -o $# -c $(filter $(*F).cpp, $(SOURCES))
This is weird, though, because $(*F) should expand to foo.cpp which means this would resolve to foo.cpp.cpp.
So, I think there's something quite unusual (or possibly incorrect) about your makefile... but since you've only provided the recipe and not shown us the entire rule we can't say for sure.
ETA
Now that we see your makefile, sure enough it has a problem. This rule is wrong:
$(OBJS_O): $(SOURCES)
$(CC) ...
What does this expand to, once variables are resolved? Say you have SOURCES resolving to source/foo.c source/bar.c and OBJS_O resolving to object/foo.o object/bar.o. Then the above rule resolves to:
object/foo.o object/bar.o: source/foo.c source/bar.c
$(CC) ...
What does make do here? It doesn't magically do some kind of file-by-file matching of targets to prerequisites. It interprets this rule as if you'd written this:
object/foo.o: source/foo.c source/bar.c
$(CC) ...
object/bar.o: source/foo.c source/bar.c
$(CC) ...
That is, every object depends on all the source files, so if any source file is changed every object is rebuilt.
If you want this to work correctly and put all the object files into a single directory regardless of which source directory they exist in, then you'll have to use vpath with a pattern rule, like this:
vpath %.c $(sort $(dir $(SOURCES)))
$(OBJ_PATH)%.o : %.c
$(CC) $(CFLAGS) -o $# -c $<
Now you can use $< instead of the filter function, because each object file depends on exactly and only its source file, not all the source files.

Creating a more generic makefile

I have the following makefile:
CC=gcc
CFLAGS= ---
LDFLAGS = ---
all: abc_test
abc_test: abc_test.o defn_abc.o abc.o cmocka_compass.o
$(CC) $(LDFLAGS) abc_test.o defn_abc.o abc.o cmocka_compass.o -o
abc_test
abc_test.o : abc_test.c
$(CC) $(CFLAGS) abc_test.c
defn_abc.o : ../defn_abc.c
$(CC) $(CFLAGS) ../defn_abc.c
abc.o : ../abc.c
$(CC) $(CFLAGS) ../abc.c
knownfile.o : ../../../../../knownpath.c
$(CC) $(CFLAGS) ../../../../../knownpath.c
clean:
rm *o *.log abc_test
Which will work (changed some files names) but I want to make it generic. I tried the following but I keep getting errors that there are no targets.
CC=gcc
CFLAGS= ---
LDFLAGS = ---
SRCFILES := $(shell find ../ -name '*.c')
OBJFILES := $(patsubst %.c,%.o,%(SRCFILES))
OBJFILES: all
all: $(OBJFILES)
%.o: %.c
$(CC) $(CFLAGS) %< -o %#
knownfile.o : knownpath.c
$(CC) $(CFLAGS) knownpath.c
the make file is a test folder, which contains all the test code (abs_test.c). This is also where all the objects should go. One directory up contains the c files defn_abc.c and abc.c.
Any idea what I am doing wrong?
UPDATE: Here is my latest makefile, with the error 'missing separator'
CC=gcc
CFLAGS=-c -Wall -DUNIT_TESTING -DSYS_LINUX -Ipath1 -Ipath2
LDFLAGS = -Wl,---
SRCFILES := $(shell find ../ -name '*.c')
OBJFILES := $(patsubst %.c,%.o,$(SRCFILES))
all: $(PROG)
$(PROG): $(OBJFILES)
$(CC) $(CFLAGS) $(OBJFILES) -o $# $(LDFLAGS)
all: $(OBJFILES)
%.o: %.c
$(CC) $(CFLAGS) %< -o %#
knownfile.o : knownpath.c
$(CC) $(CFLAGS) knownfile.c
This line does not do what you think it does:
OBJFILES: all
Or at least I assume so, for although it is mostly harmless, it is also useless. It declares that a target named 'OBJFILES' depends on target 'all'. It also happens to be the first target in the file, so it is the default target, but because 'all' is its prerequiste, it will cause the 'all' target to be rebuilt by default. This is precisely what would happen if you omitted that line altogether. Note, too, that this has nothing to do with the variable $(OBJFILES).
Your main problem appears to be that you are using the wrong syntax for most of your variable references. The values of variables with multi-character names are obtained via expressions of the form $(VAR) or ${VAR}, not %(var). The parentheses / braces can be omitted for single-character names. I advise you to favor the form with parentheses over the one with curly braces, especially in commands in recipes, for the latter is easy to confuse with shell syntax.
I would recommend you read about the basics of Makefile. This is a useful link intro to makefile
The variable OBJFILES is being over-written in consecutive lines in the example provided. I suspect removing line
OBJFILES: all
and using patsubst as
$(patsubst %suffix,%replacement,$(var))
might help.
#edit: Since now you asked on how to use LDFLAGS and get rid of the 'missing separator' error, here are some suggestions.
Purpose of LDFLAGS is to use to provide link time flags to compiler when all the object files are linked to make the final executable. They could look like this
all: $(PROG)
$(PROG): $(OBJFILES)
$(CC) $(CFLAGS) $(OBJFILES) -o $# $(LDFLAGS)
The error 'missing seperator' is fixed by inserting tabs instead of space in the beginning of a line describing an action/recipe to a rule. Open the Makefile again in an editor and remove the spaces in front of below lines and replace with tab.. the arrow I am using to show a tab
---->$(CC) $(CFLAGS) $(OBJFILES) -o $# $(LDFLAGS)
---->$(CC) $(CFLAGS) %< -o %#
---->$(CC) $(CFLAGS) knownfile.c

Compile multiple .c files with makefile

I would like to compile multiple .c files at once using a makefile.
I already made this:
CC= gcc
CPPFLAGS = -I.
CFLAGS = -W -Wall -ansi -pedantic
TARGET = test
RM = rm
OBJECTS = xxx.o yyy.o zzz.o
SOURCES = $(OBJECTS:.o =.c)
.PHONY: all clean
all: $(TAREGT)
clean:
$(RM) $(TARGET) $(OBJECTS)
$(TAREGT) : $(OBJECTS)
$(CC) $^ -o $#
$(OBJECTS) : $(SOURCES)
$(CC) $(CFLAGS) $(CPPFLAGS) -c $^
I have no Idea why this does not work("nothing to be done for "all"). Someone has an idea?
This line is creating a circular dependency:
SOURCES = $(OBJECTS:.o =.c)
Try replacing it with this:
SOURCES = $(patsubst %.o,%.c,$(OBJECTS))
You forgot -o $# in your 'sources to objects' rule. Thus it doesn't create anything.
You have also spelling error - your $(TARGET) is 'test', but your 'all' rule depends on $(TAREGT) which is empty. You are also using $(TAREGT) as input to compile 'test'.
You don't need to specify $(SOURCES) or "sources to objects" rule - implicit rules will do the trick.
In fact your "sources to objects" rule is incorrect - it says that each object depends on all sources. If you want each object to depend on one source you should use either suffix rule, pattern rule or static pattern rule. Or just implicit rule.
$(OBJECTS) : $(SOURCES)
The above tells Make that every .o file depends on all sources, i.e. if you change one of your .c files Make will recompile all .o files. Not something what you really want, I guess. I'd rework this rule as follows:
$(foreach s,$(SOURCES),$(eval $(filter %$(basename $(notdir $s)).o,$(OBJECTS)): $s))
This will iterate every source in SOURCES, find corresponding .o file in OBJECTS and create correct rule: <obj>: <source>. It is that complicated to work in case of more complex mapping between source and object files. Say, when building object files in separate directory.
This cryptic code will work even for the following weird source to object file mapping:
SOURCES := a.cpp boo/b.c c.C
OBJECTS := foo/a.o bar/b.o c.o
$(foreach s,$(SOURCES),$(eval $(filter %$(basename $(notdir $s)).o,$(OBJECTS)): $s))
It will generate the following rules:
foo/a.o: a.cpp
bar/b.o: boo/b.c
c.o: c.C
Thank you guys for you help, it is working now
I just added some rules:
CC= gcc
CPPFLAGS = -I.
CFLAGS = -W -Wall -ansi -pedantic
TARGET = test
RM = rm
SOURCES = xxx.c yyy.c zzz.c
OBJECTS = $(SOURCES:.c=.o)
.PHONY: all clean
all: $(TARGET)
clean:
$(RM) $(TARGET) $(OBJECTS)
$(TARGET) : $(OBJECTS)
$(CC) $^ -o $#
%.o: %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -c $<

Make file that compiles gcc and puts the objects in a separate folder

I am trying to create a make file that will work accordingly
OBJECT_DIRECTORY := out/obj
C_SOURCE_FILES = (Path and files fetched from different make files)
CFLAGS += -mcpu=$(CPU) -mthumb -mabi=aapcs -mfloat-abi=soft
CFLAGS += -Wall -Werror
CFLAGS += -D$(DEVICE) -std=gnu99
$(OBJECT_DIRECTORY)/%.o: %.c
$(CC) $(C_SOURCE_FILES) $(CFLAGS) -c -o $# $<
I verified that the C_SOURCE_FILES variable actually contains the c source files. This since I am able to compile using this:
$(OBJECT_DIRECTORY)/%.o:
$(CC) $(C_SOURCE_FILES) $(CFLAGS) -c
Problem with that is that the object files are not placed in the folder where I need them for the linking.
By the way, I am executing the make file from the Eclipse C/C++ IDE
I would be extremely happy if someone could help me solve this problem.
Try this:
$(OBJECT_DIRECTORY)/%.o: %.c
$(CC) $(CFLAGS) -c -o $# $<
You don't need the C_SOURCE_FILES variable here. This recipe will create out/obj/{file}.o for every file called {file}.c.
You don't show it, but the dependency list for the executable being created from the object files must explicitly call out each object file.
I solved the problem, I think... By creating a list of target files to be used in the compilation.
# Create the object file names needed for the target. Make needs these file names as target for the compilation
TEMP := $(notdir $(C_SOURCE_FILES:.c=.o))
C_OBJECT_FILES := $(addprefix $(OBJECT_DIRECTORY)/, $(TEMP:.c=.o) )
TEMP_1 := $(notdir $(ASSEMBLER_SOURCE_FILES:.s=.o))
ASSEMBLER_OBJECT_FILES := $(addprefix $(OBJECT_DIRECTORY)/,$(TEMP_1:.s=.o) )
# Tells make to compile all the files in the C_OBJECTS_VARIABLE
all: $(C_OBJECT_FILES)
# Do the compilation of the c files and place the object files in the out/obj folder
$(C_OBJECT_FILES): $(C_SOURCE_FILES)
$(CC) $(CFLAGS) -M $< -MF "$(#:.o=.d)" -MT $#
$(CC) $(CFLAGS) -c -o $# $<
# Tells make to compile all the files in the ASSEMBLER_OBJECTS_VARIABLE
all: $(ASSEMBLER_OBJECT_FILES)
# Do the compilation of the assembler files and place the object files in the out/obj folder
$(ASSEMBLER_OBJECT_FILES): $(ASSEMBLER_SOURCE_FILES)
$(CC) $(ASMFLAGS) -c -o $# $<
This works well and consistently. Issue I have now is that the rule for linking is not executed at all...
## Link C and assembler objects to an .out file
$(BINARY_DIRECTORY)/$(OUTPUT_FILENAME).out: $(C_OBJECT_FILES) $(ASSEMBLER_OBJECT_FILES) $(LIBRARIES)
$(CC) $(LDFLAGS) -o $(BINARY_DIRECTORY)/$(OUTPUT_FILENAME).out
I am wondering if it has anything to do with "all:"
Found the solution to that problem as well. I created a couple of new rules to make sure that the linking is getting executed. Now the make file works well.

Resources