I have several files for my GNU make setup. In this.mk, I have
define this_template
THIS = $(1)
THIS_DIR = $(2)
THIS_LIBNAME = $(3)
THIS_EXTERNAL_DIRS = $(4)
...
endef
In my Makefile, I have
include this.mk
... # define VAR1 and VAR2
include util/make.mk
...
util/make.mk contains one line:
$(eval $(call this_template,UTIL,$(VAR1),plutil,$(VAR2)))
However, when I run make, I get
util/make.mk:1: *** recipe commences before first target. Stop.
Reading up on other questions that relate to this error message, what I'm understanding is that this error is caused by evaluating a string which begins in a way that looks like it's inside of a recipe. However, what I'm evaluating does not.
This error means that (a) the line begins with a TAB (or more specifically, with the character defined as .RECIPE_PREFIX if your version of GNU make supports it), and (b) it is not recognized as any sort of make command such as a rule introduction, etc.
Given what you've shared with us here, that cannot happen. So there must be something going on that you haven't shared with us. Maybe one of the other included makefiles is modifying the this_template variable to contain something else.
The way to debug eval problems is always the same no matter what they are: change the eval to info so that make will print out what it will evaluate. This usually makes it pretty obvious what the problem is. So use:
$(info $(call this_template,UTIL,$(VAR1),plutil,$(VAR2)))
$(eval $(call this_template,UTIL,$(VAR1),plutil,$(VAR2)))
and see what make shows you.
I am trying to use a makefile in order to compile my story in LaTex. I am trying to use a variable in order to complete the file name for my story. If I simply run make, it works. However, I need to be able to run a specific command from make.
pdflatex "\\def\\isdraft{1} \\input{FMPGC.tex}"
How would I create a variable from PROJ + OBJS so that I could do something like what I am trying to do below. If I run the below code for make draft, it fails out and APPEARS that it is adding numerous spaces between FMPGC and tex.
How could I combine two variables with a "." symbol between the pair so I can compile my story in the below command. I have also experimented with not escaping the \ symbols and that seems to have no effect.
# This makefile compiles my story using LaTex
# Author:
#
# VARS - Variables to be changed for reuse of my script
PROJ = "FMPGC" # The name of the project
OBJS = "tex" # The extension for the content
AUXS = "aux" # The aux extensions
CHAP = "chapters/" # The chapters
FOO = $(PROJ) += "."
F002 = $(FOO) += $(OBJS)
# Configuration:
CC = pdflatex # The compiler
# Rules
all:
$(CC) $(PROJ).$(OBJS)
draft:
$(CC) "\\def\\isdraft{1} \\input{$(FOO2)}"
The current error comes from it not inputting anything into the variable as of right now -
pdflatex "\\def\\isdraft{1} \\input{}"
Below seems to be the exact issue.
<*> \def\isdraft{1} F
MPGC.tex
---------------- Updated Make File
# This makefile compiles my story using LaTex
# Author:
#
# VARS - Variables to be changed for reuse of my script
# The name of the project
PROJ:=FMPGC
# The extension for the content
OBJS:=tex
# The aux extensions
AUXS:=aux
# The chapters
CHAP:=chapters/
# Configuration:
# The compiler
CC=pdflatex
# Rules
all:
$(CC) $(PROJ).$(OBJS);
draft:
$(CC) "\def\isdraft{1} $(PROJ).$(OBJS)";
Updated Error ----
pdflatex "\def\isdraft{1} FMPGC.tex";
This is pdfTeX, Version 3.14159265-2.6-1.40.15 (TeX Live 2014) (preloaded format=pdflatex)
restricted \write18 enabled.
entering extended mode
LaTeX2e <2014/05/01>
Babel <3.9k> and hyphenation patterns for 21 languages loaded.
! LaTeX Error: Missing \begin{document}.
See the LaTeX manual or LaTeX Companion for explanation.
Type H <return> for immediate help.
...
<*> \def\isdraft{1} F
MPGC.tex
?
! Emergency stop.
...
<*> \def\isdraft{1} F
MPGC.tex
! ==> Fatal error occurred, no output PDF file produced!
Transcript written on texput.log.
In the The Two Flavors of Variables section of the GNU make Manual we find:
If you put whitespace at the end of a variable value, it is a good idea to put a comment like that at the end of the line to make your intent clear. Conversely, if you do not want any whitespace characters at the end of your variable value, you must remember not to put a random comment on the end of the line after some whitespace, such as this:
dir := /foo/bar # directory to put the frobs in
Here the value of the variable dir is ‘/foo/bar ’ (with four trailing spaces), which was probably not the intention. (Imagine something like ‘$(dir)/file’ with this definition!)
Thanks to #Etan Reisner I was able to fix it after reviewing the documentation.
My make file now looks like this -
# This makefile compiles my story using LaTex
# Author:
#
# VARS - Variables to be changed for reuse of my script
# The name of the project
PROJ:=FMPGC
# The extension for the content
OBJS:=tex
# The aux extensions
AUXS:=aux
# The chapters
CHAP:=chapters/
# Configuration:
# The compiler
CC=pdflatex
# Rules
all:
$(CC) $(PROJ).$(OBJS);
draft:
$(CC) "\def\isdraft{1} \input{$(PROJ).$(OBJS)}";
I can now compile my document and it adds my variable for use inside of LaTex.
I'm trying to create a common template to generate rules build a set of test cases and place them in unique target locations but have hit a bit of snag with the define directive. The following is the relevant section of my Makefile:
ROOT=../..
PLATFORM=akyboard_gcc
# include all the test cases for the current platform
# They add to the TEST_CASES variable
TEST_CASES=A B
A_FILES = a1.c a2.c
B_FILES = b1.c b2.c
check: $(TEST_CASES:%=check_%)
define CHECK_template
# build artifact directories
$(1)_BLDDIR=$(ROOT)/build/$(PLATFORM)/$(1)
$(1)_OBJDIR=$$($(1)_BLDDIR)/obj
$(1)_EXEDIR=$$($(1)_BLDDIR)/exe
# prepend src/ to all the files that are part of the test case
$(1)_FILES := $($(1:%=%_FILES):%=src/%)
# add the test runner as one of the files to be compiled
$(1)_FILES += test_runner/$(PLATFORM)/main.c
# construct list of objects generated by sources
$(1)_OBJ = $($(1)_FILES:%.c=$$($(1)_OBJDIR)/%.o)
# This creates a rule such as check_{test_case}:
check_$(1): $$($(1)_OBJ)
#echo 1 $(1)
#echo 2 $$($(1)_FILES)
#echo 3 $$($(1)_OBJ)
#echo 5 $$($(1)_OBJDIR)
#echo 4 $$($(1)_BLDDIR)
#echo 6 $$($(1)_EXEDIR)
$$($(1)_OBJDIR)/%.o: $(ROOT)/%.c
#echo coconut
endef
$(foreach testcase, $(TEST_CASES), \
$(eval $(call CHECK_template,$(testcase))) \
)
Issuing "make check" gives the following error
*** No rule to make target `../../build/akyboard_gcc/A/obj/a1.o', needed by `check_A'. Stop.
If I manually create the target rules below it builds without errors
../../build/akyboard_gcc/A/obj/a1.o:
../../build/akyboard_gcc/A/obj/a2.o:
../../build/akyboard_gcc/B/obj/b1.o:
../../build/akyboard_gcc/B/obj/b2.o:
But changing rules like below causes the build error:
../../build/akyboard_gcc/A/obj/%.o:
Would be grateful for any help.
You can find what wrong with your template by replacing eval with info call.
$(foreach testcase, $(TEST_CASES), $(info $(call CHECK_template,$(testcase))))
And your template is fine. But you probably have a problem with pattern rules.
From GNU make manual:
A pattern rule can be used to build a given file only if there is a
target pattern that matches the file name, and all prerequisites in
that rule either exist or can be built.
Perhaps you don't have required sources in $(ROOT) directory. And make just can't create a rule for object file from pattern.
In my makefile, I have a variable 'NDK_PROJECT_PATH', my question is how can I print it out when it compiles?
I read Make file echo displaying "$PATH" string and I tried:
#echo $(NDK_PROJECT_PATH)
#echo $(value NDK_PROJECT_PATH)
Both gives me
"build-local.mk:102: *** missing separator. Stop."
Any one knows why it is not working for me?
You can print out variables as the makefile is read (assuming GNU make as you have tagged this question appropriately) using this method (with a variable named "var"):
$(info $$var is [${var}])
You can add this construct to any recipe to see what make will pass to the shell:
.PHONY: all
all: ; $(info $$var is [${var}])echo Hello world
Now, what happens here is that make stores the entire recipe ($(info $$var is [${var}])echo Hello world) as a single recursively expanded variable. When make decides to run the recipe (for instance when you tell it to build all), it expands the variable, and then passes each resulting line separately to the shell.
So, in painful detail:
It expands $(info $$var is [${var}])echo Hello world
To do this it first expands $(info $$var is [${var}])
$$ becomes literal $
${var} becomes :-) (say)
The side effect is that $var is [:-)] appears on standard out
The expansion of the $(info...) though is empty
Make is left with echo Hello world
Make prints echo Hello world on stdout first to let you know what it's going to ask the shell to do
The shell prints Hello world on stdout.
As per the GNU Make manual and also pointed by 'bobbogo' in the below answer,
you can use info / warning / error to display text.
$(error text…)
$(warning text…)
$(info text…)
To print variables,
$(error VAR is $(VAR))
$(warning VAR is $(VAR))
$(info VAR is $(VAR))
'error' would stop the make execution, after showing the error string
from a "Mr. Make post"
https://www.cmcrossroads.com/article/printing-value-makefile-variable
Add the following rule to your Makefile:
print-% : ; #echo $* = $($*)
Then, if you want to find out the value of a makefile variable, just:
make print-VARIABLE
and it will return:
VARIABLE = the_value_of_the_variable
If you simply want some output, you want to use $(info) by itself. You can do that anywhere in a Makefile, and it will show when that line is evaluated:
$(info VAR="$(VAR)")
Will output VAR="<value of VAR>" whenever make processes that line. This behavior is very position dependent, so you must make sure that the $(info) expansion happens AFTER everything that could modify $(VAR) has already happened!
A more generic option is to create a special rule for printing the value of a variable. Generally speaking, rules are executed after variables are assigned, so this will show you the value that is actually being used. (Though, it is possible for a rule to change a variable.) Good formatting will help clarify what a variable is set to, and the $(flavor) function will tell you what kind of a variable something is. So in this rule:
print-% : ; $(info $* is a $(flavor $*) variable set to [$($*)]) #true
$* expands to the stem that the % pattern matched in the rule.
$($*) expands to the value of the variable whose name is given by by $*.
The [ and ] clearly delineate the variable expansion.
You could also use " and " or similar.
$(flavor $*) tells you what kind of variable it is. NOTE: $(flavor)
takes a variable name, and not its expansion.
So if you say make print-LDFLAGS, you get $(flavor LDFLAGS),
which is what you want.
$(info text) provides output.
Make prints text on its stdout as a side-effect of the expansion.
The expansion of $(info) though is empty.
You can think of it like #echo,
but importantly it doesn't use the shell,
so you don't have to worry about shell quoting rules.
#true is there just to provide a command for the rule.
Without that,
make will also output print-blah is up to date. I feel #true makes it more clear that it's meant to be a no-op.
Running it, you get
$ make print-LDFLAGS
LDFLAGS is a recursive variable set to [-L/Users/...]
All versions of make require that command lines be indented with a TAB (not space) as the first character in the line. If you showed us the entire rule instead of just the two lines in question we could give a clearer answer, but it should be something like:
myTarget: myDependencies
#echo hi
where the first character in the second line must be TAB.
#echo $(NDK_PROJECT_PATH) is the good way to do it.
I don't think the error comes from there.
Generally this error appears when you mistyped the intendation : I think you have spaces where you should have a tab.
No need to modify the Makefile.
$ cat printvars.mak
print-%:
#echo '$*=$($*)'
$ cd /to/Makefile/dir
$ make -f ~/printvars.mak -f Makefile print-VARIABLE
Run make -n; it shows you the value of the variable..
Makefile...
all:
#echo $(NDK_PROJECT_PATH)
Command:
export NDK_PROJECT_PATH=/opt/ndk/project
make -n
Output:
echo /opt/ndk/project
This makefile will generate the 'missing separator' error message:
all
#echo NDK_PROJECT_PATH=$(NDK_PROJECT_PATH)
done:
#echo "All done"
There's a tab before the #echo "All done" (though the done: rule and action are largely superfluous), but not before the #echo PATH=$(PATH).
The trouble is that the line starting all should either have a colon : or an equals = to indicate that it is a target line or a macro line, and it has neither, so the separator is missing.
The action that echoes the value of a variable must be associated with a target, possibly a dummy or PHONEY target. And that target line must have a colon on it. If you add a : after all in the example makefile and replace the leading blanks on the next line by a tab, it will work sanely.
You probably have an analogous problem near line 102 in the original makefile. If you showed 5 non-blank, non-comment lines before the echo operations that are failing, it would probably be possible to finish the diagnosis. However, since the question was asked in May 2013, it is unlikely that the broken makefile is still available now (August 2014), so this answer can't be validated formally. It can only be used to illustrate a plausible way in which the problem occurred.
The problem is that echo works only under an execution block. i.e. anything after "xx:"
So anything above the first execution block is just initialization so no execution command can used.
So create a execution blocl
If you don't want to modify the Makefile itself, you can use --eval to add a new target, and then execute the new target, e.g.
make --eval='print-tests:
#echo TESTS $(TESTS)
' print-tests
You can insert the required TAB character in the command line using CTRL-V, TAB
example Makefile from above:
all: do-something
TESTS=
TESTS+='a'
TESTS+='b'
TESTS+='c'
do-something:
#echo "doing something"
#echo "running tests $(TESTS)"
#exit 1
This can be done in a generic way and can be very useful when debugging a complex makefile. Following the same technique as described in another answer, you can insert the following into any makefile:
# if the first command line argument is "print"
ifeq ($(firstword $(MAKECMDGOALS)),print)
# take the rest of the arguments as variable names
VAR_NAMES := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))
# turn them into do-nothing targets
$(eval $(VAR_NAMES):;#:))
# then print them
.PHONY: print
print:
#$(foreach var,$(VAR_NAMES),\
echo '$(var) = $($(var))';)
endif
Then you can just do "make print" to dump the value of any variable:
$ make print CXXFLAGS
CXXFLAGS = -g -Wall
You could create a vars rule in your make file, like this:
dispvar = echo $(1)=$($(1)) ; echo
.PHONY: vars
vars:
#$(call dispvar,SOMEVAR1)
#$(call dispvar,SOMEVAR2)
There are some more robust ways to dump all variables here: gnu make: list the values of all variables (or "macros") in a particular run.
if you use android make (mka) #echo $(NDK_PROJECT_PATH) will not work and gives you error *** missing separator. Stop."
use this answer if you are trying to print variables in android make
NDK_PROJECT_PATH := some_value
$(warning $(NDK_PROJECT_PATH))
that worked for me
I usually echo with an error if I wanted to see the variable value.(Only if you wanted to see the value. It will stop execution.)
#echo $(error NDK_PROJECT_PATH= $(NDK_PROJECT_PATH))
The following command does it for me on Windows:
Path | tr ; "\n"
I am using Makefiles.
However, there is a command (zsh script) I want executed before any targets is executed.
How do I do this?
Thanks!
There are several techniques to have code executed before targets are built. Which one you should choose depends a little on exactly what you want to do, and why you want to do it. (What does the zsh script do? Why do you have to execute it?)
You can either do like #John suggests; placing the zsh script as the first dependency. You should then mark the zsh target as .PHONY unless it actually generates a file named zsh.
Another solution (in GNU make, at least) is to invoke the $(shell ...) function as part of a variable assignment:
ZSH_RESULT:=$(shell zsh myscript.zsh)
This will execute the script as soon as the makefile is parsed, and before any targets are executed. It will also execute the script if you invoke the makefile recursively.
Just make that a dependancy of one of the other targets
foo.obj : zsh foo.c
rule for compileing foo.c
zsh:
rule for running zsh script.
or alternatively, make your first target depend on it
goal: zsh foo.exe
Solution for both preprocessing and postprocessing in makefiles using MAKECMDGOALS and double colon rules.
MAKECMDGOALS are the targets listed on the command line.
First step is to get the first and last targets from the command line,
or if there are no targets listed, use the default target.
ifneq ($(MAKECMDGOALS),)
FIRST_GOAL := $(word 1, $(MAKECMDGOALS))
LAST_GOAL := $(word $(words $(MAKECMDGOALS)), $(MAKECMDGOALS))
else
FIRST_GOAL := all
LAST_GOAL := all
endif
Double colon rules allow multiple recipes for the same target executed in order. You'll have to change all command line targets to double colon rules.
#Dummy rule to set the default
.PHONY: all
all ::
#Preprocessing
$(FIRST_GOAL) ::
echo "Starting make..."
all :: normal_prerequistes
normal_recipe
other_stuff
#Postprocessing
$(LAST_GOAL) ::
echo "All done..."
There is a solution without modifying your existing Makefile (main difference with the accepted answer). 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 accepted answer).