How can I set up the "make" command when use without a makefile? - 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.

Related

Order of libraries and source files from makefile

I should start by saying I'm a bit of a newbie when it comes to gcc and makefiles.
On an Ubuntu machine that I've recently started using, I find that when running gcc, the order in which I put the source files and the libraries/headers makes a difference. On another machine I could do:
gcc -I../include -L../lib myProgram.c -o myProgram
But on the new machine, this will not link the libraries, and I must do:
gcc myProgram.c -o myProgram -I../include -L../lib
Now, I have the following makefile:
SHELL = /bin/sh
CC = gcc -O3
CFLAGS = -I../include
LDFLAGS = -L../lib
PROGS = myProgram
all: $(PROGS)
$(all): $(PROGS).o
$(CC) -o $# $#.o $(LIBS) $(CFLAGS) $(LDFLAGS)
rm -f $#.o
clean:
rm -f *.o $(PROGS)
But when I do "make", the actual gcc command that it runs has the libraries and source files in the wrong order. My question is: what do I need to do in the makefile to force the "-L../libs" option to come after the source files, so that the libraries will link properly?
I've also tried including the "-Wl,--no-as-needed" option, as I thought that an --as-needed flag might be the reason that the order matters in the first place, but this didn't appear to change anything (i.e. it still fails to link the libraries unless "-L../libs" comes after the source files).
The problem was that you thought you were using that rule, but you weren't. You never defined a variable named all, so the target of the second rule actually expanded to nothing. When you commanded Make to build myProgram, Make found no suitable rule in this makefile. Make has a toolbox of implicit rules it can fall back on in such cases; it wanted to build myProgram, it saw a file named myProgram.c, and one of its rules looks something like this:
%: %.c
$(CC) $(LDFLAGS) $^ -o $#
There you have it, linker flags before sources.
You can write your own pattern rule which Make will use instead:
%: %.o
$(CC) -o $# $^ $(LIBS) $(CFLAGS) $(LDFLAGS)
(Note that this builds myProgram from myProgram.o, and lets Make figure out how to build myProgram.o.)
If your executable is to be built from several object files, add a rule like this:
myProgram: other.o yetAnother.o
If you like you can have one more rule (the first) to tell Make what you want built:
all: myProgram myOtherProgram friendsProgram
(A final note: we've all had tight work deadlines. Asking for help once can be faster than learning the tools, but learning the tools is faster than asking for help N times. Determining the value of N is up to you.)

Makefile dependency file error when including it

I am finding problem when I try to include a C source file in my Makefile. This C source file contains a function which is called by the C++ code (list.cpp) through external C linkage option. I would like to know which is the right place in the Makefile to include this C source code whose function is invoked inside C++ code. If I try adding this C file in the Makefile's SOURCES variable in order to built it, then the C++ code fails to correctly resolve the function call of C and I am getting linker error: undefined reference
Following is my Makefile content:
CFLAGS =-c -g -Wall -std=c++11
SOURCES = list.cpp
OBJECTS = $(SOURCES:.cpp=.o)
EXEC = a.out
all: $(SOURCES) $(EXEC)
$(EXEC): $(OBJECTS)
#$(CXX) $(OBJECTS) -o $# && $(EXEC)
.cpp.o:
#$(CXX) $(CFLAGS) $< -o $#
Let's assume the C source file that you need in the build is bar.c,
and that it has an associated header file bar.h that you are
#include-ing in list.cpp, and that you have correctly coded the extern C
boilerplate in bar.h.
Then the following makefile will do what you need:
Makefile
CXX_SOURCES := list.cpp
C_SOURCES := bar.c
OBJECTS = $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o)
CXXFLAGS := -g -Wall -std=c++11
CFLAGS := -g -Wall
CPPFLAGS :=
LDFLAGS :=
LDLIBS :=
EXEC := a.out
.PHONY: all clean test
all: $(EXEC)
test: $(EXEC)
./$<
$(EXEC): $(OBJECTS)
$(CXX) $(LDFLAGS) $^ -o $# $(LDLIBS)
list.o: bar.h
clean:
rm -f $(EXEC) *.o
There are a lot of learning-points here:
1. Use immediate evaluation (:=) rather than recursive evaluation (=) of
make variables unless you particularly want recursive evaluation. See
6.2 The Two Flavors of Variables
2. If a target is merely a name for a task and not the name of a file that
the task will create, then it's a phony target
and you should tell make that it is a phony target, like:
.PHONY: all clean test
3. It is not normal for the make-recipe that builds a program to run the program as
well, like your:
#$(CXX) $(OBJECTS) -o $# && $(EXEC)
You don't always want to run a program just because you've built it, and
if the program is a long-running or interactive one then this approach
will make it impractial to build the program at all.
Probably, you want to run the program to test that it has been built correctly.
But building is one task, testing is another (that may take much longer and
involve additional resources); so you should provide a separate phony target
for testing. I've called it test in this makefile: often it is called check.
To build the program without testing it, just run make. To test it,
run make test - and this will also (re)build the program if it needs to be (re)built.
4. You don't need to write a rule to make name.o from a name.cpp, or
a rule to make name.o from a name.c. GNU make has builtin rules for doing
this correctly, as long as you have correctly set the make-variables that
make uses in those builtin rules:
CC: The command that invokes C compilation or linkage, e.g. gcc
CXX: The command that invokes C++ compilation or linkage, e.g. g++
CFLAGS: Options for C compilation
CXXFLAGS: Options for C++ compilation
CPPFLAGS: Options for the C/C++ preprocessor
5. Two more important make-variables that have conventional meanings are:
LDFLAGS: Options for linkage, excluding library (-l) options
LDLIBS: Library options (-l) for linkage.
In the simple makefile above, CPPFLAGS, LDFLAGS and LDLIBS are not
needed and could be ommitted. Instead, I've assigned them empty values
just to illustrate their use.
6. A makefile should have a phony target clean that deletes any files
that the makefile might have created, so that make clean gets you
ready to build anything or everything from scratch.
7.. If name.o is compiled from name.c or name.cpp, then of
course name.o depends on name.c|name.cpp, but it also depends
on every header file that is included by name.c|name.cpp, and the
makefile needs to express all those dependencies to work reliably. So
in this case you need (at least) the rule:
list.o: bar.h
so that if you change bar.h then make will see that foo.o is out of
date and will carry out its recipe for re-making foo.o. When you
start building complex programs it will become impractical for you
to figure out all these header-file dependencies yourself: then you'll need
to find out about auto dependency generation.
Here is the GNU Make manual

Compiling SDL project on Raspberry Pi

I am trying to build a project with make (gcc on Raspbian)
Here is the makefile (I removed some unnecessary parts):
objects = 3d.o Affichage.o [...]
cflags = -I/usr/local/include/SDL2 -L/usr/local/lib -lSDL2
poly : %(objects)
gcc $(cflags) $(objects) -o poly
($objects) : types.h
[...]
When running Make, I got:
cc -c -o Affichage.o Affichage.c
fatal error: SDL.h: No such file or directory
#include <SDL.h>
I checked the folders, everything seems ok. SDL.h is indeed in /usr/local/include/SDL2. I tried to remove options one by one in cflags, no luck...
What am I missing?
Make told you exact command it tried to execute:
cc -c -o Affichage.o Affichage.c
This don't have -I path, which is the source of an error.
You have target for your resulting executable but not for object files. Make have builtin rule to compile object files from C sources, but it isn't aware of your cflags variable. So far your options are:
Define your own pattern rule
e.g:
%.o: %.c
gcc $(cflags) -c $< -o $#
However, your cflags contains -lSDL2, which is linking flag, which should be specified only on linking phase (so technically it isn't cflag). Move it to separate variable (usually LIBS, which may then be enfolded into make's semi-standard LDFLAGS).
Use variables that make is aware of
In that case, it is CFLAGS:
CC:=gcc
CFLAGS:=-I/usr/local/include/SDL2
LIBS:=-lSDL2
LDFLAGS:=-L/usr/local/lib $(LIBS)
objects:=3d.o Affichage.o
poly: $(objects)
$(CC) $^ -o $# $(LDFLAGS)
$(objects): types.h
The rest will be done by implicit rules.

Why wouldn't make not execute a simple line in the 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

Makefile for using make as gcc

Is it possible to write universal Makefile which would get any target and act like a wrapper to gcc, but with parameters? For example, this means that
make 01.c
will have the same result as
g++ -o 01.out 01.c
make already has several "implicit rules" to do what you're trying.
For example, even with no makefile,
make 01.o
Will run:
c++ -c -o 01.o 01.cpp
If it finds a file called 01.cpp in your current directory. You can set the CXXFLAGS environment variable if you want to pass more flags. If you're really set on using g++ rather than the system compiler, you can set CXX=g++, too.
Yes - You using implicit rules.
Summat like (if memory serves me right)
.cpp.o:
$(CCC) $(CFLAGS) $< -o $#
Maybe in the set of default implicit rules
You can use a wildcard - %.
However, the thing specified on the commandline is the target, not the source - what you want, not what you have.
It looks like what you want is approximately:
%.out: %.c
g++ -o $# $<
This means: to make (something).out, first make sure you have (something).c, then run g++ -o (something).out (something).c
$# is always the target file, and $< is the first prerequisite.
You will need to run make 01.out, not make 01.c

Resources