]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Add support for the clang compiler; update RAII_VAR to use BlocksRuntime
authorMatthew Jordan <mjordan@digium.com>
Thu, 12 Mar 2015 12:26:57 +0000 (12:26 +0000)
committerMatthew Jordan <mjordan@digium.com>
Thu, 12 Mar 2015 12:26:57 +0000 (12:26 +0000)
RAII_VAR, which is used extensively in Asterisk to manage reference counted
resources, uses a GCC extension to automatically invoke a cleanup function
when a variable loses scope. While this functionality is incredibly useful
and has prevented a large number of memory leaks, it also prevents Asterisk
from being compiled with clang.

This patch updates the RAII_VAR macro such that it can be compiled with clang.
It makes use of the BlocksRuntime, which allows for a closure to be created
that performs the actual cleanup.

Note that this does not attempt to address the numerous warnings that the clang
compiler catches in Asterisk.

Much thanks for this patch goes to:
* The folks on StackOverflow who asked this question and Leushenko for
  providing the answer that formed the basis of this code:
  http://stackoverflow.com/questions/24959440/rewrite-gcc-cleanup-macro-with-nested-function-for-clang
* Diederik de Groot, who has been extremely patient in working on getting this
  patch into Asterisk.

Review: https://reviewboard.asterisk.org/r/4370/

ASTERISK-24133
ASTERISK-23666
ASTERISK-20399
ASTERISK-20850 #close
Reported by: Diederik de Groot
patches:
  RAII_CLANG.patch uploaded by Diederik de Groot (License 6600)

git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@432807 65c4cc65-6c06-0410-ace0-fbb531ad65f3

Makefile
configure
configure.ac
include/asterisk/inline_api.h
include/asterisk/utils.h
main/Makefile
makeopts.in

index b39e1d7d630c5fd9e66fe769e0162cdafe6cbf19..e7e3823e08fae9cededb523b7d38ae451ff9a75d 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -179,7 +179,7 @@ ifeq ($(findstring -Wall,$(_ASTCFLAGS) $(ASTCFLAGS)),)
   _ASTCFLAGS+=-Wall
 endif
 
-_ASTCFLAGS+=-Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations $(AST_NESTED_FUNCTIONS) $(DEBUG)
+_ASTCFLAGS+=-Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations $(AST_NESTED_FUNCTIONS) $(AST_CLANG_BLOCKS) $(DEBUG)
 ADDL_TARGETS=
 
 ifeq ($(AST_DEVMODE),yes)
@@ -901,7 +901,7 @@ nmenuselect: menuselect/nmenuselect menuselect-tree menuselect.makeopts
        -@menuselect/nmenuselect menuselect.makeopts && (echo "menuselect changes saved!"; rm -f channels/h323/Makefile.ast main/asterisk) || echo "menuselect changes NOT saved!"
 
 # options for make in menuselect/
-MAKE_MENUSELECT=CC="$(BUILD_CC)" CXX="" LD="" AR="" RANLIB="" \
+MAKE_MENUSELECT=CC="$(CC)" CXX="$(CXX)" LD="" AR="" RANLIB="" \
                CFLAGS="$(BUILD_CFLAGS)" LDFLAGS="$(BUILD_LDFLAGS)" \
                $(MAKE) -C menuselect CONFIGURE_SILENT="--silent"
 
index 83d6098b6bf58bb025d6b5f0e6a62d227bb7e679..9cc87abe3754f98fc85443d1ac8767a2181c0852 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,5 +1,5 @@
 #! /bin/sh
-# From configure.ac Revision: 421228 .
+# From configure.ac Revision: 432280 .
 # Guess values for system-dependent variables and create Makefiles.
 # Generated by GNU Autoconf 2.69 for asterisk trunk.
 #
@@ -685,6 +685,8 @@ PBX_IP_MTU_DISCOVER
 PBX_GLOB_BRACE
 PBX_GLOB_NOMAGIC
 AST_RPATH
+AST_CLANG_BLOCKS
+AST_CLANG_BLOCKS_LIBS
 AST_NESTED_FUNCTIONS
 AST_NATIVE_ARCH
 AST_SHADOW_WARNINGS
@@ -16244,7 +16246,7 @@ fi
 
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -Wtrampolines support" >&5
 $as_echo_n "checking for -Wtrampolines support... " >&6; }
-if $(${CC} -Wtrampolines -S -o /dev/null -xc /dev/null > /dev/null 2>&1); then
+if $(${CC} -Wtrampolines -Werror -S -o /dev/null -xc /dev/null > /dev/null 2>&1); then
        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
        AST_TRAMPOLINES=-Wtrampolines
@@ -16313,11 +16315,29 @@ $as_echo "no" >&6; }
 fi
 
 
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for -fnested-functions" >&5
-$as_echo_n "checking for -fnested-functions... " >&6; }
 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 ()
 {
@@ -16329,16 +16349,41 @@ _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=
+                       AST_NESTED_FUNCTIONS=
 else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: required" >&5
-$as_echo "required" >&6; }
-       AST_NESTED_FUNCTIONS=-fnested-functions
+  { $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 :
   enableval=$enable_rpath; case "${enableval}" in
index b638bce01b71aaaba6cb3f559d10085796f96255..afc5181e200fb68a54d4638ffa27a035d0328775 100644 (file)
@@ -995,7 +995,7 @@ fi
 AC_SUBST(AST_DECLARATION_AFTER_STATEMENT)
 
 AC_MSG_CHECKING(for -Wtrampolines support)
-if $(${CC} -Wtrampolines -S -o /dev/null -xc /dev/null > /dev/null 2>&1); then
+if $(${CC} -Wtrampolines -Werror -S -o /dev/null -xc /dev/null > /dev/null 2>&1); then
        AC_MSG_RESULT(yes)
        AST_TRAMPOLINES=-Wtrampolines
 else
@@ -1050,16 +1050,41 @@ fi
 AC_SUBST(AST_NATIVE_ARCH)
 
 dnl Nested functions required for RAII implementation
-AC_MSG_CHECKING(for -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(required)
-       [AST_NESTED_FUNCTIONS=-fnested-functions]
+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)
+       ]
 )
-AC_SUBST(AST_NESTED_FUNCTIONS)
 
 dnl Check to see if rpath should be set in LDFLAGS
 AC_ARG_ENABLE(rpath,
index 2347d09d7f3b82142ba5925d2b17ed5f458b18ad..a54fd9005c25b7cad75302a8e7395e6c068e9310 100644 (file)
   Small API functions that are candidates for inlining need to be specially
   declared and defined, to ensure that the 'right thing' always happens.
   For example:
-       - there must _always_ be a non-inlined version of the function
+       - there must _always_ be a non-inlined version of the function
        available for modules compiled out of the tree to link to
        - references to a function that cannot be inlined (for any
        reason that the compiler deems proper) must devolve into an
        'extern' reference, instead of 'static', so that multiple
-       copies of the function body are not built in different modules
+       copies of the function body are not built in different modules.
+       However, since this doesn't work for clang, we go with 'static'
+       anyway and hope for the best!
        - when LOW_MEMORY is defined, inlining should be disabled
        completely, even if the compiler is configured to support it
 
 #if !defined(LOW_MEMORY)
 
 #if !defined(AST_API_MODULE)
+#if defined(__clang__)
+#define AST_INLINE_API(hdr, body) static hdr; static inline hdr body
+#else /* if defined(__clang__) */
 #define AST_INLINE_API(hdr, body) hdr; extern inline hdr body
-#else
+#endif
+#else /* if !defined(AST_API_MODULE) */
 #define AST_INLINE_API(hdr, body) hdr; hdr body
 #endif
 
index efe283f6a57417cf25ac1227111dde364b42670c..ec9167404182db1b38051bb1875f67f00e95f200 100644 (file)
@@ -942,10 +942,31 @@ char *ast_utils_which(const char *binary, char *fullpath, size_t fullpath_size);
  * }
  * \encode
  */
-#define RAII_VAR(vartype, varname, initval, dtor) \
-    /* Prototype needed due to http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36774 */ \
-    auto void _dtor_ ## varname (vartype * v); \
-    void _dtor_ ## varname (vartype * v) { dtor(*v); } \
+
+#if defined(__clang__)
+
+#if defined(__has_feature) && __has_feature(blocks)
+typedef void (^_raii_cleanup_block_t)(void);
+static inline void _raii_cleanup_block(_raii_cleanup_block_t *b) { (*b)(); }
+
+#define RAII_VAR(vartype, varname, initval, dtor)                                                                \
+    _raii_cleanup_block_t _raii_cleanup_ ## varname __attribute__((cleanup(_raii_cleanup_block),unused)) = NULL; \
+    vartype varname = initval;                                                                                   \
+    _raii_cleanup_ ## varname = ^{ dtor(varname); }
+
+#else
+       #error "CLANG must support the 'blocks' feature to compile Asterisk."
+#endif /* #if defined(__has_feature) && __has_feature(blocks) */
+
+#elif defined(__GNUC__)
+
+#define RAII_VAR(vartype, varname, initval, dtor)                              \
+    auto void _dtor_ ## varname (vartype * v);                                 \
+    void _dtor_ ## varname (vartype * v) { dtor(*v); }                         \
     vartype varname __attribute__((cleanup(_dtor_ ## varname))) = (initval)
 
+#else
+    #error "Cannot compile Asterisk: unknown and unsupported compiler."
+#endif /* #if __GNUC__ */
+
 #endif /* _ASTERISK_UTILS_H */
index e563ffd464f7e8bc979473b670f9dfcfb7a0d3a6..e061cf8e196e8243a7237a4ea3b7029cd204a932 100644 (file)
@@ -35,6 +35,7 @@ AST_LIBS+=$(BKTR_LIB)
 AST_LIBS+=$(LIBXML2_LIB)
 AST_LIBS+=$(SQLITE3_LIB)
 AST_LIBS+=$(ASTSSL_LIBS)
+AST_LIBS+=$(AST_CLANG_BLOCKS_LIBS)
 
 ifneq ($(findstring $(OSARCH), linux-gnu uclinux linux-uclibc kfreebsd-gnu),)
   ifneq ($(findstring LOADABLE_MODULES,$(MENUSELECT_CFLAGS)),)
index d32f44a8a85d3966e1fa3a0e67f31095d960a1fb..7606d691b0c1edc485c23c1997905ba0336a641d 100644 (file)
@@ -107,6 +107,8 @@ AST_TRAMPOLINES=@AST_TRAMPOLINES@
 AST_NO_STRICT_OVERFLOW=@AST_NO_STRICT_OVERFLOW@
 AST_SHADOW_WARNINGS=@AST_SHADOW_WARNINGS@
 AST_NESTED_FUNCTIONS=@AST_NESTED_FUNCTIONS@
+AST_CLANG_BLOCKS=@AST_CLANG_BLOCKS@
+AST_CLANG_BLOCKS_LIBS=@AST_CLANG_BLOCKS_LIBS@
 AST_RPATH=@AST_RPATH@
 AST_FORTIFY_SOURCE=@AST_FORTIFY_SOURCE@
 AST_MARCH_NATIVE=@AST_MARCH_NATIVE@