Why wouldn't make not execute a simple line in the makefile - makefile

This is my first time using make, and i've been spinning my wheels trying to get past an issue. I can't understand why a simple echo never gets executed:
CFLAGS = -Wall
LDFLAGS = -g
CC = gcc
SRCS = p4a.c p4b.c
p4static: p4a.c
gcc $(LDFLAGS) -o $# $< -static -L. -lpthread
p4dynlink: p4a.c
#echo "this doesn't print/echo/execute"
gcc $(LDFLAGS) -o p4dynlink $< -L. -lpthread
I'm using tab instead of spaces. Here is the outputs:
mike#elementary:~/p4$ make
gcc -g -o p4static p4a.c -static -L. -lpthread
mike#elementary:~/p4$ make
make: `p4static' is up to date.

From How make Processes a Makefile:
By default, make starts with the first target (not targets whose names start with ‘.’). This is called the default goal. [....]
Thus, when you give the command:
make
make reads the makefile in the current directory and begins by processing the first rule.
So when you type make make tries to build your p4static target which doesn't have an echo line. And the next time you run make it says that target is up to date and has nothing to do.
To build p4dynlink you need to tell make to build that target make p4dynlink.
You can set the default goal manually (in the makefile) with .DEFAULT_GOAL:
# Set our own.
.DEFAULT_GOAL := foo
But convention is usually to create an all target as the first target and have it "Do the Right Thing" by default.
So in your case, assuming you wanted both targets built by default, you would use:
all: p4static p4dynlink

Related

Avoid gnu make automatic file deletion

GNU make is deleting my object files automatically. I don't understand why...
My goal is small test programs generation, hence each source file is an independent program which uses no other module.
My makefile is:
# This makefile is written for Windows cmd shell
SHELL=C:\Windows\System32\cmd.exe
# FILES
SRCS=$(wildcard src/*.cpp)
BINS=$(patsubst %.cpp,bin/%.exe,$(notdir $(SRCS)))
all:compile
obj/%.o:src/%.cpp
g++ -Wall -Wextra -std=gnu++11 -m64 -D_WIN32_WINNT=0x0400 -c -o $# $<
bin/%.exe:obj/%.o
g++ -Wall -Wextra -std=gnu++11 -m64 $^ -o $#
clean:
if exist obj\*.o del /Q obj\*.o
mrproper:clean
if exist bin\*.exe del /Q bin\*.exe
compile:$(BINS)
rebuild:clean all
.PHONY:all compile clean mrproper rebuild
Running GNU make with, for instance, a single source file does as follows:
g++ -Wall -Wextra -std=gnu++11 -m64 -D_WIN32_WINNT=0x0400 -c -o obj/Tester.o src/Tester.cpp
g++ -Wall -Wextra -std=gnu++11 -m64 obj/Tester.o -o bin/Tester.exe
rm obj/Tester.o
Why is my object file deleted?
How to avoid it?
If I replace either obj/%.o:src/%.cpp by obj/Tester.o:src/Tester.cpp or bin/%.exe:obj/%.o by bin/Tester.exe:obj/Tester.o the file Tester.o is not deleted, but this is not what I need.
Since you use implicit rule (such as ‘%.o’), object file will be delete after make.
Add special target .PRECIOUS to protect it.
.PRECIOUS: obj/%.o
Reference:
Special Built-in Target Names
Chains of Implicit Rules
After reading the links yihsiui provides, I come with another answer to my own question.
The object files are deleted because they don't exist and the rules I wrote made them intermediate. To avoid them to be flagged as intermediate, they must be an explicit target in some rule. I still need the pattern rule to generate the object file because I use the pattern substitution to compute the name of the object file. So, why not simply add an "empty" rule?
OBJS=$(patsubst %.cpp,obj/%.o,$(notdir $(SRCS)))
(...)
$(OBJS):

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.

What is the importance of target in makefile?

I am learning how to create makefile on a Linux distro.
I am using the following code (I know it can be written in a small form, but the long form is intentional) to properly understand the behavior of makefile
test: test.o
cc -o test test.o
test.o: test.c
cc -c test.c
clean:
rm test.o
Now, when I use make and make clean in the shell, they are working as intended.
However, I want to know the importance of target in makefile. Hence, started by changing test.o: test.c line to test2.o: test.c and typed make in the shell; my initial guess was that there would be a file in my home directory called test2.o, but that's not the case, I still see test.o being created again.
So, the above behavior begs my question, what is the important of target component in makefile?
The 'target' is the file which Make checks to determine whether it needs to execute the commands associated with the target at all.
I.e. if you change test.o: test.c to test2.o: test.c, Make sees that test2.o does not exist and hence executes the command cc -c test.c -- which still only creates test.o. Hence, if you re-run make, you will see that the compiler is executed again because test.o still does not exist.
In the original version, test.o: test.c, the compiler will only be executed if test.o does not exist, or if the modification time of test.c is newer than that of test.o.
The target becomes available in the commands section as a variable $#, which can be used to define what gets built.
In your makefile you had:
test2.o: test.c
cc -c test.c
Because you didn't tell the compiler what the output would be as part of the cc command, it created test.o from test.c, which is the default behaviour. If you run cc -c file.c it will generate file.o by default.
You need to specify the destination file as part of the commands run for generating the target, so:
test2.o: test.c
cc -c test.c -o $#
Would cause the compiler to generate the test2.o file appropriately.
At a fundamental level, a makefile is nothing more that a set of targets, dependencies for the targets and the sets of commands for making those targets. You have to ensure that as part of the build process, the final product from a set of commands is the target in order to have a properly functioning makefile.
The compiler doesn't know anything about the fact that it's being run in the makefile.
There are a bunch of automatic rules, pre-created by the default make system. These include rules for making .o files from .c files - it knows that it needs to compile a file using the following rule and commands:
%.o: %.c
# commands to execute (built-in):
$(COMPILE.c) $(OUTPUT_OPTION) $<
where COMPILE.c:
COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
and OUTPUT_OPTION is:
OUTPUT_OPTION = -o $#
CC defaults to cc, CFLAGS defaults to empty, CPPFLAGS defaults to empty and TARGET_ARCH defaults to empty. You can see these definitions using make -p
So the resulting command is:
cc -c -o $# $<
Where $# is the name of the target and $< is the first item in the list of dependencies. This pattern matches all target files called <something>.o where there is an existing file called <something>.c. If there's a request to build test.o as a target then it will compile a file called test.c, because that file exists and matches these rules.
tl;dr
Your test2.o rule is never executed. test.o is created by make's implicit rule.
Let's take this apart.
test.o: test.c
cc -c test.c
This is a rule.
The general syntax for a rule is:
targets : prerequisites
recipee
So, test.o is the target, and test.c the prerequisite.
If:
the target (file) does not exist, or
(one of) the prerequisite(s) is newer than the target,
the recipee is executed (which should, but does not have to, create the target).
So, let's look at your Makefile:
test: test.o
cc -o test test.o
test.o: test.c
cc -c test.c
When you say make test, you want to create the target test. This target has test.o as prerequisite.
For test.o exists another rule, with test.c as prerequisite. So that rule gets checked and executed first (compiling your source to object code), before the test prerequisite is checked, and the recipee run if required (linking your object code to executable format).
Hence, started by changing test.o: test.c line to test2.o: test.c and typed make in the shell; my initial guess was that there would be a file in my home directory called test2.o, but that's not the case, I still see test.o being created again.
No target has a test2.o prerequisite, and you did not ask for that to be build specifically (make test2.o), so the recipee for test2.o is never executed.
But test still has test.o as a prerequisite. As there is no explicit rule for a target of that name in your Makefile, make substitutes it with its implicit rule for creating a .o file from an existing .c file...
The default output file from cc -c test.c is test.o. If you want it to create test2.o, you need to tell it explicitly:
test2.o: test.c
cc -o test2.o -c test.c
cc doesn't know anything about the makefile or what target it's being run from.
The importance of targets is that they're used for finding all the dependencies. So the first rule in your makefile says that test is dependent on test.o: before you can create test, you first need to create test.o, and if test.o has changed, you need to rebuild test.
The commands below the target are expected to do whatever it takes to create the target. But you have to code that explicitly (although there are some macros that can automatically substitute targets and dependencies into the command line -- these are mostly useful when the target contains a wildcard pattern).

How can I set up the "make" command when use without a makefile?

New guy learning programming with C in ubuntu
Using a hello.c for example
From some video tutorial I saw the teacher can use "make hello" to compile the hello.c without setting up a Makefile in current directory
And the command goes like
bash$ make hello
gcc -g -Wall hello.c -o hello
I tried to use make on my own ubuntu 14.04
I installed build-essential and tried out the same hello.c
bash$ make hello
cc hello.c -o hello
It goes like above
How can I make changes to get -g, -Wall or any other flags?
What you need
The way make works is that it produces targets out of sources through known recipes.
When you write your own Makefile, you provide the recipes for it, however, make has internal recipes, which can be used. You can list them by make -p.
One of the recipes tells make how to produce <something> out of <something>.c. When you run make hello, make checks how to produce hello, finds that there is a file hello.c and that it knows how to produce hello from hello.c -- using that internal rule.
Now the rule looks like this.
%: %.c
# recipe to execute (built-in):
$(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o $#
and the important part, $(LINK.c) looks like this
LINK.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
You don't need to understand the syntax at this point, the important thing is, that your make hello will be transformed into (some unused variables omitted)
$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) hello.c -o hello
Now CC, CFLAGS, CPPFLAGS and LDFLAGS may be set by make (in your case, CC is set to "cc" and the rest is not set), but you can override this with your environment variables. What you want is having
CC=gcc
CFLAGS="-g -Wall"
How to get it
To do that for one command only run:
CC=gcc CFLAGS="-g -Wall" make hello
To do that for one session (until you close your terminal) run
export CC=gcc
export CFLAGS="-g -Wall"
and then just make hello or make whatever as long as you want.
To do that permanently, set these variables in your .profile file (open ~/.profile (create it if it doesn't exist) and add
export CC=gcc
export CFLAGS="-g -Wall"
to it. Or just run
echo 'export CC=gcc' >> ~/.profile
echo 'export CFLAGS="-g -Wall"' >> ~/.profile
In both cases, you need to source ~/.profile or start a new terminal. It will work happily ever after.
Make has a number of implicit rules, which are used in the absence of a Makefile.
The one regarding .c files is:
n.o is made automatically from n.c with a recipe of the form $(CC) $(CPPFLAGS) $(CFLAGS) -c
This means you can set the environment variables:
CC to set the compiler used;
CPPFLAGS to set the preprocessor flags used (the same would be used e.g. for C++ .cpp or Fortran .F sources);
CFLAGS to set the compiler flags used.
The implicit rule turns the .c source file into a .o object file, which is then linked to an executable according to another implicit rule:
n is made automatically from n.o by running the linker (usually called ld) via the C compiler. The precise recipe used is ‘$(CC) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS)’.
Again, you see the environment variables used.

Makefiles in multiple directories

I want to build an app and I have multiple modules stored in multiple directories. I've decided to follow this idea, i.e. to have a makefile in each directory and then to merge it. But - as a beginner programmer - I still do not see how to do that. First of all, how would such "partial" makefiles look like. They cannot have main function as there can be only one per binary, though when I try to compile it gcc complains for the undefined reference to main. Secondly, I have no idea how would putting all those modules together look like.
I would appreciate any help, but please try to keep your answers simple. Makefiles are still a bit of black magic to me.
Before you can do anything with a makefile, you must know how to do it without a makefile.
Since you are using gcc, I will assume that your source code is C++.
You haven't told us what your directory structure looks like, so I'll suppose that you have three source files in two directories: primary/main.cc, other/foo.cc and other/bar.cc. (We can deal with header files like foo.h later.) And you want to build myApp.
STEP 1: Doing It By Hand
To do this in one command, you might use:
gcc -Wall primary/main.cc other/foo.cc other/bar.cc -o myApp
This will compile the three source files and link the binary objects together into the executable myApp.
STEP 2: Doing It In Pieces (Do not attempt this until you can get the previous step to work perfectly.)
Instead of building with one command, you could take an intermediate step, compiling the source files into binary object files:
gcc -Wall -c primary/main.cc -o primary/main.o
gcc -Wall -c other/foo.cc -o other/foo.o
gcc -Wall -c other/bar.cc -o other/bar.o
This will produce alpha/main.o, beta/foo.o and beta/bar.o. The compiler won't complain about foo and bar lacking a main() function, because an object file doesn't need one. Then link the objects together into an executable:
gcc -Wall primary/main.o other/foo.o other/bar.o -o myApp
STEP 3: Doing It Locally (Do not attempt this until you can get the previous step to work perfectly.)
Just like the previous step, but we act in primary/ and other/:
cd primary
gcc -Wall -c main.cc -o main.o
cd ../other
gcc -Wall -c foo.cc -o foo.o
gcc -Wall -c bar.cc -o bar.o
cd ..
gcc -Wall primary/main.o other/foo.o other/bar.o -o myApp
STEP 4: Using a Makefile (Do not attempt this until you can get the previous step to work perfectly.)
We could have a makefile perform STEP 1, but that isn't really necessary. Write a makefile in primary (i.e. primary/makefile) like this:
main.o:
gcc -Wall -c main.cc -o main.o
(That whitespace in fromt of gcc... is a TAB.)
Now try this:
cd primary
make
cd ../other
gcc -Wall -c foo.cc -o foo.o
gcc -Wall -c bar.cc -o bar.o
cd ..
gcc -Wall primary/main.o other/foo.o other/bar.o -o myApp
STEP 5: Using Several Makefiles (Do not attempt this until you can get the previous step to work perfectly.)
Write a other/makefile:
both: foo.o bar.o
foo.o:
gcc -Wall -c foo.cc -o foo.o
bar.o:
gcc -Wall -c bar.cc -o bar.o
and a makefile in the top directory, where you're building myApp:
myApp:
gcc -Wall primary/main.o other/foo.o other/bar.o -o myApp
Now try this:
cd primary
make
cd ../other
make
cd ..
make
STEP 6: Using One Makefile That Calls Others (Do not attempt this until you can get the previous step to work perfectly.)
Edit the top makefile:
myApp:
cd primary; make
cd other; make
gcc -Wall primary/main.o other/foo.o other/bar.o -o myApp
Now try:
make
If all of this works, what you have is a crude but effective makefile system. There are many refinements possible, when you're ready to take the training wheels off.
EDIT:
If there are many source files in a subdirectory (e.g. other/) and you don't want to maintain a list in the top makefile by hand, there are several ways to handle it. This is one:
OTHER_SOURCES := $(wildcard other/*.cc)
OTHER_OBJECTS := $(OTHER_SOURCES:.cc=.o)
myApp:
cd primary; make
cd other; make
gcc -Wall primary/main.o $(OTHER_OBJECTS) -o myApp
But you should get these makefiles working and understand them, before you try any more streamlining.

Resources