I'd like to enable a verbose compilation in my makefile, but I can't figure out how to make a conditional OR.
Let me explain: I want to be able to specify a verbose compilation either by setting V=1 or VERBOSE=1. I want to keep VERBOSE=1 available because we have some scripts that make use of it (and use other makefiles only aware of VERBOSE)
So the result must be that these two commands are the same:
make all VERBOSE=1 # pain to write
make all V=1
Now, my makefile looks like this today:
ifdef VERBOSE
[issue compilation commands with verbose mode]
endif
What I'd like to achieve is close to the preprocessor in C:
if defined(VERBOSE) || defined(V)
[issue compilation commands with verbose mode]
endif
Do you know how to do that?
I do like this:
ifneq "$(or $(LINUX_TARGET),$(OSX_TARGET))" ""
endif
Similar to the $(strip approach, but using the more intuitive $(or keyword
VERBOSE := $(or $(VERBOSE),$(V))
...then...
ifeq ($(VERBOSE),1)
#Conditional stuff
endif
I like Neil Butterworth's approach, but if you really want to do it in the style you describe, this will give you OR:
ifneq "$(strip $(VERBOSE) $(V))" ""
[be verbose]
endif
As far as I know, the conditional stuff in GNU make doesn't allow for ORs and ANDS. You could always do something like:
ifdef VERBOSE
DOVERBOSE = yes
endif
ifdef V
DOVERBOSE = yes
endif
ifeq( $DOVERBOSE, yes )
main verbose stuff here
endif
but I don't see why you need to introduce the (hardly self documenting) define of V in the first place.
Ok, really late to the party, but I came across this, and wanted to add another solution for others who were looking how to add logic to makefiles: basically, do the logic in a shell, and get the output that way.
ifneq ( $(shell ( [ $(VERBOSE) ] || [ $(V) ] ) && echo y ),)
it seems more convoluted, but if you have an if statement with many ands and ors, this offers a lot of flexibility, and would be easier to read than nested $(and .. $(or ...)) statements.
Related
I would like to check multiple conditions in an if loop of GNU make file. Here's an example:
ifeq ($(TEST_FLAG),TRUE && ($(DEBUG_FLAG),FALSE))
true statement
else
false statement
endif
What's the right way to do it?
Although Hasturkun's solution will work, I think the idiomatic way to write this is:
ifeq ($(TEST_FLAG),TRUE)
ifeq ($(DEBUG_FLAG),FALSE)
# Stuff
endif
endif
You can use ifeq with a concatenation of your values, eg.
ifeq ($(TEST_FLAG)$(DEBUG_FLAG),TRUEFALSE)
do something
endif
It's also possible to use the Conditional functions, which are more likely to be useful in a loop (as ifeq will probably not do what you expect in a loop, it will be tested exactly once).
I have a makefile that looks something like this:
include anotherFile.mk
all:
someStuff
The file anotherFile.mk is like this:
include yetAnotherFile.mk
export SOME_VAR = 93
The problem is that anotherFile.mk and yetAnotherFile.mk are in a different directory from my Makefile. So my makefile can't just be changed to this:
include $(OTHER_PROJECT_PATH)/anotherFile.mk
all:
someStuff
The problem with this approach is that the include statement in anotherFile.mk will fail because it will be searching in the current directory.
A partial solution that I found is to pass the --include-dir=$OTHER_PROJECT_PATH flag to the invocation of make, but that's a bit user-unfriendly.
So my question is: Is there something I can put inside my makefile that will add to the directories that make searches for when executing an include? Something like MAKE_INCLUDE_DIRS += $(OTHER_PROJECT_PATH)
Surprisingly there doesn't seem to be a good answer to that question. Forcing .INCLUDE_DIR doesn't help and there doesn't seem to be any way around invoking make with --include-dir=$OTHER_PROJECT_PATH.
It is however possible to put the appropriate recursive make invocation inside the makefile but, in order to get it to work for all reasonable cases it quickly becomes too complicated to be worth it. In summary it requires:
a top level condition to check if the OTHER_PROJECT_PATH is in .INCLUDE_DIR
the appropriate target with the recipe invoking make recursively
possibly additional targets if there are multiple command goals
the real make file enclosed in the else part of the conditional
You Makefile would look like this:
OTHER_PROJECT_PATH := other
ifeq (,$(filter $(OTHER_PROJECT_PATH), $(.INCLUDE_DIRS)))
# this is the mechanism to add the include dir in a recursive make
$(or $(firstword $(MAKECMDGOALS)),all):
$(MAKE) -I$(OTHER_PROJECT_PATH) $(MAKECMDGOALS)
# add empty targets for additional goals if needed
ifneq (,$(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS)))
$(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS)):
endif
else
# this is where the real makefile starts
all more:
echo $#: $< $^
include a.mak
endif
It still does not seem possible from a makefile, but if you have a script that sets up environment variables, you can use MAKEFLAGS (e.g. export MAKEFLAGS=I/your/path ordentlich on Linux, or SET on Windows)
I have a somewhat complex makefile that I want to change and I don't know much about make.
BUILD_TYPE = SERVER
BAS_CSRC = a.c \
b.c \
c.c
What I want to do is conditionally add things to BAS_CSRC like so:
ifeq ($(BUILD_TYPE), SERVER)
USR_CSRC = $(BAS_CSRC) \
d.c \
e.c
endif
all_csrc = $(USR_CSRC) $(foreach var, $(COMMON_OBJECTS), $($(var)_csrc))
But when I compile the d.c and e.c are just ignored so the ifeq fails. Why? What about quoting?
Based on what you've typed here it should work (and I cut and pasted this into a test makefile which worked for me), which likely means there's something different about your real environment, than this example. Can you show us where you use the variable all_csrc? Maybe it's that that's the problem, not the assignment of the variable.
Make sure you don't have any trailing whitespace. Make sure you have matching case in your variables and values (make, like all UNIX tools, is case-sensitive). You can try adding $(info ...) statements to your makefile and it will print out what it's doing. Put one inside the ifeq to see if it fires, and after the endif to see what the value of USR_CSRC is.
Also, in general it's not a good idea to add whitespace into if statements or function calls like foreach. In the above situations it shouldn't matter but in general it's best avoided.
I am trying to check a file against a list before I try to compile it in a GNU makefile. Will the conditional ifneq below be evaluated every time the rule is invoked or just once? The condition seems to always evaluate the same way.
If not is the only way to do this to put the conditional in the shell command? I realize it may seem weird that the target list could be "not OK" ... the Make system could certainly be fixed to eliminate that weirdness but the pain will be greater.
Any suggestions?
Eli
OKSRC := realfile1.cpp realfile2.cpp
%.o: %.cpp
ifneq ($(findstring $<,$(OKSRC),),)
... do the compile
else
#skip the file
endif
Quoting from the Make documentation:
Conditional directives are parsed immediately. This means, for example, that automatic variables cannot be used in conditional directives, as automatic variables are not set until the recipe for that rule is invoked. If you need to use automatic variables in a conditional directive you must move the condition into the recipe and use shell conditional syntax instead.
ifneq is a conditional directive, and $< is an automatic variable. So in short, your above code will not work, so you would have to use the shell-based conditional.
But I would strongly suggest that you fix the root cause (i.e. the erroneous dependency generation), rather than trying to hack around it.
I think you can use if function to defer the expansion of automatic variables until the condition is evaluated.
OKSRC = realfile1.cpp realfile2.cpp
.cpp.o:
$(if $(findstring $<,$(OKSRC)),$(CC) $(CFLAGS) -c $<,#echo skip $<)
And the result shows:
$ make realfile1.o realfile2.o realfile3.o
cc -c realfile1.cpp
cc -c realfile2.cpp
skip realfile3.cpp
How to check for flags in Makefile ? Suppose I run make -a, I need to be able to do certain things, How do I detect if the flag is set inside a Makefile ?
If you're using GNUMake, you can check MAKEFLAGS, like this:
someTarget:
ifneq (,$(findstring a,$(MAKEFLAGS)))
do something
else
do something else
endif