some questions about GNU makefiles - makefile

i was wondering if anyone have sometime to answer some questions about GNU makefiles...
how to create a directory if it doesn't exists ("./obj") for output?
i have one makefile, but i got 2 build methods "Debug" and "Release", can i have both in 1 makefile and how to tell it which one to build?
ive been using Code::Blocks which builds only changed files, but my makefile builds them everytime i call make command, without touching any files. how can i make it build changed files only?
here is my current makefile
OBJPATH=./obj
COMPILER=gcc
Output: main.o Base64.o
$(COMPILER) -o Output.exe $(OBJPATH)/main.o $(OBJPATH)/Base64.o
strip Output.exe
main.o: main.c main.h
$(COMPILER) -c main.c -o $(OBJPATH)/main.o
Base64.o: Base64.c Base64.h
$(COMPILER) -c Base64.c -o $(OBJPATH)/Base64.o
thanks.

For the first question, you can put a fake target before any of the others, along the lines of:
preamble:
-mkdir obj
main.o: preamble main.c
blah blah blah
That will automatically execute everything in the preamble (you have to make it the first dependency in every rule) before it builds anything else. The - at the start of the mkdir ignores failures if, for example, the directory already exists.
For the second question, you can provide something like:
all: debug release
debug: blah blah blah
release: blah blah blah
and actually put the debug and release code in separate subdirectories. That way, you can build either with make release or make debug and build them both with make all.
Third question: Your makefile builds every time because the rules tell it to. For example, Output: main.o Base64.o will always try to build since Output never exists (the correct target seems to be Output.exe).
Similarly your object file rules will always execute since neither main.o nor Base64.o are updated by their statements (they update the files in the obj directory instead).
You may be able to fix that case by making the target $(OBJPATH)/main.o but, to be honest, I don't usually worry about separating objects and executables into separate directories. I tend to just lump them all into one directory and let make -clean clean them up.
So the makefile I would start with would be:
COMPILER=gcc
# Meta rules
all: release debug
release: Output.exe
debug: Output-d.exe
# Release stuff
Output.exe: main.o Base64.o
$(COMPILER) -o Output.exe main.o Base64.o
strip Output.exe
main.o: main.c main.h
$(COMPILER) -c main.c -o main.o
Base64.o: Base64.c Base64.h
$(COMPILER) -c Base64.c -o Base64.o
# Debug stuff
Output-d.exe: main-d.o Base64-d.o
$(COMPILER) -g -o Output-d.exe main-d.o Base64-d.o
main-d.o: main.c main.h
$(COMPILER) -g -DDEBUG -c main.c -o main-d.o
Base64-d.o: Base64.c Base64.h
$(COMPILER) -g -DDEBUG -c Base64.c -o Base64-d.o
In response to your comment question:
Is there anyway I can re-set a variable based on the Target Selected? for example if selected release OBJPATH will be "./obj/Release" if selected debug OBJPATH = "./obj/Debug"?
GNU Make may be more powerful than the ones I'm used to but you can do that by setting an environment variable then re-running make as per the following:
all: release debug
release:
( export zzvar=release ; $(MAKE) zz_Output.exe )
debug:
( export zzvar=debug ; $(MAKE) zz_Output-d.exe )
zz_Output.exe:
echo $(zzvar)
touch zz_Output.exe
zz_Output-d.exe: zz_main-d.o zz_Base64-d.o
echo $(zzvar)
touch zz_Output-d.exe
which outputs:
( export zzvar=release ; make zz_Output.exe )
make[1]: Entering directory '/home/pax'
echo release
release <==
touch zz_Output.exe
make[1]: Leaving directory '/home/pax'
( export zzvar=debug ; make zz_Output-d.exe )
make[1]: Entering directory '/home/pax'
echo debug
debug <==
touch zz_Output-d.exe
make[1]: Leaving directory '/home/pax'
You can see the two separate variables marked with <== above.
As I said, there's probably an easier way to do it with GNU Make but that'll get you started.

how to create a directory if it doesn't exists ("./obj") for output?
rm -Rf ./obj && mkdir ./obj
i have one makefile, but i got 2 build methods "Debug" and "Release", can i have both in 1 makefile and how to tell it which one to build?
You can have multiple top level build targets. Output in your makefile is a top level target. Make two. One called "Debug" and the other "Release". You can then say make Debug for the debug build and make Release for the release build.
ive been using Code::Blocks which builds only changed files, but my makefile builds them everytime i call make command, without touching any files. how can i make it build changed files only?
I haven't used Code::Blocks (I don't know what it is) but if your Makefiles are written properly (i.e. with dependencies properly specified), it will only rebuild the required targets.

In response to your comment question:
Is there anyway I can re-set a variable based on the Target Selected?
for example if selected release OBJPATH will be "./obj/Release" if
selected debug OBJPATH = "./obj/Debug"?
Here is how you do it without recursion:
COMPILER=gcc
release: OBJPATH = obj
release: Output.exe
debug: OBJPATH = obj-dbg
debug: Outputd.exe
Output%.exe: main.o Base64.o
$(COMPILER) -o $# $(OBJPATH)/main.o $(OBJPATH)/Base64.o
strip $#
main.o: main.c main.h
$(COMPILER) -c main.c -o $(OBJPATH)/main.o
Base64.o: Base64.c Base64.h
$(COMPILER) -c Base64.c -o $(OBJPATH)/Base64.o

Related

'make: nothing to be done for p1 and' no rule to make target 'clean''

I'm trying to create a makefile titled 'p1' for a project.
When I try the command make p1 it returns with make: nothing to be done for p1
Also, when I try the command make p1 clean it returns no rule to make p1 'clean.' Stop
Here is my makefile:
a.out: main.o P1LinkedList.o const_iterator.o iterator.o Node.o
g++ -std=c++11 main.o const_iterator.o iterator.o Node.o
main.o:
g++ -std=c++11 -c main.cpp
P1LinkedList.o:
g++ -std=c++11 -c P1LinkedList.cpp
iterator.o:
g++ -std=c++11 -c iterator.cpp
const_iterator.o:
g++ -std=c++11 -c const_iterator.cpp
Node.o:
g++ -std=c++11 -c Node.cpp
depend:
g++ -MM main.cpp > p1.dep
clean:
rm -f a.out *.o
What do I need to fix to have the makefile compile .o files from my .cpp files and how do I fix the issue with the clean command?
Edit:
Here are the commands I've used to compile manually:
Helens-Air:p1a helenade$ g++ -std=c++11 *.cpp
Helens-Air:p1a helenade$ ./a.out
^^ and this just continues with the program execution from there
We may have to take this in stages.
First, you seem to misunderstand the difference between a makefile name and a target name. This appears to have been a miscommunication between you and your teacher, but it's easy to clear up.
Suppose you have a makefile named "Makefile", containing the following:
foo:
#echo running the foo rule
bar:
#echo running the bar rule
If you make foo, you will get:
running the foo rule
The argument (foo) tells Make which target to attempt to build. And how did Make know which makefile to use? (After all, you could have a dozen makefiles in the working directory.) You can specify which makefile to use, but if you don't then by default Make will look for a makefile named Makefile (or makefile or GNUmakefile, don't worry about this for now). To specify a makefile with another name, like "Buildfile", you can use the -f flag:
make -f Buildfile
So "p1" ought to have been the name of a target, not a makefile. Within the makefile, rename your a.out rule to p1. Then rename the whole makefile to Makefile. Then
make p1
should work (or at least run).
Edit:
I'll go out on a limb. In the a.out rule (which should now be called the p1 rule), I notice that you have left P1LinkedList.o out of the list of object files to be linked. So try changing it:
p1: main.o P1LinkedList.o const_iterator.o iterator.o Node.o
g++ -std=c++11 main.o P1LinkedList.o const_iterator.o iterator.o Node.o
If that works, you can simplify it with an automatic variable:
p1: main.o P1LinkedList.o const_iterator.o iterator.o Node.o
g++ -std=c++11 $^
And there will be other small improvements you can make.
If it doesn't work, try ls *.cpp and see if you've overlooked some other source file.

Why makefile is not saving output files to different directory?

I'm playing with makefile and I have this issue - it's not saving output files to different directories.
CC = g++
CFLAGS = -c -Wall
ODIR = obj
BDIR = bin
$(BDIR)/test: test.o print.o
$(CC) test.o print.o -o test
$(ODIR)/%.o: %.cpp %.h
$(CC) $(CFLAGS) $< -o $#
.PHONY : clean
clean:
rm -f $(ODIR)/*.o $(BDIR)/test
Even if I create these directories manually it doesn't work as expected. Both dirs are empty after "make" without any errors. Output files are always created in main directory. Will be gret if you can give me an advice.
This rule:
$(BDIR)/test: test.o print.o
tells make that to build $(BDIR)/test it first needs to build test.o and print.o. So, it does build those two files. You have defined a rule to build $(ODIR)/%.o, but test.o does not match the pattern $(ODIR)/%.o so that rule is not used.
Instead make uses its own default built-in rules that know how to create %.o; that pattern DOES match your target test.o.
If you want make to build objects in another directory, you have to list them there when you write your rules:
$(BDIR)/test: $(ODIR)/test.o $(ODIR)/print.o
Now, make knows you want to build targets in the $(ODIR) directory so it will use a rule that can do so.

Multiple Targets Not Being Executed By Makefile

I'm updating the title and content here to make it clear that this particular question was asking something that I didn't see answered plainly elsewhere. The key notion is understanding that something that looks like a single target doing multiple things in a Makefile is actually multiple targets doing one thing each.
I will also remove some extraneous material since that ended up not being relevant.
Original Content
My problem is that I have a Makefile that is (apparently) not calling one of my sub-directory Makefiles correctly. I have a project structure like this:
quendor
src
cheap
cheap_init.c
Makefile
zmachine
main.c
Makefile
Makefile
The Makefile in the project root will refer to the Makefiles in the individual directories. Here is that core Makefile:
CC ?= gcc
CFLAGS += -Wall -std=c99
CFLAGS += -D_POSIX_C_SOURCE=200809L
CFLAGS += -O2 -fomit-frame-pointer
RANLIB ?= $(shell which ranlib)
AR ?= $(shell which ar)
export CC
export AR
export CFLAGS
export RANLIB
SRC_DIR = src
ZMACHINE_DIR = $(SRC_DIR)/zmachine
ZMACHINE_LIB = $(ZMACHINE_DIR)/quendor_zmachine.a
CHEAP_DIR = $(SRC_DIR)/cheap
CHEAP_LIB = $(CHEAP_DIR)/quendor_cheap.a
SUB_DIRS = $(ZMACHINE_DIR) $(CHEAP_DIR)
SUB_CLEAN = $(SUB_DIRS:%=%-clean)
$(SUB_DIRS):
#echo $(SUB_DIRS) # src/zmachine src/cheap
#echo "DIR:"
#echo $# # src/zmachine
$(MAKE) -C $#
$(SUB_CLEAN):
-$(MAKE) -C $(#:%-clean=%) clean
clean: $(SUB_CLEAN)
help:
#echo "Quendor"
.PHONY: $(SUB_DIRS) $(SUB_CLEAN) clean help
A key problem for me is this bit from the above:
$(SUB_DIRS):
#echo $(SUB_DIRS) # src/zmachine src/cheap
#echo "DIR:"
#echo $# # src/zmachine
$(MAKE) -C $#
I put the echo statements in just to show what's happening. Notice the $SUB_DIRS is correctly showing both directories, but when the Makefile runs it only shows src/zmachine. (The comments there indicate what I see during runtime.) The Makefile (apparently) doesn't process src/cheap.
The full output of the Makefile running is this (the first three lines there being my echo statements):
src/zmachine src/cheap
DIR:
src/zmachine
/Applications/Xcode.app/Contents/Developer/usr/bin/make -C src/zmachine
cc -Wall -std=c99 -D_POSIX_C_SOURCE=200809L -O2 -fomit-frame-pointer -fPIC -fpic -o main.o -c main.c
ar rc quendor_zmachine.a main.o
/usr/bin/ranlib quendor_zmachine.a
** Done with Quendor Z-Machine.
The only thing I could think of initially was that perhaps after running the sub-makefile in src/zmachine, the Make process was either erroring out or thinking it was done. But the $(SUB_DIRS) part should have iterated through both directories, I would have thought.
So I'm a bit stuck as to how to proceed.
Extra Note: The "I would have thought" part of what I said was where I was incorrect. $(SUB_DIRS) was not being executed as I thought it was; the accepted answer has clarified this.
The way make works is, if you don't provide an argument, it will start by scanning the Makefile looking for the "default goal". The default goal is simply the first target it encounters (notice it's the first target, not targets).
In your case, the rule:
$(SUB_DIRS):
$(MAKE) -C $#
Is equivalent to:
src/zmachine src/cheap:
$(MAKE) -C $#
Which is equivalent to:
src/zmachine:
$(MAKE) -C $#
src/cheap:
$(MAKE) -C $#
So the first target make encounters is src/zmachine, and that's its default goal and the one that gets processed. The way to fix this is, as user657267 said in the comments, to add one target that you know will be processed first that would have the other targets (that you really want to build) as its prerequisites.

make don't build file even if dependency is updated

this is my make file:-
VER = Debug
CC = g++
OBJECTFIELS = main.o Time.o
main: $(OBJECTFIELS)
$(CC) $(OBJECTFIELS) -o $#
$(OBJECTFILES): Time_.h
clean:
rm $(OBJECTFIELS) main
every time I change the Time_.h file, nothing happens:-
$ make
make: 'main' is up to date.
$ touch Time_.h
$ make
make: 'main' is up to date.
other files compile when changed :-
$ touch main.o
$ make
g++ main.o Time.o -o main
please I am complete noob. Please tell why is this happening
You need to generate new .o files in your rule for Time_.h.
$(OBJECTFILES): Time_.h
This says make should run a command whenever Time_.h is updated, and that the command will generate both main.o and Time.o. But no command is given!
Time.o: Time_.h
$(CC) Time_.cpp -o Time.o
This is the kind of rule you want. Whenever Time_.h changes, we run $(CC) Time_.cpp -o Time.o, which will generate Time.o. Now if some other rule depends on Time.o, make will know that this command can be used to create Time.o, but that it only needs to be run if Time_.h changed since the last time make was run.
I'm specifying "Time.o" explicitly, since your source filenames don't seem to exactly match the object files you're expecting. (Time.o vs Time_.o)

C Makefile - recompile only changed files

Hello I have a shared library libnsd.so (made up of nsd.c,nsd.h,nd.c,nd.h) linked to main file.
My question is how to write the makefile so that it recompiles only those source files that have been changed.
I have read some topics about this but got somewhat confused, I'm a beginner programmer.
My makefile code so far:
CC=gcc
all : lib alll
alll : main.c
$(CC) main.c -o main -L. libnsd.so
lib : nsd.c nsd.h nd.c nd.h
$(CC) -c -fPIC nsd.c -o nsd.o
$(CC) -c -fPIC nd.c -o nd.o
$(CC) -shared -Wl,-soname,libnsd.so -o libnsd.so nsd.o nd.o
clean:
rm main libnsd.so nd.o nsd.o
Makefiles have the concept of build targets. The build targets are, really, all the intermediate as well as the final files and, by the way they are written, they can be made to use dependencies.
A sample solution for your makefile:
CC=gcc
all: main
main: main.c libnsd.so
$(CC) main.c -o main -L. libnsd.so
libnsd.so: nsd.o nd.o
$(CC) -shared -Wl,-soname,libnsd.so -o libnsd.so $#
%.o: %.c nsd.h nd.h
$(CC) -c -fPIC $< -o $#
A few things to note:
You should properly correct my dependencies on the object file creation (since I consider that each of the C files depends on both of the headers).
You may wish to note the wildcard construction I have used...
If there was nothing special with some of these commands I could have left default commands work. Do note that I have used $< for the first dependency and $# for the output in the wildcard rule.
I haven't copied the clean rule, since it was written correctly in the question itself.
Each of the targets (besides the "phony" target all) creates a file with the same name: The target libnsd.so creates a file with the name libnsd.so. The target main creates a file with the name main.
As a dependency of a target changes date so that the dependency is newer than the output, make will recreate the target, as well as other targets that depend on it. But if you have a target that is not mapped to any output file, that target is always called (in our code, the all target is always called but thankfully it has no commands and it depends only on actual files which may or may not need being recreated)
Do note that GNU Make doesn't need to have compiling in particular. The creation of an output file can happen by any means, and indeed I have seen a target create a .cpio.gz archive. But if that archive is older than any of the dependencies (the folder it would pack in) then it would be recreated, according to make.

Resources