I have a makefile which calls itself, in order to obtain a license for the compiler before compiling anything, and release the license even when compilation fails, like this:
.PHONY main_target
main_target:
#license_grab &
#sleep 2
-#$(MAKE) real_target
#license_release
This works great if the makefile is named "makefile". But if I make a copy of the makefile to experiment with something, and invoke it with make -f makefile_copy, then the wrong makefile gets used in the recursive call. How do I prevent this without hard-coding the makefile name in the makefile itself?
Edit: Unfortunately I'm stuck using GNU Make version 3.79.1, so I cannot use MAKEFILE_LIST, which was apparently introduced in version 3.80. Therefore none of the answers in this question will work for me.
You can use the MAKEFILE_LIST variable:
THIS_MAKEFILE := $(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
.PHONY main_target
main_target:
#license_grab &
#sleep 2
-#$(MAKE) -f $(THIS_MAKEFILE) real_target
#license_release
You can set the MAKE variable outside the makefile, to include the makefile name (unless of course, it gets overridden). Something like this (for bash):
MAKE="make -f makefile_copy" make -e -f makefile_copy
or this (in pretty much any shell):
make MAKE="make -f makefile_copy" -f makefile_copy
Related
I know this could be done in different ways, but I am actually looking for learning more about makefiles.
I want to be able to call make somefile.txt and run a given script.
In my current folder I have:
makefile
%.txt:
# perl -pe "s/#.*//g; s/^\n//g; s/\n/\t/g;" .txt
echo "Hi"
When I call make, I am getting
make: `somefile.txt' is up to date.
I know I would need to use .PHONY, but I am having trouble trying to use it with %.txt.
I already tried things such as
files = *.txt
.PHONY = $(files)
%.txt:
# perl -pe "s/#.*//g; s/^\n//g; s/\n/\t/g;" .txt
echo "Hi"
But that didn't actually work.
The (a) conventional way to do this is to make your real target have a phony one as a prerequisite. Phony targets are always considered initially out of date, so anything that depends on a phony target will also always be considered out of date. "force" is a conventional name for a target used for this purpose.
For example,
.PHONY: force
force:
%.txt: force
echo "Hi at $$(date)" > $#
As demonstrated in the example, this does not require the phony target to have a recipe.
If you don't want to list your targets to be built in your makefile but instead just give them on the command line, you can use this:
.PHONY: $(MAKECMDGOALS)
The variable MAKECMDGOALS will be set to the set of goals you gave make on the command line.
It's important to understand that a makefile is not the shell, and so just sticking *.txt anywhere in your makefile won't always expand it. Only particular areas of the makefile work with shell globs directly.
If you want to always expand it, you can use make's wildcard function like this:
files = $(wildcard *.txt)
I have a Makefile with tons of targets and would like for a certain script to get executed first, irrespective of what target is being called. I like to call it a global prerequisite.
I do not want to create a target for the script and set it as a prerequisite for all existing targets (which, as I said aren't few). Besides, someone else could add a target in future and not add my script as a prerequisite for their target, so the global prerequisite would take care of that.
Does GNU-make provide for a means to achieve this?
Another approach:
-include dummy
.PHONY: dummy
dummy:
run-the-script
Make will always attempt to rebuild any file which the makefile attempts to include (if it is out of date or does not exist). In this case there is no such file, and the rule to build it runs the script and does nothing else.
There is a solution without modifying your existing Makefile (main difference with the answers pointed to by tripleee). Just create a makefile containing:
.PHONY: all
all:
pre-script
#$(MAKE) -f Makefile --no-print-directory $(MAKECMDGOALS) MAKE='$(MAKE) -f Makefile'
post-script
$(MAKECMDGOALS): all ;
The only drawback is that the pre- and post- scripts will always be run, even if there is nothing else to do. But they will not be run if you invoke make with one of the --dry-run options (other difference with the answers pointed to by tripleee).
I'm new to using makefiles and trying to produce a basic makefile as part of an exercise for university. I have two source code files, chello.c and writeexit.s, which have to be compiled/assembled and then linked to produce chello.
This is the code I have so far for the makefile:
chello: chello.o writeexit.o
ld -N chello.o writeexit.o -o chello
chello.o: chello.c
gcc -c chello.c -o chello.o
writeexit.o: writeexit.s
as writeexit.s -o writeexit.o
The whitespace before ld, gcc and as are all tabs, so I think the whitespacing is fine. When I call 'make makefile', it returns 'make: Nothing to be done for `makefile'.' However, if I change the dependencies of chello, like chello.c, the same message is returned and chello's behaviour is not modified.
From man make:
make executes commands in the makefile to update one or more target
names, where name is typically a program. If no -f option is present,
make will look for the makefiles GNUmakefile, makefile, and Makefile,
in that order.
make makefile will actually execute your "makefile" (because it is listed among the default names in the man page) file, trying to build the "makefile" target (because of the argument you are passing), which already exists
What you need is to build the "chello" binary, so you have to type:
make chello
Or alternatively:
make -f makefile chello
Alternative account here, it seems to work fine if I just call "make" instead of "make makefile". This question can be ignored.
I have a makefile in a directory of mine which builds scripts with certain environment variables set. What if I want to create another makefile in the same directory with different environment variables set? How should I name the two make files? Does makefile.1 and makefile.2 work? How do I call them?
You can give sensible names to the files like makefile.win and makefile.nix and use them:
make -f makefile.win
make -f makefile.nix
or have a Makefile that contains:
win:
make -f makefile.win
nix:
make -f makefile.nix
and use make win or make nix
You can name makefile whatever you want. I usually name it like somename.mk. To use it later you need to tell make what makefile you want. Use -f option for this:
make -f somename.mk
Actually you can have two set of environment variables in the same make file. for example
COMPILER = gcc
CCFLAGS1 = -g
CCFLAGS2 = -Wall
a: main.c
${COMPILER} ${CCFLAGS1} main.c
b: test.c
${COMPILER} ${CCFLAGS2} test.c
then you can just say make a or make b. Depending on what you want.
Also it is possible with -f flag to call which makefile you want to call.
You can do something like this rather than using multiple makefiles for the same purpose. You can pass the environment or set a flag to the same makefile. For eg:
ifeq ($(ENV),ENV1)
ENV_VAR = THIS
else
ENV_VAR = THAT
endif
default : test
.PHONY : test
test:
#echo $(ENV_VAR)
Then you can simply run the make command with arguments
make ENV=ENV1
I have two makefiles in the same directory. Many of the recipes have identical names and here are two solutions:
1. Prefix in make
proja_hello:
#echo "hello A"
projb_hello:
#echo "hello N"
2. Keep two separate files
Project A has makefile. Type make hello.
Project B has a separate make file called projb.mk. Type bmake hello.
This works since I've added alias bmake ='make -f projb.mk to my .bashrc. Note! This command can be called anywhere but only works where projb.mk exists.
Note! You lose autocompletion of make with the alias and typing make -f projb.mk hello is not better than typing make projb_hello.
What is the correct way to get the directory where the currently executing makefile resides?
I'm currently using export ROOT=$(realpath $(dir $(lastword $(MAKEFILE_LIST)))) and am running into some problems where when running make with the exact same options will result in different values for ROOT. About 90%of the time it has the correct value, but in the remaining 10% there are a number of invalid paths.
realpath,abspath,lastword and a couple of more functions were only introduced in GNU Make 3.81 [See ref]. Now you can get the current filename in older versions using words and word:
THIS_MAKEFILE:=$(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
But I am not sure of a workaround for realpath without going to the shell. e.g. this works with make v3.80:
THIS_MAKEFILE_PATH:=$(word $(words $(MAKEFILE_LIST)),$(MAKEFILE_LIST))
THIS_DIR:=$(shell cd $(dir $(THIS_MAKEFILE_PATH));pwd)
THIS_MAKEFILE:=$(notdir $(THIS_MAKEFILE_PATH))
all:
#echo "This makefile is $(THIS_MAKEFILE) in the $(THIS_DIR) directory"
Which gives
$ make -f ../M
This makefile is M in the /home/sandipb directory
Ref: http://cvs.savannah.gnu.org/viewvc/make/NEWS?revision=2.93&root=make&view=markup
$(shell pwd) is not correct since the makefile might exist in a directory other than pwd (as allowed by make -f).
The OP's proposed
export ROOT=$(realpath $(dir $(lastword $(MAKEFILE_LIST))))
is fine, except, s/he probably wants to use firstword instead, especially if the top level makefile (potentially) includes other makefile(s) prior to assiging to ROOT.
The OPs 10% problem could be explained if there was a conditional include 10% of the time prior to the assignment, but, hey, that's a guess...
For your convenience, when GNU make starts (after it has processed any -C options)
it sets the variable CURDIR to the pathname of the current working directory. This value
is never touched by make again: in particular note that if you include files from other
directories the value of CURDIR does not change. The value has the same precedence it
would have if it were set in the makefile (by default, an environment variable CURDIR will
not override this value). Note that setting this variable has no impact on the operation of
make (it does not cause make to change its working directory, for example).
all:
echo $(CURDIR)