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.
Related
We are supporting 32 bit and 64 bit build in our workflow.For that We have multiple rules in makefiles which are separate for 32-bit and 64-bit. Let me show pair of rules which are same except for the string “32” vs “64” .
Makefile Snippet:-
$(TGTDIR32)/logdir/set_user.c: $(CURDIR)/slv/set_user.c
$(file_transfer)
$(TGTDIR64)/logdir/set_user.c: $(CURDIR)/slv/set_user.c
$(file_transfer)
If you notice, We have targets with same except for the string “32” vs “64”, i want to replace them by single rule/definition. Because we have hundreds of rules like above in our infrastructure code.
Do we have any simplified way in GNUmake to do that?
Thanks in Advance!
Targets which have the same prerequisites and recipe can simply be combined, like so:
$(TGTDIR32)/logdir/set_user.c $(TGTDIR64)/logdir/set_user.c: $(CURDIR)/slv/set_user.c
$(file_transfer)
or more generally:
THESE_TARGETS := $(TGTDIR32)/logdir/set_user.c $(TGTDIR64)/logdir/set_user.c # More...?
...
$(THESE_TARGETS): $(CURDIR)/slv/set_user.c
$(file_transfer)
If Make decides that any member of $(THESE_TARGETS) is out-of-date with respect to the prerequisites, then it will run the recipe for that target.
This makefile:
.PHONY: all clean
all: a b c
a: d e
touch $#
b: d e
touch $#
c: d e
touch $#
d:
touch $#
e:
touch $#
clean:
$(RM) a b c d e
is equivalent to this one:
.PHONY: all clean
all: a b c
a b c: d e
touch $#
d e:
touch $#
clean:
$(RM) a b c d e
Later
There are some static pattern rules...
The same applies. This makefile with static pattern rules:
.PHONY: default clean
default: a.k b.k
a.k: %.k: %.j
cp -f $< $#
b.k: %.k: %.j
cp -f $< $#
a.j:
touch $#
b.j:
touch $#
clean:
$(RM) a.k b.k a.j b.j
is equivalent to this one:
.PHONY: default clean
JS := a.j b.j
KS := $(JS:.j=.k)
default: $(KS)
$(KS): %.k: %.j
cp -f $< $#
$(JS):
touch $#
clean:
$(RM) $(JS) $(KS)
In my opinion this is an appropriate place to use recursive make, at least for the top-level build.
In this situation you could do something like this:
TGTDIR64 = ...
TGTDIR32 = ...
.PHONY: all all32 all64 build
all: all32 all64
all32:
$(MAKE) TGTDIR=$(TGTDIR32) build
all64:
$(MAKE) TGTDIR=$(TGTDIR64) build
# Things below here should just use TGTDIR
build: $(TGTDIR)/b1 $(TGTDIR)/b2
$(TGTDIR)/logdir/set_user.c: $(CURDIR)/slv/set_user.c
$(file_transfer)
$(HEADERGEN_NOTSPLIT_H_COPY): $(TGTDIR)/%.h: %.h $(copy_file)
...
The two rules are semantically identical, they only use a different way to refer to a "parameterized" target. Why you don't just use one target for this
$(TGTDIR)/logdir/set_user.c: $(CURDIR)/slv/set_user.c
$(file_transfer)
and use a properly configured TGTDIR (I suspect this would be something like "xxxx_32" vs "xxxx_64")?
You could achieve this in several ways; one typical would be
ifdef choose32
TGTDIR=xxxx_32
else
TGTDIR=xxxx_64
endif
I am grouping some type of files like:
https://www.gnu.org/software/make/manual/html_node/Wildcard-Function.html
about 100 sub directories...
CC_FILES_TO_BUILD += $(wildcard $(SRC_DIR)/01-Application/*.c)
ASM_FILES_TO_BUILD += $(wildcard $(PROJECT_ROOT)/01-Sources/07-Target/01-MC9S12G/04-STARTUP/01-CPL_LIB/*.s)
When I dump for example CC_FILES_TO_BUILD per rule, I get nice lists of files names:
E:\1983_1\02-Safety>make dump-CC_FILES_TO_BUILD
make[1]: Entering directory `E:/1983_1/02-Safety/01-Application'
E:\1983_1\02-Safety\01-Application/01-Sources//01-Application/01-INIT/app_init.c E:\1983_1\02-Safety\01-Application/01-Sources//01-Applicat
ion/02-MAIN/app.c E:\1983_1\02-Safety\01-Application/01-Sources//01-Application/03-FM/fm.c E:\1983_1\02-Safety\01-Application/01-Sources//01
-Application/05-SMCM/SMCM.c E:\1983_1\02-Safety\01-Application/01-Sources//01-Application/06-LIM/LIM.c E:\1983_1\02-Safety\01-Application/0
1-Sources//02-Services/01-CanM/can_user.c E:\1983_1\02-Safety\01-Application/01-Sources//02-Services/01-CanM/v_par.c E:\1983_1\02-Safety\01-
Application/01-Sources//02-Services/01-CanM/vstdlib.c E:\1983_1\02-Safety\01-Application/01-Sources//02-Services/01-CanM/sip_vers.c ...
......make[1]: Leaving directory `E:/1983_1/02-Safety/01-Application'
I then build new lists out these by normal subst to get the corresponding lists of depend and obj files, like:
CC_TO_MAK_BUILD_LIST = $(call unique, $(foreach src,$(CC_FILES_TO_BUILD ),
$(DEP_PATH)\$(basename $(notdir$(subst,\,/,$(SRC)))).$(MAK_FILE_SUFFIX)))
I then want to use these depend and obj lists as targets in rules like:
$(filter-out $(GCC_IGNORE_LIST), $(CC_TO_MAK_BUILD_LIST)) :$(DEP_OUTPUT_PATH)\\%.$(MAK_FILE_SUFFIX):$(DEPEND_FORCE) | $(DEPEND_CPP_OPTIONS_FILE) $(DIRECTORIES_TO_CREATE)
$(SEPARATOR) [depend] $(notdir $#)
$(CPP) #$(DEPEND_CPP_OPTIONS_FILE) -undef -MM -MF "$#" -MT "$(call depend_get_target,$#)" -MT "$#" "$(getSourceFile)"
Then the target depend:
depend: $(LIB_TO_MAK_BUILD_LIST) $(CC_TO_MAK_BUILD_LIST) | $(DEPEND_CPP_OPTIONS_FILE) $(DIRECTORIES_TO_CREATE)
and the output:
E:\1983_1\02-Safety\01-Application>make depend
* [build] depend.cpp_options
E:\1983_1\02-Safety\01-Application>
apparently nothing to be done although the dependcies files(*.mak) are not there. No force or phony could solve it for me.
I'm writing a makefile that requires some enviroment variables to be defined. I am trying to use something like this to acheive this:
define check-var-defined
ifndef $(1)
$(error $(1) is not defined)
endif
endef
$(call check-var-defined,VAR1)
$(call check-var-defined,VAR2)
$(call check-var-defined,VAR3)
rule1:
#stuff
When I run make with no args I get this:
$ make
Makefile:7: *** VAR1 is not defined. Stop.
But when I run it with VAR1 specified I get the same error.
$ make VAR1=hello
Makefile:7: *** VAR1 is not defined. Stop.
Any ideas why this doesn't work? What can I do to make this work? Thanks in advance.
(Note that I need to check that the variables are actually defined when the makefile is run, as I need to include another makefle further down and the variables need to be set correctly by the time I do this).
The $(call ...) function does not evaluate the results of the function as if it were makefile code, so you can't things like ifdef there.
What happens is that the contents of check-var-defined are expanded and since it doesn't recognize the ifdef operation, it just proceeds to expand the $(error ...) function every time.
If you want to use ifdef you have to use $(eval ...) with $(call ...) which will evaluate the result as if it were a makefile.
Simpler is to use the $(if ...) function, like this:
check-var-defined = $(if $(1),,$(error $(1) is not defined))
Note that this will fail if the variable is empty, which is not quite the same thing as being undefined; it could have been defined to be empty (as VAR1=). But that's the way ifdef works, too, confusingly.
the macro in 1st answer is great but doesn't actually report the name of the 'empty' variable. here is a slight improvement with example/test:
# -*- mode: makefile -*-
check-var-defined = $(if $(strip $($1)),,$(error "$1" is not defined))
my_def1:=hello
my_def3:=bye
$(call check-var-defined,my_def1)
$(call check-var-defined,my_def2)
$(call check-var-defined,my_def3)
and the result:
Makefile:10: * "my_def2" is not defined. Stop.
defined = $(strip $(filter-out undefined,$(flavor $1)))
ensure-defined = \
$(eval .ensure-defined :=) \
$(foreach V,$(sort $1), \
$(if $(call defined,$V),,$(eval .ensure-defined += $V)) \
) \
$(if $(strip ${.ensure-defined}), \
$(foreach V,${.ensure-defined}, \
$(info NOT DEFINED: $$$V) \
) \
$(error Required variables not defined) \
)
ifFOO = $(if $(call defined,FOO), \
$(info FOO is defined: '${FOO}'), \
$(info FOO not defined) \
)
$(ifFOO)
FOO := foo
$(ifFOO)
$(call ensure-defined,FOO BAR)
all: ; #:
OUTPUT:
$ make -f foo.mk
FOO not defined
FOO is defined: 'foo'
NOT DEFINED: $BAR
foo.mk:25: *** Required variables not defined. Stop.
I would like to create a makefile for LaTeX documents (in this minimal
example). When there is no file "makeindexstyle.ist", it should be created (by
running make makeindexstyle.ist) and used for formatting the index. The rule for
%.pdf reflects this. However, it is not working yet, I receive the error
ifneq (, ) {
/bin/sh: 1: Syntax error: word unexpected (expecting ")")
make: *** [master.pdf] Error 2
What's wrong?
Parts from Makefile:
MASTER = master
TEX = slave
TEXI = texi2dvi -p
all: $(MASTER:=.pdf)
%.pdf: %.tex $(TEX:=.tex)
ifneq ($(wildcard makeindexstyle.ist), ) { # if makeindexstyle.ist exists, compile and build index
$(TEXI) $<
make makeindexstyle.ist
makeindex -c -s makeindexstyle.ist $(MASTER:=.idx)
}
endif
$(TEXI) $<
makeindexstyle.ist:
#(echo "...") > makeindexstyle.ist
UPDATE:
I tried to make it as simple as possible to see where the error comes from. Among other things (like quoting), I tried this:
%.pdf: %.tex $(TEX:=.tex)
exist := $(wildcard "absolute-path-to-makeindexstyle.ist")
ifneq ($strip $(exist)),)
echo "foo"
endif
$(TEXI) $<
but the result is
exists :=
make: exists: Command not found
make: *** [book.pdf] Error 127
In the meanwhile, I could solve it on the shell side:
IDX = "makeindexstyle.ist"
%.pdf: %.tex $(TEX:=.tex)
#if test -f $(IDX); then \
echo "foo"; \
fi
$(TEXI) $<
This sounds like a duplicate of How do I check if file exists in Makefile? or How to conditional set up a Makefile variable by testing if a file exists.
Try
ifneq ($(wildcard makeindexstyle.ist),)
without the space. Alternatively, throw "" around the arguments?
I've this:
include makefile_vars.mk
# Target
TARGET := $(OBJ)/$(TARGETNAME)
# Move objects to ../Obj
OBJECTS := $(addsuffix .obj,$(SOURCES))
override OBJECTS := $(OBJECTS:$(SRC)/%.obj=$(OBJ)/%.obj)
# Objects o
OBJ_INC_DIRS := $(sort $(dir $(OBJECTS)))
# Target
all: $(TARGET)
$(TARGET): $(OBJECTS)
# Objects
$(OBJ)/%.c.obj: $(SRC)/%.c | $(OBJ_INC_DIRS)
#echo Compiling $(<F) ...
$(OBJ)/%.a66.obj: $(SRC)/%.a66 | $(OBJ_INC_DIRS)
#echo Compiling $(<F) ...
$(OBJ_INC_DIRS):
mkdir -p $#
The first time I launch it, it says me that there is no rule to make the target MyFile.c.obj, when running again (whitout modifying anything) the rule is found and the compilation goes on.
What am I doing wrong?
I'm not sure that this will work, but I would move $(OBJ_INC_DIRS) order-only prerequisite out from the pattern rules:
$(OBJECTS) : | $(OBJ_INC_DIRS)
$(OBJ)/%.c.obj: $(SRC)/%.c
#echo Compiling $(<F) ...
...