CLion does not accept `$(eval include <some file>)` - makefile

Question:
CLion gives an error on the following line in a Makefile:
$(eval include <file name>.mk)
The GNU Make version CLion points to 4.2.1. The error provided by CLion is
'!=', $, '(', '+=', ',', ':', '::=', ':=', ';', , , '=', '?=', '`', chars, split, '{', '|' or '}' expected, got 'include'
Context:
The reason I need this syntax is because I want to write something like
$(foreach MODULE,$(MODULES), \
$(eval SRC_DIRS :=) \
$(eval include $(MODULE)/$(MODULE).mk) \
... \
)
where the .mk files are appending directory names to the SRC_DIRS variable, and after the inclusion, I am using the content of SRC_DIRS to collect source files and generate object files names, etc. CLion doesn't like this syntax. However, this works fine if I just invoke make on the command line.

Related

Replace dot . in make file recipe

In a make rule like below. I want to replace to the dot "." character
APPS := example.helloworld example.sample
$(APPS):
#appdir=`echo $#|sed -e s/\./\//`
# do something...
It doesn't work as make does not escape the "\." and "/" characters. Is there an alternative to this?
Note: I can't change app names and I can't use gnu make.
Found a workaround using shell variables. It works like this:
APPS := example.helloworld example.sample
$(APPS):
#dot="\."; \
#slash="\/"; \
appdir=`echo $#|sed -e s/$$dot/$$slash/`
# do something...

Insert a new-line in a Makefile $(foreach ) loop

I'm compiling a large list of files in a Makefile.
my.list : ${deps}
rm -f $#
$(foreach F,$^,echo "${F}" >> $#;)
but ${deps} can be large and the generated command-line could be too large for one SHELL call. Is it possible to replace ';' by a newline '\n' ?
As already mentioned in Jonathan Wakely's answer, the straightforward answer is
define newline
endef
Interestingly enough, for all chars except newline there is an easier way to get non-printable characters into variables with some help from the shell, e.g.:
tab := $(shell printf '\011')
It won't work here, though, because the builtin shell function replaces all newlines by spaces.
The version above is still a bit fragile though, in particular when combining with automake which will silently remove the second consecutive newline from the input file, turning newline into an empty variable. To force it to keep the newline, we can extend the snippet:
blank :=
define newline
$(blank)
endef
Finally, to actually get a separate shell command for each dependency, you need to run the generated string through eval:
define generate-rule =
my.list : $(1)
rm -f $$#
$(foreach F,$$^,$(newline)$(tab)echo "${F}" >> $#)
endef
$(eval $(call generate-rule,$(deps)))
You can define a variable that expands to a newline like so:
define NEWLINE
endef
Now you can use $(NEWLINE) to expand to a newline.
This won't change anything though, the foreach will still generate a single command with embedded newlines between the statements, rather than a single command with ; between the statements.
Possibly the most straight-forward answer is to use:
#printf "\n"
You can also use this, as I commonly do, to show a description when each new make target executes. An example target:
.PHONY: clean-version
clean-version: ## Reset version back to committed version number
#printf "\n## Reset version to last committed version number ##\n\n"; \
$(GIT) checkout $(VERSION_FILE);
Replacing ';' by a carriage-return will produce a string of the same size, subject to the same problem.
"foreach" is simply a string expansion. If you want to execute a separate command for each item, you can use a for loop.
my.list : ${deps}
rm -f $#
(for F in $^; do echo $$F >> $# ; done)
Edit -- after some revisions, it looks like the only problem with my original was not due to the whitespaces, but with MAKE_O. I've fixed it in my version, but I'll mostly be removing them below.
By the way the original post was written, I'm not sure if my solution will be relevant. However, I found myself in the middle of a define already inside a foreach, and couldn't figure out how to insert a newline using any of the other answers as given.
Solution:
define BR
$(1)
endef
define MAKE_O
$(1): $(wildcard $(1:obj/%.o=src/%.cpp)); \
$(CXX) ... -c $$< \$(call BR)-o $1 ... \
\$(call BR)&& touch $$#
endef
$(foreach N,main.o,$(eval $(call MAKE_O,$(N))))
Desired output (compilation is truncated from auto-dependency generation, hence the touch):
> make obj/main.o
g++ ... -c src/main.cpp \
-o obj/main.o ... \
&& touch obj/main.o
I changed BR to perform the indentation but leave the end of the line up to you:
define BR
$(1)
$(1:%= ) #<remove this comment
endef
define MAKE_O
$(1): $(wildcard $(1:obj/%.o=src/%.cpp)); \
$(CXX) ... -c $$< $(call BR,\)-o $1 ... \
$(call BR,\)&& touch $$#
endef
$(foreach N,main.o,$(eval $(call MAKE_O,$(N))))
The markup won't help to show this, but line 2 of BR is $(1:%=_space_)_tab_ (the comment itself is not allowed.) Result:
> make -n obj/main.o
g++ obj/main.o -c \
-o obj/main.o && \
echo statement on new line
I used $(call BR,\) so that the newline was not parsed as an escape of the new line, and $(1:%=space)tab so that the tab is forced (many similar rules have been defined, like SPACE:=$(SPACE) $(SPACE) without a prior value.) The variable left of the whitespace must evaluate to something. To be clear, removing the whitespace before and after the call: ...lastword$(call BR,\)firstword... yields ...lastword\n\tfirstword..., or written out,
[^]...lastword \[$]
[^]$(call BR,\)firstword...[$]
...yields...
[^]...lastword \[$]
[^] firstword...[$]
to achieve the same (using ^,$ to denote the beginning and end of the line. Someone else will probably know how to format/annotate this better.)
My syntax highlighter is decidedly unimpressed with the 'escaped' parentheses and trailing whitespace, but the result is decent.

make error (Windows) : line 1: syntax error near unexpected token `,'

I'm a starter at this(make), and having some problems trying to grep for a text in a file (as part of the make process on Windows). The larger problem I'm trying to solve is to check whether all binary executables in a given directory have their respective dependencies satisfied. I use depends.exe (Dependency Walker) for the later part, whose output file I'm trying to grep, and possibly abort the build process if the dependency validation fails.
binary-dependency-validate:
for BINARYEXEC in $(shell $(PATH_TO_FIND_EXE) $(PRE_DEFINED_DIR) -name "*.exe"); do \
$(PATH_TO_DEPENDS_EXE) /c /pb /ot $(PRE_DEFINED_DIR)/$$BINARYEXEC-depends.txt $(PRE_DEFINED_DIR)/$$BINARYEXEC ; \
ifeq ($(shell $(PATH_TO_GREP_EXE) "Error: At least one required implicit or forwarded dependency was not found." $(PRE_DEFINED_DIR)/$$BINARYEXEC-depends.txt),); \
#echo "Dependency ok" ; \
endif ; \
done
I'm encountering the following error :
line 1: syntax error near unexpected token `,'
Any suggestions would greatly help. I looked at this post and tried aligning ifeq without indentation as well (that didn't help either.)
The problem is that you are mixing Make language with shell language.
A makefile contains rules, and a rule contains commands which are executed by a shell:
target:
first command
second command
The commands are in shell language, and each command must be preceded by a TAB.
There are conditionals in Make:
ifeq (foo, bar)
VAR = something
endif
(The indentation is just for the eye.)
There are also conditionals in the various scripting languages:
if [ -f log ]
then
echo "log exists."
fi
A Make conditional can enclose a command within a rule:
target:
ifeq (foo, bar)
first command
endif
second command
Make will evaluate this conditional before running the rule, and there must be no TAB before ifeq or endif, because Make must not interpret them as commands to be passed to the shell.
A command (in a rule) can contain a shell conditional:
target:
if [ -f log ]; \
then echo "log exists." ; \
fi
The indentation before if is a TAB. The other whitespace is for the eye.
Your makefile has a Make conditional in the middle of a shell command; Make can't evaluate the conditional before the command executes, and the shell can't understand Make syntax. You should use a shell conditional.
It seems like you have a stray comma on the ifeq line
binary-dependency-validate:
for BINARYEXEC in $(shell $(PATH_TO_FIND_EXE) $(PRE_DEFINED_DIR) -name "*.exe"); do \
$(PATH_TO_DEPENDS_EXE) /c /pb /ot $(PRE_DEFINED_DIR)/$$BINARYEXEC-depends.txt $(PRE_DEFINED_DIR)/$$BINARYEXEC ; \
ifeq ($(shell $(PATH_TO_GREP_EXE) "Error: At least one required implicit or forwarded dependency was not found." $(PRE_DEFINED_DIR)/$$BINARYEXEC-depends.txt)); \
#echo "Dependency ok" ; \
endif ; \
done

ifeq issue I try to understand

is my first question here and first time I manage GNU Make so I want to explain my problem.perhaps you could help me to find a light at the end of this tunnel.
That thing Im trying to do is to check a word into my path and do something after check path
I've got that code on make:
WORD=GNUMAKE; \
FOUND=1; \
echo "$$FOUND"; \
PWD=$(PWD); \
ifeq ($(findstring $$WORD,$$PWD),) \
$(warning list contains "$$WORD") \
endif
but when I run $make I get this error, for me so strange and can't find a solution
could you please help me?
/bin/sh: syntax error at line 1: `ifeq' unexpected
make: *** [all] Error 2
Thank you
Gnu make treats lines joined with \ as a single line. ifeq et. al. need to be on their own line, rather like #ifdef in C (if that's any help to you).
You seem rather confused over what make does.
Make executes a makefile in three distinct phases:
It reads in the Makefile, building a graph in memory, saving macros/expanding macros as necessary.
It looks at what you asked it to make, and decides how to walk the graph.
It walks the graph, expanding the shell recipes before passing the manufactured string to the shell.
You can get make to do your bidding as it reads the makefile
WORD = GNUMAKE
FOUND = 1
$(warning ${FOUND})
ifneq ($(findstring ${WORD},${CURDIR}),)
$(warning list contains "${WORD}")
endif
Or you can get make to do this just as it is making the command to pass to the shell (i.e., before the shell is executed):
.PHONY: target
target:
$(if $(findstring ${WORD},${CURDIR}),$(warning list contains "${WORD}"))echo Shell command here
Or indeed get the shell to do it.
You are messing make commands with shell commands. ifeq is apparently belongs to make but got into shell somehow.
This will find occurance of GNUMAKE word in current path, i.e. it will be one of parent directories. Put this into Makefile and call make.
INPUT := $(shell pwd | tr -s "/" " ")
WORD=GNUMAKE
ifneq ($(filter $(WORD),$(INPUT)),)
$(warning list contains $(WORD))
endif
WORD = GNUMAKE
FOUND = 0
$(warning $$FOUND)
ifneq ($(findstring $$WORD,$(PWD)),)
$(warning list contains $$WORD)
endif
that is exactly what I have been set
hope it helps

Make error for ifeq: syntax error near unexpected token

I'm writing a Makefile that does string matching at one place, the code is like:
if test ...; \
then \
shell scripts... \
fi
ifeq ($(DIST_TYPE),nightly)
shell scripts ...
endif
Here the first if is shell script, the second ifeq is GNU Make's conditional. However the following error generates:
ifeq (nightly,nightly)
/bin/sh: -c: line 0: syntax error near unexpected token `nightly,nightly'
/bin/sh: -c: line 0: `ifeq (nightly,nightly)'
What's happening here? It seems that Make is trying to call the shell.
I played around the code and found that the conditional statements should be written without indentation, and this solved my problem.
If there is no indentation, Make will treat it as a directive for itself; otherwise, it's regarded as a shell script.
Example code
Wrong:
target:
ifeq (foo, bar)
...
endif
Correct:
target:
ifeq (foo, bar)
...
endif
In addition, if the conditional statements is used in define functions, like:
define myFunc
ifeq (foo, bar)
...
endif
endef
In this case, Make will also treat it as a shell script.
This problem can be solved by using if-function instead:
define myFunc
$(if condition,then-part[,else-part])
endef

Resources