Shell command within Makefile causing error - makefile

I'm using a Makefile to speed up development on my Python project. In part, I'm using the pep8 utility to perform style checks on the source code, using the command pep8 <filename>.
I have all of the source files in the same subdirectory, called evientclassifier. I added the following rule to my Makefile:
style:
for py_file in evientclassifier/*.py; do
pep8 $py_file
done
However, when I run make style, I get the following error:
Makefile:15: *** missing separator. Stop.
I'm not sure what is going on here, since the shell command is syntactically correct.
Is there a correct/better way to do this?

Shell command has to be a single line
$ has to be escaped
style has to be declared as .PHONY because otherwise make treats style as a file name
This is how I would fix it:
.PHONY: style
style:
for py_file in *.py; do pep8 $$file; done

Related

How to use brace expansnsion in makefile prerequisites?

In bash I can use src/{foo/{one,two},bar/{three,four}}.o to describe the files:
src/foo/one.o
src/foo/two.o
src/bar/three.o
src/bar/four.o
I would like to describe the prerequisites of a makefile target in a similar manner. Is there a way to accomplish this in GNU Make?
This is what I have:
SHELL:=/bin/bash
all: src/{foo/{one,two},bar/{three,four}}.o
#echo "$(^)"
And I get:
make: *** No rule to make target 'src/{foo/{one,two},bar/{three,four}}.o', needed by 'all'. Stop.
I came across this and this questions that suggest to add SHELL=/usr/bin/bash to the makefile. But I still cannot get it to work.
Thanks.
Ok, so GNU make has this shell command that alone is not much relevant here because the brace expansion is a bash thing, and make uses Bourne shell (/bin/sh). But, together with the recommendation of the cited questions, I can do something like this:
SHELL:=/bin/bash
all: $(shell echo src/{foo/{one,two},bar/{three,four}}.o)
#echo "$(^)"
With this, the braces are correctly expanded.

How to set environment variables in makefile?

How can I correctly set environment variables in a makefile on Windows?
I get an error about CreateProcess.
C:\>make.exe -f build.makefile start
export MALLOC_PERTURB_=110
process_begin: CreateProcess(NULL, export MALLOC_PERTURB_=110, ...) failed.
make (e=2): The system cannot find the file specified.
c:\testmake.makefile:4: recipe for target 'start' failed
make: *** [start] Error 2
START:
export NODE_ENV=110
echo $(NODE_ENV)
Your question isn't entirely clear but there are a number of obvious things wrong there.
First off you are running make under Windows but writing recipes as if they were shell scripts. That's not the case on Windows (by default at least).
So export is being attempted to be run as an external command which is failing (hence the error message about CreateProcess failing).
You also don't show us the target that is actually throwing that error.
Additionally you are expecting the export and assignment on the first line of the recipe to be in effect for the second line in the recipe body (for the start target).
But that isn't the case. Each line in a makefile target's recipe runs in an independent environment. So the export and assignment on the first line of the START target's recipe doesn't affect the second line.
To do that you need to use one long line or use the .ONESHELL feature of recent versions of make.
Additionally, you are using $(NODE_ENV) in your recipe expecting that to be the shell variable you previously set. And even ignoring the previously stated problem that isn't correct.
make is going to expand $(NODE_ENV) as a make variable before it even runs the recipe at all. You meant ${NODE_ENV} or $NODE_ENV for a shell variable. That said for a make recipe you actually need to escape the $ because ${NODE_ENV} is also a valid make variable expansion. So you need $${NODE_ENV} or $$NODE_ENV there.
Put together you end up with this (assuming you have a shell somewhere to use).
SHELL := /path/to/your/shell
START:
export NODE_ENV=110; \
echo "$${NODE_ENV}"
(though you don't actually need export at that point but that's a different issue entirely).
But if you don't have a shell to use then you get to use cmd.exe and I'm not sure what the equivalent of export there is (though as I just said you don't need it for this) and you end up with something like this (entirely untested):
START:
NODE_ENV=110; \
echo %NODE_ENV%

defines the variable in Makefile

The Makefile is written as the followings:
all:
iceking='$#';
echo $$iceking;
However the output is as the followings:
[root#localhost test]# make
iceking='all';
echo $iceking;
The string 'all' doesn't output. Why?
New sub-shell for each line of the recipe.
From GNU make manual:
When it is time to execute recipes to update a target, they are
executed by invoking a new sub-shell for each line of the recipe...
Set of shell commands, that called by your makefile is equivalent to:
bash -c iceking='all';
bash -c echo $iceking;
The variable iceking is not accessible from the environment of the second invocation of bash. That's why you receive empty output.
.ONESHELL (only since GNU make 3.82)
One way to fix it, is use .ONESHELL special target. From GNU make manual:
If the .ONESHELL special target appears anywhere in the makefile then
all recipe lines for each target will be provided to a single
invocation of the shell.
But there is one problem with .ONESHELL, this feature was added only since version 3.82 of GNU make.
One line recipes.
Another way to fix it, is write recipes in one line, since all commands in the line will be passed to a single invocation of the shell.
all:
iceking='$#'; echo $$iceking;

MAKEFILES variable environment

How to use MAKEFILES variable environment? I writing in a bash MAKEFILES=/home/toker/mymake, but if I'm running a /home/toker/bundocode/gettingstart/testMF/Makefile then /home/toker/mymake doesn't executed. When I'm type $MAKEFILES in the bash then bash: /home/toker/mymake: Permission denied is displayed.
The MAKEFILES variable contains one or more makefiles, not the make program. From the above messages it looks like mymake is a make program you're trying to run. The shell decides what programs to run (by looking in directories listed in the $PATH environment variable) and the shell doesn't pay any special attention to the MAKEFILES variable. Only once make is running does it look at the MAKEFILES variable to see what other makefiles it might want to parse.
What is in the /usr/toker/mymake file? What do you mean by running a .../Makefile? One typically runs make, not a makefile. Then make reads in the makefile. There are ways to change a makefile to be executable but I don't think that's what you're looking for here.
ETA:
If the file /usr/toker/mymake is actually a makefile (BTW, convention typically uses .mk extensions to denote makefiles although there's no really official extension), then you can do this:
$ cat /usr/toker/mymake
$(info loaded /usr/toker/mymake)
foo: ; #echo building $#
$ export MAKEFILES=/usr/toker/mymake
$ cat Makefile
bar: foo ; #echo building $#
$ make
loaded /usr/toker/mymake
building foo
building bar
If you can show an example of exactly what you did (show the makefile and the commands you typed and the results you got) and explain what you don't understand about it, then we can see much more accurately what's going on than by you trying to describe it in words).

How to handle setting up environment in makefile?

So, to compile my executable, I need to have the library locations set up correctly. The problem is, the setup comes from a bunch of scripts that do the env variable exporting, and what needs to be set up may change (beyond my control) so I need to use those scripts instead of copying their functionality. To compile in regular command line, I need to do something like:
setup library1
setup library2
source some_other_setup_script.bash
g++ blah.c
# setup is a executable on my system that run some scripts
How would I write a makefile that accomplishes that? As far as I tried, the env variable exporting does not carry over (i.e. "export VAR=remember; echo $VAR" won't work)
You can also add environment variables properly with the machinery of GNU make, like so:
export TEST:="Something Good!"
test:
echo $$TEST
This (I think) has different semantics from:
TEST2:="Something not quite so useful?"
test2:
echo ${TEST2}
Which (again, I think) does the substitution within make before passing along to the shell. Note that the export command doesn't work within a target block, just unindented as an immediately executed command.
If variable exporting is not working the way it does on your command line, that suggests that Make is choosing a shell different from the one you're using, with different syntax for handling variables (export VAR=remember; echo $VAR works fine for me). Make uses /bin/sh by default, but you can override this with the SHELL variable, which Make does not import from the environment. I suggest setting SHELL (in the Makefile) to whatever you're using in your environment and trying the export VAR=remember experiment again.
Ultimately you will need to define the variable and execute the compiler in a shell list or even a script, rather than in separate make commands. There are a couple of refinements you could add, however. You could tell make about the script:
maintarget: script.sh blah.c
source script.sh; g++ blah.c
script.sh:
setup include script here
Another thing would be to just execute all that stuff in the same shell
maintarget: blah.c
run this; run that; run the other thing; g++ blah.c
I believe all make versions will run a ; list in the same shell, but you can always force a subshell with (list) or by calling specifically a shell script as a compiler command wrapper.
Don't forget to have the appropriate targets depend on your scripts themselves. BTW, some make versions (pmake aka bsd make) can execute a command when defining a make variable, and all versions of make then exports those. But I don't think gmake can do that.
You could write another shell script that executes all those commands, then prints out variable assignments that make can use. Run the script, pipe its output to a file, then include that file from your Makefile. For example:
Makefile:
all:
echo $(FOO)
test.mk: test.sh
./$< > $#
include test.mk
test.sh
echo "FOO=1"
Running "make" in the directory containing this Makefile produces:
make: Entering directory `/home/luser/build/mktest'
Makefile:7: test.mk: No such file or directory
./test.sh > test.mk
make: Leaving directory `/home/luser/build/mktest'
make: Entering directory `/home/luser/build/mktest'
echo 1
1
make: Leaving directory `/home/luser/build/mktest'
make creates test.mk by running the shell script, then includes it. test.mk contains the output of test.sh, and is parsed as a Makefile. See http://www.gnu.org/software/make/manual/make.html#Include for more details.
We use a variant of this in Mozilla's client.mk to let you define options in a "mozconfig" file:
http://mxr.mozilla.org/mozilla-central/source/client.mk#138
Restatement: How do I get a shell variable into a make file?
Something like:
MYVAR := $(shell echo $(MYVAR)) <any_makefile_additions_here>
So, this defines MYVAR inside a MAKEFILE when an environment variable named MYVAR is also set.
It might be of interest, that, in order to override an option that is already defined in a makefile, make supports (I am referring to GNU Make 3.82, but other version probably too) the option -e.
Example:
Makefile:
CC=gcc
...
Run make:
CC=gcc-4.7
make -e
will use gcc-4.7 instead of gcc.

Resources