make[1]: Command not found - gcc

I am getting below error while building some set of files. Would someone give some pointers on why do I get this error? Am I missing installation of some package?
Snippet of error log:
make[1]: MMD: Command not found
CC drivers/usb/usbhid.libc.o
make[1]: MMD: Command not found
CC drivers/usb/usbmsc.libc.o
make[1]: MMD: Command not found
CC drivers/hid.libc.o
make[1]: MMD: Command not found
AR build/libc.a
make[1]: invalidar: Command not found
Makefile.inc:89: recipe for target 'build/libc.a' failed
Snippet of my makefile:
# macro to define template macros that are used by use_template macro
define create_cc_template
# $1 obj class
# $2 source suffix (c, S)
# $3 additional compiler flags
# $4 additional dependencies
ifn$(EMPTY)def $(1)-objs_$(2)_template
de$(EMPTY)fine $(1)-objs_$(2)_template
$(obj)/$$(1).$(1).o: $$(1).$(2) $(obj)/libpayload-config.h $(4)
#printf " CC $$$$(subst $$$$(obj)/,,$$$$(#))\n"
$(CC) $(3) -MMD $$$$(CFLAGS) -c -o $$$$# $$$$<
en$(EMPTY)def
end$(EMPTY)if
endef

It looks to me as if the CC variable is not defined to anything when you invoke this macro, and the third argument is empty. This means that the recipe make internalizes after the eval is expanded is:
-MMD $$(CFLAGS)...
A quick fix is to escape the variable for CC:
$$(CC) $(3) -MMD ...
I think your expansion model for this is very odd, and probably incorrect in other ways. But, without seeing how this macro is used it's hard to say.
One easy way to debug eval issues is to duplicate the context where the eval appears and replace the eval with the info function. This will print exactly what make will parse, and it should be completely normal and understandable makefile syntax; e.g., change something like:
$(foreach X,$(STUFF),$(eval $(call FOO,$X)))
to:
$(foreach X,$(STUFF),$(info $(call FOO,$X)))
$(foreach X,$(STUFF),$(eval $(call FOO,$X)))

Related

GNU Make: Canned recipe which is meant to generate prerequisites for rule causes error "No rule to make target"

I have this simple Makefile:
define some_canned_recipe
find 'foobar' -print
endef
run-something: $(call some_canned_recipe)
#$(info ** [Make] run-something)
#touch $#
I want the 'run-something' rule to be run if and only if one or more files or directories has changed under subdirectory 'foobar'. When I invoke 'make run-something' inside WSL2 however I get this error:
make: *** No rule to make target 'find', needed by 'run-something'. Stop.
Is there a way to achieve what I want (in terms of dynamically generating the prerequisites for the 'run-something' rule)?
PS: I'm aware that a silly solution would be:
define some_canned_recipe
$(shell find 'foobar' -print)
endef
even though this works its not really a good idea because $(shell ...) will run even when the rule 'run-something' is not being targeted.
You can do this using secondary expansion combined with implicit rules:
.SECONDEXPANSION:
run-something:
run-%: $$(shell find 'foobar' -print)
#$(info ** [Make] $#)
#touch $#
(note the $$ before the shell function)
I make no comments on whether I think this is the best way to do it :).

Conditional inclusion of sub-Makefiles based on ifeq test

Is there a way to conditionally include a sub-Makefile based on the result of a an ifeq test as suggested below
CC = g++
CENTOS_VERSION := $(shell rpm -E %{rhel})
TARGET = main
$(TARGET): $(TARGET).cpp
ifeq ($(CENTOS_VERSION),6)
#echo "Building on CentOS 6"
include(CentOS6_Makefile.mk)
else
#echo "Building on CentOS 7"
include(CentOS7_Makefile.mk)
endif
$(CC) $(CFLAGS) -o $(TARGET) $(TARGET).cpp
This does not work and generates the error message
Building on CentOS 6
include(CentOS6_Makefile.mk)
/bin/sh: -c: line 0: syntax error near unexpected token `CentOS6_Makefile.mk'
/bin/sh: -c: line 0: `include(CentOS6_Makefile.mk)'
make: *** [main] Error 1
Based on the answer by #MadScientist the solution to my problem boils down to just 2 lines
CENTOS_VERSION := $(shell rpm -E %{rhel})
include CentOS$(CENTOS_VERSION)_Makefile.mk
Your problem is not related to ifeq; if you remove the ifeq and always include one or the other you'll see the same problem.
First, your syntax for including files is wrong. There are no parentheses around filenames in make's include directive. It should just be:
include CentOS6_Makefile.mk
Second, you cannot use makefile processor commands like include as part of a recipe (that is, indented by a TAB). In a make recipe ALL lines that indented by TAB are passed to the shell as commands to run to build the target, they are not interpreted by make (except to expand macros). Also, you cannot include some other makefile in the middle of a recipe: once make starts to include a new makefile that's the end of any recipe that is currently being defined.
You can do this:
CENTOS_VERSION := $(shell rpm -E %{rhel})
ifneq ($(CENTOS_VERSION),6)
CENTOS_VERSION := 7
endif
include CentOS$(CENTOS_VERSION)_Makefile.mk
$(TARGET): $(TARGET).cpp
#echo "Building on CentOS $(CENTOS_VERSION)"
$(CC) $(CFLAGS) -o $(TARGET) $(TARGET).cpp

Match patten rule before explicit rule

I'm trying to generically add some behaviour to every target in a Makefile, without modifying the targets.
My current attempt is thus:
%: $*
#echo 'Logging $* target'
.PHONY: test
test:
#echo 'Inside explicit test target'
When I run make test, I'd like to match the % pattern rule, which would execute test as a prerequisite ($* expanding to the pattern stem), and then log the target that was run.
$ make test
Inside explicit test target
Logging test target
Instead, what happens is that make test matches the explicit test target (presumably since it's a closer match):
$ make test
Inside explicit test target
How can I get this to work, without changing the explicit test target?
EDIT:
Another attempt...
.SECONDEXPANSION:
%: $$*
#echo 'Logging $* target'
results in
$ make test
make: Circular Makefile <- Makefile dependency dropped.
inside actual test target
I appears from your own answer, which has beaten me to the punch, that
you're concerned only to trigger a preliminary action for targets that are
mentioned on the commandline - $(MAKECMDGOALS). From the posting I took
it that you wanted such an action for "every target in a Makefile", which
would include all targets that are prerequisite to the commandline targets or,
if there are no commandline targets, to the default target.
Anyhow, you may still be interested in a solution to the more general problem.
You want a preliminary action to be executed before the recipe for every target.
Your question is: how to match a patten rule before explicit rule?
This is an XY way of posing the problem, because make will consult pattern
rules to find a way of making a target only if you don't give it an explicit
recipe. You know, for example, that make has a pre-defined pattern rule for
making an .o file from a .c file. Even so, if my makefile is:
test.o:
#echo $#
then make prints test.o, without any attempt to find test.c and compile it.
And if my make file is:
test.o: test.c
#echo $#
test.c:
#echo $#
then make prints:
test.c
test.o
needing no resort to the pattern rule. But if my makefile is:
test.o: test.c
Then make says:
make: *** No rule to make target 'test.c', needed by 'test.o'. Stop
So you can't do what you're after in the way your question supposes,
because the preliminary action you want to provoke from the pattern
rule could be provoked only if there were no other action for the target.
In that case the reasons for the failures of your two posted attempts are fairly academic,
and you may wish to scroll to The Chase.
In your first attempt, with:
%: $*
#echo 'Logging $* target'
The pattern rule - which is unemployed by make test - is equivalent to:
%:
#echo 'Logging $* target'
because $* only assumes a value in the recipe, not in the pattern rule. You
can make this pattern rule be employed by making any target for which the
makefile does not provide a recipe, e.g. make nonsuch will print Logging nonsuch target;
but that is of no use.
The second attempt, with:
.SECONDEXPANSION:
%: $$*
#echo 'Logging $* target'
does the right thing to create the rule you intend to create. But the
meaning of that rule is:
<target>: <target>
#echo 'Logging <target> target'
making every target to which this rule is applied a prerequisite of itself.
Inevitably this will result in a circular dependency error for all such targets.
As you saw, this circularity does not affect the your test target because
it has an explicit recipe and does not employ the rule. But it does provoke
the surprising error:
make: Circular Makefile <- Makefile dependency dropped.
That happens because the first target that make automatically considers is
the makefile itself. Unlike the test target, you have no recipe for
the makefile; so the pattern rule applies to it, making the makefile dependent
on itself.
The Chase
You can achieve what you want by a different approach. In a actual project
it is more than likely that in any makefile you can compute a list of
all possible targets. From this you can generate a corresponding list of
auxiliary targets, say, target => target.prelim, where the
sole purpose of target.prelim is to provoke, when it should and not
otherwise, the required preliminary action for target; and you can get make
to generate a list of order-only rules, target: | target.prelim,
for each target, such that target.prelim will not be considered in determining whether target
must be made, but will be made before target whenever target needs to be made.
Here is an illustration:
SRCS := main.c foo.c
OBJS := $(SRCS:.c=.o)
TARGETS := all prog $(OBJS)
PRELIMS := $(patsubst %,%.prelim,$(TARGETS))
define prelim_rule =
$(1): | $(1).prelim
endef
$(foreach target,$(TARGETS),$(eval $(call prelim_rule,$(target))))
.PHONY: all
all: prog
prog: $(OBJS)
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o $# $(OBJS) $(LIBS)
clean:
rm -f $(OBJS) $(PRELIMS) prog
%.prelim:
#echo "Logging target $(#:%.prelim=%)"
#touch $#
And a sample session:
$ make
Logging target all
Logging target main.o
cc -c -o main.o main.c
Logging target foo.o
cc -c -o foo.o foo.c
Logging target prog
cc -o prog main.o foo.o
$ make
make: Nothing to be done for 'all'.
$ make clean
rm -f main.o foo.o all.prelim prog.prelim main.o.prelim foo.o.prelim prog
$ make main.o
Logging target main.o
cc -c -o main.o main.c
$ make main.o
make: 'main.o' is up to date.
$ # A prelim can't out-date its target...
$ touch main.o.prelim
$ make main.o
make: 'main.o' is up to date.
I realise that this isn't answering my question as asked, but it has the effect I want - executing a shell command as late in the Makefile processing as possible.
MYVAR?=foo
.PHONY: test
test:
#echo 'Inside test target'
LOG=$(shell echo 'Logging $(MAKECMDGOALS), myvar=$(MYVAR)' > log)
.SECONDEXPANSION:
force: $$(LOG)
LOG is a deferred variable, so is not expanded until Make evaluates the prerequisite list of the force target.
In a single Makefile, the .SECONDEXPANSION: part is not needed, since the force target is evaluated after MYVAR is set.
However, if I move the LOG variable and force variable into a sub-makefile, it would be easy to include subMakefile before the MYVAR?= line - which would not work.
By specifying .SECONDEXPANSION for force, the reliance on ordering is removed.

How to get pattern rules to match file names with spaces in Makefile?

In the GNU make docs, '%' is documented to match "any nonempty substring". However, it seems it actually only matches non-empty substrings that do not contain whitespace. For example, say you do this:
mkdir /tmp/foo
cd /tmp/foo
echo 'int main() { return 0; }' > "test.c"
echo 'int main() { return 0; }' > "test space.c"
Now, you should be able to build these using GNU Make's built-in pattern rules:
anthony#Zia:/tmp/foo$ make "test"
cc test.c -o test
anthony#Zia:/tmp/foo$ make "test space"
make: *** No rule to make target `test space'. Stop.
The same problem happens when you write a makefile.
anthony#Zia:/tmp/foo$ rm test
anthony#Zia:/tmp/foo$ echo 'all: test test\ space' > Makefile
anthony#Zia:/tmp/foo$ make
cc test.c -o test
make: *** No rule to make target `test space', needed by `all'. Stop.
Even if you explicitly add in a %: %.c rule, the result is the same. But if you add in an explicit rule to the Makefile, like this, it works:
test\ space: test\ space.c
$(CC) -o "$#" "$<" # first char is tab, of course.
Is there a trick to get spaces to work with implicit rules?
edit
I've sent a bug report: http://lists.gnu.org/archive/html/bug-make/2011-06/msg00002.html
I don't believe so. The notion of a list of whitespace-separated tokens being passed around as a string is pretty deeply ingrained in make. Those lists are parsed and reparsed. There's a reason why spaces in directory and file names is considered bad practice in the UNIX world.
This is a kludge, but as of today, people still get given paths with spaces in sometimes.
Anyway, making a link instead of directly accessing the directory in the % rule works OK.
# GNU makefile
DIR_WITH_SPACE=/c/Users/me/My\ Code
# *** DOESN'T WORK ***
%.h : $(DIR_WITH_SPACE)/%.h
cp -v "$<" "$#"
fix:
ln -s $(DIR_WITH_SPACES) dir_fixed
# Does work :)
%.h : dir_fixed/%.h
cp -v "$<" "$#"

How to generate Makefile rule

I want to do generate rules in Makefile by this:
# $(call cc-defs, ccfiles)
define cc-defs
$1.files = $(patsubst %.cc,%.proto,$1)
$1: $1.files
endef
$(foreach ccfile,$(ccfiles), $(eval $(call cc-defs, $(ccfile))))
but failed with error message:
Makefile:19: *** commands commence before first target. Stop.
Instead that, I can do this by:
# $(call cc-defs, ccfiles)
define cc-defs
$1.files = $(patsubst %.cc,%.proto,$1)
endef
$(foreach ccfile,$(ccfiles), $(eval $(call cc-defs, $(ccfile))))
$(foreach ccfile,$(ccfiles), $(eval $(ccfile):$($(ccfile).files)))
How to make the 1st method works?
Which version of make are you using? $(eval) only appeared in 3.80 (and it only properly works in 3.81 IMHO).
To debug makefiles you'll often have to revert to printf debugging. To see what's going on, replace eval with warning. This shows what you are giving to make:
$ make --warn
Makefile:6: warning: undefined variable `ccfiles'
make: *** No targets. Stop.
(Aside: --warn-undefined-variables is always useful. Undefined variables are untidy.)
O.K., so we need to define $ccfiles. Now we get the for loop firing:
$ make --warn ccfiles=1.cc
Makefile:6: 1.c.files = 1.cc
1.cc: 1.c.files
make: *** No targets. Stop.
Fine. You have given make no recipes, nor a default target. You also have missed out on some variable expansion, and have an extra space in the $(for) invocation (naughty!). Try this:
$ cat Makefile
# $(call cc-defs,ccfiles)
define cc-defs
$1.files = $(patsubst %.cc,%.proto,$1)
$1: $$($1.files) ; echo '[$$#]'
endef
$(foreach ccfile,$(ccfiles), $(eval $(call cc-defs,$(ccfile))))
$ make ccfiles=1.cc
make: *** No rule to make target `1.proto', needed by `1.cc'. Stop.
Note that if all you want to do is for all files in a variable to depend on (or be made from) .proto files, you don't need $(eval).
A pattern rule will do (and will work in older versions of GNU Make too):
$(ccfiles): %.cc: %.proto
echo '[$#]'
This does have the side effect of complaining when the ccfiles variable contains any entries not named *.cc (although it still executes the rule in that case).
$ make ccfiles=hello.cc
make: *** No rule to make target `hello.proto', needed by `hello.cc'. Stop.
$ touch hello.proto
$ make ccfiles=hello.cc
[hello.cc]
$ make ccfiles=hello.c
Makefile:1: target `hello.c' doesn't match the target pattern
[hello.c]
If the variable can contain many things but you only want to add this processing to .cc files, simply add a filter:
$(filter %.cc,$(ccfiles)): %.cc: %.proto
echo '[$#]'
This then results in:
$ make ccfiles=hello.cc
[hello.cc]
$ make ccfiles=hello.c
make: *** No targets. Stop.

Resources