[Asterisk-code-review] Update configure.ac/Makefile for clang (asterisk[master])

Matt Jordan asteriskteam at digium.com
Sun May 3 10:05:07 CDT 2015


Matt Jordan has uploaded a new change for review.

  https://gerrit.asterisk.org/344

Change subject: Update configure.ac/Makefile for clang
......................................................................

Update configure.ac/Makefile for clang

Created autoconf/ast_check_raii.m4: contains AST_CHECK_RAII which
checks compiler requirements for RAII:
gcc: -fnested-functions support
clang: -fblocks (and if required -lBlocksRuntime)
The original check was implemented in configure.ac and now has it's
own file. This function also sets C_COMPILER_FAMILY to either gcc or
clang for use by makefile

Created autoconf/ast_check_strsep_array_bounds.m4 (contains
AST_CHECK_STRSEP_ARRAY_BOUNDS):
which checks if clang is able to handle the optimized strsep & strcmp
functions (linux). If not, the standard libc implementation should be
used instead. Clang + the optimized macro's work with:
strsep(char *, char []), but not with strsepo(char *, char *).
Instead of replacing all the occurences throughout the source code,
not using the optimized macro version seemed easier

See 'define __strcmp_gc(s1, s2, l2) in bits/string2.h':
llvm-comment: Normally, this array-bounds warning are suppressed for
macros, so that unused paths like the one that accesses __s1[3] are
not warned about.  But if you preprocess manually, and feed the
result to another instance of clang, it will warn about all the
possible forks of this particular if statement. Instead of switching
of this optimization, another solution would be to run the preproces-
sing step with -frewrite-includes, which should preserve enough
information so that clang should still be able to suppress the diag-
nostic at the compile step later on.

See also "https://llvm.org/bugs/show_bug.cgi?id=20144"
See also "https://llvm.org/bugs/show_bug.cgi?id=11536"

Makefile.rules: If C_COMPILER_FAMILY=clang then add two warning
suppressions:
-Wno-unused-value
-Wno-parentheses-equality
In an earlier review (reviewboard: 4550 and 4554), they were deemed a
nuisace and less than benefitial.

configure.ac:
Added AST_CHECK_RAII() see earlier
Added AST_CHECK_STRSEP_ARRAY_BOUNDS() see earlier
Removed moved content

ASTERISK-24917
Change-Id: I12ea29d3bda2254ad3908e279b7effbbac6a97cb
---
M Makefile.rules
A autoconf/ast_check_raii.m4
A autoconf/ast_check_strsep_array_bounds.m4
M configure
M configure.ac
M include/asterisk/autoconfig.h.in
M makeopts.in
7 files changed, 298 insertions(+), 107 deletions(-)


  git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/44/344/1

diff --git a/Makefile.rules b/Makefile.rules
index a24cc72..a274c95 100644
--- a/Makefile.rules
+++ b/Makefile.rules
@@ -65,6 +65,11 @@
 CC_CFLAGS=$(PTHREAD_CFLAGS) $(_ASTCFLAGS) $(ASTCFLAGS)
 CXX_CFLAGS=$(PTHREAD_CFLAGS) $(filter-out -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations $(AST_DECLARATION_AFTER_STATEMENT),$(_ASTCFLAGS) $(ASTCFLAGS))
 
+# Clang -Werror warning suppressions
+ifeq ($(C_COMPILER_FAMILY),clang)
+	CC_CFLAGS+=-Wno-unused-value -Wno-parentheses-equality
+endif
+
 ifeq ($(GNU_LD),1)
 SO_SUPPRESS_SYMBOLS=-Wl,--version-script,$(subst .so,.exports,$@),--warn-common
 ifneq ($(wildcard $(subst .so,.dynamics,$@)),)
diff --git a/autoconf/ast_check_raii.m4 b/autoconf/ast_check_raii.m4
new file mode 100644
index 0000000..e39a43d
--- /dev/null
+++ b/autoconf/ast_check_raii.m4
@@ -0,0 +1,56 @@
+dnl check RAII requirements
+dnl
+dnl gcc / llvm-gcc: -fnested-functions
+dnl clang : -fblocks / -fblocks and -lBlocksRuntime"
+AC_DEFUN([AST_CHECK_RAII], [
+	AC_MSG_CHECKING([for RAII support])
+	AST_C_COMPILER_FAMILY=""
+	AC_LINK_IFELSE(
+		[AC_LANG_PROGRAM([], [
+			int main() {
+				#if defined(__clang__)
+				choke
+				#endif
+				return 0;
+			}
+			])
+		],[
+			dnl Nested functions required for RAII implementation
+			AC_MSG_CHECKING(for gcc -fnested-functions)
+			AC_COMPILE_IFELSE(
+				dnl Prototype needed due to http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36774
+				[
+					AC_LANG_PROGRAM([], [auto void foo(void); void foo(void) {}])
+				],[
+					AST_NESTED_FUNCTIONS=""
+					AC_MSG_RESULT(no)
+				],[
+					AST_NESTED_FUNCTIONS="-fnested-functions"
+					AC_MSG_RESULT(yes)
+				]
+			)
+			AC_SUBST(AST_NESTED_FUNCTIONS)
+			AST_C_COMPILER_FAMILY="gcc"
+		],[
+			AC_MSG_CHECKING(for clang -fblocks)
+			if test "`echo "int main(){return ^{return 42;}();}" | ${CC} -o /dev/null -fblocks -x c - 2>&1`" = ""; then
+				AST_CLANG_BLOCKS_LIBS=""
+				AST_CLANG_BLOCKS="-Wno-unknown-warning-option -fblocks"
+				AC_MSG_RESULT(yes)
+			elif test "`echo "int main(){return ^{return 42;}();}" | ${CC} -o /dev/null -fblocks -x c -lBlocksRuntime - 2>&1`" = ""; then
+				AST_CLANG_BLOCKS_LIBS="-lBlocksRuntime"
+				AST_CLANG_BLOCKS="-fblocks"
+				AC_MSG_RESULT(yes)
+			else
+				AC_MSG_ERROR([BlocksRuntime is required for clang, please install libblocksruntime])
+			fi
+			AC_SUBST(AST_CLANG_BLOCKS_LIBS)
+			AC_SUBST(AST_CLANG_BLOCKS)
+			AST_C_COMPILER_FAMILY="clang"
+		]
+	)
+	if test -z "${AST_C_COMPILER_FAMILY}"; then
+		AC_MSG_ERROR([Compiler ${CC} not supported. Mminimum required gcc-4.3 / llvm-gcc-4.3 / clang-3.3 + libblocksruntime-dev])
+	fi
+	AC_SUBST(AST_C_COMPILER_FAMILY)
+])
diff --git a/autoconf/ast_check_strsep_array_bounds.m4 b/autoconf/ast_check_strsep_array_bounds.m4
new file mode 100644
index 0000000..47a41e5
--- /dev/null
+++ b/autoconf/ast_check_strsep_array_bounds.m4
@@ -0,0 +1,81 @@
+dnl macro AST_CHECK_STRSEP_ARRAY_BOUNDS0
+dnl
+dnl The optimized strcmp and strsep macro's in
+dnl /usr/include/xxx-linux-gnu/bits/string2.h produce a warning (-Warray-bounds)
+dnl when compiled with clang (+ -O1), when the delimiter parameter is
+dnl passed in as a char *, instead of the expected char[]
+dnl
+dnl Instead of replacing all occurrences of strsep and strcmp, looking like:
+dnl xxx_name = strsep(&rest, ",");
+dnl
+dnl with:
+dnl char delimiters[] = ",";
+dnl xxx_name = strsep(&rest, delimiters);
+dnl
+dnl to get around this warning, without having to suppress the warning completely.
+dnl This macro detects the warning and force these 'optimizations' to be
+dnl switched off (Clang already has a set of builtin optimizers which should result
+dnl in good performance for these type of functions).
+dnl
+dnl When the issue is detected it will add a define to autoconfig.h which will prevent
+dnl bits/string2.h from replacing the standard implementation of strsep/strcmp with it's
+dnl macro optimized version. bits/string.h checks these defines before inserting it's
+dnl replacements.
+dnl
+dnl When bits/string2.h get's fixed in the future, this macro should be able to
+dnl detect the new behaviour, and when no warning is generated, it will use the optimize
+dnl version from bits/string2.h
+dnl
+dnl
+dnl See 'define __strcmp_gc(s1, s2, l2) in bits/string2.h'
+dnl
+dnl llvm-comment: Normally, this array-bounds warning are suppressed for macros, so that
+dnl unused paths like the one that accesses __s1[3] are not warned about.  But if you
+dnl preprocess manually, and feed the result to another instance of clang, it will warn
+dnl about all the possible forks of this particular if statement.
+dnl
+dnl Instead of switching of this optimization, another solution would be to run the pre-
+dnl processing step with -frewrite-includes, which should preserve enough information
+dnl so that clang should still be able to suppress the diagnostic at the compile step
+dnl later on.
+dnl
+dnl See also "https://llvm.org/bugs/show_bug.cgi?id=20144"
+dnl See also "https://llvm.org/bugs/show_bug.cgi?id=11536"
+dnl
+AC_DEFUN([AST_CHECK_STRSEP_ARRAY_BOUNDS], [
+	AC_MSG_CHECKING([for clang strsep/strcmp optimization])
+	save_CFLAGS="$CFLAGS"
+	CFLAGS="$CFLAGS -O1 -Werror=array-bounds"
+	AC_COMPILE_IFELSE(
+		[
+		    	AC_LANG_SOURCE([
+				#include <stdio.h>
+				#include <string.h>
+
+				/* fails with clang and -O1 */
+				void test_strsep_strcmp (void) {
+					char *haystackstr = "test1,test2";
+					char *outstr;
+					if (!strcmp(haystackstr, ",")) {
+						printf("fail\n");
+					}
+					if ((outstr = strsep(&haystackstr, ","))) {
+						printf("fail:%s\n", outstr);
+					}
+				}
+				int main(int argc, char *argv[]) {
+					test_strsep_strcmp();
+					return 0;
+				}
+			])
+		],[
+			AC_MSG_RESULT(no)
+		],[
+			dnl setting this define in autoconfig.h will prevent bits/string2.h from replacing the standard implementation of strsep/strcmp
+			AC_DEFINE([_HAVE_STRING_ARCH_strcmp], 1, [Prevent clang array-bounds warning by not using strcmp from bits/string2.h])
+			AC_DEFINE([_HAVE_STRING_ARCH_strsep], 1, [Prevent clang array-bounds warning by not using strsep from bits/string2.h])
+			AC_MSG_RESULT([prevent use of __string2_1bptr_p / strsep / strcmp from bits/string2.h])
+		]
+	)
+	CFLAGS="$save_CFLAGS"
+])
diff --git a/configure b/configure
index c539ee9..9f7a862 100755
--- a/configure
+++ b/configure
@@ -687,9 +687,6 @@
 PBX_GLOB_BRACE
 PBX_GLOB_NOMAGIC
 AST_RPATH
-AST_CLANG_BLOCKS
-AST_CLANG_BLOCKS_LIBS
-AST_NESTED_FUNCTIONS
 AST_NATIVE_ARCH
 AST_SHADOW_WARNINGS
 AST_NO_STRICT_OVERFLOW
@@ -1148,6 +1145,10 @@
 ALSA_DIR
 ALSA_INCLUDE
 ALSA_LIB
+AST_C_COMPILER_FAMILY
+AST_CLANG_BLOCKS
+AST_CLANG_BLOCKS_LIBS
+AST_NESTED_FUNCTIONS
 AST_CODE_COVERAGE
 AST_DEVMODE_STRICT
 AST_DEVMODE
@@ -8225,6 +8226,146 @@
 	esac
 fi
 
+
+
+
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for RAII support" >&5
+$as_echo_n "checking for RAII support... " >&6; }
+	AST_C_COMPILER_FAMILY=""
+	cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+			int main() {
+				#if defined(__clang__)
+				choke
+				#endif
+				return 0;
+			}
+
+  ;
+  return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+						{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for gcc -fnested-functions" >&5
+$as_echo_n "checking for gcc -fnested-functions... " >&6; }
+			cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+
+int
+main ()
+{
+auto void foo(void); void foo(void) {}
+  ;
+  return 0;
+}
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+					AST_NESTED_FUNCTIONS=""
+					{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+else
+
+					AST_NESTED_FUNCTIONS="-fnested-functions"
+					{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+			AST_C_COMPILER_FAMILY="gcc"
+
+else
+
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for clang -fblocks" >&5
+$as_echo_n "checking for clang -fblocks... " >&6; }
+			if test "`echo "int main(){return ^{return 42;}();}" | ${CC} -o /dev/null -fblocks -x c - 2>&1`" = ""; then
+				AST_CLANG_BLOCKS_LIBS=""
+				AST_CLANG_BLOCKS="-Wno-unknown-warning-option -fblocks"
+				{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+			elif test "`echo "int main(){return ^{return 42;}();}" | ${CC} -o /dev/null -fblocks -x c -lBlocksRuntime - 2>&1`" = ""; then
+				AST_CLANG_BLOCKS_LIBS="-lBlocksRuntime"
+				AST_CLANG_BLOCKS="-fblocks"
+				{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+			else
+				as_fn_error $? "BlocksRuntime is required for clang, please install libblocksruntime" "$LINENO" 5
+			fi
+
+
+			AST_C_COMPILER_FAMILY="clang"
+
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+	if test -z "${AST_C_COMPILER_FAMILY}"; then
+		as_fn_error $? "Compiler ${CC} not supported. Mminimum required gcc-4.3 / llvm-gcc-4.3 / clang-3.3 + libblocksruntime-dev" "$LINENO" 5
+	fi
+
+
+
+	{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for clang strsep/strcmp optimization" >&5
+$as_echo_n "checking for clang strsep/strcmp optimization... " >&6; }
+	save_CFLAGS="$CFLAGS"
+	CFLAGS="$CFLAGS -O1 -Werror=array-bounds"
+	cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+
+				#include <stdio.h>
+				#include <string.h>
+
+				/* fails with clang and -O1 */
+				void test_strsep_strcmp (void) {
+					char *haystackstr = "test1,test2";
+					char *outstr;
+					if (!strcmp(haystackstr, ",")) {
+						printf("fail\n");
+					}
+					if ((outstr = strsep(&haystackstr, ","))) {
+						printf("fail:%s\n", outstr);
+					}
+				}
+				int main(int argc, char *argv) {
+					test_strsep_strcmp();
+					return 0;
+				}
+
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+else
+
+
+$as_echo "#define _HAVE_STRING_ARCH_strcmp 1" >>confdefs.h
+
+
+$as_echo "#define _HAVE_STRING_ARCH_strsep 1" >>confdefs.h
+
+			{ $as_echo "$as_me:${as_lineno-$LINENO}: result: prevent use of __string2_1bptr_p / strsep / strcmp from bits/string2.h" >&5
+$as_echo "prevent use of __string2_1bptr_p / strsep / strcmp from bits/string2.h" >&6; }
+
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+	CFLAGS="$save_CFLAGS"
 
 
 # AST_EXT_LIB_SETUP is used to tell configure to handle variables for
@@ -17430,74 +17571,6 @@
 fi
 
 
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-
-		#if defined(__clang__)
-		choke
-		#endif
-
-  ;
-  return 0;
-}
-
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-
-				{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for gcc -fnested-functions" >&5
-$as_echo_n "checking for gcc -fnested-functions... " >&6; }
-		cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-auto void foo(void); void foo(void) {}
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-			AST_NESTED_FUNCTIONS=
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-			AST_NESTED_FUNCTIONS=-fnested-functions
-
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-
-
-else
-
-		{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for clang -fblocks" >&5
-$as_echo_n "checking for clang -fblocks... " >&6; }
-		if test "`echo "int main(){return ^{return 42;}();}" | ${CC} -o /dev/null -fblocks -x c - 2>&1`" = ""; then
-			AST_CLANG_BLOCKS_LIBS=""
-			AST_CLANG_BLOCKS="-Wno-unknown-warning-option -fblocks"
-			{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-		elif test "`echo "int main(){return ^{return 42;}();}" | ${CC} -o /dev/null -fblocks -x c -lBlocksRuntime - 2>&1`" = ""; then
-			AST_CLANG_BLOCKS_LIBS="-lBlocksRuntime"
-			AST_CLANG_BLOCKS="-fblocks"
-			{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-		else
-			as_fn_error $? "\"BlocksRuntime is required for clang\"" "$LINENO" 5
-		fi
-
-
-
-
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
 
 # Check whether --enable-rpath was given.
 if test "${enable_rpath+set}" = set; then :
diff --git a/configure.ac b/configure.ac
index 8a37075..c09d30a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -386,6 +386,9 @@
 	esac])
 AC_SUBST(AST_CODE_COVERAGE)
 
+AST_CHECK_RAII()
+AST_CHECK_STRSEP_ARRAY_BOUNDS()
+
 # AST_EXT_LIB_SETUP is used to tell configure to handle variables for
 # various packages.
 # $1 is the prefix for the variables in makeopts and autoconfig.h
@@ -1134,42 +1137,6 @@
 fi
 AC_SUBST(AST_NATIVE_ARCH)
 
-dnl Nested functions required for RAII implementation
-AC_LINK_IFELSE(
-	[AC_LANG_PROGRAM([], [
-		#if defined(__clang__)
-		choke
-		#endif
-		])
-	],[
-		dnl Nested functions required for RAII implementation
-		AC_MSG_CHECKING(for gcc -fnested-functions)
-		AC_COMPILE_IFELSE(
-			dnl Prototype needed due to http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36774
-			[AC_LANG_PROGRAM([], [auto void foo(void); void foo(void) {}])],
-			AC_MSG_RESULT(no)
-			[AST_NESTED_FUNCTIONS=],
-			AC_MSG_RESULT(yes)
-			[AST_NESTED_FUNCTIONS=-fnested-functions]
-		)
-		AC_SUBST(AST_NESTED_FUNCTIONS)
-	],[
-		AC_MSG_CHECKING(for clang -fblocks)
-		if test "`echo "int main(){return ^{return 42;}();}" | ${CC} -o /dev/null -fblocks -x c - 2>&1`" = ""; then
-			[AST_CLANG_BLOCKS_LIBS=""]
-			[AST_CLANG_BLOCKS="-Wno-unknown-warning-option -fblocks"]
-			AC_MSG_RESULT(yes)
-		elif test "`echo "int main(){return ^{return 42;}();}" | ${CC} -o /dev/null -fblocks -x c -lBlocksRuntime - 2>&1`" = ""; then
-			[AST_CLANG_BLOCKS_LIBS="-lBlocksRuntime"]
-			[AST_CLANG_BLOCKS="-fblocks"]
-			AC_MSG_RESULT(yes)
-		else
-			AC_MSG_ERROR("BlocksRuntime is required for clang")
-		fi
-		AC_SUBST(AST_CLANG_BLOCKS_LIBS)
-		AC_SUBST(AST_CLANG_BLOCKS)
-	]
-)
 
 dnl Check to see if rpath should be set in LDFLAGS
 AC_ARG_ENABLE(rpath,
diff --git a/include/asterisk/autoconfig.h.in b/include/asterisk/autoconfig.h.in
index 474fb8c..6b41a8c 100644
--- a/include/asterisk/autoconfig.h.in
+++ b/include/asterisk/autoconfig.h.in
@@ -1314,6 +1314,14 @@
 /* Number of bits in a file offset, on hosts where this is settable. */
 #undef _FILE_OFFSET_BITS
 
+/* Prevent clang array-bounds warning by not using strcmp from bits/string2.h
+   */
+#undef _HAVE_STRING_ARCH_strcmp
+
+/* Prevent clang array-bounds warning by not using strsep from bits/string2.h
+   */
+#undef _HAVE_STRING_ARCH_strsep
+
 /* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
 #undef _LARGEFILE_SOURCE
 
diff --git a/makeopts.in b/makeopts.in
index cc23310..69636f1 100644
--- a/makeopts.in
+++ b/makeopts.in
@@ -111,6 +111,7 @@
 AST_NESTED_FUNCTIONS=@AST_NESTED_FUNCTIONS@
 AST_CLANG_BLOCKS=@AST_CLANG_BLOCKS@
 AST_CLANG_BLOCKS_LIBS=@AST_CLANG_BLOCKS_LIBS@
+C_COMPILER_FAMILY=@AST_C_COMPILER_FAMILY@
 AST_RPATH=@AST_RPATH@
 AST_FORTIFY_SOURCE=@AST_FORTIFY_SOURCE@
 AST_MARCH_NATIVE=@AST_MARCH_NATIVE@

-- 
To view, visit https://gerrit.asterisk.org/344
To unsubscribe, visit https://gerrit.asterisk.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I12ea29d3bda2254ad3908e279b7effbbac6a97cb
Gerrit-PatchSet: 1
Gerrit-Project: asterisk
Gerrit-Branch: master
Gerrit-Owner: Matt Jordan <mjordan at digium.com>
Gerrit-Reviewer: Diederik de Groot <dkgroot at talon.nl>



More information about the asterisk-code-review mailing list