Check for flags in Makefile - makefile

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

Related

Export preprocessor macro in makefile

I want to export preprocessor macro to an internal makefile from the main makefile in a particular target.
example:
Main_Makefile
target1 :
CXXFLAGS+=-DNewFlag=NewFlag
cd some_directory; make
Here I want to use value of CXXFLAGS which is -DNewFlag=NewFlag and is only defined under target1 in some_directory/make
Please let me know how can I achieve this.
There is no way to append to a variable from the command line, unless you've made arrangements for it in the makefile of the subdirectory.
The simplest thing to do is use a different variable, like this:
target1:
cd some_directory && $(MAKE) EXTRA_CXXFLAGS=-DNewFlag=NewFlag
(note you should always use $(MAKE) or ${MAKE} when invoking a sub-make, never make directly.)
Then in the subdirectory makefile you do something like this:
CXXFLAGS += $(EXTRA_CXXFLAGS)

How can I add a directory to the search path of GNU Make?

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)

How to check if a file exists in Makefile

I am using makefile to build my program in multiple system. Some system have installed colorgcc script. In my Makefile i want to check, if script exists
and depending on it i setting up CC variable. But my Makefile don't work correctly - in system, that haven't colorgcc, make always set $(CC) as colorgcc. Here's part of Makefile:
ifneq ("$(wildchar /usr/bin/colorgcc)","")
CC=colorgcc
else
CC=gcc
endif
I also tried to use this variant:
ifeq ( $(shell test -e /usr/bin/colorgcc), )
CC=colorgcc
else
CC=gcc
endif
In both case $(CC) doesn't depend of existence file /usr/bin/colorgcc
How can i solve my problem?
In the first case, you mistyped the function $(wildcard ...) so you get nothing, always.
In the second case, the output of test is always the empty string. It will set its exit code depending on whether the condition is true or not, but you are not examining its exit code, just the output it prints, which will always be nothing at all.

Programmatically selecting a sub-makefile to include when running make

I have the following logic in a Makefile:
ifdef INCLUDE_FILE
$(shell cp $(INCLUDE_FILE) include.make)
else
$(shell cp -n default.make include.make)
endif
include include.make
The intended behavior is:
If one just runs make and include.make exists, include.make is included. Otherwise, a default file is copied to include.make and then included.
If one runs make INCLUDE_FILE=myinclude.make, then myinclude.make is copied and included.
This seems to work fine to allow makefile customizations (compiler flags, etc) in include.make, which will persist if one does something like
$make INCLUDE_FILE=myinclude.make
$...
$make
but also allow a new user to simply type make and see default behavior.
My questions are
Is this good/standard (gnu) makefile practice?
Are there any serious portability concerns? [That is, is relying on cp in this way dangerous?]
Is there a better alternative method to implement similar behavior?
If the intention of this is to persist then I think this idea is reasonable though I wouldn't implement it this way.
I'd probably do something like this instead.
include include.mk
include.mk:
#cp $(or $(INCLUDE_FILE),default.mk) $#
Assuming you want the copy to only happen once (unless include.mk is manually deleted). There are other ways this could be done to handle copying again (if default.mk changes, etc. but those require more information about your goal).
The simplest (albeit hack) way to get make INCLUDE_FILE=myinclude.mk to always copy over include.mk is likely to add something like the following to the above makefile snippet.
ifdef INCLUDE_FILE
.PHONY: $(INCLUDE_FILE)
include.mk: $(INCLUDE_FILE)
endif
Though this does copy the file multiple times. You could add a check on $(MAKE_RESTARTS) also to avoid that.
include include.mk
include.mk:
cp $(or $(INCLUDE_FILE),default.mk) $#
ifdef INCLUDE_FILE
ifndef MAKE_RESTARTS
.PHONY: $(INCLUDE_FILE)
include.mk: $(INCLUDE_FILE)
endif
endif
This is slightly abusive of the behaviour of a normal target when it specifies a .PHONY target as a prerequisite but it seems to work and is, I believe, only depending on documented behaviour.
Why don't you just use:
INCLUDE_FILE := $(firstword $(wildcard include.make default.make))
include $(INCLUDE_FILE)
? This will include either include.make, if it exists, or else default.make, or if you define INCLUDE_FILE on the command line it will override the setting in the makefile.

Conditional OR in makefile

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.

Resources