gcc: ignore unrecognized option - gcc

Is there a way to make gcc ignore an invalid option, instead of dying with "unrecongized option"? Reason is I want to use an option only available in later versions of gcc (-static-libstdc++), but it should also compile on older compilers. I could check for gcc version in the makefile but it is a bit ugly.

no, but you can set the flags based on the gcc version as follows:
version=`gcc --version | head -1 | cut -d ' ' -f3`
if [ `echo -e "$version\n4.6.1" | sort -V -C; echo $?` == 0 ]; then
flags = -static-libstdc++;
fi
gcc $flags ...
(Disclaimer: I'm not sure which version first uses static-libstdc++, 4.6.1 is just a guess).
John

You can run gcc and check if it accepts the flag:
STATIC_LIBCPP_FLAG := $(shell if gcc -static-libstdc++ --version 2>&1 | grep -q 'unrecognized option'; then true; else echo -static-libstdc++; fi)
CFLAGS += $(STATIC_LIBCPP_FLAG)

Related

How do I read BASH parameters correctly from a file?

I have this configuration file in my CI where I'm specifying a header file and some CMAKE flags on one line.
The configuration file looks like this (filelist):
./settings6.h -DMY_COMPILE_FLAGS="-m32 -fstrict-aliasing"
./settings7.h -DMY_FEATURE_1=ON
./settings8.h -DMY_FLAG=ON -DMY_FEATURE_2=ON -DMY_INCLUDE_DIR=/usr/include/
Now, I'm using a bash script to process this configuration file:
#!/bin/bash
SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
while read i; do
HEADERFILE=$(echo $i | cut -d ' ' -f 1)
CMAKEFLAGS=$(echo $i | cut -s -d ' ' -f 2-)
if [[ "$HEADERFILE" == "" ]]; then
continue
fi
CFLAGS="-Werror" cmake "my_build_dir" "$CMAKEFLAGS" -G "Ninja" -DMY_EXTRA_INCLUDE="$SCRIPTDIR/$HEADERFILE" -B"build_env_dir" > /dev/null
ninja -C "build_env_dir"
done <<ENDOFINPUT
$(grep -v '^#' $SCRIPTDIR/filelist)
ENDOFINPUT
When I have the bash script as above, the line with settings6.h gets processed properly, i.e. the MY_COMPILE_FLAGS are set to -m32 -fstrict-aliasing.
However, settings8.h is failing because the value of MY_FLAG is seen by CMAKE as ON -DMY_FEATURE_2=ON -DMY_INCLUDE_DIR=/usr/include/, so MY_FEATURE_2 and MY_INCLUDE_DIR are not processed correctly.
After googling around a bit, I thought, well, surely a quoting issue, probably I have to remove the quotes around $CMAKEFLAGS like this:
CFLAGS="-Werror" cmake "my_build_dir" $CMAKEFLAGS -G "Ninja" -DMY_EXTRA_INCLUDE="$SCRIPTDIR/$HEADERFILE" -B"build_env_dir" > /dev/null
In fact, this lets settings8.h work as expected (all three options are processed), but now, settings6.h is suddenly failing since CMAKE complains:
CMake Error: The source directory "/src/-fstrict-aliasing"" does not exist
Can someone guide me please how I read the settings correctly from my filelist so that settings6.h and settings8.h both succeed?
Here's a Makefile which refactors this into a sequence of recipes.
Cases := $(patsubst %.h,%,$(wildcard ./settings*.h))
all_done := $(patsubst %,.%.done,$(Cases))
.PHONY: all
all: $(all_done)
cases.mk: filelist.txt
sed 's%^\./%case_%;s% % := %' $< >$#
include cases.mk
.%_done: ./%.h
CFLAGS="-Werror" cmake "my_build_dir" $(case_$*) -G "Ninja" \
-DMY_EXTRA_INCLUDE="$<" -B"build_env_dir" > /dev/null
ninja -C "build_env_dir"

GNU Make: Check number of parallel jobs

I'd like to add a quick check to a (GNU) makefile which can alert the user to the availability of -j/--jobs (parallel make). That is, something like
$ make
TIP: this will build faster if you use use "make -j"
Building ..
$ make -j
Building in parallel ..
How can I determine the number of parallel jobs when a Makefile is executed?
There is a trick here
http://blog.jgc.org/2015/03/gnu-make-insanity-finding-value-of-j.html
and a proposed change to GNU Make itself here
https://github.com/esantoro/make/commit/b0334e7f3009dc58dbc8e6e6fdec94711537fb3b
but perhaps there is something newer and/or easier.
The simplest/best solution is to upgrade your version of GNU make to 4.2 or above. Starting with that version, the MAKEFLAGS variable will provide the full -j option including the number. The NEWS file says:
The amount of parallelism can be determined by querying MAKEFLAGS, even when
the job server is enabled (previously MAKEFLAGS would always contain only
"-j", with no number, when job server was enabled).
So:
$ make --version
GNU Make 4.2.1
...
$ echo 'all:;#echo $(MAKEFLAGS)' | make -f-
$ echo 'all:;#echo $(MAKEFLAGS)' | make -f- -j
-j
$ echo 'all:;#echo $(MAKEFLAGS)' | make -f- -j10
-j10 --jobserver-auth=3,4
$ echo 'all:;#echo $(patsubst -j%,%,$(filter -j%,$(MAKEFLAGS)))' | make -f- -j10
10
You can determine the number of jobs easier and faster than that blog proposes by using make Jobserver protocol:
SHELL := /bin/bash
all:
#${MAKE} --no-print-directory job_count_test
job_count_test:
#+[[ "${MAKEFLAGS}" =~ --jobserver[^=]+=([0-9]+),([0-9]+) ]] && ( J=""; while read -t0 -u $${BASH_REMATCH[1]}; do read -N1 -u $${BASH_REMATCH[1]}; J="$${J}$${REPLY}"; done; echo "Building with $$(expr 1 + $${#J}) jobs."; echo -n $$J >&$${BASH_REMATCH[2]} ) || echo "TIP: this will build faster if you use use \"make -j$$(grep -c processor /proc/cpuinfo)\""
.PHONY: all job_count_test
And then:
$ make
TIP: this will build faster if you use use "make -j8"
$ make -j12
Building with 12 jobs.

configure freezes at "checking for ld used by GCC" - MSYS2

I have recently been experiencing problems with the configure step of two open source projects, GNU GetText and W3M.
The configure step fails at the same place for both projects.
checking for ld used by GCC...
System details:
Operating System: Windows 10 Pro 64-bit
MSYS2
gcc --version: gcc.exe (Rev4, Built by MSYS2 project) 5.2.0
gcc -dumpmachine: x86_64-w64-mingw32
bash --version: GNU bash, version 4.3.42(2)-release (x86_64-pc-msys)
Any ideas on what might be causing this?
The following is the code that configure uses to perform this test.
# Check if gcc -print-prog-name=ld gives a path.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by GCC" >&5
$as_echo_n "checking for ld used by GCC... " >&6; }
case $host in
*-*-mingw*)
# gcc leaves a trailing carriage return which upsets mingw
ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
*)
ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
esac
case $ac_prog in
# Accept absolute paths.
[\\/]* | [A-Za-z]:[\\/]*)
re_direlt='/[^/][^/]*/\.\./'
# Canonicalize the path of ld
ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'`
while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"`
done
test -z "$LD" && LD="$ac_prog"
;;
"")
# If it fails, then pretend we aren't using GCC.
ac_prog=ld
;;
*)
# If it is relative, then search for the first ld in PATH.
with_gnu_ld=unknown
;;
esac
I added debugging code to determine exactly where the problem is occurring. It is happening in the while loop in which grep is called.
I do not know why, but I found that the following packages interfered with configure.
mingw-w64-i686-grep
mingw-w64-i686-sed
mingw-w64-x86_64-grep
mingw-w64-x86_64-sed
These packages appear to be obsolete. When I removed them configure worked.

Extracting OS name and version number in Makefile

I want to set up some environment variable in the makefile only if the system is Ubuntu 11.04 or higher.
I am able to extract the OS name using
cat /etc/lsb-release | grep DISTRIB_ID| cut -d "=" -f 2
and version number using
cat /etc/lsb-release | grep DISTRIB_RELEASE| cut -d "=" -f 2
So in my makefile I do
OSNAME := $(shell cat /etc/lsb-release | grep DISTRIB_ID| cut -d "=" -f 2)
I get the error that /etc/lsb-release not found.
My approach 2 was to use lsb_release -si and -sr , although these commands works fine in the terminal, the below prints that Ubuntu not found in a Makefile
ifeq ($(shell lsb_release -si),Ubuntu)
$(info YES UBUNTU DETECTED)
else
$(info NO UBUNTU DETECTED)
endif
What am I doing wrong is there a clean way conditionally setup environment variables is the system is Ubuntu 11.04 or higher?
Try this
if [ -f /etc/lsb-release ]; then
. /etc/lsb-release
OS=$DISTRIB_ID
VER=$DISTRIB_RELEASE
else
OS=$(uname -s)
VER=$(uname -r)
fi
echo $OS
echo $VER
Or like this sort command
OS=$(lsb_release -si)
ARCH=$(uname -m | sed 's/x86_//;s/i[3-6]86/32/')
VER=$(lsb_release -sr)
echo $OS
echo $VER
echo $ARCH
Or in makefile you require like this
UNAME_OS := $(shell lsb_release -si)
ifeq ($(UNAME_OS),Ubuntu)
$(info YES UBUNTU DETECTED)
else
$(info NO UBUNTU DETECTED)
endif

What's wrong with the following GNU make shell variable expansion?

On this line:
GCCVER:=$(shell a=`mktemp` && echo $'#include <stdio.h>\nmain() {printf("%u.%u\\n", __GNUC__, __GNUC_MINOR__);}' | gcc -o "$a" -xc -; "$a"; rm "$a")
I get:
*** unterminated call to function `shell': missing `)'. Stop.
What's wrong with my stupidly circuitous variable?
Update0
$ make --version
GNU Make 3.81
$ bash --version
GNU bash, version 4.2.8(1)-release (x86_64-pc-linux-gnu)
$ uname -a
Linux 2.6.38-10-generic #46-Ubuntu SMP x86_64 GNU/Linux
$ gcc --version
gcc (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2
when using $ for Bash inside a Makefile, you need to double them: $$a for example. I'm not familiar with the notation $' but I'll have to assume you know what you're doing with that. unless it's a Makefile construct, you need to double the dollar sign on that one too.
also, the hash sign # is terminating the shell expansion in Make's evaluation, which is why it never sees the right paren. escaping it helps, but I don't have it working quite right yet.
I'm debugging it by having two steps: first is setting GCCVER to be the list of commands without the enclosing $(shell), then in the 2nd step setting GCCVER := $(shell $(GCCVER)). you might want to try that too, commenting out the $(shell) step when it doesn't work, using export, and making a "set" recipe:
GCCVER := some commands here
#GCCVER := $(shell $(GCCVER)) # expand the commands, commented out now
export # all variables available to shell
set:
set # make sure this is prefixed by a tab, not spaces
Then:
make set | grep GCCVER
[update] this works:
GCCVER := a=`mktemp` && echo -e '\#include <stdio.h>\nmain() {printf("%u.%u\\n", __GNUC__, __GNUC_MINOR__);}' | gcc -o "$$a" -xc -; "$$a"; rm "$$a"
GCCVER := $(shell $(GCCVER))
export
default:
set
jcomeau#intrepid:/tmp$ make | grep GCCVER
GCCVER=4.6
And full circle, having gotten rid of the extra step:
jcomeau#intrepid:/tmp$ make | grep GCCVER; cat Makefile
GCCVER=4.6
GCCVER := $(shell a=`mktemp` && echo -e '\#include <stdio.h>\nmain() {printf("%u.%u\\n", __GNUC__, __GNUC_MINOR__);}' | gcc -o "$$a" -xc -; "$$a"; rm "$$a")
export
default:
set
Using the $' Bash construct:
jcomeau#intrepid:/tmp$ make | grep GCCVER; cat Makefile
GCCVER=4.6
GCCVER := $(shell a=`mktemp` && echo $$'\#include <stdio.h>\nmain() {printf("%u.%u\\n", __GNUC__, __GNUC_MINOR__);}' | gcc -o "$$a" -xc -; "$$a"; rm "$$a")
export
default:
set
Since your system doesn't work the same as mine, I'm going to cop out and say either use reinierpost's suggestion or, alternatively:
GCCVER := $(shell gcc -dumpversion | cut -d. -f1,2)

Resources