Let make fail, if Makefile encounters undefined variable - makefile

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).

Related

Can't override target-specific variable

I have such Makefile:
print: var1=inside
print:
#echo $(var1)
When I run var1=outside make -e print. I expected to see:
outside
Because of:
Variables provided on the command line (and in the environment if the ā€˜-eā€™ option is in force) will take precedence.
But I get:
inside
Is it a correct output?
It is expected; whether or not it's correct I guess depends on who you ask.
The -e option is in effect for "global" variables in makefiles, but target-specific variables take precedence over globally-scoped variables.
Personally I think -e was a mistake and never should have existed. But, you know, POSIX and all. Even though it exists I recommend that it be avoided. It's far, far too easy to completely mess up your build in confusing and surprising ways.
ETA Well, maybe it's not expected. Maybe it is a bug. Where did you get that quote you provided? With just that sentence from a 225-page document it's hard to say... a link or at least a section name would be helpful.

Conditional part of makefile always evaluating to true

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.

A simple (trivial) c++ makefile on UNIX

I am trying to make a makefile for one cpp file. I've tried googling and none of the examples I've seen have helped... I keep getting errors when I type make. Here is what I have...
Interpreter: Interpreter.o
g++ -o Interpreter Interpreter.o
Interpreter.o: Interpreter.cpp
g++ -c Interpreter.cpp
When I type make I get this error... "'ake: Fatal error: Don't know how to make target `Interpreter.o"
Where am I going wrong?
OK. A few simple things to start with here:
As mentioned in some of the comments, the makefile file must be named properly for make to find it. You can try specifing it manually with the -f flag to verify that it is being found.
Make is one of those few unfortunate languages where whitespace is important. The rules must not have a tab in front of them, and the commands for the rules should all have exactly one tab in front of them. When I checked your code above in the SO editor, it looked like your commands had two tabs at the front instead of one.
If I'm reading those rules right, you need a file named Interpreter.cpp in your working directory for this to work. If you don't have that file, you'll get an error.
If all else fails, try running make with the debugging flag (-d). This should give you more information about the decisions it is making.

No rule to make target `/Makefile', needed by `Makefile'

I'm trying to 'make' using a pretty simple makefile. My makefile is named 'Makefile' so I'm simply using the command 'make'.
I get this strange error:
make: *** No rule to make target `/Makefile', needed by `Makefile'. Stop.
If, however, I use
make -f "full-path-to-makefile" it actually does run (with odd consequences...). I should say that I'm running all this from the directory where the Makefile lies, of course.
I'm working on Mac OSX, using tcsh.
Edit:
I'm working in the LLVM framework, trying to compile a pass function and this is the associated makefile:
LEVEL = ../../../
LIBRARYNAME = FunctionName
LOADABLE_MODULE = 1
include $(LEVEL)/Makefile.common
Any ideas will be appreciated :)
I had the same problem trying to write a new pass for LLVM i followed these instructions trying to make a HelloB (as Hello already exsited) http://llvm.org/docs/WritingAnLLVMPass.html#quickstart
What i has to do was do a ./configure again then make from the base directory.
I'll go out on a limb: you have an extra slash. Try omitting the final slash in $(LEVEL).
I found the answer, sort of:
The problem was with the installation process of LLVM. It seems that if you do the installation in one order instead of another it can lead to this error. It doesn't make any sense to me, but after I installed it properly everything compiles great (same code, same Makefile, same make program).
I don't really know why this happened, but I know how to fix it :)
What you want to do is ./configure again then make from the base directory (contrary to what is stated in the instructions on the web-site). That worked for me.
BTW - I got the same results running on Ubuntu (with the same fix).
Just to add some information here (since this is the first hit that comes up on Google when looking for the error) - I had the same problem which suddenly popped up on a (previously working) LLVM setup on OSX, and traced it back to the behavior of the realpath command in make.
Specifically, what was happening was that I had a directory called "LLVM/llvm-2.9-build", but for some reason the attempt to resolve PROJECT_OBJ_ROOT at the top of Makefile.config would decide that this directory was in fact called "llvm/llvm-2.9-build". Since OSX is case-insensitive by default, this doesn't cause an immediate problem, except that subsequently LLVM_SRC_ROOT would be set to "LLVM/llvm-2.9-build". This then meant that the creation of PROJ_SRC_DIR using patsubst to replace the object directory would result in a non-existent path (as the unmatched case means that no pattern replace occurs), which in turn would get resolved to / by realpath.
With PROJ_SRC_DIR set to /, this results in the makefile copy rule in Makefile.rules deciding that the source makefile is at $(PROJ_SRC_DIR)/Makefile (ie /Makefile), and the error message described.
It seems that it is only the built-in implementation of realpath in Make (GNU Make 3.81 in my case) that has this behaviour, as forcibly using the macro version of realpath from the top of Makefile.config fixes the problem. However, this isn't a good long-term fix, as you'd have to manually patch every one of the LLVM makefiles.
In the end, I couldn't see where realpath would be getting the lower-case "llvm" from, but figured it was probably an artifact somehow of some caching of the name from a point in time when I'd referenced the directory using its lower-case name. Hence I tried going to that directory and mv-ing it to a completely different name, and then back to "LLVM" before going in and building again, and that seems to have solved the problem.
I hope that's of some use to anyone else who comes across this particular weirdness!
It's not a complete answer, but what you are seeing is gmake not finding the Makefile it is told to include, and thus it is trying to remake it and failing because it can't find a recipe for it either.
However, the Makefile snippet you posted does not produce the error message you are seeing, so I think the problem is inside the Makefile.common file. Look for include statements which reference a $(some variable expansion)/Makefile and work backwards from there. You can also try to run gmake with the -d option and follow the processing based on the output.
Since your include line reads:
include $(LEVEL)/Makefile.common
it is puzzling that you are not getting an error about /Makefile.common. If you were, then I'd suggest that maybe you have a trailing blank after the definition of LEVEL.
Could there be a line in Makefile.common that itself includes $(SOMEMACRO)/Makefile and you have not set the value of SOMEMACRO?
here's my fixes for this issue: (https://github.com/rust-lang/rust/issues/24887#issuecomment-99391849)
update src/llvm/Makefile.config.in before running ./configure
or update x86_64-apple-darwin/llvm/Makefile.config before make
line 59:
PROJ_SRC_DIR := $(LLVM_SRC_ROOT)$(patsubst $(PROJ_OBJ_ROOT)%,%,$(PROJ_OBJ_DIR))
update to
PROJ_SRC_DIR := $(patsubst $(PROJ_OBJ_ROOT)%,$(LLVM_SRC_ROOT)%,$(PROJ_OBJ_DIR))
line 86:
PROJ_SRC_DIR := $(call realpath, $(PROJ_SRC_ROOT)/$(patsubst $(PROJ_OBJ_ROOT)%,%,$(PROJ_OBJ_DIR)))
update to
PROJ_SRC_DIR := $(call realpath, $(patsubst $(PROJ_OBJ_ROOT)%,$(PROJ_SRC_ROOT)%,$(PROJ_OBJ_DIR)))

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.

Resources