how to call a makefile target it it contain variable name? - bash

If let's say target of makefile (i.e. $(SESSION)/compiled.csh) contains a variable name .. how can we call a makefile to run with that target ??
--------------calling makefile -------------------------
make \
-f makefile \
session_name=rtl_unit \
---------------- makefile content ----------------------
ifeq ($(MAKECMDGOALS), all)
DEFAULT_DEP := dep1 dep2
else
DEFAULT_DEP := dep1
endif*
export SESSION = $(TESTBENCH_PATH)/blocks/$(session_name)
$(SESSION)/compiled.csh : something

Just add another phony target and make it depend on your hard-to-spell target:
$(SESSION)/compiled.csh : something
compiled : $(SESSION)/compiled.csh
.PHONY: compiled
And then:
make compiled

Related

set numbers of variables for recursive make using another makefile

I am new to makefile and I am recursively calling make to build my libraries. I need to setup "n" number of variables to build libraries. I tried adding in a file and include it in the makefile but it doesnot seems to be working.
where am I going wrong? what is the better approach to achieve this.
My main makefile :
include main_setup.mk
VER := $(shell getVersion)
main_setup:
//setupsteps
release:
$(MAKE) main_setup
$(MAKE) -j8 --output_sync=target build_main
build_main:import_a import_b import_c
import_a: build_a
//import_steps
import_b: build_b
//import_steps
import_c: build_c
//import_steps
build_a:
cd $aDir ; $(MAKE) -j4 build
import_a:
cd $bDir ; $(MAKE) -j4 build
import_a:
cd $cDir ; $(MAKE) -j4 build
my setup file: main_setup.mk
plat_prefix = /main
buildroot = $(plat_prefix)/submain/another
ifneq ('$(JAVA_PATH)','')
export PATH := $(JAVA_PATH):$(PATH)
endif
export BUILD_ROOT = $(buildroot)
ifneq ('$(LOCAL_BUILD_ROOT)','')
export BUILD_ROOT= $(LOCAL_BUILD_ROOT)
endif
export VAR1 = 1
export VAR2 = 2
export VAR3 = 3
export VAR4 = 4
export PATH := /var/main/bin:$(VAR1)/tools/bin:$(VAR2)/tools/bin:$(VAR3)/tools/bin:$(PATH)
Error :
/bin/bash: getVersion: command not found
which getVersion
/var/main/bin/getVersion
UPDATED THE QUESTION

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.

Make: Setting target-specific variables in static pattern rules

I'm writing a Makefile using static pattern rules and I want for each element of TARGETS a variable assigned to the current target name (here the stem '%').
TARGETS = a b c d
all : $(TARGETS)
$(TARGETS) : % : DIR = %
$(TARGETS) : % : %_setup build
a_setup :
code for a
b_setup :
code for b
...
build
code using "DIR = XX" previously configured
but gnumake complains about the target-specific variable DIR:
make: *** No rule to make target 'DIR', needed by 'a'
Is it possible to mix static pattern rules and variable assignation? Thanks!
According to the GNU make manual you can't do it like that. However, you can use $#. In you example you can directly assign DIR=$# but more generally you can use $# in combination with patsubst:
TARGETS = a b c d
all : $(TARGETS)
$(TARGETS) : DIR = $(patsubst %,%,$#)
$(TARGETS) : % : %_setup build
echo $#: DIR:$(DIR)
%_setup :
echo $#
build:
echo $#

Dynamically generating a list of targets

If a file exists, I want to add a target to build. If the file does not exist, I want the target to be skipped.
an example:
FILENAME = f
TARGETS := normal
ifneq($(shell stat test_$(FILENAME).c), "")
TARGETS += test
endif
all: $(TARGETS)
normal:
#echo normal
test:
#echo test
I'm not sure the $(shell stat ...) part even works, but the bigger problem is that make with any file test_f.c in the current folder gives:
Makefile:4: *** multiple target patterns. Stop.
Removing the ifneq ... endif block makes the target normal. How can I only run the target test if test_f.c exists?
What you can do is generate a string variable (let's call it OPTIONAL) such that when 'test_f.c' exists, OPTIONAL=test; otherwise, OPTIONAL=_nothing_. And then add OPTIONAL as a prerequisite of all. e.g.:
FILENAME = f
TARGETS = normal
OPTIONAL = $(if $(wildcard test_f.c), test, )
all: $(TARGETS) $(OPTIONAL)
normal:
#echo normal
test:
#echo test
You can also iterate over targets with for loop
.PHONY: all
RECIPES = one
all: RECIPES += $(if $(wildcard test_f.c), two, )
all:
for RECIPE in ${RECIPES} ; do \
$(MAKE) $${RECIPE} ; \
done
one:
$(warning "One")
two:
$(warning "Two")
> make
for RECIPE in one ; do \
/Applications/Xcode.app/Contents/Developer/usr/bin/make ${RECIPE} ; \
done
makefile:11: "One"
make[1]: `one' is up to date.
> touch test_f.c
> make
for RECIPE in one two ; do \
/Applications/Xcode.app/Contents/Developer/usr/bin/make ${RECIPE} ; \
done
makefile:11: "One"
make[1]: `one' is up to date.
makefile:14: "Two"
make[1]: `two' is up to date.

Makefile set variable in target

I have a makefile where a variable $DEBUG decides whether to build for deployment or debugging. There is one main Makefile, and multiple platform-specific makefiles that get included. I want the variable $DEBUG to be set to 1 automatically when the target test is built.
The main makefile:
DEBUG := 0
test : override DEBUG := 1
DIST_DIR := dist/
ifeq ($(DEBUG), 1)
BUILD_DIR := build/debug
else
BUILD_DIR := build/deploy
endif
# detect operating system
ifeq ($(OS), Windows_NT)
UNAME := Windows
else
UNAME := $(shell uname -s)
endif
# include platform-specific Makefile
export
ifeq ($(UNAME), Darwin)
include Makefile.darwin
endif
ifeq ($(UNAME), Linux)
include Makefile.linux
endif
And the platform-specific Makefile.linux:
...
CXX := clang++-3.8
CXXFLAGS := -std=c++14 -fPIC -I./external/include -fcolor-diagnostics
LDFLAGS :=
LDLIBS := -lpthread -lm
ifeq ($(DEBUG), 1)
CXXFLAGS += -g
else
CXXFLAGS += -O3 -DNDEBUG
endif
...
all : $(TARGET)
test : $(TEST_TARGET)
$(TEST_TARGET)
So there are two rules for test: One in the main makefile sets the target-specific variable $DEBUG, and the one in Makefile.linux builds the test. The variables used for building ($CXXFLAGS, $BUILDDIR, and others) are set before the rules, and use conditionals.
Everything in the makefiles is working correctly, however calling make test does not alter the variable $DEBUG: both $CXXFLAGS and $BUILDDIR still get set to the values they would have for a deployment built.
Is there a way to first set $DEBUG := 1 in Makefile when the target is test, and then normally proceed?
Or is there a special variable that contains the target name, for example
ifeq ($(MAKEFILE_TARGET), test)
...
endif
test : override DEBUG := 1 doesn't work because it declares a target-specific variable that is only visible within that recipe.
There does exist a variable containing the target names that were specified at the command line: MAKECMDGOALS. Note that it doesn't include the default target if it wasn't explicitly specified at the command line.
Example makefile:
DEBUG := $(filter test,$(MAKECMDGOALS))
all:
#echo all : $(MAKECMDGOALS) : $(DEBUG) : $(if $(DEBUG),1,0)
test:
#echo test : $(MAKECMDGOALS) : $(DEBUG) : $(if $(DEBUG),1,0)
Usage:
$ make
all : : : 0
$ make all
all : all : : 0
$ make test
test : test : test : 1
$ make all test
all : all test : test : 1
test : all test : test : 1
One simple option is to have your test target recursively invoke make with DEBUG=1. That works with included makefiles as well. Example:
DEBUG := 0
test:
make DEBUG=1
DIST_DIR := dist/
...

Resources