rule to call another Makefile from inside a Makefile - c

I have a Makefile from which I run the command of another Makefile if some objects file do not exist already.
The rule is the following:
$(OBJDIRCOMMON)/%.o: $(COMMONDIR)/%.c $(COMMONDIR)/Makefile | $(OBJDIRCOMMON)
+$(MAKE) -C $(COMMONDIR)
where the variables are defined as follows in the same Makefile:
COMMONDIR := ../common
SOURCESCOMMON := $(wildcard $(COMMONDIR)/*.c)
OBJDIRCOMMON := $(COMMONDIR)/obj
OBJECTSCOMMON := $(patsubst $(COMMONDIR)/%.c,$(OBJDIRCOMMON)/%.o, $(SOURCESCOMMON))
DEPENDSCOMMON := $(patsubst $(COMMONDIR)/%.c,$(OBJDIRCOMMON)/%.d, $(SOURCESCOMMON))
This rule works fine but at the end of the day the only real input required by the rule is the other Makefile so I tried:
$(OBJDIRCOMMON)/%.o: $(COMMONDIR)/Makefile | $(OBJDIRCOMMON)
+$(MAKE) -C $(COMMONDIR)
but this does not work, why is that?
For completeness here is the complete Makefile
CC = gcc
INC_PATH = -I../common/
SOURCEDIR := ./
SOURCES := $(wildcard $(SOURCEDIR)/*.c)
OBJDIR :=./obj
OBJECTS := $(patsubst $(SOURCEDIR)/%.c,$(OBJDIR)/%.o, $(SOURCES))
DEPENDS := $(patsubst $(SOURCEDIR)/%.c,$(OBJDIR)/%.d, $(SOURCES))
COMMONDIR := ../common
SOURCESCOMMON := $(wildcard $(COMMONDIR)/*.c)
OBJDIRCOMMON := $(COMMONDIR)/obj
OBJECTSCOMMON := $(patsubst $(COMMONDIR)/%.c,$(OBJDIRCOMMON)/%.o, $(SOURCESCOMMON))
DEPENDSCOMMON := $(patsubst $(COMMONDIR)/%.c,$(OBJDIRCOMMON)/%.d, $(SOURCESCOMMON))
# ADD MORE WARNINGS!
WARNING := -Wall -Wextra
# OBJS_LOC is in current working directory,
EXECUTABLE := ../server
# .PHONY means these rules get executed even if
# files of those names exist.
.PHONY: all clean
# The first rule is the default, ie. "make",
# "make all" and "make parking" mean the same
all: $(EXECUTABLE)
clean:
$(RM) $(OBJECTS) $(DEPENDS) $(EXECUTABLE)
# Linking the executable from the object files
# $^ # "src.c src.h" (all prerequisites)
$(EXECUTABLE): $(OBJECTS) $(OBJECTSCOMMON)
$(CC) $(WARNING) $^ -o $#
-include $(DEPENDS) $(DEPENDSCOMMON)
$(OBJDIR):
mkdir -p $(OBJDIR)
$(OBJDIR)/%.o: $(SOURCEDIR)/%.c Makefile | $(OBJDIR)
$(CC) $(WARNING) -MMD -MP -c $(INC_PATH) $< -o $#
$(OBJDIRCOMMON):
mkdir -p $(OBJDIRCOMMON)
$(OBJDIRCOMMON)/%.o: $(COMMONDIR)/%.c $(COMMONDIR)/Makefile | $(OBJDIRCOMMON)
+$(MAKE) -C $(COMMONDIR)
EDIT
The error I get is like this:
Entering directory '/home/user/Documents/UnixSystem/network/common'
gcc -Wall -Wextra -MMD -MP -c utilities.c -o obj/utilities.o
gcc -Wall -Wextra -MMD -MP -c error.c -o obj/error.o
make[2]: Leaving directory '/home/user/Documents/UnixSystem/network/common'
gcc ../common/obj/error.d.o -o ../common/obj/error.d
gcc: error: ../common/obj/error.d.o: No such file or directory
gcc: fatal error: no input files
compilation terminated.
From which I understand the execution of the other Makefile was successful. However after that it is trying to execute this command gcc ../common/obj/error.d.o -o ../common/obj/error.d which is wrong but I do not know which rule and why it's generating it.

Why what you did was wrong
Recipe A:
$(OBJDIRCOMMON)/%.o: $(COMMONDIR)/%.c $(COMMONDIR)/Makefile | $(OBJDIRCOMMON)
+$(MAKE) -C $(COMMONDIR)
and recipe B:
$(OBJDIRCOMMON)/%.o: $(COMMONDIR)/Makefile | $(OBJDIRCOMMON)
+$(MAKE) -C $(COMMONDIR)
have essentially different meanings and will certainly not yield the same behaviour.
Recipe A says:
Any target $(OBJDIRCOMMON)/file.o must be made up-to-date if does not exist
or is older than either $(COMMONDIR)/file.c or $(COMMONDIR)/Makefile.
If a target $(OBJDIRCOMMON)/file.o must be made up-to-date, then $(OBJDIRCOMMON)
must be made up-to-date first.
To make a target $(OBJDIRCOMMON)/file.o up-to-date, run the expansion of $(MAKE) -C $(COMMONDIR) in a shell.
Recipe B says:
Any target $(OBJDIRCOMMON)/file.o must be made up-to-date if does not exist
or is older than $(COMMONDIR)/Makefile.
If a target $(OBJDIRCOMMON)/file.o must be made up-to-date, then $(OBJDIRCOMMON)
must be made up-to-date first.
To make a target $(OBJDIRCOMMON)/file.o up-to-date, execute the expansion of $(MAKE) -C $(COMMONDIR) in a shell.
Notice that criterion A.1 is different from criterion B.1. Recipe A will execute
if $(OBJDIRCOMMON)/file.o is older than $(OBJDIRCOMMON)/file.c. Recipe B will not.
Recipe B discards the dependency of the object files on the corresponding source files,
and tells Make that $(OBJDIRCOMMON)/file.o is only ever to be remade if it
is older than $(COMMONDIR)/Makefile.
at the end of the day the only real input required by the rule is the other Makefile
What you mean by "the rule" here is actually the commandline (expanded from) $(MAKE) -C $(COMMONDIR).
The inputs of this command are one thing; the criteria for executing it are another.
How what you did caused the error you see.
This is thornier. Let's reproduce it.
Here's a playpen:
$ ls -R
.:
app common
./app:
foo.c main.c Makefile
./common:
bar.c Makefile
Here, ./app/Makefile is exactly your Makefile with recipe A. ./common/Makefile,
which you didn't post, is just:
obj/bar.o: bar.c
gcc -MMD -MP -c -I. $< -o $#
because that will do for illustration.
We build in ./app:
$ cd app
$ make
mkdir -p ./obj
gcc -Wall -Wextra -MMD -MP -c -I../common/ foo.c -o obj/foo.o
gcc -Wall -Wextra -MMD -MP -c -I../common/ main.c -o obj/main.o
mkdir -p ../common/obj
make -C ../common
make[1]: Entering directory '/home/imk/develop/so/make_prob/common'
gcc -MMD -MP -c -I. bar.c -o obj/bar.o
make[1]: Leaving directory '/home/imk/develop/so/make_prob/common'
gcc -Wall -Wextra obj/foo.o obj/main.o ../common/obj/bar.o -o ../server
which is fine.
Now I change ./app/Makefile as you did, to use recipe B, and rebuild.
$ make
gcc -Wall -Wextra -MMD -MP -c -I../common/ foo.c -o obj/foo.o
gcc -Wall -Wextra -MMD -MP -c -I../common/ main.c -o obj/main.o
gcc -Wall -Wextra obj/foo.o obj/main.o ../common/obj/bar.o -o ../server
Still fine... But wait a minute! That one didn't invoke the ./common make
at all, which is the one that the change might affect. Better clean:
$ make clean
rm -f ./obj/foo.o ./obj/main.o ./obj/foo.d ./obj/main.d ../server
and try again:
$ make
gcc -Wall -Wextra -MMD -MP -c -I../common/ foo.c -o obj/foo.o
gcc -Wall -Wextra -MMD -MP -c -I../common/ main.c -o obj/main.o
gcc -Wall -Wextra obj/foo.o obj/main.o ../common/obj/bar.o -o ../server
No difference? Ah, that's because this Makefile's clean fails to delete all
the files that make builds: it leaves out ../common/obj/bar.o. So I'll just:
$ rm ../common/obj/*
And have another go:
$ make
make -C ../common
make[1]: Entering directory '/home/imk/develop/so/make_prob/common'
gcc -MMD -MP -c -I. bar.c -o obj/bar.o
make[1]: Leaving directory '/home/imk/develop/so/make_prob/common'
gcc ../common/obj/bar.d.o -o ../common/obj/bar.d
gcc: error: ../common/obj/bar.d.o: No such file or directory
gcc: fatal error: no input files
compilation terminated.
which is your mystery.
When I zapped the ../common/obj files, I deleted not only all the object files therein
but also the dependency file ../common/obj/bar.d. And now Make is trying to remake it by running:
gcc ../common/obj/bar.d.o -o ../common/obj/bar.d
How come? To answer that, we'll first change ./app/Makefile back to use recipe A
- consider it done - and then do:
$ make --print-data-base > out.txt
which dumps in out.txt all the information that Make gleans from reading all
the makefiles (Makefile and all the makefiles that it recursively include-s,
in this case just the auto-generated .d files).
Let's see what the database has to say about ../common/obj/bar.d. It says:
# Not a target:
../common/obj/bar.d:
# Implicit rule search has been done.
# Last modified 2019-01-11 16:01:33.199263608
# File has been updated.
# Successfully updated.
Certainly we don't want ../common/obj/bar.d to be a target, and it isn't a
target because, having read all the makefiles, and considered all its builtin rules,
and all of the files it can actually find, Make can't see any way in which ../common/obj/bar.d
has to be made up-to-date with respect to any of those files. Good.
Now let's revert to recipe B in ./app/Makefile again - consider it done -
and again do:
$ make --print-data-base > out.txt
and again look in out.txt concerning ../common/obj/bar.d. This time we find:
../common/obj/bar.d: ../common/obj/bar.d.o
# Implicit rule search has been done.
# Implicit/static pattern stem: '../common/obj/bar.d'
# Last modified 2019-01-11 16:01:33.199263608
# File has been updated.
# Successfully updated.
# recipe to execute (built-in):
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $#
So this time ../common/obj/bar.d is a target! And it depends on ../common/obj/bar.d.o!
And the recipe to make it is:
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $#
which will expand, of course, to:
gcc ../common/obj/bar.d.o -o ../common/obj/bar.d
How was Make able to work that out, thanks to recipe B?
Well first it considered whether any of the rules in the makefiles or any of the
builtin rules gave it direct way to make ../common/obj/bar.d from any existing files,
and drew a blank.
Next it considered whether any of those rules gave it a way to
make ../common/obj/bar.d from an intermediate file. An intermediate file being a file that doesn't exist but itself can be made
from existing files, by any of the rules it has read or its builtin-rules. This
time it saw a way.
One of Make's builtin pattern rules is:
%: %.o
# recipe to execute (built-in):
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $#
You can find it in right there in out.txt. And you can see this is the pattern rule that
it matches with:
../common/obj/bar.d: ../common/obj/bar.d.o
The recipe there is a recipe to link a program called ../common/obj/bar.d given
an object file ../common/obj/bar.d.o.
There is no object file ../common/obj/bar.d.o, but can it be an intermediate file? If
Make can find a rule for making ../common/obj/bar.d.o from files that do exist,
then it can also make ../common/obj/bar.d with this %: %.o rule.
And it can find a recipe for making ../common/obj/bar.d.o from existing files
because we just gave it one! - recipe B:
$(OBJDIRCOMMON)/%.o: $(COMMONDIR)/Makefile | $(OBJDIRCOMMON)
+$(MAKE) -C $(COMMONDIR)
That tells Make that if any target matching $(OBJDIRCOMMON)/%.o (like ../common/obj/bar.d.o)
does not exist, but $(COMMONDIR)/Makefile does exist (which it does), then that target
is made up-to-date by running:
$(MAKE) -C $(COMMONDIR)
Make believed us. It ran $(MAKE) -C $(COMMONDIR):
make -C ../common
make[1]: Entering directory '/home/imk/develop/so/make_prob/common'
gcc -MMD -MP -c -I. bar.c -o obj/bar.o
make[1]: Leaving directory '/home/imk/develop/so/make_prob/common'
and then considered ../common/obj/bar.d.o up-to-date. So it moved on to:
../common/obj/bar.d: ../common/obj/bar.d.o
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $#
and ran:
gcc ../common/obj/bar.d.o -o ../common/obj/bar.d
which failed because we lied:
make -C ../common
does not make ../common/obj/bar.d.o at all.
gcc: error: ../common/obj/bar.d.o: No such file or directory
This does not arise with recipe A, because
$(OBJDIRCOMMON)/bar.d.o: $(OBJDIRCOMMON)/bar.d.c $(COMMONDIR)/Makefile | $(OBJDIRCOMMON)
+$(MAKE) -C $(COMMONDIR)
does not offer Make a way to make $(OBJDIRCOMMON)/bar.d.o from existing files,
because $(OBJDIRCOMMON)/bar.d.c does not exist. So ../common/obj/bar.d is not
a target.
Stick with recipe A, because it's right, and recipe B is wrong. Also review
and fix the makefiles so that make clean always deletes all the non-.PHONY targets that might have been built, and nothing else. Lastly avoid writing recipes with non-.PHONY targets where the recipe does not mention the target.

Should there be && instead of pipe
$(OBJDIRCOMMON)/%.o: $(COMMONDIR)/Makefile | (OBJDIRCOMMON)
+$(MAKE) -C $(COMMONDIR

Related

Makefile tries to compile one of it's own rules as if it were a file

I have a simple makefile to compile some C code that uses OpenGL libraries, however, it appears to be interpreting one of it's own rules as a file to compile. The simplified version is as follows:
CC = gcc
COMPILEFLAGS = -Wall -lglut -lGL -lGLU -lm -c
LINKFLAGS = -lglut -lGL -lGLU -lm
castle: castle_link
run_castle:
./castle $(ARGS)
castle_link: castle_compile
${CC} -o castle castle.o ${LINKFLAGS}
castle_compile:
${CC} ${COMPILEFLAGS} castle.c
clean:
rm *.o castle
Executing make -n castle yields the following:
gcc -Wall -lglut -lGL -lGLU -lm -c castle.c
gcc -o castle castle.o -lglut -lGL -lGLU -lm
gcc castle.o castle_link -o castle
And I cant understand why this happens. On this very same file there is another set of rules that follow precisely the same pattern, only changing file names, that work flawlessly.
(This only happens when executing the rule make castle, manually executing castle_compile and then castle_link does not cause that).
Any help is very much appreciated.
To explain what happened, you have a rule without a recipe:
castle: castle_link
which means that make will try to find an implicit rule for it. From the manual:
If none of the explicit rules for a target has a recipe, then make searches for an applicable implicit rule to find one
And earlier in that page it says that prerequisites for targets are combined:
One file can be the target of several rules. All the prerequisites mentioned in all the rules are merged into one list of prerequisites for the target.
The implicit rule that matches will be either:
%: %.o
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $#
if the .o file exists or:
%: %.c
$(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $#
if it doesn't. (make -p will print definitions of the implicit rules).
So the prerequisites for target castle will be:
either castle.o castle_link
or castle.c castle_link
And the $^ variable in the recipe from the implicit rule will put them in the cc command to execute. Let's see with this simplified makefile:
castle: castle_link
castle_link: castle_compile
$(CC) -o castle castle.o -lm
castle_compile:
$(CC) -Wall -c castle.c
If we execute it on a clean directory (i.e. with no castle.o):
]$ make --debug=m castle
...
Must remake target 'castle_compile'.
cc -Wall -c castle.c # This is our recipe, notice -Wall
Successfully remade target file 'castle_compile'.
Must remake target 'castle_link'.
cc -o castle castle.o -lm # This is our reicpe, notice -lm
Successfully remade target file 'castle_link'.
Must remake target 'castle'.
cc castle.c castle_link -o castle # This is implicit rule with castle.c
cc: error: castle_link: No such file or directory
Now that castle.o was created, we execute it again:
]$ make --debug=m castle
...
Must remake target 'castle_compile'.
cc -Wall -c castle.c # This is our recipe, notice -Wall
Successfully remade target file 'castle_compile'.
Must remake target 'castle_link'.
cc -o castle castle.o -lm # This is our recipe, notice -lm
Successfully remade target file 'castle_link'.
Prerequisite 'castle_link' of target 'castle' does not exist.
Must remake target 'castle'.
cc castle.o castle_link -o castle # This is implicit rule with castle.o
cc: error: castle_link: No such file or directory
As you can see, in the first invocation it was "cc castle.c castle_link -o castle" and in the second it was "cc castle.o castle_link -o castle".
Don't ask me why only the second invocation printed "Prerequisite 'castle_link' of target 'castle' does not exist." :-)

How to run and execute a makefile C

I'm trying to make a Makefile for my program. It is so difficult because i've read a lot of guide but none is clear. I have 3 files : main.c , library.c , library.h . Main.c and library.c depend on library.h . The structure of my directory project is formed by :
MyProject directory -> Build directory and Exercise1 directory -> all of my files . In compiler I wrote make and it compiled ; then when I write make execute command, it gives me this error:
cd ../build; ./test
Error: No such file or directory
makefile:23: recipe for target 'execute' failed
make: *** [execute] Error 1
MAKEFILE
CC=gcc
CFLAGS=-Wall
ODIR=../build
DIR = build
.PHONY: all
all: main.o library.o test
$(ODIR)/%.o: %.c $(DEPS)
$(CC) -std=c99 -c -o $# $< $(CFLAGS)
library.o: library.c library.h
$(CC) -std=c99 -c -o $(ODIR)/$# $< $(CFLAGS)
main.o: main.c library.h
$(CC) -std=c99 -c -o $(ODIR)/$# $< $(CFLAGS)
test: $(ODIR)/library.o $(ODIR)/main.o
$(CC) -std=c99 -o $(ODIR)/$# $^ $(CFLAGS)
execute:
cd $(ODIR); ./test
clean:
rm -f $(ODIR)/*.o
These lines:
execute:
cd $(ODIR); ./test
tell make that, when you give the command make execute, it should change the working directory to $(ODIR) and then execute ./test, which means to execute the file test in the current working directory. However, there is no file test in the $(ODIR) directory because you have not built it yet.
You can make that file by executing make test, but that is a bad way to do it. It is better to tell make that the execute target depends on $(ODIR)/test:
execute: $(ODIR)/test
cd $(ODIR); ./test
Then we should change the rule for test to $(ODIR)/test:
$(ODIR)/test: $(ODIR)/library.o $(ODIR)/main.o
$(CC) -std=c99 -o $(ODIR)/$# $^ $(CFLAGS)
Next, delete the rule for all and the .PHONY rule. A rule for all should be used when a makefile can make several different final targets, like ProgramA, ProgramB, and ProgramC, and you want one target that makes all of them. It should not be used to make all of the intermediate object files for a target. The intermediate files should arise out of the rules for building a final target.
Then delete the rules for library.o and main.o. Those are names for files in the current directory, but you are building in $(ODIR). We will let the pattern rule for $(ODIR)/%.o build those.
But we need to fix the pattern rule. It uses DEPS, but that is not defined. Add a line above that says what all the object files depend on:
DEPS=library.h
Nothing in the makefile uses DIR, so delete the line DIR = build.
Finally, you might want to put the execute target first, so that it is the default. Then your makefile is:
CC=gcc
CFLAGS=-Wall
ODIR=../build
DEPS=library.h
execute: $(ODIR)/test
cd $(ODIR); ./test
$(ODIR)/%.o: %.c $(DEPS)
$(CC) -std=c99 -c -o $# $< $(CFLAGS)
$(ODIR)/test: $(ODIR)/library.o $(ODIR)/main.o
$(CC) -std=c99 -o $(ODIR)/$# $^ $(CFLAGS)
clean:
rm -f $(ODIR)/*.o
You might also change the command for clean to remove test:
rm -f $(ODIR)/*.o $(ODIR)/test

-Wunused-command-line-argument error when compiling (C Makefile)?

When I compile using my makefile I get these warnings:
clang: warning: -lllist: 'linker' input unused [-Wunused-command-line-argument]
clang: warning: argument unused during compilation: '-L./bin' [-Wunused-command-line-argument]
This is probably because I have messed something up in my Makefile (below). Am I not linking the lib properly? Can anyone point me toward the problem?
all: list parser
parser: list parserCal bin/LinkedListAPI.o bin/CalendarParser.o
ar cr bin/libcparser.a bin/LinkedListAPI.o bin/CalendarParser.o
list: listparser bin/LinkedListAPI.o
ar cr bin/libllist.a bin/LinkedListAPI.o
listparser: src/LinkedListAPI.c include/LinkedListAPI.h
gcc -Wall -std=c11 -c -Iinclude src/LinkedListAPI.c -o bin/LinkedListAPI.o
parserCal: src/CalendarParser.c include/LinkedListAPI.h include/CalendarParser.h include/HelperFunctions.h
gcc -Wall -std=c11 -c -L./bin -lllist -Iinclude src/CalendarParser.c -o bin/CalendarParser.o
TEST: list parser main.c
gcc -Wall -std=c11 -Iinclude main.c -o bin/runMe -L./bin -lllist -lcparser
clean:
rm bin/*.o bin/*.a
The immediate problem is in this rule:
TEST: list parser main.c
gcc -Wall -std=c11 -c -Iinclude main.c -o bin/runMe -L./bin -lllist -lcparser
The option -c means only compile, do not link, so any linker-related command line arguments are ignored, therefore you get that warning. Remove -c and it will work.
That said, this Makefile is "messed up". Normally, your targets should be the files created, e.g.
bin/libllist.a: listparser bin/LinkedListAPI.o
ar cr bin/libllist.a bin/LinkedListAPI.o
The way you do it, make is not more useful than a shell script, as it doesn't know which files are created and can't check whether rebuilding is necessary. Also, it would stop working at all if there was by accident a file named list. If you have rules that don't create a file, you must tell make about it by putting them as phony targets, e.g.:
.PHONY: all clean
a makefile is set of sequential things that need to be done, however, if a certain created file has no changes in its' dependency files, then that file will not be recreated.
It is best to be very specific about what specific utility program is to be run.
targets in the make file that don't actually create a file with the same name should be flagged using the .PSEUDO operator.
here is an example of a correctly written makefile, using the posted makefile as the basis: I've included a few comments in the makefile to clarify what is being done at each step
notice there (in this make file) is no mixing of compile parameters and rules with link parameters and rules
# use ':=' so the macro will only be evaluated once
# using just '=' results in the macro being reevaluated each time it is referenced.
# notice that desirable parameters are being set inside the macro definitions
CFLAGS := -Wall -Wextra -pedantic -std=c11
RM := /bin/rm -f
CC := /bin/gcc
AR := /bin/ar cr
# tell 'make' that these targets do not produce a file of the same name
.PSEUDO: all clean
# this is the first target in this makefile
# it lists the three 'final' targets
# so each of those target rules will be executed
all: bin/runMe bin/libcparser.a bin/libllist.a
# link step
bin/runMe: main.o bin/CalendarParser.o bin/LinkedListAPI.o
$(CC) main.o bin/CalendarParser.o bin/LinkedListAPI.o -o bin/runMe -L./bin -lllist -lcparser
# archive creation step
bin/libcparser.a: bin/LinkedListAPI.o bin/CalendarParser.o
$(AR) bin/libcparser.a bin/LinkedListAPI.o bin/CalendarParser.o
# archive creation step
bin/libllist.a: bin/LinkedListAPI.o
$(AR) bin/libllist.a bin/LinkedListAPI.o
# notice the archive targets and final runnable file
# reference certain dependencies.
# when a dependency is not available or not 'up to date'
# then the associated rule is executed to bring that dependency 'up to date'
# compile ./src/LinkedListAPI.c to create ./bin/LinkedListAPI.o
bin/LinkedListAPI.o: src/LinkedListAPI.c include/LinkedListAPI.h
$(CC) $(CFLAGS) -c src/LinkedListAPI.c -o bin/LinkedListAPI.o -Iinclude
# compile ./src/CalendarParser.c to create ./bin/calendarParser.o
bin/CalendarParser.o: src/CalendarParser.c include/LinkedListAPI.h include/CalendarParser.h include/HelperFunctions.h
$(CC) $(CFLAGS) -c src/CalendarParser.c -o ./bin/CalendarParser.o -Iinclude
# compile main.c to create main.o
main : main.c include/LinkedListAPI.h include/CalendarParser.h include/HelperFunctions.h
$(CC) $(CFLAGS) -c main.c -o main.o -Iinclude
clean:
$(RM) bin/*.o bin/*.a

How can I write Makefile (with sub Makfile ) more concise

When I do practice , I have a practice path.
Under this path , I have an Include path named myInclude (I have some useful function is this folder and I always use it.)
And a code path named symbol_try.I always make add new folder (with a c file and main function in it) in symbol_try and compile it.
Each time I have to compile it by gcc in terminal .Its a boring work , so I write a Makefile.
Here is an example:
the main Makefile in practice path:
FOBJS=
include myInclude/Rule.mk
include symbol_try/codeList_13.1/Rule.mk
symbol:$(FOBJS) <==What exactly I what . A executable file.
gcc -o symbol $(FOBJS) -pthread -lpthread
subsystem:
cd myInclude/ && $(MAKE)
cd symbol_try/codeList_13.1/ &&$(MAKE)
clean:
rm -rf symbol
In the myInclude/Rule.mk
FOBJS+=myInclude/otherFunction.o myInclude/error.o \
myInclude/unit.o myInclude/unitTest.o\
In the symbol_try/codeList_13.1/Rule.mk
FOBJS+=symbol_try/codeList_13.1/codeList_13.1.o
In myInclude/Makefile:
OBJS=otherFunction.o error.o unit.o unitTest.o
ALL:$(OBJS)
.PHONY:ALL
$(OBJS):%.o:%.c
gcc -c $< -o $#
clean :
otherFunction.o error.o unit.o
In symbol_try/codeList_13.1/Makefile:
codeList_13.1.o:codeList_13.1.c
gcc -c codeList_13.1.c
Well.That can work. But as you see , I have to write a Rule.mk(to initialize the FOBJS) and a Makefile for each folder.
I am new for make , I want find a way more concise , witch I only need write one Makefile for each folder and a main Makefile.No Rule.mk any more.
PS: I always change the code in myInclude ,so I don't want to build it a library.
Thanks for any help.
Here's one way you can do it with just one Makefile:
CC = gcc
CPPFLAGS += -I myInclude/ (1)
CFLAGS += -std=c99 -Wall (2)
VPATH = myInclude/ \ (3)
symbol_try/codeList_13.1/
symbol: otherFunction.o error.o unit.o unitTest.o codeList_13.1.o (4)
$(CC) -o $# $^ (5)
.PHONY : clean
clean:
rm -f symbol *.o
Note that make knows how to build C files and has some standard macros: CC, CPPFLGAS, CFLAGS
Add the include paths of your headers. You presumably have some headers for the individual object files in the myInclude directory.
Put the compiler flags here.
Add the paths to the source files you want to build.
List the object files that the executable depends upon
As there is no file called symbol.c you need to tell make how to create symbol.o with a rule. $# means the target ('symbol', here), and $^ means all of the prerequisites (the object files listed).
Here's a list of all of the files in my test directories for this:
$ find . -type f
.
./Makefile
./myInclude/error.c
./myInclude/header.h
./myInclude/otherFunction.c
./myInclude/unit.c
./myInclude/unitTest.c
./symbol_try/codeList_13.1/codeList_13.1.c
And the build output:
$ make
gcc -std=c99 -Wall -I myInclude/ -c -o otherFunction.o myInclude/otherFunction.c
gcc -std=c99 -Wall -I myInclude/ -c -o error.o myInclude/error.c
gcc -std=c99 -Wall -I myInclude/ -c -o unit.o myInclude/unit.c
gcc -std=c99 -Wall -I myInclude/ -c -o unitTest.o myInclude/unitTest.c
gcc -std=c99 -Wall -I myInclude/ -c -o codeList_13.1.o symbol_try/codeList_13.1/codeList_13.1.c
gcc -o symbol otherFunction.o error.o unit.o unitTest.o codeList_13.1.o
Why don't you create a library from the objects in myInclude and do the linking in the Makefile in your code path (symbol_try/codeList_13.1). The latter is better anyway because the needed libraries (-pthread -lpthread in your case) might change as well for some other code.
The main Makefile now would have got nothing to do but call make in all needed subdirectories.
In each folder have a makefile with
SOURCES=sample.c sampletest.c
OBJECTS=$(SOURCES:%.c=$(OBJDIR)/%.o)
all: $(OBJECTS)
$(OBJDIR)/%.o: %.c
$(CC) $(CFLAGS) -o $# $<
In the root directory of a project, create a makefile with a rule to compile every sub-folder like the below.
Dirs= path-to-rootdir
objs:
set -e ; \
for i in $(Dirs) ; do \
$(MAKE) CC="$(CC)" CFLAGS="$(CFLAGS_MODULE)" LDFLAGS="$(LDFLAGS)" OBJDIR="$(OBJDIR)" -C $$i; \
done
And then you could use it build the executable by adding a rule
EXE: objs
$(CC) -L./Path1 $(LIB_PATH) -llib1 -o $(EXE_NAME) $(wildcard $(OBJDIR)/*.o)
Hope this helps!!!

linking and compiling with Makefile

gcc 4.7.2
c89
GNU Make 3.82
I am trying compile this program I have using this Makefile. I have only 1 src file at the moment, but I will have more later to include.
I am trying to get the Makefile to create the bin directory if it doesn't exist and put the binary executable in there.
INC_PATH=-I/home/dev_tools/apr/include/apr-1
LIB_PATH=-L/home/dev_tools/apr/lib
LIBS=-lapr-1
RUNTIME_PATH=/home/dev_tools/apr/lib
CC=gcc
CFLAGS=-Wall -Wextra -g -m32 -D_DEBUG -D_THREAD_SAFE -D_REENTRANT -D_LARGEFILE64_SOURCE -O2 $(INC_PATH)
OBJECTS=timeout.o
EXECUTABLE=bin/to
all: build $(EXECUTABLE)
$(EXECUTABLE):
$(CC) -m32 -o $# -Wl,-rpath,$(RUNTIME_PATH), $(LIB_PATH) $(OBJECTS) $(LIBS)
build:
#mkdir -p bin
clean:
rm -rf *~ timeout *.o
I am getting this error:
make
gcc -m32 -o bin/to -Wl,-rpath,/home/dev_tools/apr/lib, -L/home/dev_tools/apr/lib timeout.o -lapr-1
gcc: error: timeout.o: No such file or directory
make: *** [bin/to] Error 1
When I remove the $(OBJECTS) I get the following:
gcc -m32 -o bin/to -Wl,-rpath,/home/dev_tools/apr/lib, -L/home/dev_tools/apr/lib -lapr-1
/usr/bin/ld: cannot find : No such file or directory
collect2: error: ld returned 1 exit status
make: *** [bin/to] Error 1
Not sure where I am going wrong with this.
You have not specified how to build the target timeout.o.
You need to add the following code:
timeout.o: timeout.c
$(CC) $(CFLAGS) -c -o $# $<
If you end up with more source file that you need compiled, you can use a pattern matching rule like this:
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $#
Makefiles can be a bit tricky. Because you want to continue adding more objects to your OBJECT variable, I would actually add a prerequisite to EXECUTABLE to make sure all of your objects are compiled. From there, the automatic rule inference should take care of the rest.
Basically replace the line with:
$(EXECUTABLE): $(OBJECTS)
$(CC) -m32 -o $# -Wl,-rpath,$(RUNTIME_PATH), $(LIB_PATH) $(OBJECTS) $(LIBS)
Its showing error because make is not able to find timeout.o file in the current directory.
If you have timeout.c file then add the following to your makefile
OBJECTS: timeout.c
$(CC) -c timeout.c

Resources