Detecting gcc warnings from a bash wrapper - bash

Writing a bash script that will tell me is the gcc had Errs or warnings
i have this code
#!/bin/bash
# execute gcc command
gcc "$2".c -Wall -g -o "$2"> "$1" 2>&1
# grab exit status of gcc
ret=$?
# write appropriate message as per return status value
((ret == 0)) && echo "compile V" || echo "compile X"
# return the exit status of gcc
exit $ret
the problem is when it gets warnings its still return 0 and so i get Compile V
But without any luck.. The numbers 6 21 118 are random the rest are consts
edit
i cant use -Werror beause its for school and i must get same output as they want...

If you want to look at whether the file you redirected gcc's output to is empty, that'll tell you whether any warnings were written:
gcc "$2".c -Wall -g -o "$2" >"$1" 2>&1; rc=$?
if (( rc > 0 )) || [ -s "$1" ]; then
echo "compile X"
else
echo "compile V"
fi
This works because test -s checks whether a file exists and is non-empty -- so you know that if the file you redirected the output to is non-empty, you had at least one error or failure.

use gcc -Werror option to treat all warnings as errors.

Related

clang++: command not found

clang++: command not found
OS: Ubuntu 20.4 LTS
clang --version: 10.0.0
clang++ work outside of this program. But when I run this program show this error message clang++ command not found
PATH=/home/musleh/programming/cpp
DIR=''
FILE=''
execute () {
cd ${PATH}/${DIR}
clang++ ${FILE} -o a
time ./a
rm a
if [[ $? -ne 0 ]]
then
echo "***************************Program Fail***************************"
fi
}
while getopts i:d: OPTION
do
case ${OPTION} in
d)
DIR=${OPTARG}
;;
i)
FILE=${OPTARG}
;;
?)
usage
;;
esac
done
if [[ $# -lt 4 ]]
then
usage
elif [[ ! -d ${PATH}/${DIR} ]]
then
echo "${DIR} dir not found!" >&2
elif [[ ! -f ${PATH}/${DIR}/${FILE} ]]
then
echo "${FILE} file not found!" >&2
else
execute
fi```
PATH=/home/musleh/programming/cpp
Is very probably wrong and should be instead perhaps
PATH=/usr/bin:/bin:/usr/local/bin:$HOME/programming/cpp
export PATH
Read much more more about the PATH variable and execvp(3) (which most shells use)
Use strace(1) on your shell script. Read Advanced Linux Programming and more about syscalls(2).
Study for inspiration the source code of GNU bash and read its documentation. It is free software so your are allowed to study (and perhaps improve) its source code.
Of course, clang++ needs to be installed. Check by using the which command. Or view your PATH variable using echo $PATH
See also this

VERBOSE environment in shell script

I'm trying to write a Bash script, which compiles and runs all C files in the current directory. My Bash script is the following:
#!/bin/bash
LIST="$(ls *.c)"
echo "Compile all C source files"
for f in $( ls *.c); do
#echo "C file: $f"
gcc $f -o "${f%.*}"
./"${f%.*}"
done
Now, I'm trying to define a VERBOSE environment variable. If VERBOSE environment variable is set then my Bash script should display the command that is being used to compile the source file.
How can I define such a VERBOSE environment variable in this Bash script?
When verbose is defined my output should be like,
Compiling all C source files:
gcc copyfile.c -o copyfile
---- successful ----
gcc haserror.c -o haserror
haserror.c: In function ‘main’:
haserror.c:9:10: warning: missing terminating " character
printf("Hello !\n);
^
haserror.c:9:10: error: missing terminating " character
printf("Hello!\n);
^~~~~~~~~~~~~~~~~~~
haserror.c:11:1: error: expected expression before ‘}’ token
}
^
haserror.c:11:1: error: expected ‘;’ before ‘}’ token
gcc hello.c -o hello
---- successful ----
gcc p005.c -o p002
---- successful ----
gcc p103.c -o p101
---- successful ----
gcc p102.c -o p105
---- successful ----
============
5 C source files are compiled successfully.
1 C source files have compilation error(s).
**Otherwise, when my VERBOSE not defined, my output should be like**
Compiling all C source files:
haserror.c: In function ‘main’:
haserror.c:9:10: warning: missing terminating " character
printf("Hello!\n);
^
haserror.c:9:10: error: missing terminating " character
printf("Hello!\n);
^~~~~~~~~~~~~~~~~~~
haserror.c:11:1: error: expected expression before ‘}’ token
}
^
haserror.c:11:1: error: expected ‘;’ before ‘}’ token
============
5 C source files are compiled successfully.
1 C source files have compilation error(s).
The trivially obvious shoud work.
#!/bin/bash
[ "$VERBOSE" ] && echo "$0: Compile all C source files" >&2
for f in *.c; do
[ "$VERBOSE" ] && echo "$0: C file: $f" >&2
# [ "$VERBOSE" ] && set -x
gcc $f -o "${f%.*}"
# set +x
./"${f%.*}"
done
Notice also how we avoid the useless (and slightly dangerous) use of ls and print the diagnostic output to standard error, with the script's name included in the message.
The condition is simple; [ "$VERBOSE" ] evaluates to true (returns a zero exit code) when VERBOSE is set and non-empty. You can perform arbitrarily complex actions conditionally using the shell's normal flow control statements, such as perhaps
if [ "$VERBOSE" ]; then
echo "$0: compiling $f" >&2
(set -x; gcc "$f" -o "${f.c}") &&
echo "$0: ----- $f: successful -----" >&2
else
gcc "$f" -o "${f.c}"
fi
(though I would perhaps then also refactor the compilation command into a separate function.)
A better design is to have the script accept a command-line option. Also, you should probably avoid using upper case for your private variables.

How to compare two shell command output in Makefile?

My Makefile is:
.PHONY: check
check:
ifneq $(shell echo 123), $(shell echo 123)
$(error Not equal)
endif
When I run, I've got the error:
$ make
Makefile:3: *** Not equal. Stop.
But this should happen only when they're different, but they're not. Why?
ifneq cannot be indented. the way you've written it, it's being run via a shell command which means the $(error) is being evaluated first by the make command.
i'm guessing you want the make check to actually run two commands only when make check is invoked, and compare their output. you can do:
.PHONY: check
check:
if [ "`echo 123`" != "`echo 123`" ]; then \
echo "Not equal"; \
exit 1; \
fi
According to GNU Make docs, Conditional Parts cannot be used to control shell commands at the time of execution, since conditionals control what make actually "sees" in the makefile.
So to perform condition during compilation process, shell syntax is preferred, e.g.
SHELL := /bin/bash -e
.PHONY: check
check:
#test "$(shell echo 123)" = "$(shell echo 123)" \
|| { echo Not equal; exit 2; } \
&& { echo Equal; }

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.

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

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.

Resources