Writing Makefile in C - c

I am writing(at first time) a makefile for my program in C. This is my make file:
CC = gcc
FILES = in_one.c in_two.c in_two.h
OUT_EXE = out_executable
build: $(FILES)
$(CC) -o $(OUT_EXE) $(FILES)
clean:
rm -f *.o core
rebuild: clean build
Actually, everything works properly : Gcc compiler doesn't show any errors, but maybe someone could explain what does these lines mean:
clean:
rm -f *.o core
rebuild: clean build

The clean lines say that if you want to make clean it does not depend on anything (nothing behind ":"). Furthermore the rm command deletes all object files.
The rebuild: clean build says that if you want to make rebuild it depends on clean and build. So the first thing to do is clean (= delete all object files) and then make build (= compile all source files). After that there is nothing more to do so make stops.
For a quick start, make recipes have the following syntax:
target: dependency1 dependency2 ... dependencyN
command1
command2
...
command3
So if target needs to be made at first all dependencies (dependency1 - dependencyN) are made. After this is done command1 - commandN are executed in that order.

You are rm (removing) or deleting all (*) the existing .o Files. So the next time you compile or call the make file you are just left with the new ones.
Build: $(Files) is creating the .o so the compiler can link them together into an executable

Related

Simplest C makefile using implicit rules

I know it is not optimal at all to rely on make's implicit rules but
my goal is to understand why they are not working in this case.
I want to write the simplest makefile one can write for a C project
without having to specify the sources.
I have tried to run make -d but the ouput is too big and verbose to
really be helpful.
I have written makefiles for some time and I believe I am familiar with how it
works. I am pretty sure I have managed to get implicit rules to work for me both
compiling and linking in the past but apparently I am forgetting something.
Here's what I have tried :
SRCS = $(wildcard *.c)
OBJS = ${SRCS:.c=.o}
NAME=exe
${NAME}: ${OBJS}
clean:
rm -rf *.o
fclean: clean
rm -rf ${NAME}
re: fclean ${NAME}
.PHONY: clean fclean re
It almost works but it doesn't link.
I am using gnu make version 4.3
Your Makefile doesn't execute the link step because there is only a very simple implicit rule for linking. From the documentation:
Linking a single object file
n is made automatically from n.o by running the C compiler to link the program. The precise recipe used is $(CC) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS).
This rule does the right thing for a simple program with only one source file. It will also do the right thing if there are multiple object files (presumably coming from various other source files), one of which has a name matching that of the executable file. Thus,
x: y.o z.o
In other words, for your Makefile to work, NAME needs to match the basename of one of your object files.
For example, if I have your Makefile and a single source file named hello.c, I can run:
make NAME=hello
And see the result:
cc -c -o hello.o hello.c
cc hello.o -o hello

How to properly create and use makefile

I'm getting started with makefiles and I'm having some problems.
I have one file which is fase_1.c that I want to compile and run.
I'm trying to make a simple makefile where I make and make clean.
This is what I tried:
OBJECTS = fase_1.o
CFLAGS = -Wall
NAME = makefile
build: $(OBJECTS)
cc $(CFLAGS) $(OBJECTS) -o $(NAME)
clean:
rm -f *.o
rm -f $(NAME)
I do make, and it creates fase_1.o and makefile. Then I run ./makefile (is there another way to do it without like make or make clean but to run it?). Then I type make clean, and it says that there's a missing separator and that the line is ignored and doesn't remove fase_1.o and makefile (what I want to do). Am I separating the lines right? Maybe it has something to do with tab or my editing but I can't find where.
Here's a rewrite. Call it Makefile, though, not makefile:
OBJECTS = fase_1.o
CFLAGS = -Wall
NAME = fase
$(NAME): $(OBJECTS)
cc $(CFLAGS) $(OBJECTS) -o $(NAME)
run : $(NAME)
./fase
.PHONY: clean
clean:
rm -f *.o
rm -f $(NAME)
There are fancier improvements that could be made, but it's probably best not to get bogged down at this stage. As a bonus, I have added .PHONY. This tells make that the target clean is a phony target; it doesn't actually create anything called clean.
You don't have to make run dependent on $(NAME), of course, but it makes sense in this particular context.
It looks like you are using GNU make. From the info page:
By default, when 'make' looks for the makefile, it tries the following
names, in order: 'GNUmakefile', 'makefile' and 'Makefile'.
Your executable is called makefile. When you run make, it tries to parse the executable as Makefile. Either rename the executable, or specify the makefile explicitly:
make -f Makefile clean

I'm having trouble understanding all: ex1 in Makefile? (Learn C The Hard Way)

I'm working through Learn C The Hard Way and in Ex2 Extra Credit they ask you to create an all: ex1 target that will build ex1 with just the command make.
This is the code I've created:
CFLAGS=-Wall -g
all: ex1
clean:
rm -f ex1
It works.
When I run just make from the command line it makes the ex1 file. And when I run make clean it removes the file.
What I don't understand is why:
all: ex1
isn't:
all:
make ex1
Where is it getting the make command from? The command line I guess, but then why does make clean run rm -f ex1 and not make rm -f ex1 and fail. It seems inconsistent to me. Can somebody explain what's going on?
The name all is not fixed, it's just a conventional name. all: target denotes that if you invoke it, make will build all what's needed to make a complete build.
So in essence, you could have written make ex1, but if you, lets say, had 100 files (ex1, ex2, ex3...) you wouldn't want to type 100 lines, right?
all is usually also a .PHONY target.

What is the difference between makefile and sh file

What is the difference between makefile and sh file. sh(shell
script file) file also can work at the place of makefile(means we can
do same thing using shell file like makefile can do) then what is
difference between them. there is any execution difference or any
standard where we have to use makefile and sh file.
one Example of this to compile a hello.c file with Makefile and shell file
shell.sh
param="$1";
CC="gcc"
CFLAGS="-c -Wall";
if [ "$param" == "clean" ];
then
rm -rf hello
else
$CC $CFLAGS hello.c -o hello
fi
./shell.sh { will build hello.c file }
./shell.sh clean { this will clean the build file }
Same thing with Makefile..
CC=gcc
CFLAGS=-c -Wall
hello: hello.c
$(CC) $(CFLAGS) hello.c -o hello
clean:
rm -rf hello
make {it will build}
make clean {it will clean build file}
Both files can generate same output.
This question because some people use Makefile and some people use shell..
make automatically checks (based on time stamps) which targets need to be remade and which ones can be left untouched. If you write your own shell script, you'll either have to program this logic yourself or else all your components will be rebuilt when you run your script - even those that haven't changed since the last build.

recursive makefile not building

I have a bunch of C files in different directories and I'm getting a make: nothing to be done for 'all' error with my recursive Makefile; however if I tweak the dependences I can get it to work... but I don't understand why I have to.
Here's my original Makefile:
APP_DIRS=rescoco ressys resvm
.PHONY: all
all: $(APP_DIRS)
$(APP_DIRS):
$(MAKE) --directory $#
clean:
$(RM) *~
Now if I change my line: .PHONY to .PHONY: all $(APP_DIRS) it builds fine.
Another possibility is if I change the line: $(APP_DIRS): to $(APP_DIRS): clean it builds fine.
(NOTE: removing .PHONY target doesn't change anything)
So what's going on here? Is the Makefile trying to tell me I haven't listed dependencies correctly? I was thinking make would do something like:
to build .PHONY I first have to build all
to build all I first have to build $(APP_DIRS)
$(APP_DIRS) has no prereqs so execute the command for that (which would cause the recursive makes to run).
Clearly I am wrong; but why?
FYI, if it matters my files are structured something like this:
Makefile #top level makefile as seen above
/rescoco
rescoco.c
Makefile #builds rescoco src and moves archive to ../lib directory
/ressys
ressys.c
Makefile #same as above but for ressys
/resvm
resvm.c
Makefile #same as above but for resvm
/lib
and my build command is simply make. When I run with make -n or make -n all I get no output at all:
:~/proj$ make -n all
make: Nothing to be done for 'all'.
:~/proj$
Things first you should be aware of:
If you have directories as dependencies, make is going to consider building the targets (i.e. executing the recipes for such directory targets), only if the modification timestamp of the directory gets updated.
This would happen only when you add a new file in the directory but not for file modifications in the directory. Adding files in a sub-directory does not change the timestamp of the directory.
PHONY targets are meant to be used when executing such a target does not create a file with the name of the target. In other words, you want make to execute the rule irrespective of whether the file already exists or not.
So your Makefile esentially only tells this:
To build the target all, I need to build $(APP_DIRS). Since all is a PHONY target, I will always execute the recipe for all.
$(APP_DIRS) is not a PHONY target and does not have any dependencies. So *only if $(APP_DIRS) does not exist already (i.e. the file or directory), I'm going to execute the recipe, otherwise I'm doing nothing for this target.
clean has no pre-requisite and not a PHONY, so I expect to execute this rule only when explicitly invoked by make (from the command line or another Makefile). Also clean is not a PHONY, so I expect the recipe to create a file called clean after execution (which is incorrect for your case)
Hence changing the .PHONY line to:
.PHONY: all $(APP_DIRS)
makes the Makefile go and execute the recipe for $(APP_DIRS) always.
So if you would like make to always traverse into all of the $(APP_DIRS) directories and invoke make again on them, you need to add $(APP_DIRS) to .PHONY, which makes $(APP_DIRS) a PHONY target, and executes the recipe irrespective of the file's/directory's timestamp if it exists.
For your particular use-case, I think this is the Makefile you should be using:
APP_DIRS=rescoco ressys resvm
.PHONY: all clean $(APP_DIRS)
all: $(APP_DIRS)
$(APP_DIRS):
$(MAKE) --directory $#
clean:
$(RM) *~
BONUS:
Changing $(APP_DIRS): to $(APP_DIRS): clean implies that $(APP_DIRS) depends on the clean target.
Although clean is not marked a PHONY, make does not see a file named clean in the current directory. So it goes ahead and tries to execute the recipe for clean.
Since a dependency of $(APP_DIRS) (i.e. clean) was built, this makes the Makefile execute the recipe for building $(APP_DIRS).
This brings us to an interesting observation:
- Any target that depends on a PHONY target will always get rebuilt (i.e. the recipe would be executed).
Take this simple Makefile:
all: target1
target1: target2
#echo "$#"
#touch $#
target2: target3
#echo "$#"
#touch $#
target3:
#echo "$#"
.PHONY: all target3
The first time I run make, I see this output:
target3
target2
target1
After this, files target1 and target2 are created. Even then, if I run make again, I would see the output:
target3
target2
target1
As you can see, the PHONY dependencies get propagated up and not the other way down. target2 gets rebuilt just because target3 is a PHONY, and target1 gets rebuilt just because target2 got rebuilt.
You are defining a variable named 'APP_DIRS' with a list of directories. That is fine.
You then do
$(APP_DIRS): make blah blah, which is essentially equivalent to rescoco ressys resvm: make blah blah
which obviously isnt valid.
So you need to pretend your $(APP_DIRS) is a variable, not a target name, which seems to be what you're using it as.
having said that, think why .PHONY: all $(APP_DIRS) works
This is how you can do it, just remove the wildcard if you don't want it.
make wildcard subdirectory targets

Resources