Multi directory makefile for project - makefile

This is how my directory looks like:
/project
makefile
/ceda_lib
makefile
files....
/general
makefile
files....
/CLI
makefile
files....
/objects
files.o
Makefile(main):
1 #start other makefiles
2
3
4 o= ./objects
5 DEPS= Affine.hpp CEDA.hpp generalParameters.hpp generalFunctions.hpp
6 OBJ= $o/main.o $o/Affine.o $o/generalFunctions.o
7 CC=g++
8 CFLAGS= -Wall -g -I.
9 export CC
10 export CFLAGS
11 export DEPS
12
13 all:
14 ▸---+$(MAKE) -C general
15 ▸---+$(MAKE) -C ceda_lib
16 ▸---+$(MAKE) -C CLI
17
18 run: $(OBJ) $(DEPS)
19 ▸---$(CC) -o $# $^
The other makefiles look like this:(update2)
1 include ../makefile.variables
2
3 OBJ = main.o
4 all: $(OBJ)
5
6 $(OBJ): %.o: %.cpp $(DEPS)
7 ▸---$(CC) -o ../objects/$# -c $< $(CFLAGS)
What I want to do is for all code in the 3 directories to be compiled and all objects to be stored in the /object directory. Then an executable will be created from the $DEPS and the contents of /object directory.
This makefile doesn't work sadly. Could you please find what I've done wrong and also could you suggest me ways to improve the code. (I'm quite new to makefiles).
Also this is the output whenever I try making the project:(Update2)
make: Entering directory '/home/george/Documents/CEDA'
make -C general
make[1]: Entering directory '/home/george/Documents/CEDA/general'
g++ -o ../objects/generalFunctions.o -c generalFunctions.cpp -Wall -g -I.
make[1]: Leaving directory '/home/george/Documents/CEDA/general'
make -C ceda_lib
make[1]: Entering directory '/home/george/Documents/CEDA/ceda_lib'
g++ -o ../objects/Affine.o -c Affine.cpp -Wall -g -I.
Affine.cpp:4:33: fatal error: generalParameters.hpp: No such file or directory
#include "generalParameters.hpp"
^
compilation terminated.
makefile:7: recipe for target 'Affine.o' failed
make[1]: *** [Affine.o] Error 1
make[1]: Leaving directory '/home/george/Documents/CEDA/ceda_lib'
makefile:8: recipe for target 'All' failed
make: *** [All] Error 2
make: Leaving directory '/home/george/Documents/CEDA'
This is the makefile.variables
1 #variables used by all makefiles in project directory
2
3 PATH_TO_DIR = ~/Documents/CEDA
4 c = $(PATH_TO_DIR)/ceda_lib
5 g = $(PATH_TO_DIR)/general
6 e = $(PATH_TO_DIR)/CLI #e for executable
7
8 DEPS= $c/Affine.hpp $c/CEDA.hpp $g/generalParameters.hpp $g/generalFunctions.hpp
9 CC=g++
10 CFLAGS= -Wall -g -I.

Here:
OBJ= main.o
../objects/%.o: %.cpp $(DEPS)
$(CC) -c $< $(CFLAGS)
This makefile contains one rule, which is a pattern rule, a way to build any file with a name like ../objects/foo.o. But it doesn't tell Make which object file it is to build. To be precise, a pattern rule cannot be the default rule.
The simplest way to fix this is with the addition of an ordinary rule:
../objects/$(OBJ):
Once you have this working you will have the object files, but there are still problems in the main makefile. The run rule will not build an executable, and if you want to execute that rule you will have to invoke it on the command line, it won't follow automatically.
You are attempting recursive use of Make -- which is tricky -- before you've mastered the basics. I suggest you try using the makefile to build the object files, then try to build the executable using the command line, then look carefully at the command you used and rewrite the run rule.
Once you get that far, other improvements are possible. (Make is a powerful tool, but it has a long learning curve.)
EDIT: If it isn't working at all, try something simpler first.
Pick a source file in ceda_lib, like, I don't know main.cpp. Verify that the source file exists and that the corresponding object file (main.o) does not. Edit the makefile (in ceda_lib/) to this:
main.o: main.cpp
$(CC) -c $< $(CFLAGS)
Then within ceda_lib/, try make and see what happens.
If it builds main.o, then delete main.o, and then from project/ try make -C ceda_lib, and see what happens. If that builds ceda_lib/main.o, then we can move on to more advanced makefiles.

Related

How to create a makefile that will place object code in different folder

I am very new to Makefile. I had build the following makefile(Which don't work).I wan't put genarated object codes in differnt folder(the folder is in current directory).
$ ls
main.cpp Makefile object_code Time.cpp Time_.h
how can I do this ??
VER = Debug
CC = g++
OBJECTFIELS = ./object_code/main.o ./object_code/Time.o
../$(VER)/main: $(OBJECTFIELS)
$(CC) $(OBJECTFIELS) -o $#
$(OBJECTFIELS): Time_.h
./object_code/main.o: main.cpp
./object_code/Time.o: Time.cpp
clean:
rm $(OBJECTFIELS) main
this is error.
$ make
g++ ./object_code/main.o ./object_code/Time.o -o ../Debug/main
g++: error: ./object_code/main.o: No such file or directory
g++: error: ./object_code/Time.o: No such file or directory
g++: fatal error: no input files
compilation terminated.
Makefile:8: recipe for target '../Debug/main' failed
make: *** [../Debug/main] Error 1
please this is last question.
I don't see how you can possibly get that output given the makefile you've posted here.
Either the object files already exist in which case the link will succeed rather than printing that error.
Or the object files don't exist in which case make will complain because it doesn't know how to make them. There must be some difference between the makefile you're using and the one you've posted here.
In any event, make knows how to build a file foo.o from a file foo.cpp for any string foo. There's a built-in rule that tells it how to do that.
But, make doesn't know how to build a file ./object_code/foo.o from a file foo.cpp, regardless of foo. There's no built-in rule that tells make how to build object files in some random other directory. If you want make to do that, you'll have to tell it how. You should remove the lines:
./object_code/main.o: main.cpp
./object_code/Time.o: Time.cpp
and replace them with a pattern rule describing how to build object files into the object_code directory (I'm using CXX as the compiler variable here: by convention CC is the C compiler and CXX is the C++ compiler, and you should always stick with convention unless there's a good reason not to):
VER = Debug
CXX = g++
OBJECTFIELS = ./object_code/main.o ./object_code/Time.o
../$(VER)/main: $(OBJECTFIELS)
$(CXX) $(OBJECTFIELS) -o $#
$(OBJECTFIELS): Time_.h
./object_code/%.o : %.cpp
$(CXX) -c -o $# $<
clean:
rm $(OBJECTFIELS) main

Error while executing makefile in c

I'm trying to create one makefile using c. For that I have main.c,add.c,minus.c,print.c and Functions.h header file.In this list other than main.c add files have simple add function, subtract function and print function. That Functions.h file have declarations for all functions.
my problem is I have written one makefile. In that I'm trying to redirect the object files into one directory. When I execute the makefile. It throws an error like
make: *** No rule to make target /%.c', needed byobj'. Stop
.
Make file has the lines
CFLAG :=-Wall -g
CC := gcc
INCLUDE:=-I include
OBJDIR:=obj
SRCDIR:=src
TARGET:=bin/Math
CFILES:=$(wildcard src/*.c)
OBJECTS:=$(patsubst src/%.c,obj/%.o,$(CFILES))
$(OBJDIR)/%.o:$(SRCDIR)/%.c
#$(CC) -c $(INCLUDE) -o $# $< $(CFLAG)
(TARGET):$(OBJECTS)
#$(CC) $(CFLAG) -o $# $(OBJECTS)
.PHONY : clean
clean :
-rm -f $(OBJDIR)/*.o
Please help me guys....

Switching from g++ to clang++ in makefile

I 've got following makefile:
all: xmltest
xmltest: xmltest.cpp tinyxml2.cpp tinyxml2.h
This works fine - after executing make all executable 'xmltest' is produced.
However, I want to switch compiler to clang++. So I've added this line at the beginning of the file:
CXX=clang++
and now executing make all produces an error:
clang++ xmltest.cpp tinyxml2.cpp tinyxml2.h -o xmltest
clang++.exe: warning: treating 'c-header' input as 'c++-header' when in C++ mode, this behavior is deprecated
clang++.exe: error: cannot specify -o when generating multiple output files
<builtin>: recipe for target 'xmltest' failed
make: *** [xmltest] Error 1
How to fix this with minimal modifications to original make file?
You might as well just write a shell script: there's no advantage to using the makefile in your solution. Any time you change any file, the entire thing will be rebuilt, so you might as well just run:
clang++ -g -o xmltest xmltest.cpp tinyxml2.cpp
whenever you change anything and skip the makefile.
If you wanted a makefile which took advantage of some of the capabilities of make, you would write it something like this:
CXX = clang++
all: xmltest
xmltest: xmltest.o tinyxml2.o
xmltest.o tinyxml2.o: tinyxml2.h
Now you have something useful, where only the files that need to be rebuilt based on what you've changed will be rebuilt. If your program gets more complex, you can use even more make facilities to keep it manageable.
You shouldn't list the header file as a translation unit (those are the cpps)
You should usually make the .h prerequisites:
xmltest.cpp: tinyxml2.h
tinyxml2.cpp: tinyxml2.h
And compile/link the translation units:
all: xmltest
xmltest: xmltest.cpp tinyxml2.cpp
$(CXX) $(CXXFLAGS) -o $# $^ $(LDFLAGS)
IIRC you /might/ also put the 'dependency only' items on the same line using |
xmltest: xmltest.cpp tinyxml2.cpp | tinyxml2.h
$(CXX) $(CXXFLAGS) -o $# $^ $(LDFLAGS)
But I'm unable to check that right now

Adding functionality to Makefile gives error :- "multiple definitoon here ..."

I have been given an already working Makefile which is actually working fine.
Makefile Contents can be found here in this post ...
Questions about Makefile - what is "$+" & where are .c files/dependencies called here ?
I am asking this question separately from my previous post mentioned above as it involves a different issue and adding it to that question would unnecessarily increase its length.
Now I have added one more functionality which is being used quite frequently at many places so I thought creating a separate file would be a nice idea so I created linklayer.c and added linklayer.o to $LIBOBJS.
I added this ...
LIBOBJS= linklayer.o csum.o compact.o protoname.o headers.o
parseargs.o cryptomod.o crc32.o
and this
linklayer.o: linklayer.c
$(CC) -o $# -c -I. $(CFLAGS) $+
I have declared function in sendip_module.h which is already declared and accessed in each of the module present in the project.
But now this multiple definition error is coming ... Have I done something wrong or misunderstood something?
Note: "ipv6_opts" is defined in ipv6.h
$ make all
for subdir in mec ; do \
cd $subdir ;\
make ;\
cd .. ;\
done
make[1]: Entering directory `/home/udit/Desktop/sendip-2.5-mec-2/mec'
make[1]: Nothing to be done for `all'.
make[1]: Leaving directory `/home/udit/Desktop/sendip-2.5-mec-2/mec'
gcc-4.4 -o ipv6.so -fPIC -fsigned-char -pipe -Wall -Wpointer-arith
-Wwrite-strings -Wstrict-prototypes -Wnested-externs -Winline -Werror
-g -Wcast-align -DSENDIP_LIBS=\"/usr/local/lib/sendip\" -shared ipv6.c
libsendipaux.a libsendipaux.a
libsendipaux.a(linklayer.o):(.data.rel.local+0x0)
: multiple definition of `ipv6_opts'
/tmp/ccxa4tMX.o:(.data.rel.local+0x0): first defined here
collect2: ld returned 1 exit status
make: *** [ipv6.so] Error 1
and why this libsendipaux.a libsendipaux.a two times ? Is there something wrong with the Makefile itself.
Do I first need to manually compile it and then add it to libsendipaux.a ?
I am new to this Makefile stuff, so please help me understand how this is all working out here ?
Thanks.
Edit :
Remake debugging output -
remake -x
Reading makefiles...
Updating goal targets....
/home/udit/Desktop/sendip-2.5-mec-2/Makefile:33 File `all' does not exist.
/home/udit/Desktop/sendip-2.5-mec-2/Makefile:48 File `subdirs' does not exist.
/home/udit/Desktop/sendip-2.5-mec-2/Makefile:48 Must remake target `subdirs'.
for subdir in mec ; do \
cd $subdir ;\
make ;\
cd .. ;\
done
make[1]: Entering directory `/home/udit/Desktop/sendip-2.5-mec-2/mec'
make[1]: Nothing to be done for `all'.
make[1]: Leaving directory `/home/udit/Desktop/sendip-2.5-mec-2/mec'
/home/udit/Desktop/sendip-2.5-mec-2/Makefile:48 Successfully remade target file
`subdirs'.
File `ipv6.so' does not exist.
Must remake target `ipv6.so'.
gcc-4.4 -o ipv6.so -fPIC -fsigned-char -pipe -Wall -Wpointer-arith
-Wwrite-strings -Wstrict-prototypes -Wnested-externs -Winline -Werror
-g -Wcast-align -DSENDIP_LIBS=\"/usr/local/lib/sendip\" -shared ipv6.c
libsendipaux.a libsendipaux.a
libsendipaux.a(linklayer.o):(.data.rel.local+0x0)
: multiple definition of `ipv6_opts'
/tmp/ccb0oaXR.o:(.data.rel.local+0x0): first defined here
collect2: ld returned 1 exit status
remake: *** [ipv6.so] Error 1
#0 ipv6.so at ??
#1 all at /home/udit/Desktop/sendip-2.5-mec-2/Makefile:33
33rd line -> all: $(LIBS) subdirs sendip $(PROTOS) sendip.1 sendip.spec
I guess it could not help me out .... actual problem is with my understanding of scenario itself. Please help me bring out of the mess.
the problem you are facing, is that you are linking together several objects where at least two of them define de function ipv6_opts.
since there are two implementations of the function, your linker cannot decide which one to use and throws an error.
the problem most likely comes from the fact that you are linking libsendipaux.a twice into your final binary.
the reason why this happens is here:
%.so: %.c $(LIBS)
$(CC) -o $# $(CFLAGS) $(LIBCFLAGS) $+ $(LIBS)
in this target, $+ will expand to all the dependencies of your target (that is: %.c $(LIBS), which will in turn be resolved to ipv4.c libsendipaux.a
the actual call to the compiler can then be read as $(CC) -o $# $(CFLAGS) $(LIBCFLAGS) ipv4.c $(LIBS) $(LIBS), and $(LIBS) $(LIBS) will expand to libsendipaux.a libsendipaux.a, which will produce the erroneous double linkeage.
so the solution is to remove extraneous $(LIBS) from the .so target:
%.so: %.c $(LIBS)
$(CC) -o $# $(CFLAGS) $(LIBCFLAGS) $+
btw, the errors you get in remake about non-existing files, are because all and subdirs are indeed no files, but phony targets (targets that do no generate files called after the target-name).
to prevent those warnings, add something like the following to your makefile:
.PHONY: all subdirs

make: *** No rule to make target `all'. Stop

I keep getting this error:
make: *** No rule to make target `all'. Stop.
Even though my make file looks like this:
CC=gcc
CFLAGS=-c -Wall
all: build
build: inputText.o outputText.o main.o
gcc main.o inputText.o outputText.o -o main
main.o: main.c
$(CC) $(CFLAGS) main.c -o main.o
inputText.o: inputText.c
$(CC) $(CFLAGS) inputText.c -o inputText.o
outputText.o: outputText.c
$(CC) $(CFLAGS) outputText.c -o outputText.o
Yes there should be a tab space underneath the target and there is in my make file.
I can get it to work if I try one of the targets like main.o, inputText.o and outputText.o but can't with either build or all.
EDIT:
I just randomly tried running make and telling it the file using the following command:
make -f make
This works but why doesn't just typing make work?
Your makefile should ideally be named makefile, not make. Note that you can call your makefile anything you like, but as you found, you then need the -f option with make to specify the name of the makefile. Using the default name of makefile just makes life easier.

Resources