Makefile - how to differentiate between a variable assignment and a command - bash

I have the following code in my Makefile, but I get the error mentioning that O?=2 is not a command that sh -c can run. What am I doing wrong here?
gcc:
O?=2
#if test -z "$(DEBUG)" ; then \
g++ -O${O} *.c -o palindrome ; \
fi
I am trying to set O to 2 if the user did not provide it, and then build my palindrome executable.
Exact error:
$ make gcc
O?=2
/bin/sh: O?=2: command not found
make: *** [gcc] Error 127
$

Move it outside the command, so that it gets processed by "make" instead of the shell:
O?=2
gcc:
#if test -z "$(DEBUG)" ; then \
g++ -O${O} *.c -o palindrome ; \
fi

The line O?=2 is not an assignment, but a command executed to rebuild target gcc. This means it is fed to $(SHELL), which doesn't know a thing about it. If you want a variable assingment, put it on line by itself and not as a part of commands:
O?=2
gcc:
#if test -z "$(DEBUG)" ; then \
g++ -O${O} *.c -o palindrome ; \
fi
You can just use O = 2. When the user provides a value on the command line it will override it:
make O=1
will use -O1 for optimization.

Related

GNU makefile syntax for loop in windows

I have a GNU makefile written for linux operating system. I want to compile it on windows but there are some syntax changes for windows. I have done some changes but I am getting an error on for loop syntax.
Make file code is already written and I have to modify it for running on windows OS. Original code is attached and the changes i made are also given
Original code:
This is the original code:
#for i in $(subdirs); do \ (cd $$i && $(MAKE) $#) || break; \ done
After changes:
# pass make directives to subdirectories
SHELL = sh
%:
for f in $$(subdirs); \
do \
(cd $$i && $(MAKE) $#) || break; \
done
# eof
I am getting the error on line 16 which is first line of for loop
GNUmakefile(16) : fatal error U1035: syntax error : expected ':' or '=' separator
I made certain changes after reading nmake syntax. Now the problem is resolved.
The %: is not needed and #for does not work. So we need to turn off echo using #echo off: and then for loop will work with simple 'for' keyword instead of #for.
Working code is here:
SHELL = sh
# %:
#echo off :
for i in $(subdirs) ; \
do \
(cd $$i && $(MAKE) $#) || break; \
done
# eof

Makefile error in Protobuf 2.6.0 (Windows 10 Mingw)

I tried to install Protobuf 2.6.0 on Windows, with Mingw.
The command ./configure worked, it provided me a Makefile, but when I use the command mingw32-make to run the Makefile I have this error:
C:\Users\taka\gz-ws\protobuf-2.6.0> mingw32-make
! était inattendu. //translation: "! was not expected"
Makefile:558: recipe for target 'config.h' failed
mingw32-make: *** [config.h] Error 255
The line 558 of the Makefile:
config.h: stamp-h1
#if test ! -f $#; then rm -f stamp-h1; else :; fi
#if test ! -f $#; then $(MAKE) $(AM_MAKEFLAGS) stamp-h1; else :; fi`
I don't know what to do here.
I found the solution. You need to use Msys and not MinGW, be cause MinGW doesn't have access to all Unix Bash. (run make and not mingw32-make)
So it cannot recognize the line 558 but Msys can read it correctly.

GNU Make: "dir not expected at this moment"

I have a makefile including the following lines:
buildrepo:
#$(call make-repo)
define make-repo
for dir in $(C_SRCS_DIR); \
do \
mkdir -p $(OBJDIR)/$$dir; \
done
endef
On the line with the commands for dir in $(C_SRCS_DIR); \ I get the following error message:
"dir not expected at this moment"
make: *** [buildrepo] Error 255
I am using GNU make.
Can anybody tell me what is going wrong?
Actually this for ... in ... ; do ... done statement is a Unix command not a GNU make command, therefore I guess you are using a Windows machine (or any other one). You have to find the equivalent for your system.
But GNU make has a foreach function which works like this :
$(foreach dir,$(C_SRCS_DIR),mkdir -p $(OBJDIR)/$(dir);)
Also note that in your very specific case (not related to GNU make but to Windows) you can create all the dirs without a for/foreach loop, just like this :
mkdir -p $(addprefix $(OBJDIR)/,$(C_SRCS_DIR))

Makefile remove files

For a schoolproject I try around with makefiles. First I create the files with
install: main.c
gcc -asve-temps main.c
#if test ! -d bin/; then mkdir bin; else : fi
mv a.out $(shell pwd)/bin/
chmod 555 ./bin/a.out
Now I want to clear the project:
clear:
#if test -d *.[osia]; then rm *.[osia] else : ; fi
#if test -d a.out then rm a.out; else: ; fi
Running make install works fine. Running make clear produces the error code:
/bin/sh: 1: test: main.i: unexpected operator
and does not remove the requested files. I want to delete all the *.o *.s *.i and *.a files by running the make clear target using the pattern given above avoiding the error cannot remove ... : no such file or directory
test expects a single argument; when you pass it a glob, it's getting a bunch of them. Something like find will work in this case:
find . -maxdepth 1 -name '*.[osia]' -delete
Or, why check if the file exists at all?
rm -f *.[osia]
Couple of other notes: if you don't have an else clause in your if statement, don't include it. Read up on the test command; you certainly don't want to be using -d if you're looking for files. And, you can use the variable $PWD in place of running a subshell to get it.

Giving input to a shell script through command line

I have a file like this with .sh extension..
clear
echo -n "Enter file name: "
read FILE
gcc -Wall -W "$FILE" && ./a.out
echo
When I can execute this file, it asks for a .c file and when given, it compiles and gives output of the .c file.
For this, everytime I have to first execute this .sh file and then give it the .c file name when asked. Is there anyway, so that, I can just give the .c file in the command line itself, so that it takes that file and does the work...
What I mean is, if I give "./file.sh somecommand cfile.c", then it takes cfile.c as input, compiles it and gives the output...
Use '$1' variable:
clear
gcc -Wall -W $1 && ./a.out
echo
$1 means "first argument from the command line".
Alternatively, if you want to compile multiple files at once using your script, you can use $# variable, on example:
gcc -Wall -W $# && ./a.out
You will invoke your script as follows (assuming it's called 'script.sh'):
./script.sh file.c
Plase see section 3.2.5 of the following article.
If your project gets bigger, you may also want to consider using tools designated for building, like automake.
You can also have it do things either way:
if [ -n "$1" ] ; then
FILE="$1"
else
echo -n "Enter file name: "
read FILE
fi
gcc -Wall -W "$FILE" && ./a.out
This will use the command line argument if it is there, otherwise it asks for a file name.

Resources