gcc Makefile: Variable Substitution error with % - variables

My make file has worked, up until I tried some variable substitution. %.o is not recognized.
I get make: * No rule to make target `%.o', needed by `parser'. Stop.
CC=gcc
CFLAGS=-ansi -pedantic -Wall -ggdb3
PROJECT=project.c project.h
PARSER=parser.c parser.h
OBJ=project.o parser.o
#CFILE=project.c parser.c
#1 no problem
#parser: project.o parser.o
# $(CC) $(CFLAGS) -o $# $^
#2 no problem
#parser: $(OBJ)
# $(CC) $(CFLAGS) -o $# $^
#3 this fails
parser: %.o
$(CC) $(CFLAGS) -o $# $^
#parser: project.o parser.o
# gcc -ansi -pedantic -Wall -ggdb -o parser project.o parser.o
project.o: $(PROJECT)
$(CC) $(CFLAGS) -c $^
parser.o: $(PARSER)
$(CC) $(CFLAGS) -c $^
clean:
rm -f $(OBJ) parser

You're not creating a pattern rule, since there is no % in the target name. As a result the % has no special meaning in the list of dependencies. It's seen as a literal part of a file name; you can't use it as a regular wildcard.

Related

Problem with makefile after rename variable

after changing the name of a variable into a makefile, its behavior changed drastically. From unsuccessful compilation to successful one.
I tried everything - different names, adding various additional conditions, but all without success.
Version of make:
$make --version
GNU Make 3.82
Built for x86_64-redhat-linux-gnu
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
This is a source code file
int main(int argc, char *argv[])
{
return 0;
}
Original(desired) behavior makefile:
SHELL = /bin/sh
.SUFFIXES:
.SUFFIXES: .c .o
CC := gcc
LD := gcc
CFLAGS := -g
STRICT_CFLAGS := -Wall -Wextra -Wpedantic -Werror
INCLUDE_CFLAGS :=
ALL_CFLAGS := $(INCLUDE_CFLAGS) $(STRICT_CFLAGS) $(CFLAGS)
STRICT_LDFLAGS := -Wall -Wextra -Wpedantic -Werror
INCLUDE_LDFLAGS :=
LDFLAGS := $(STRICT_LDFLAGS) $(INCLUDE_LDFLAGS) $(CFLAGS)
SOURCES := $(wildcard *.c)
BINARIES := $(SOURCES:%.c=%)
.PHONY: all
all: $(BINARIES)
%: %.o
#echo "Checking..."
$(LD) $(LDFLAGS) -o $#
.c.o:
#echo "Creating object..."
$(CC) $(ALL_CFLAGS) -c $< -o $#
.PHONY: clean
clean:
#echo "Cleaning up..."
-rm -rvf *.o $(BINARIES)
Compile output:
$make
gcc -g -Wall -Wextra -Wpedantic -Werror -g test.c -o test
test.c: In function ‘main’:
test.c:1:14: error: unused parameter ‘argc’ [-Werror=unused-parameter]
} return 0;nt argc, char *argv[])
^
test.c:1:26: error: unused parameter ‘argv’ [-Werror=unused-parameter]
} return 0;nt argc, char *argv[])
^
cc1: all warnings being treated as errors
make: *** [test] Error 1
Makefile after renaming variable (LDFLAGS -> T_LDFLAGS) - wrong behavior:
SHELL = /bin/sh
.SUFFIXES:
.SUFFIXES: .c .o
CC := gcc
LD := gcc
CFLAGS := -g
STRICT_CFLAGS := -Wall -Wextra -Wpedantic -Werror
INCLUDE_CFLAGS :=
ALL_CFLAGS := $(INCLUDE_CFLAGS) $(STRICT_CFLAGS) $(CFLAGS)
STRICT_LDFLAGS := -Wall -Wextra -Wpedantic -Werror
INCLUDE_LDFLAGS :=
T_LDFLAGS := $(STRICT_LDFLAGS) $(INCLUDE_LDFLAGS) $(CFLAGS)
SOURCES := $(wildcard *.c)
BINARIES := $(SOURCES:%.c=%)
.PHONY: all
all: $(BINARIES)
%: %.o
#echo "Checking..."
$(LD) $(T_LDFLAGS) -o $#
.c.o:
#echo "Creating object..."
$(CC) $(ALL_CFLAGS) -c $< -o $#
.PHONY: clean
clean:
#echo "Cleaning up..."
-rm -rvf *.o $(BINARIES)
Compile output:
$make
gcc -g test.c -o test
Please someone explain to me why, after the name change, we lose flags for a strict code.
Thanks for your time!
Neither of your make targets are being hit. If you look at the output, you'll notice that Checking... is not printed and Creating object... is not printed. So your program is being build with the default target. This default target automatically adds $(CFLAGS) and $(LDFLAGS) to the build line. That's why things stopped working when you renamed LDFLAGS.
Also, your makefile currently is trying to create an executable for each individual .c file.
You need to change your targets as follows:
SOURCES := $(wildcard *.c)
OBJECTS := $(SOURCES:%.c=%.o)
BINARY := myprog
.PHONY: all
all: $(BINARY)
$(BINARY): $(OBJECTS)
#echo "Checking..."
$(LD) $(T_LDFLAGS) $(OBJECTS) -o $#
%.o: %.c
#echo "Creating object..."
$(CC) $(ALL_CFLAGS) -c $< -o $#
The OBJECTS variable will contain a list of .o files that correspond to each .c file. This will be the dependency list for the binary and the list of objects to link. The target for object files says to create a .o file for each .c file.

Makefile: How do I use variables in the left hand side of the rule?

Let's say I want to rewrite this:
main.o: main.cpp
g++ -c main.cpp
factorial.o: factorial.cpp
g++ -c factorial.cpp
hello.o: hello.cpp
g++ -c hello.cpp
in a more generic way as something like this:
SOURCES = main factorial hello
$(SOURCES).o: $(SOURCES).cpp
g++ -c $(SOURCES).cpp
How do I do that?
First we tell the compiler how to nme the output files, just to avoid misunderstanding:
main.o: main.cpp
g++ -c main.cpp -o main.o
factorial.o: factorial.cpp
g++ -c factorial.cpp -o factorial.o
hello.o: hello.cpp
g++ -c hello.cpp -o hello.o
Then we put in automatic variables, to reduce redundancy:
main.o: main.cpp
g++ -c $< -o $#
factorial.o: factorial.cpp
g++ -c $< -o $#
hello.o: hello.cpp
g++ -c $< -o $#
Then we realize that these rules all look the same, so we combine them as a static pattern rule:
main.o factorial.o hello.o: %.o : %.cpp
g++ -c $< -o $#
Then we use a variable to store the names of the objects:
OBJECTS := main.o factorial.o hello.o
$(OBJECTS): %.o : %.cpp
g++ -c $< -o $#

specifying a make variable in a rule

I would like to set a variable $(CFLAGS2) to hold different values depending on the target i make. Specifically, i want to have a target which compiles my project with "-g -Wall", and another one which compiles with "-O3"
I tried it like this:
CC=gcc
COPT=-c $< -o $# $(CADD) $(CFLAGS) $(CFLAGS2)
.PHONY: opti
.PHONY: debi
opti: seto
make hammingtest
debi: setd
make hammingtest
.PHONY: seto
seto:
$(eval CFLAGS2 := -O3)
.PHONY: setd
setd:
$(eval CFLAGS2 :=-g -Wall)
hamming.o: hamming.cpp hamming.h
$(CC) $(COPT) $(DEFS) $(CFLAGS2)
hammingtest.o: hammingtest.cpp hamming.h
$(CC) $(COPT) $(DEFS) $(CFLAGS2)
hammingtest: hammingtest.o hamming.o
$(CC) -o hammingtest hammingtest.o hamming.o
But when i do "make debi" it acts as if $(CFLAGS") was not set at all (the same with "make opti")
How can i achieve this?
Do not use $(eval ...) in shell lines. That is usually just plain wrong.
There is a number of ways to do what you want. Since you already have recursive make set up, you could use command-line variables:
opti:
${MAKE} COPTS2='-O3' hammingtest
debi:
${MAKE} COPTS2='-g -Wall' hammingtest
A better style is to eschew the recursive make, maybe in favour of target specific variables:
CC=gcc
COPT=-c $< -o $# $(CADD) $(CFLAGS) $(CFLAGS2)
CFLAGS2 = $(error Someone tried to deref CFLAGS2!)
opti: CFLAGS2 := -O3
debi: CFLAGS2 := -g -Wall
.PHONY: all
all:
#echo 'What do you want to make?'
.PHONY: opti debi
opti debi: hammingtest
opti debi: ; #echo $# Success
.
.
.
This looks likely to work at a cursory glance.
The way this is set up though is problematic. For example, the following sequence of shell commands will give you an optimised build, with no warnings.
$ make opti
$ make debi

Makefile rule using the automatic variable $^ without dependencies

I learnt from the GNU Make manual that the sign $^ is an automatic variable which represents the names of all the prerequisites. However I fell upon a makefile like this one:
SVR_OBJECT_FILES = server.o\
server_func.o
CLT_OBJECT_FILES = client.o
CFLAGS = -Wall -Werror -W
CC = gcc
all: client/client server/serveur
client/client: $(CLT_OBJECT_FILES)
server/serveur: $(SVR_OBJECT_FILES)
client/client server/serveur:
#mkdir -p $(dir $#)
$(CC) $(CFLAGS) $^ -o $#
%.o: %.c
$(CC) -c $<
clean:
rm -f client/client server/serveur *.o
Which works fine so my question is :
How can the command below can link the right object files while the $^ variable is refering no preprerequisites at all. (the rule has no prerequisites)
$(CC) $(CFLAGS) $^ -o $#
$^ contains all the prerequisites of the target, not just the ones that are mentioned with the rule itself. The same file can appear as a target several times in rules with no commands:
sometarget: dependency1
…
sometarget: dependency2
assemble -o $# $^
…
sometarget: dependency3
The dependencies of sometarget are dependency1, dependency2 and dependency3, and when the assemble command is invoked by make sometarget, it will receive all three as arguments.
Here, $^ will contain all $(CLT_OBJECT_FILES) or $(SRV_OBJECT_FILES) depending on which target the command is executed for.

Prepending a path on make

In my makefile I have an object variable. I need to prepend obj/ to every .o file. How would I do this?
CC=g++
CFLAGS=-C -Wall
LDFLAGS=-lsqlite3 -lpthread -ldl
SOURCES=main.cpp Database.cpp actionInit.cpp TileSet.cpp Player.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=mahjong-counter
all: bin $(OBJECTS) $(EXECUTABLE)
bin:
mkdir -p bin
%.o: %.cpp
$(CC) $(LDFLAGS) $< -c -o $#
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -o $(EXECUTABLE)
clean:
rm $(OBJECTS)
You want CXX, not CC. CC is for C compiler, not the C++ compiler
In any case, I believe the following should work:
CXX=g++
CXXFLAGS=-C -Wall
LDFLAGS=-lsqlite3 -lpthread -ldl
OBJ_DIR = obj
BIN_DIR = bin
EXECUTABLE=mahjong-counter
SOURCES= main.cpp Database.cpp actionInit.cpp TileSet.cpp Player.cpp
OBJECTS= $(SOURCES:%.cpp=$(OBJ_DIR)/%.o)
all: dirs $(OBJECTS) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -o $(EXECUTABLE)
$(OBJ_DIR)/%.o: %.cpp
$(CXX) $(CXXFLAGS) $< -o $#
dirs:
mkdir -p $(BIN_DIR)
mkdir -p $(OBJ_DIR)
.PHONY: dirs all
You could use more expressive version of substitution you employed when assigning OBJECTS
OBJECTS=$(SOURCES:%.cpp=obj/%.o)
or use a standard text transformation function
OBJECTS=$(addprefix obj/,$(SOURCES:.cpp=.o))