Define compilation variables based on target for - makefile

my c++ source file look for a specific variable passed from the makefile. when making a different target, this variable definition is different.
How can I define a variable in Makefile based on target.
Thanks

You can use target-specific variable values, they propagate to target's prerequisites:
all : foo bar
foo : CXXFLAGS += -DFOO
bar : CXXFLAGS += -DBAR
foo bar :
#echo target=$# CXXFLAGS=${CXXFLAGS}
.PHONY : all

Do you mean something like this:
$ cat Makefile
BUILD := debug
cxxflags.debug := -g -march=native
cxxflags.release := -g -O3 -march=native -DNDEBUG
CXXFLAGS := ${cxxflags.${BUILD}}
all :
#echo BUILD=${BUILD}
#echo CXXFLAGS=${CXXFLAGS}
.PHONY : all
Output:
$ make
BUILD=debug
CXXFLAGS=-g -march=native
$ make BUILD=release
BUILD=release
CXXFLAGS=-g -O3 -march=native -DNDEBUG

What about that?
ifeq ($(MAKECMDGOALS),release)
CFLAGS += -O3
else
CFLAGS += -O0 -ggdb
endif

Related

Problem when passing argument to Makefile

My Makefile looks like this:
OBJ = $(SRC:.c=.c.o) #yes it it should be renamed to .c.o, not .o
LIBS = -lchecl -lchecs -lchengine-dev -lglfw -lm -lGL -lGLEW -lcheio -lopenal -lfreetype
EXE = test
VER = -std=c99
MODE = -g
OPT = -O0
ERR = -Wall -Wuninitialized -Werror=implicit-function-declaration -Wextra -Wno-unused-parameter -Wno-incompatible-pointer-types -Werror=int-conversion -Wduplicated-cond -Wlogical-op -Wrestrict -Wnull-dereference -Wjump-misses-init -Wdouble-promotion -Wshadow -Wformat=2
LFLAGS = -o
CFLAGS = $(ERR) $(VER) $(OPT) -c $(MODE) `pkg-config --cflags freetype2`
run: $(EXE)
./$(EXE)
$(EXE): $(OBJ)
gcc $(LFLAGS) $(EXE) $(OBJ) $(LIBS)
%.o: %.c
gcc -c $(CFLAGS) $*.c
mv "$$(basename $*.o)" "$$(dirname $*)"
cleanall:
rm $(OBJ)
rm $(SRC)
And I am passing the SRC variable like this:
files=$(find . -type f -name '*.c.c')
make run SRC="$files"
But this gives the the following error:
make: *** No rule to make target 'src/setup.c
./states/mainMenuState.c
...
(a list of all source files)'
However if I manually copy the value of $files into the Makefile, writing SRC = and then the source files, it compiles just fine. If I write instead of OBJ = $(SRC:.c.c=.c.o) OBJ = $($(SRC):.c.c=.c.o) it seems to compile but not link correctly, because then I get this error:
//usr/local/lib/libchengine-dev.so: undefined reference to `vector_find'
//usr/local/lib/libchengine-dev.so: undefined reference to `che_init'
//usr/local/lib/libchengine-dev.so: undefined reference to `vector_destruct'
SRC is used in the definition of OBJ. But this can't be your real makefile, because it won't work. So something must be different about your real makefile versus what you've shown us, and that difference is critical to the problem you're having. As Renaud says, please provide a MCVE.
I created a simple makefile:
OBJS := $(SRC:.c=.c.o)
all: $(OBJS)
%.c.o : %.c
: $< $#
then ran it:
files=$(find -name \*.c)
make SRC="$files"
and it worked just fine:
: foo.c foo.c.o
: bar.c bar.c.o
: biz.c biz.c.o
: baz.c baz.c.o
You can work around the problem in GNU make 4.1 by not including newlines in the $files variable. For example you can change how you set it to this:
files=$(find . -type f -name '*.c.c' -printf '%p ')
so it uses space separators instead of newlines.

Makefile : include in loop / loop outside targets

In my makefile I want to include some other makefile depending on a variable in a for loop, Is it possible.
Top Makefile :
CC = gcc
CFLAGS = -O0 -g3 -W -Wall -pedantic
LDFLAGS =
DEFINES =
PROJECT = proj
INCLUDES =
SOURCES =
TEMP_PATH := $(PROJECT)
include $(TEMP_PATH)/Makefile
$(for blocks in $(BLOCKS); do \
include $$(blocks)/Makefile; \
done)
all : $(PROJECT).exe
$(PROJECT).exe :
$(CC) $(CFLAGS) $(LDFLAGS) $(DEFINES) $(INCLUDES) $(SOURCES) -o $#
clean :
rm -rf *.exe
proj/Makefile :
CC = gcc
CFLAGS = -O0 -g3 -W -Wall -pedantic
LDFLAGS =
DEFINES =
BLOCKS := std_communication
INCLUDES := $(INCLUDES) -I $(TEMP_PATH)/Utils
INCLUDES := $(INCLUDES) -I $(TEMP_PATH)/Communication
SOURCES := $(SOURCES) $(wildcard $(TEMP_PATH)/Utils/*.c)
SOURCES := $(SOURCES) $(wildcard $(TEMP_PATH)/Communication/*.c)
SOURCES := $(SOURCES) $(wildcard $(TEMP_PATH)/main.c)
The for loop syntax seems to be wrong outside of loop.
You cannot write it like that, but you can just write:
include $(addsuffix /Makefile,$(BLOCKS))

make error : *** missing separator. Stop

This is my makefile:
OBJECTS = main.o
CFLAGS = -g -wall
NAME = make
CC = gcc
build: $(OBJECTS)
$(CC) $(CFLAGS) $(OBJECTS) -o $(NAME)
I'm getting below error when I tried to make(Applied tab before gcc command) :
makefile:6: *** missing separator. Stop.
How can I fix this?
First of all, it looks like you have spaces instead of tab.
As for the Makefile itself, I'd make it little bit simpler. For a source file main.c:
int main() {
return 0;
}
I would go with Makefile:
CFLAGS = -g -wall
CC = gcc
main: main.c
$(CC) $(CFLAGS) $< -o $#

Makefile: $(CC) isn't working with ifeq

So, this is odd. In my makefile I have
CC:=icc
ifeq ($(CC),icc)
CFLAGS := $(ICCFLAGS)
LIBS := $(LIBS) -openmp
else
CFLAGS := $(GCCFLAGS)
LIBS := $(LIBS) -fopenmp
endif
for make, the condition is false but
CCC:=icc
ifeq ($(CCC),icc)
CFLAGS := $(ICCFLAGS)
LIBS := $(LIBS) -openmp
else
CFLAGS := $(GCCFLAGS)
LIBS := $(LIBS) -fopenmp
endif
here the condition is true, and
CC:=icc
CCC:=$(CC)
ifeq ($(CCC),icc)
CFLAGS := $(ICCFLAGS)
LIBS := $(LIBS) -openmp
else
CFLAGS := $(GCCFLAGS)
LIBS := $(LIBS) -fopenmp
endif
here the condition is false again. What the hell is going on?
It seem that you're either passing CC as a command line option, like:
make CC=...
... or invoking make with -e switch, which forces environment variables to take precedence over the ones defined in Makefile.
You can use origin function to check how the variable has been defined:
CC := icc
$(error CC comes from $(origin CC))
If this prints command line or environment override, then the solution is to use override directive:
override CC := icc
This will set CC variable even if there is another one from command line or environment.

Can't assign variable inside recipe

How do I make this work? It errors out with "make: somevariable: Command not found"
sometarget:
somevariable = somevalue
Full example:
CXXFLAGS = -I/usr/include/test -shared -fPIC
OBJ = main.o Server.o
blabla : $(OBJ)
ifeq ($(argsexec),true)
# Creates an executable
CXXFLAGS = -I/usr/include/test
$(CXX) -o blabla $(OBJ) $(CXXFLAGS)
else
# Creates a library
DESTDIR = /home/pc
$(CXX) -o blabla $(OBJ) $(CXXFLAGS)
./bn.sh
endif
I found a solution using the eval function:
$(eval variablename=whatever)
This works :)
(although I may now try to find an easier build system ;))
Thanks everyone for reading and also of course #eriktous for writing!
If you write it like you did, the assignment will be executed as a shell command, which gives the error you got.
I would try organising it something like this:
CXXFLAGS = -I/usr/include/test
ifneq ($(argsexec),true)
CXXFLAGS += -shared -fPIC
DESTDIR = /home/pc
endif
OBJ = main.o Server.o
blabla : $(OBJ)
$(CXX) -o blabla $(OBJ) $(CXXFLAGS)
ifneq ($(argsexec),true)
./bn.sh
endif
This should do what you want, although I'm not quite happy with using the ifneq construct twice. I'd have to think harder to come up with something that avoids that.

Resources