How to execute a bash script into a makefile - bash

I have a simple bash script, that install and zip a NodeJS application. It's worked great local. Now I want to execute this script from a Makefile. So I wrote this code
.FOO: install_and_zip
install_and_zip: ./install_and_zip_foo.sh
So if I run this Makefile with make foo I'm getting this error message:
make: *** No rule to make target `foo'. Stop.
Makefile and bash script are in the same directory.
What I'm doing wrong? Can you help me to fix this Makefile?

Different errors. This will work:
foo: install_and_zip
install_and_zip:
# next line must start with a real TAB (ASCII 9)
./install_and_zip_foo.sh
If you want to make foo, then call the rule foo, but not FOO or .FOO.
Code goes always below the rule. All command lines must start with a real TAB (ASCII 9, but not a series of spaces).
Rule foo calls rule install_and_zip. Is this your whish? Otherwise this will do it too:
foo:
# next line must start with a real TAB (ASCII 9)
./install_and_zip_foo.sh

You should write "make .FOO" as you have defined it to be that way. However, you have to properly write your Makefile (tab identations and so on). If you do, you can just write 'make' and the tool will identify "install_and_zip" as the main target, thus executing your script.
PD: targets with a leading '.' (and without slashes) will be ignored by make when trying to identify the main goal (i.e. they won't run just executing 'make'). So, unless you know what you are doing, just rename your target to 'foo'.

Related

Makefile:1: *** missing separator. Stop error when using Make with a config file with no tabs or spaces

I have seen this question and has read its many answers. I understand that this problem usually (always??) appears because of a mistake in using tabs vs spaces in Makefiles. So far that is the general case.
In my case, I have found the error in the title but not when doing make with a Makefile I suspect.
I do:
make a_configuration_file
and I get
Makefile:1: *** missing separator. Stop.
I suppose this "1" means that the error is occurring in the first line of the file, right?
This a_configuration_file is actually a generated file and the first lines are copied here :
#
# Automatically generated file; DO NOT EDIT.
# Ambarella SDK Configuration
#
CONFIG_THREADX=y
CONFIG_BOOT_CORE_SRTOS=0
So my questions for my particular case are:
The "1" refers to the comment line "#"? or the CONFIG_THREADX line?
This configuration file is not using Tabs. So what could be the problem?
EDIT:
Robert tells me that the problem could be the end-of-line. I checked with cat -A a_configuration_file and it seems there are no \r characters (I ve had problems with this before so I learned how to check for end-of-line chars)
Wander Nauta tells me the problem is in the Makefile. Which Makefile should I check? Right now there is a Makefile in the directory from where I call make and it is like this
build/Makefile
no tabs or spaces
I also did cat -A Makefile and I got
build/Makefileroot#themachine.....
If you are wondering what is that, is just that it seems that the Makefile does not have an end of the line at the end, so the cat command prints the contents and the rest (root#themachine...) is just the normal line in the command line
EDIT2:
I think I am close to finding the error.
Originally the "Makefile" was a link as in
ls ./ -l
lrwxrwxrwx 1 1133 543 13 Mar 18 Makefile -> build/Makefile
However now it is just a plain text file
ls ./ -l
-rw------- 1 11250 10513 14 Jul 6 Makefile
Somehow in the linux-windows-linux transference the link condition got lost
In my case, I have found the error in the title but not when doing make with a Makefile I suspect.
The error in the title specifies the name of the file in which the error is encountered: Makefile. Thus, your suspicion about "not when doing so with a Makefile" is unfounded. Although it is possible to run make without a makefile, and doing so can even be advantageous, make will always read a makefile if it can find one by one of the default names it looks for.
Moreover, though it may not be obvious in this case, the name given in the message is not just a base name but a (relative) path to the file. It is therefore complaining about a file named Makefile in make's working directory.
Right now there is a Makefile in the directory from where I call make
and it is like this
build/Makefile
no tabs or spaces I also did cat -A Makefile and I got
build/Makefileroot#themachine.....
Those two claims do not appear to be consistent with each other. In any case, however, neither one attributes valid makefile content to the makefile in question. This is likely the cause of the error message, which would then be a bit misleading.
It looks like you may be trying to have one makefile specify that another make be run in the build/ directory -- a so-called "recursive make". There are a couple of variations on how that is done, and they differ slightly in effect, but here's a guess at what you might be after for that top-level Makefile:
all:
$(MAKE) -C build
Of course, that second line needs to be indented with a leading tab, not spaces.
That will cause the top-level make run to trigger a second make run with the build/ directory as the second's working directory.

Makefile if statement causing some weird behavior

In my makefile, the user supplies an argument called EXEC (make target EXEC=something). I want this to happen:
if EXEC equals "server"
make the variable NOT equal to "client"
if EXEC equals "client"
make the variable NOT equal to "server"
I tried doing this:
ifeq ($(EXEC),server)
NOT := client
endif
ifeq ($(EXEC),client)
NOT := server
endif
I run this by saying make -f build.mk EXEC=server
the output is:
NOT := client
make[2]: NOT: No such file or directory
Why is this error happening?
It seems you've indented the variable assignment with a TAB character. That means that line is considered part of the recipe for the previous target.
Since you haven't provided the entire makefile, or at least the section of the makefile before/after this, we can't say more than that.
However, in general in a makefile you should never indent any lines with TAB characters unless they are intended to be a part of a recipe.

Makefile recursive install?

Suppose I have the following: A chain of dependencies, each of which may or may not be present, and each of which installs in the exact same way (with the exception being the string name of the dependency). In order to get rid of repetitive makefile code, I prototype the following function:
define install_utility =
$(1):
# recursion
$(foreach bar, $(1)_dependencies,$(eval $(call install_utility,$(bar)))
ifeq(`which $(1)`,) # check for existence of dependency
echo will install $(1) # show me make is executing expected commands
endif
endef
foo_dependencies=A B
foo=foo
eval $(call install_utility,$(foo))
# Expected results:
will install A
will install B
will install foo
# Actual result: no error message, just:
... (infinite loop that prints nothing)
And when I run, I get the following error: an infinite loop.
This seems like really simple functionality. However, I am having trouble getting it to work in make. Is there a manner in which I am "expected" to do this in make?
Have tinkered a bit... and getting a variety of errors depending on whether I tab out the recursion:
$(1):
$(foreach bar, ...
ifeq(`which $(1)`,)
...
# error messages:
make: *** no rule to make target '$(foo_dependencies)
ifeq(`which', needed by 'foo'. Stop.
I don't really understand what you're trying to do... it looks extremely non-make-like to me.
But, this definitely will not work:
ifeq(`which $(1)`,)
If you want this to be part of the recipe, you have to indent it with a TAB character and write it in shell syntax, not make syntax.
If you want this to be part of the makefile (not the recipe) you need to write it in correct make syntax: first you have to include a space between the ifeq and the (. Second, make does not support backquotes. If you want to run a shell command you have to use the $(shell ...) function.

GNU make yields "commands commence before first target" error

In my makefile, I would like to check for the existence of a library and give an informative error message. I created a conditional that should exit the make process when the file is not found:
9: ifeq ($(${JSONLIBPATH}),)
10: JSONLIBPATH = ${ALTJSONLIBDIR}/${LIBJSON}
11: endif
12: ifeq ($(${JSONLIBPATH}),)
13: $(error JSON library is not found. Please install libjson before building)
14: endif
My makefile gets stuck on line 13:
Makefile:13: *** commands commence before first target. Stop.
After line 13, my makefile has its targets.
I tried putting this conditional block into a target (e.g. a target called isJSONLibraryInstalled) but this does not execute correctly.
How would I check for a file's existence and handle the error case, before processing targets? Apologies if this is a dumb question.
First of all, you are looking at the contents of a variable that is named after the current path, which is probably not what you want. A simple environment variable reference is $(name) or ${name}, not $(${name}). Due to this, line 13 is always evaluated.
Second, I think it is choking on the indentation of the $(error ...) expression. While the expression resolves to an empty string, there is still a tab character at the start of the line, which indicates a command, which in turn cannot exist outside a rule.
I think using spaces rather than tabs to indent would work.
When you get Make error messages, always check the Error message documentation
On GNU Make 3.81 (error appears to have been removed from newer versions), it says:
This means the first thing in the makefile seems to be part of a command script: it begins with a TAB character and doesn't appear to be a legal make command (such as a variable assignment). Command scripts must always be associated with a target.
What makes matters more confusing is that "doesn't appear to be a legal make command" part. That explains why in:
a := b
$(error a)
the error happens at line 2 and not 1: make simply accepts statements that it can parse, like the assignment, so the following works:
a := b
a:
echo $a
Note: SO currently converts tabs to spaces in code, so you can't just copy the above code into your editor.
For me it was an unnecessary white space before the connector that was causing this.
On slickEdit I selected the option to view all special character and noticed the black sheep.
You can check whitespaces, spaces and tabs by using VSCode [View > Render Whitespace]
As you can see;
command-1 has a tab (->) and whitespace at the end
command-2 has space at first
command-3/4 has tab+spaces
So, you should remove the whitespaces at the end and apply the same spaces with the same action. e.g: tab like the following;

Firefox make file

I want to backtrace the makefile for firefox so that I can get the final gcc command that is used to compile the c++ files. How can I do that?
If you find a line in there that begins with "# $(CXX)" or "# g++", then change the line to "$(CXX)" or "g++" -- in other words, delete the "#" symbol from the line. When an "#" symbol appears at the beginning of a command in a Makefile, it causes Make to not echo the command before executing it. Deleting the "#" symbol will cause the expanded form of the line to be echoed before the command is invoked.
I haven't looked at Firefox's makefile, so it is more than possible that they are using predefined pattern rules for building the code, in which case you won't see any lines beginning with "$(CXX)" . If that is the case, you will need to override the rules, so that the default build rules echo the commands before executing them.
For more information on overriding Makefile pattern build rules, see this link:
http://www.gnu.org/software/make/manual/make.html#Pattern-Rules
The usual stunt for this is to replace gcc with a program that reads the gcc command line,
store it in some log file so it can be inspected, and then launches gcc with the command line. You can do this by replacing "gcc.exe" in your development directories by this stepping stone program.
Here's the make rule that compiles C++ files:
http://hg.mozilla.org/mozilla-central/annotate/c1ab8650e0ce/config/rules.mk#l1391
If all you want to do is replace the compiler, you can (in your mozconfig, or on the configure commandline) set CXX="whatever".
Can you redirect the output of make to a file, then use a text editor to search for the line of interest?

Resources