I am trying to a create a makefile architecture so I have one global makefile at the top which call another in a subdirectory.
Global makefile :
CC = gcc
CFLAGS = -W -Wall -pedantic
LDFLAGS =
PROJECT = proj
SOURCES =
PATH = $(PROJECT)
include $(PATH)/Makefile
all : $(PROJECT).exe
$(PROJECT).exe :
$(CC) $(CFLAGS) $(LDFLAGS) $(DEFINES) $(INCLUDES) $(SOURCES) -o $#
clean :
rm -rf *.exe
Subdirectory makefile :
CC = gcc
CFLAGS = -W -Wall -pedantic
LDFLAGS =
SOURCES += $(PATH)/main.c
When I "make" in the top directory I have the following error :
gcc -W -Wall -pedantic proj/main.c -o proj.exe
make: gcc: Command not found
make: *** [Makefile:17: FK16_jake.exe] Error 127
But when i type exactly the same command (gcc -W -Wall -pedantic proj/main.c -o proj.exe) in my terminal, it's building.
And if I remove the makefile include, he recognize gcc but don't build because no sources (normal behavior).
You are overriding PATH, which is used to determine where to look for executables. Change this variable and it should work.
In the UNIX shell, the environment variable PATH specifies the set of directories to search for executables when you run a command.
The GNU Make manual says:
When make runs a recipe, variables defined in the makefile are
placed into the environment of each shell. This allows you to pass
values to sub-make invocations (see Recursive Use of make). By default, only variables that came from the environment
or the command line are passed to recursive invocations.
Because PATH is a shell variable and is defined in the environment of make, it is "came from the environment". That means when you modify the value with PATH = $(PROJECT) the updated value will be set in the environment of the shell that runs the recipe for $(PROJECT).exe. That means the shell runs with a bad value for the PATH and so cannot find gcc.
To avoid this confusion, do not use PATH as a makefile variable. Use another name which is not the same as an environment variable that the shell depends on. You could call it PROJECT_PATH instead, or just use $(PROJECT) instead of $(PATH).
Related
I'm using mingw32-make to run my makefile. The contents of the Makefile are the following:
#OBJS specifies which files to compile as part of the project
OBJS = SDLpp.o SDLpp_exception.o SDLpp_window.o
#CC specifies which compiler we're using
CC = g++
#INCLUDE_PATHS specifies the additional include paths we'll need
INCLUDE_PATHS = -IC:\mingw_dev_lib\include\SDL2 \
-IC:\mingw_dev_lib\include\SDL_image \
-IC:\mingw_dev_lib\include\SDLpp
#LIBRARY_PATHS specifies the additional library paths we'll need
LIBRARY_PATHS = -LC:\mingw_dev_lib\lib
#COMPILER_FLAGS specifies the additional compilation options we're using
# -w suppresses all warnings
# -Wall includes all warnings
# -Wl,-subsystem,windows gets rid of the console window
COMPILER_FLAGS = -Wall
#LINKER_FLAGS specifies the libraries we're linking against
LINKER_FLAGS = -lmingw32 -lSDL2main -lSDL2 -lSDL2_image
#LIB_NAME specifies the name of our library
LIB_NAME = libSDLcpp.a
#This is the target that compiles our executable
all : $(OBJS)
ar rvs $(LIB_NAME) $(OBJS)
%.o : %.c
$(CC) $< $(INCLUDE_PATHS) $(LIBRARY_PATHS) $(COMPILER_FLAGS) -c $(LINKER_FLAGS) -o $#
^(the white-space before the commands are tabs)^
When run, the shell outputs
g++ -c -o SDLpp.o SDLpp.cpp
which indicates that the other variables are not being expanding in the first pattern rule. Oddly, only CC is expanding into g++. Why is this happening?
The issue is not one of non-expanding variables. Rather, the makefile is using the default rule instead of the one you provided.
The reason may be that your rule uses *.c, while you likely have *.cpp files, IIRC.
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.
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
I read a lot of tutorials about CFLAGS and also looked in the official docs. Everywhere they say CFLAGS is implicit but still pass it explicitly in their example makefile to the compiler:
CFLAGS=-O2
gcc $(CFLAGS) -c foo.c -o foo.o
So, what does the term "implicit" mean in this context? If I declare CFLAGS=-O2 in my makefile and later just say gcc -c foo.c -o foo.o, will -O2 be active or not (so, is it really implicit)? If so, why do all tutorials (including official docs) still pass it explicitly in their examples?
Everywhere they say CFLAGS is implicit but still pass it explicitly in their example makefile to the compiler.
gcc does not use CFLAGS environment variable. See Environment Variables Affecting GCC.
CFLAGS is a conventional name for a Makefile variable with C-compiler flags and it is used by implicit make rules. See Variables Used by Implicit Rules for more details.
If you use your own make rules instead of the built-in ones, you do not need to use CFLAGS at all. Although it is a useful convention to do so because people are familiar with the conventional make variable names.
I believe CFLAGS is implicitly passed to the compiler command line by the makefile via the default compilation rule... Yet the CFLAGS can be overridden with custom flags so that each compilation command will take it and use.
You can test it easily:
$ cat cflags.mak
CFLAGS = -wrong
foo.o: foo.c
$ make -f cflags.mak
cc -wrong -c -o foo.o foo.c
cc: unrecognized option '-wrong'
So you can see it used the value of CFLAGS even though it was not explicitly specified in a rule; thus it is implicit.
But if you do specify your own rule for compiling .c files, you have to include it if you want it used:
$ cat cflags.mak
CFLAGS = -wrong
foo.o: foo.c
gcc -c $<
$ make -f cflags.mak
gcc -c foo.c
Here I provided my own rule for .c files which did not include CFLAGS, so CFLAGS was not used.
So the bottom line is if you rely on the built-in make rule for compiling .c files, CFLAGS will be included implicitly. But if you override that rule, you have to include it explicitly if you still want it to be used.
It means that there are implicit make rules, that use the CFLAGS, you can use.
So you can write a one line makefile with:
CFLAGS=-O2
if you later do:
make filename
(omitting extension) it will use an implicit rule that references the CFLAGS to convert you source file .c in an executable, so you don't need to write an explicit build statement for simple builds.
E.g. if you prepared a source name file.c it will build it with an implicit rule like:
$GCC $CFLAGS file.c -o file $LDFLAGS
see: GNU make documentation
When I compile code using GNU Make I get multiple warnings like:
clang: warning: -lGui: 'linker' input unused
This is probably because I have messed something up in my Makefile (below). Can anyone point me toward the problem?
CXX=g++
CC=g++
CXXFLAGS=-g -Wall -W -Wshadow -Wcast-qual -Wwrite-strings $(shell root-config --cflags --glibs)
CPPFLAGS+=-MMD -MP
LDFLAGS=-g $(shell root-config --ldflags)
LDLIBS=$(shell root-config --libs)
xSec_x: xSec_x.o xSec.o Analysis.o
-include xSec_x.d xSec.d Analysis.d
xSec.o: xSec.cpp xSec.h Analysis.h Analysis.cpp
xSec_x.o: xSec_x.cpp xSec.h Analysis.h
clean:
rm -f #rm -f $(PROGRAMS) *.o *.d
That message means you are passing linker flags (like -l which tells the linker to pull in a library) to the compiler.
This means that the result of running root-config --cflags --glibs is generating linker flags, and those are going into CXXFLAGS, which is being passed to the compiler. I don't know what root-config is, but you should investigate its command line and invoke it in a way where it doesn't generate linker flags. Probably removing the --glibs option will do it.
ETA: you really want to be using := to assign these flags variables if you're going to run $(shell ...) there. It will work either way, but if you use = then the shell command will be run every time make expands the variable, which is once per compilation. If you use := it will only be run once, when the makefile is parsed.
I got this same error and the reason was that I forgot to add -I in front of my included paths for cflags in makefile. For example:
CFLAGS += $(path)/dir/subdir/include -> Got the above mentioned error.
CFLAGS += -I$(path)/dir/subdir/include -> Fixed the issue.