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

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.

Related

Variables in non-recursive Makefiles

I'm using GNU Make and attempting to design Makefiles using non-recursive approach. The issue I have - there doesn't seem to be a way to limit the scope of variables in different Makefiles.
For example, if I have two Makefiles for modules libA and libB
libA Makefile.inc:
src_dir := libA/src
inc_dir := libA/inc
libB Makefile.inc:
src_dir := libB/src
inc_dir := libB/inc
Then when I include the above Makefiles into a master Makefile
include libA/Makefile.inc
include libB/Makefile.inc
Values in variables src_dir and inc_dir are overwritten by the very last Makefile that was included. OK this is probably expected since variables are global in scope here, and this messes up build commands that use those variables, i.e. build command for libA finds variable values for libB.
A way around it is to create unique variables for each Makefile
libA Makefile.inc:
src_dir_libA := libA/src
inc_dir_libA := libA/inc
libB Makefile.inc:
src_dir_libB := libB/src
inc_dir_libB := libB/inc
This solves the issue, but it's a bit awkward to use, since each variable has to be renamed. Does anyone know if there is a better way to solve this, e.g. if GNU Make has some notion of scope or namespace? I've looked at documentation, but can't seem to find anything of that sort. There are target-specific variables, but they appear to have nasty side-effects.
OK, just to be very specific, below is an example Makefile
dep_all :=
all:
# Begin Makefile.inc for project1
# ------------------------------------------------------------------------------
$(foreach var,$(filter local_%,$(.VARIABLES)),$(eval $(var) := ))
local_src_dir := project1/src
local_obj_dir := project1/obj
local_src := $(local_src_dir)/fileA.c $(local_src_dir)/fileB.c
local_obj := $(patsubst $(local_src_dir)/%.c,$(local_obj_dir)/%.o,$(local_src))
dep_all += $(local_src)
dep_all += $(local_obj)
$(info local_obj="$(local_obj)")
$(local_obj): $(local_obj_dir)/%.o: $(local_src_dir)/%.c
gcc -L$(local_obj_dir) -c -o $# $<
# ------------------------------------------------------------------------------
# End Makefile.inc for project1
# Begin Makefile.inc for project2
# ------------------------------------------------------------------------------
$(foreach var,$(filter local_%,$(.VARIABLES)),$(eval $(var) := ))
local_src_dir := project2/src
local_obj_dir := project2/obj
local_src := $(local_src_dir)/fileX.c $(local_src_dir)/fileY.c
local_obj := $(patsubst $(local_src_dir)/%.c,$(local_obj_dir)/%.o,$(local_src))
dep_all += $(local_src)
dep_all += $(local_obj)
$(info local_obj="$(local_obj)")
$(local_obj): $(local_obj_dir)/%.o: $(local_src_dir)/%.c
gcc -L$(local_obj_dir) -c -o $# $<
# ------------------------------------------------------------------------------
# End Makefile.inc for project2
$(info dep_all="$(dep_all)")
.PHONY: all
all: $(dep_all)
.PHONY: clean
clean:
rm -f project1/obj/* project2/obj/*
If I run it then the -L<object_path> option passed to gcc contains value from the last included Makefile, i.e. when building project1, it runs gcc with -Lproject2/obj, which is not the right object path for this project. This is the problem I'm trying to solve.
mkdir -p project1/{src,obj} project2/{src,obj}
touch project1/src/{fileA.c,fileB.c} project2/src/{fileX.c,fileY.c}
$ make
local_obj="project1/obj/fileA.o project1/obj/fileB.o"
local_obj="project2/obj/fileX.o project2/obj/fileY.o"
dep_all=" project1/src/fileA.c project1/src/fileB.c project1/obj/fileA.o project1/obj/fileB.o project2/src/fileX.c project2/src/fileY.c project2/obj/fileX.o project2/obj/fileY.o"
gcc -Lproject2/obj -c -o project1/obj/fileA.o project1/src/fileA.c
gcc -Lproject2/obj -c -o project1/obj/fileB.o project1/src/fileB.c
gcc -Lproject2/obj -c -o project2/obj/fileX.o project2/src/fileX.c
gcc -Lproject2/obj -c -o project2/obj/fileY.o project2/src/fileY.c
The solution is to name all your variables local to a specific file with some prefix.
For example, I use this_ prefix.
Then, in the beginning of each submakefile those variales which have this_ prefix can be cleared as follows:
$(foreach var,$(filter this_%,$(.VARIABLES)),$(eval $(var) := ))
PS. I use this approach in my implementation of non-recursive makefiles, clearing the variables described in the WIKI here: https://github.com/cppfw/prorab
I think I've just figured out a solution. I was reading "The GNU Make Book" and it states a side effect of target specific variables
Target-specific variables apply not just to a target, but also to all
that target’s prerequisites, as well as all their prerequisites, and
so on. A target-specific variable’s scope is the entire tree of
targets, starting from the target for which the variable was defined.
This is not the behaviour I want, however starting with GNU Make 3.82 there is support for private target specific variables
A target-specific variable is normally defined for a target and all
its prerequisites. But if the target-specific variable is prefixed
with the keyword private, it is defined only for that target, not its
prerequisites.
So the following Makefile seems to work correctly for those private variables
dep_all :=
all:
# Begin Makefile.inc for project1
# ------------------------------------------------------------------------------
inc_dir := project1/inc
src_dir := project1/src
obj_dir := project1/obj
src := $(src_dir)/fileA.c $(src_dir)/fileB.c
obj := $(patsubst $(src_dir)/%.c,$(obj_dir)/%.o,$(src))
# These flags will be overwritten by another Makefile
CFLAGS := -I$(inc_dir)
# These flags will be private and not be overwritten by another Makefile
CFLAGS_priv := -I$(inc_dir) -L$(obj_dir)
dep_all += $(src)
dep_all += $(obj)
# Private target specific variables
$(obj): private CFLAGS_priv:=$(CFLAGS_priv)
$(obj): $(obj_dir)/%.o: $(src_dir)/%.c
gcc $(CFLAGS) $(CFLAGS_priv) -c -o $# $<
# ------------------------------------------------------------------------------
# End Makefile.inc for project1
# Begin Makefile.inc for project2
# ------------------------------------------------------------------------------
inc_dir := project2/inc
src_dir := project2/src
obj_dir := project2/obj
src := $(src_dir)/fileX.c $(src_dir)/fileY.c
obj := $(patsubst $(src_dir)/%.c,$(obj_dir)/%.o,$(src))
# These flags will be overwritten by another Makefile
CFLAGS := -I$(inc_dir)
# These flags will be private and not be overwritten by another Makefile
CFLAGS_priv := -I$(inc_dir) -L$(obj_dir)
dep_all += $(src)
dep_all += $(obj)
# Private target specific variables
$(obj): private CFLAGS_priv:=$(CFLAGS_priv)
$(obj): $(obj_dir)/%.o: $(src_dir)/%.c
gcc $(CFLAGS) $(CFLAGS_priv) -c -o $# $<
# ------------------------------------------------------------------------------
# End Makefile.inc for project2
.PHONY: all
all: $(dep_all)
.PHONY: clean
clean:
rm -f project1/obj/* project2/obj/*
The output is what I wanted, since now for each project I can define private CFLAGS_priv variable that sets -I<dir>, -L<dir> paths and it won't be overwritten by other Makefiles.
$ make
gcc -Iproject2/inc -Iproject1/inc -Lproject1/obj -c -o project1/obj/fileA.o project1/src/fileA.c
gcc -Iproject2/inc -Iproject1/inc -Lproject1/obj -c -o project1/obj/fileB.o project1/src/fileB.c
gcc -Iproject2/inc -Iproject2/inc -Lproject2/obj -c -o project2/obj/fileX.o project2/src/fileX.c
gcc -Iproject2/inc -Iproject2/inc -Lproject2/obj -c -o project2/obj/fileY.o project2/src/fileY.c
I'm hoping this will resolve all issues I had and I don't have to use recursive make with it's various associated pitfalls.

GNU Make correct behaviour when including other makefiles

I have the following makefile in the root of the project:
Makefile
# Board version
# Available: 3
PI ?= 3
# Kernel binaries
ifeq ($(PI), 3)
KERNEL_IMG := kernel8.img
else ifeq ($(PI), 2)
KERNEL_IMG := kernel7.img
else ifeq ($(PI), 1)
KERNEL_IMG := kernel.img
else
$(error Unsupported Raspberry Pi version)
endif
KERNEL_ELF := $(patsubst %.img,%.elf,$(KERNEL_IMG))
# Directories/paths
BUILD_DIR := build
# Toolchain
TOOLCHAIN ?= aarch64-elf
OBJCOPY := $(TOOLCHAIN)-objcopy
LD := $(TOOLCHAIN)-ld
CC := $(TOOLCHAIN)-gcc
# Misc
LINKER_SCRIPT := linker.ld
# Flags
LDFLAGS := -T $(LINKER_SCRIPT)
ASFLAGS :=
CFLAGS :=
# Source files
C_SRC := $(wildcard *.c)
ASM_SRC := $(wildcard *.S)
# Include
include pi/$(PI)/mod.mk
# Object files
OBJECTS := $(patsubst %,$(BUILD_DIR)/%.o,$(C_SRC))
OBJECTS += $(patsubst %,$(BUILD_DIR)/%.o,$(ASM_SRC))
# Targets
.PHONY: all builddirs clean
all: $(BUILD_DIR)/$(KERNEL_IMG)
$(BUILD_DIR)/$(KERNEL_IMG): $(BUILD_DIR)/$(KERNEL_ELF)
$(OBJCOPY) $< -O binary $#
$(BUILD_DIR)/$(KERNEL_ELF): $(LINKER_SCRIPT) $(OBJECTS)
$(LD) $(OBJECTS) $(LDFLAGS) -o $#
$(OBJECTS): | builddirs
builddirs: $(BUILD_DIR)/pi/$(PI)
$(BUILD_DIR)/pi/$(PI):
mkdir -p $#
$(BUILD_DIR)/%.S.o: %.S
$(CC) -c $< $(ASFLAGS) -o $#
$(BUILD_DIR)/%.c.o: %.c
$(CC) -c $< $(CFLAGS) -o $#
clean:
$(RM) -r $(BUILD_DIR)
It includes pi/3/mod.mk
C_SRC +=
ASM_SRC += pi/3/start.S
$(BUILD_DIR)/pi/3/start.S.o: pi/3/start.S pi/3/include/cpu/sysregs.h
$(CC) -c $< $(ASFLAGS) -o $#
Now here's the problem: whenever I run 'make' in the root of a project, '$(BUILD_DIR)/pi/3/start.S.o' rule invokes, instead of 'all'. If I move 'include pi/$(PI)/mod.mk' to the very bottom of the root makefile, and replace 'C_SRC' and 'ASM_SRC' variables in 'pi/3/mod.mk' with 'OBJECTS += $(BUILD_DIR)/pi/3/start.S.o' and invoke 'make', this rule isn't even invoked, so I get an error that make doesn't know how to build start.S.o.
What am I doing wrong and what is the best way to handle this?
Make's default goal is the first target in your Makefile. In your case the first target is the one defined in the included Makefile: $(BUILD_DIR)/pi/3/start.S.o. Either invoke make all or move the all rule in your Makefile such that it becomes the first one, or tell make that the default goal is all:
.DEFAULT_GOAL := all
(see GNU make manual).

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 hubbub library for x32 and x64 platforms

I need to make static hubbub library files for x32 and x64 platforms. Options like -m32/64 don't work, maybe I need to specify TARGET properly, but I don't know what to write here. What should I do?
Here is the makefile of the lib:
# Component settings
COMPONENT := hubbub
COMPONENT_VERSION := 0.2.0
# Default to a static library
COMPONENT_TYPE ?= lib-static
# Setup the tooling
PREFIX ?= /opt/netsurf
NSSHARED ?= $(PREFIX)/share/netsurf-buildsystem
include $(NSSHARED)/makefiles/Makefile.tools
TESTRUNNER := $(PERL) $(NSTESTTOOLS)/testrunner.pl
# Toolchain flags
WARNFLAGS := -Wall -W -Wundef -Wpointer-arith -Wcast-align \
-Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes \
-Wmissing-declarations -Wnested-externs -pedantic
# BeOS/Haiku/AmigaOS have standard library errors that issue warnings.
ifneq ($(TARGET),beos)
ifneq ($(TARGET),amiga)
WARNFLAGS := $(WARNFLAGS) -Werror
endif
endif
CFLAGS := -D_BSD_SOURCE -I$(CURDIR)/include/ \
-I$(CURDIR)/src $(WARNFLAGS) $(CFLAGS)
ifneq ($(GCCVER),2)
CFLAGS := $(CFLAGS) -std=c99
else
# __inline__ is a GCCism
CFLAGS := $(CFLAGS) -Dinline="__inline__"
endif
# Parserutils
ifneq ($(findstring clean,$(MAKECMDGOALS)),clean)
ifneq ($(PKGCONFIG),)
CFLAGS := $(CFLAGS) $(shell $(PKGCONFIG) libparserutils --cflags)
LDFLAGS :=$(LDFLAGS) $(shell $(PKGCONFIG) libparserutils --libs)
else
CFLAGS := $(CFLAGS) -I$(PREFIX)/include
LDFLAGS := $(LDFLAGS) -lparserutils
endif
endif
include $(NSBUILD)/Makefile.top
ifeq ($(WANT_TEST),yes)
# We require the presence of libjson -- http://oss.metaparadigm.com/json-c/
ifneq ($(PKGCONFIG),)
TESTCFLAGS := $(TESTCFLAGS) \
$(shell $(PKGCONFIG) $(PKGCONFIGFLAGS) --cflags json)
TESTLDFLAGS := $(TESTLDFLAGS) \
$(shell $(PKGCONFIG) $(PKGCONFIGFLAGS) --libs json)
else
TESTCFLAGS := $(TESTCFLAGS) -I$(PREFIX)/include/json
TESTLDFLAGS := $(TESTLDFLAGS) -ljson
endif
ifneq ($(GCCVER),2)
TESTCFLAGS := $(TESTCFLAGS) -Wno-unused-parameter
endif
endif
# Extra installation rules
I := /include/hubbub
INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):include/hubbub/errors.h
INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):include/hubbub/functypes.h
INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):include/hubbub/hubbub.h
INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):include/hubbub/parser.h
INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):include/hubbub/tree.h
INSTALL_ITEMS := $(INSTALL_ITEMS) $(I):include/hubbub/types.h
INSTALL_ITEMS := $(INSTALL_ITEMS) /lib/pkgconfig:lib$(COMPONENT).pc.in
INSTALL_ITEMS := $(INSTALL_ITEMS) /lib:$(OUTPUT)
You also can download it:
git clone git://git.netsurf-browser.org/libhubbub.git
Just use this:
$ make TARGET=amd64
or
$ make TARGET=i386

Define compilation variables based on target for

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

Resources