Conditional part of makefile always evaluating to true - makefile

I have a legacy makefile based build system that I am trying to make changes to. I am not familiar with make and so was making changes on a trial and error basis.
Not being able to deduce what the problem is I inserted this bit of code in the makefile:
ARG1 = GCC
ARG2 = ARM
ifeq($(ARG1),$(ARG2))
$(warning *** WARNING ***)
endif
When I run make, I always get the print:
\PathToBuildDirectory\makefile.options:54:*** WARNING ***
NOTE: I am using clearmake with the -C gnu option.
How or why does the condition evaulate to true?

If it behaves this way for a makefile consisting of only the above content then it's a bug in clearmake. I know that clearmake's emulation of GNU make is incomplete, but this seems pretty simple.
However, since you're already echoing an error wouldn't it be straightforward to also show the values of ARG1 and ARG2? Maybe they ARE equal. Maybe one or both are set on the command line. Maybe elsewhere one or both was assigned with the override option. Maybe clearmake is invoked with the -e option and one or both of those variables are set in the environment.
If you show their values, then you'll know.
ETA: Maybe the problem is this: in GNU make you must put a space after the ifeq, like this:
ifeq ($(ARG1),$(ARG2))
If you try your original version with GNU make, you'll get an error:
Makefile:3: *** missing separator. Stop.
but I guess clearmake just ignores the line without any error messages.

Related

Let make fail, if Makefile encounters undefined variable

I had a mistake in my Makefile:
verify-prettier:
$(PRETTIER) --check **/*.yaml **/*.yml
The var PRETTIER was not set.
The result:
check **/*.yaml **/*.yml
bash: line 1: check: command not found
make: [Makefile:156: verify-prettier] Error 127 (ignored)
I would like to get an error (which does not get ignored), if I accidentaly have an undefined variable.
Is there a way to configure make accordingly?
Version: GNU Make 4.3
We don't need to support other make implementations.
I know this, but I want it to fail, not just a warning.
MAKEFLAGS=--warn-undefined-variables
Update, since this seem to be unavailable up to now, I created a feature request: https://savannah.gnu.org/bugs/?63737
As said in comments there is no way as of current (4.3) GNU Make versions. And any addition is likely to take forever before reaching the general public (WSL still stuck at 4.2.1!!!).
I can think of a few crutches that might work depending on circumstances:
Pass --warn-undefined-variables to make, then pipe output to e.g. grep testing absence of the warning message. Suitable for build automation where command line length and complexity doesn't matter, less so for interactive use.
Have blocks of ifndef and error at the end of the makefile. You'll need a specific block for each variable, however this isn't too far off how unit tests work and those are generally accepted :-)
Default initialize to something that will fail. In the case of $(PRETTIER) you could initialize it to false, silently eating any arguments and returning failure. Feasibility depends on how the variable is used. Works well for a variable used as a command, might get trickier for arguments though I'm sure some hack ought to work (because how hard can it be to intentionally write crashing code).

Changing value of a variable according to a condition inside a target in Makefile

In a makefile which I have ,I want to assign value to a variable based on a condition.
I have:
CMAKE=cmake ../
I tried doing:
if test condition;
then $(eval CMAKE := $(cmake -DCMAKE_BUILD_TYPE=Release ../));\
fi;
But this does not work.Is there any other way to do this?
P.S The error which is getting reported is :
Syntax error: ";" unexpected
When I removed ";" ,it showed another error :
Syntax error: "fi" unexpected
This kind of "back and forth" between the shell and make is not possible. It's important to understand the relationship between them: make does not implement a shell parser: it just runs the shell for that. All make gets back from the shell is a single exit code that determines whether the command succeeded or not.
Make runs a recipe by first expanding all the variables and functions in the recipe, then passing the resulting command to the shell to be invoked.
Thus it should be clear why your example doesn't work.
Before we can give you good advice we'd need higher-level information about exactly what you're trying to do and why. One way to do what you want is to use $(shell ...) to compute the conditional, all outside of any rule:
ifeq ($(shell test condition && echo true),true)
CMAKE := cmake -DCMAKE_BUILD_TYPE=Release ../
endif
However, this looks pretty strange to me. If you described what you really want to do we can probably give you better help.
ETA:
Based on your description below, the best option is target-specific variables:
CMAKE_BUILD_FLAG = -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE)
debug: CMAKE_BUILD_TYPE = Debug
release: CMAKE_BUILD_TYPE = Release
setup: CMAKE_BUILD_FLAG =
debug release setup: all
all:
cmake $(CMAKE_BUILD_FLAG) ../

How to set default to -j2 in Makefile?

I would like to have make option "-j2" as the default.
Can I modify Makefile for that?
Looking at the GNU Make manual (3.82), there is nothing I can see that allows that.
You might be able to set environment variable MAKEFLAGS (to either '-j 2' or perhaps 'j 2'), but otherwise, it appears you cannot.
As mentioned previously one can set the environment variable MAKEFLAGS. But this apparently works even inside a makefile (at least with GNU make). If you add a line
MAKEFLAGS=-j 2
at the top of the makefile this should give you the desired results. I have not tested this thoroughly and maybe it does only work with recursive invocations, but that could be easily worked around with a wrapper target.
I have used this to prevent make from printing the "Entering directory"/"Leaving directory" messages in recursive executions by setting MAKEFLAGS=-s.

Detecting (non-)GNU Make when someone runs `make`

I have a project whose makefile uses features exclusive to GNU Make. Sadly, there are platforms we must support where GNU make is still not the default when running make.
One of my colleagues was bitten by this, when a non-GNU make implementation silently failed to build our code correctly (it expanded an automatic variable to an empty string). I want to prevent that from happening again, by generating an explicit error message instead.
What can I write in a Makefile to distinguish GNU make from non-GNU make, print a clear error, and exit?
I've already figured out a workaround in renaming my real makefile to GNUmakefile, and putting a small stub in Makefile, but I'd rather something more direct.
The answers by Beta and Dan Moulding look really nice and simple, but on AIX 6.1, the make implementation can't handle either of them:
$ cat testmake
foo:
touch foo
ifeq ($(shell $(MAKE) -v | grep GNU),)
$(error this is not GNU Make)
endif
ifeq "${MAKE_VERSION}" ""
$(info GNU Make not detected)
$(error ${MIN_MAKE_VER_MSG})
endif
$ /usr/bin/make -f testmake
"testmake", line 5: make: 1254-055 Dependency line needs colon or double colon operator.
"testmake", line 6: make: 1254-055 Dependency line needs colon or double colon operator.
"testmake", line 7: make: 1254-055 Dependency line needs colon or double colon operator.
"testmake", line 8: make: 1254-055 Dependency line needs colon or double colon operator.
"testmake", line 11: make: 1254-055 Dependency line needs colon or double colon operator.
"testmake", line 12: make: 1254-055 Dependency line needs colon or double colon operator.
"testmake", line 13: make: 1254-055 Dependency line needs colon or double colon operator.
make: 1254-058 Fatal errors encountered -- cannot continue.
I run into similar issues on both archaic and modern versions (Solaris 8 & 10) of Sun's make. That one's less critical, but would be nice to manage.
As noted, GNU make checks for GNUmakefile before makefile or Makefile, I've used a trivial fix such as you described, a default (decoy) Makefile that causes an error/warning:
default:
#echo "This requires GNU make, run gmake instead"
exit 70
The GNU make documentation recommends using the GNUmakefile name when the Makefile is GNU make specific, so that's my preferred solution.
On platforms where the native make prefers a different Makefile name, you can do a variation on this, e.g. on FreeBSD I have the above decoy in the BSDmakefile which is used in preference to Makefile (thus preventing the system make from mangling my build). AFAICT the AIX or Solaris make do not have an alternate name you could use in this way.
One problem with a wrapper Makefile which tries to call GNU make is passing all the arguments.
A seemingly portable test (so far, I've found it to work on a mix of ancient OSF1, BSD and Solaris systems) you can use SOMETHING=$(shell ...) to detect if GNU make is running, non GNU versions will not set SOMETHING. Because of deferred evaluation of variables, you cannot use this as easily as might be expected though. This relies on the implementation silently handling macro names with spaces when expanded with $() (i.e. treats $(shell foo) as a variable/macro name rather than a function, even though an assignment to such a name in that implementation would cause an error).
The only portable way you can print a clear error is to have a dummy target that is always run, using the above trick:
GNUMAKE=$(shell echo GNUMAKE)
default: gnumake all
gnumake:
#[ "$(GNUMAKE)" = "GNUMAKE" ] || { echo GNU make required ; exit 70; }
This assumes you have a POSIX sh shell.
(I have seen tests which inspect $(MAKE) -v fail when both system and GNU make are called "make", the system make conspires against you and invokes GNU make ... You'd need some carefully checking of environment variables PATH, MAKE and possibly SHELL to handle every case.)
I don't know of any internal feature that is definitely unique to GNUMake, but here's a kludge: call "make -v" and parse the output for "GNU" (since it seems unlikely that a non-GNU Make would have MAKE set to a GNU Make):
ifeq ($(shell $(MAKE) -v | grep GNU),)
$(error this is not GNU Make)
endif
EDIT:
Like Dan Moulding, I am starting to see the real size of this problem. As written, it requires a Makefile that is syntactically correct in all versions of Make. I don't have access to Sun Make (and I can't find manuals for it) so I don't know whether that's even possible, or how to write it if it is, or how to test it if I did.
But I can suggest an approach that might work. Maybe something like this can be made universal:
default:
./runGNUMake.pl
That's it, that's the whole makefile. Then write the runGNUMake script in Perl (or bash, or whatever you like) that will do something like my "make -v" kludge and then either print the error message or run "make -f realMakefile".

make - specifying target name to make from command line

I am looking at C makefile, and I have a question.
I know that 'make a' will make the target a, which is supposed to be defined in the makefile.
I want to know whether the target name itself can be supplied as an argument to make.
i.e. this is what I want to do:
$(target_name) is the name supplied to command 'make'. For example, 'make foo'.
and in the makefile,
$(target_name) = dependencies
command
I am not sure whether this is possible... could not find anything in the make manual too.
If anyone can help me with this, it'll be awesome.
Thanks,
Everything you are asking about is what make does by default - there is no need to write any special code in the makefile to do this. You seem rather confused about make (it is not particularly C related, for example). The best guide to it is the GNU Make Manual, which is not only a manual but a pretty good tutorial.
I'm kind of new to Makefiles but it seems you don't pass values in Makefile like that. If the following is your Makefile
# Makefile
TARGET?=something
$(TARGET):
echo $(TARGET)
You can pass parameters in by calling make like this in the terminal
$ TARGET='ABCDEF' make

Resources