Makefile abort make if a folder is not found - makefile

I have a simple Makefile that relies on a specific folder structure. I'd like to add a test so the Makefile fails with a message telling the user the folder is missing.
My target looks like this:
check_folders:
test -d ../some_folder || $(error The ../some_folder folder does not exist)
.PHONY: check_folders
I was expecting a short-circuit logic here, so if the first statement passes (and the folder exists), the second statement isn't executed. But it isn't working, the error is thrown even if the folder exists:
$ mkdir ../some_folder
$ make check_folders
makefile:24: *** The ../some_folder folder does not exist. Stop.
Any help is appreciated!
Thanks!

You are using a make capability for throwing errors, not a shell capability. All make variables and functions in a recipe are expanded first, BEFORE the recipe is invoked.
You have two options. The first is to switch completely to recipe failure: make will stop if a recipe exits with a failure. So you can write your rule like this:
check_folders:
test -d ../some_folder || { echo The ../some_folder folder does not exist; exit 1; }
The other is to switch completely to make tests; this will happen before ANY recipe is invoked, as the makefile is parsed:
$(if $(wildcard ../some_folder/.),,$(error The ../some_folder folder does not exist))

Related

Including a newly generated file each time in gnu make makefile? Deleting tempory file not working?

I have a Makefile like so:
T:=$(shell mktemp)
include ${T}
I:=$(shell rm ${T})
all:
echo done
In theory, mktemp should create an empty file and return its name. The next line should include that file. The following line should delete it.
When I run it I get:
make: *** No rule to make target `/tmp/tmp.Cwe7kiNBA3'. Stop.
If I comment out the third line like so:
T:=$(shell mktemp)
include ${T}
#I:=$(shell rm ${T})
all:
echo done
The Makefile works as expected, but leaves the temporary file behind.
Why doesn't the original example work as expected?
Your Makefile seems good without the include ${T} command. As described by GNU, the include directive is useful to:
suspend reading the current makefile and read one or more other
makefiles before continuing.
So, the following Makefile:
T:=$(shell mktemp)
I:=$(shell rm ${T})
all:
echo done
will produce this output and it will not report errors:
echo done
done
Make is trying to remake your included Makefile - for example, it works if you replace include with -include (which doesn't complain when the remake fails). You can fix it by adding an empty recipe for it: ${T}: ;.

Is there a way to tell my makefile to output a custom error message if a certain an include file is not found?

I have a configure script that generates a config.inc file containing some variable definitions and a makefile that imports those configurations using
include config.inc
The thing that bothers me is that if the user tries to run the makefile directly without first running configure they get an unhelpful error message:
makefile:2: config.inc: No such file or directory
make: *** No rule to make target 'config.inc'. Stop.
Is there a way for me to produce a better error message, instructing the user to first run the configure script, without resorting to the autoconf strategy of generating the full makefile from inside configure?
Sure, no problem; just do something like this:
atarget:
echo here is a target
ifeq ($(wildcard config.inc),)
$(error Please run configure first!)
endif
another:
echo here is another target
include config.inc
final:
echo here is a final target
Note this is definitely specific to GNU make; there's no portable way to do this.
EDIT: the above example will work fine. If the file config.inc exists, then it will be included. If the file config.inc does not exist, then make will exit as it reads the makefile (as a result of the error function) and never get to the include line so there will be no obscure error about missing include files. That's what the original poster asked for.
EDIT2: Here's an example run:
$ cat Makefile
all:
#echo hello world
ifeq ($(wildcard config.inc),)
$(error Please run configure first!)
endif
include config.inc
$ touch config.inc
$ make
hello world
$ rm config.inc
$ make
Makefile:5: *** Please run configure first!. Stop.
I gave up and decided to use autoconf and automake to handle my makefile-generation needs.

Makefile target with wildcard to create symlink using target string

I'd like a set of makefile rules that create a symlink to one of several code modules before building the project. The name of the make target would determine the file to which the symlink points. For example:
The user invokes 'make R3000'
Make sees that 'data.asm' doesn't exist yet, so a symlink is created from 'data_R3000.asm' to 'data.asm'
The build process continues, using data.asm
How can I set up make rules to do this?
Maybe something like:
MODULES := $(patsubst data_%.asm,%,$(wildcard data_*.asm))
all:
...
data.asm:
[ -n "$(filter $(MAKECMDGOALS),$(MODULES))" ] || { echo unknown module: $(MAKECMDGOALS) ; exit 1; }
ln -s $(filter $(MAKECMDGOALS),$(MODULES)) $#
Then make sure data.asm is listed as a prerequisite in the appropriate rules.
I would do something like this:
.PHONY mklink
mklink:
test -e data_$(MAKECMDGOALS).asm || exit 1
ln -s data_$(MAKECMDGOALS).asm data.asm
and then make all (and other targets) dependent on mklink. The reason you shouldn't make data.asm your target in the rule is that if you run make R3000, then data.asm will be created, and then if you run make L2000, the data.asm file will be pointing to the wrong directory, and will not be overwritten (I'll assuming this is not what you want). The test line checks if the link target exists, and if not, it exits with 1, causing the target to fail. You should also add a check that MAKECMDGOALS is exactly one element as well.

Specifying different GNUmakefile for GNU make command

I have two GNUmakefiles in my directory as follows,
GNUmakefile &
GNUmakefile2
Could someone please let me know the command I have to use, if I have to let the "make" command to process "GNUmakefile2" instead of "GNUmakefile".
I used the below command,
make -f GNUmakefile2
but in that case, I am getting the following errors,
This is gnustep-make 2.6.1. Type 'make print-gnustep-make-help' for help.
make[1]: ** No rule to make target `internal-master-tool-all'. Stop.*
make: ** [internal-all] Error 2*
I think it is considering GNUmakefile as makefile (when I use make with -f command), so it is checking for rules in GNUmakefile.
At present what I am doing is I am renaming the required file (which I want, make command to execute) to "GNUmakefile". And I am not getting any errors while executing "make" command, but I don't think this is the correct solution.
Please let me know which command I need to use for this scenario. Thanks for your help.
After checking Beta's solution (i.e.,but that makefile is invoking Make a second time, and the second Make process is probably reading GNUmakefile) what I have done is I renamed existing "GNUmakefile" to "GNUmakefile3".
So at present in my directory the following makefiles are present:- "GNUmakefile2" & "GNUmakefile3".
And then I executed the following command:- $ make -f GNUmakefile2
I recieved the below errors,
This is gnustep-make 2.6.1. Type 'make print-gnustep-make-help' for help.
make[1]: GNUmakefile: No such file or directory
make[1]: * No rule to make target `GNUmakefile'. Stop.
make: * [internal-all] Error 2
Please let me know what is the problem here
Your makefile includes two huge makefiles from the FSF. The second, library.make, contains this rule:
ifeq ($(GNUSTEP_MAKE_PARALLEL_BUILDING), no)
# Standard building
...
else
# Parallel building. ...
internal-library-all_:: $(GNUSTEP_OBJ_INSTANCE_DIR) $(OBJ_DIRS_TO_CREATE)
$(ECHO_NOTHING_RECURSIVE_MAKE)$(MAKE) -f $(MAKEFILE_NAME) ...
endif
and the first, common.make contains this assignment:
# The default name of the makefile to be used in recursive invocations of make
ifeq ($(MAKEFILE_NAME),)
MAKEFILE_NAME = GNUmakefile
endif
So try either make -f GNUmakefile2 GNUSTEP_MAKE_PARALLEL_BUILDING=no or make -f GNUmakefile2 MAKEFILE_NAME=GNUmakefile2, and see if that solves the problem.

explicity chain dependency in Makefile

What's the pattern to follow when specialized Makefiles in a directory depends on the main one in a parent dir?
i have:
/
/Makefile
/src
/src/Makefile
/tests
/tests/Makefile
in /Makefile i have:
TESTING_COMMAND=something
dotest1:
make -C tests/ $#
in /tests/makefile i have
dotest1:
$(TESTING_COMMAND) $?
if i run:
me#host:/ $ Make dotest1
it works. but if i execute from the tests dir:
me#host:/tests/ $ Make dotest1
it will try to execute the test file in the shell, because $(TESTING_COMMAND) is empty, so it's first argument became the command passed to the shell.
I don't necessarily need that to work if executed in the /tests/ or /src/ dir, but need a way to gracefully fail.
Trying to send everything through the command line (or environment) seems like a bad idea to me. That's what inclusion was invented for. Put your common values into a separate file, something like config.mk, then in all your makefiles just use:
include config.mk
to get them included.
Your design scares me, but this will do the trick in the main Makefile:
TESTING_COMMAND=something
dotest1:
make -C tests/ $# TESTING_COMMAND=$(TESTING_COMMAND)
If you want tests/Makefile to fail well, you have a couple of options. If only that one target depends on TESTING_COMMAND, you can have it print a warning and do nothing:
ifdef TESTING_COMMAND
dotest1:
$(TESTING_COMMAND) $?
else
dotest1:
#echo warning: TESTING_COMMAND not defined
endif
Or if the whole Makefile depends on it, you can have Make print a warning or abort:
ifndef TESTING_COMMAND
$(warning TESTING_COMMAND is undefined, but Make will try to us it anyway)
$(error TESTING_COMMAND is undefined, Make will now abort)
endif
You can also have it abort the sub-make (the one that runs tests/Makefile) but still continue running the Make process that invoked it, but that's kind of a pain.

Resources