Automatically detect C99 flags for supported compilers.
authorOssama Othman <ossama.othman@intel.com>
Tue, 17 Mar 2015 21:43:18 +0000 (14:43 -0700)
committerErich Keane <erich.keane@intel.com>
Mon, 23 Mar 2015 19:54:05 +0000 (19:54 +0000)
This patch set allows the required C99 command line flags to be
automatically set earlier in the build process.  Currently only gcc is
supported, but adding support for other compilers is straightforward.

Hard-coded '-std=c99' and '-std=gnu99' CFLAGS found throughout
iotivity SConscript files have been removed.  Feature test macros have
been added where needed to enable extensions that were disabled by
automatic addition of '-std=c99' to the CFLAGS build variable.

Change-Id: I6d05313aefff1911d1aaa2097954a1878874e73a
Signed-off-by: Ossama Othman <ossama.othman@intel.com>
Reviewed-on: https://gerrit.iotivity.org/gerrit/495
Tested-by: jenkins-iotivity <jenkins-iotivity@opendaylight.org>
Reviewed-by: Jon A. Cruz <jonc@osg.samsung.com>
Reviewed-by: Erich Keane <erich.keane@intel.com>
12 files changed:
build_common/SConscript
build_common/iotivityconfig/__init__.py
build_common/iotivityconfig/compiler/configuration.py
build_common/iotivityconfig/compiler/default_configuration.py
build_common/iotivityconfig/compiler/factory.py
build_common/iotivityconfig/compiler/gcc_configuration.py
resource/csdk/SConscript
resource/csdk/libcoap-4.1.1/SConscript
resource/oc_logger/SConscript
resource/oc_logger/examples/SConscript
service/protocol-plugin/plugins/mqtt-fan/lib/SConscript
service/protocol-plugin/plugins/mqtt-fan/lib/mosquitto.c

index 56a872b23a1451489a1b29790526b14be8e6d642..22501f23c351816a91d15920411ccddb855894ba 100644 (file)
@@ -243,9 +243,15 @@ from iotivityconfig import *
 
 conf = env.Configure(
         custom_tests = {
+                'CheckC99Flags' : iotivityconfig.check_c99_flags,
                 'CheckCXX11Flags' : iotivityconfig.check_cxx11_flags
         } )
 
+# IoTivity requires support for C99 for the C SDK.
+if not conf.CheckC99Flags():
+        print('C99 support is required!')
+        Exit(1)
+
 # IoTivity requires support for C++11 for the C++ SDK.
 #
 # However, some platforms, such as Arduino, only support the C SDK.
index 3f9be7ca8448f7dffb7d02368b34bbd9c7f6f7c9..ea18ea1156511b78a0e867e5c618a084b6c45116 100644 (file)
@@ -59,6 +59,22 @@ def _inform_user_of_broken_gcc_headers(context, flag):
             # handle the issue in that case.
             _check_for_broken_gcc_headers(context, flag)
 
+def check_c99_flags(context):
+    """
+    Check if command line flag is required to enable C99 support.
+
+    Returns 1 if no flag is required, 0 if no flag was found, or the
+    actual flag if one was found.
+    """
+
+    cc = context.env['CC']
+    context.Message('Checking for C99 flag for ' + cc + '... ')
+    config = factory.make_c_compiler_config(context)
+    ret = config.check_c99_flags()
+    context.Result(ret)
+
+    return ret
+
 def check_cxx11_flags(context):
     """
     Check if command line flag is required to enable C++11 support.
@@ -69,7 +85,7 @@ def check_cxx11_flags(context):
 
     cxx = context.env['CXX']
     context.Message('Checking for C++11 flag for ' + cxx + '... ')
-    config = factory.make_compiler_config(context)
+    config = factory.make_cxx_compiler_config(context)
     ret = config.check_cxx11_flags()
     context.Result(ret)
 
index e96215e9a7b3fb92ea9e57063f4d2185cb16ce2c..e328e28228fe3d0c8753fc9e5d30360bdb19b176 100644 (file)
@@ -31,6 +31,23 @@ class Configuration:
         self._context = context      # scons configure context
         self._env     = context.env  # scons environment
 
+    def check_c99_flags(self):
+        """
+        Check if command line flag is required to enable C99
+        support.
+
+        Returns 1 if no flag is required, 0 if no flag was
+        found, and the actual flag if one was found.
+
+        CFLAGS will be updated with appropriate C99 flag,
+        accordingly.
+        """
+
+        return self._check_flags(self._c99_flags(),
+                                 self._c99_test_program(),
+                                 '.c',
+                                 'CFLAGS')
+
     def check_cxx11_flags(self):
         """
         Check if command line flag is required to enable C++11
@@ -92,13 +109,33 @@ class Configuration:
 
         return ret
 
+    # ------------------------------------------------------------
+    # Return test program to be used when checking for basic C99
+    # support.
+    #
+    # Subclasses should implement this template method or use the
+    # default test program found in the DefaultConfiguration class
+    # through composition.
+    # ------------------------------------------------------------
+    def _c99_test_program(self):
+        raise NotImplementedError('unimplemented method')
+
+    # --------------------------------------------------------------
+    # Get list of flags that could potentially enable C99 support.
+    #
+    # Subclasses should implement this template method if flags are
+    # needed to enable C99 support.
+    # --------------------------------------------------------------
+    def _c99_flags(self):
+        raise NotImplementedError('unimplemented method')
+
     # ------------------------------------------------------------
     # Return test program to be used when checking for basic C++11
     # support.
     #
     # Subclasses should implement this template method or use the
     # default test program found in the DefaultConfiguration class
-    # through inheritance or composition.
+    # through composition.
     # ------------------------------------------------------------
     def _cxx11_test_program(self):
         raise NotImplementedError('unimplemented method')
index 8735f3de91a05ef3d6c8e625b49b43459904cc1d..ed90f40a3656e092a61f3c96cd6d642e9fc1a3a1 100644 (file)
@@ -21,6 +21,42 @@ class DefaultConfiguration(Configuration):
     def __init__(self, context):
         Configuration.__init__(self, context)
 
+    # ------------------------------------------------------------
+    # Return test program to be used when checking for basic C++11
+    # support.
+    # ------------------------------------------------------------
+    def _c99_test_program(self):
+        return """
+// Some headers found in C99.
+#include <stdbool.h>
+#include <stdint.h>
+
+int main()
+{
+    struct foo
+    {
+        bool b;      // C99 type
+        int i;
+        uint64_t q;  // C99 type
+    };
+
+    // Designated initializer.
+    struct foo bar = { .b = false, .q = UINT64_MAX };
+
+    // Implicitly initialized field.
+    return bar.i != 0;
+}
+"""
+
+    # --------------------------------------------------------------
+    # Get list of flags that could potentially enable C99 support.
+    #
+    # The default configuration assumes that no flag is needed to
+    # enable C99 support.
+    # --------------------------------------------------------------
+    def _c99_flags(self):
+        return []
+
     # ------------------------------------------------------------
     # Return test program to be used when checking for basic C++11
     # support.
index fcde40294fa6cbc5e4b21258387cf7bc3f632199..7b0bee71f3801c129720f40d36db45be42ab4630 100644 (file)
 from default_configuration import *
 from gcc_configuration import *
 
-# Canonicalize the C++ compiler name to "g++" if gcc is being used to
-# simplify mapping to the appropriate C++11 flags since gcc may be
-# installed under a different name.  This will be used when mapping
-# compiler name to configuration in the factory submodule.
-_GCC = 'g++'
+# Canonicalize the C or C++ compiler name to "gcc" if gcc is being
+# used to simplify mapping to the GCC compiler configuration since GCC
+# may be installed under a different name.  This will be used when
+# mapping compiler name to configuration in the factory submodule.
+_GCC = 'gcc'
 
 # Update this dictionary with new compiler configurations as needed.
 _CONFIG_MAP = { _GCC : GccConfiguration }
 
-_compiler_config = None
+_c_compiler_config = None
+_cxx_compiler_config = None
+
+def check_for_gcc_c(context):
+    """
+    Check if the C compiler is GCC
+
+    Returns 1 if gcc, 0 otherwise
+    """
+
+    test_program = """
+#if !defined(__GNUC__)
+#  error "Not the GCC C compiler."
+#endif
+
+int foo(void)
+{
+    return 0;
+}
+"""
+
+    return context.TryCompile(test_program, '.c')
 
 def check_for_gcc_cxx(context):
     """
@@ -52,9 +73,35 @@ private:
 
     return context.TryCompile(test_program, '.cpp')
 
-def make_compiler_config(context):
+def make_c_compiler_config(context):
+    """
+    Create C compiler-specific configuration object.
+
+    Arguments:
+    context -- the scons configure context
+
+    The 'CC' key in the SCons environment will be mapped to the
+    appropriate supported compiler configuration.  If no match is
+    found compiler configuration operations will simply be no-ops.
+    """
+
+    global _c_compiler_config
+
+    if _c_compiler_config is None:
+        cc = context.env['CC']
+
+        if check_for_gcc_c(context):
+            cc = _GCC
+
+        config = _CONFIG_MAP.get(cc, DefaultConfiguration)
+
+        _c_compiler_config = config(context)
+
+    return _c_compiler_config
+
+def make_cxx_compiler_config(context):
     """
-    Create compiler-specific configuration object.
+    Create C++ compiler-specific configuration object.
 
     Arguments:
     context -- the scons configure context
@@ -64,9 +111,9 @@ def make_compiler_config(context):
     found compiler configuration operations will simply be no-ops.
     """
 
-    global _compiler_config
+    global _cxx_compiler_config
 
-    if _compiler_config is None:
+    if _cxx_compiler_config is None:
         cxx = context.env['CXX']
 
         if check_for_gcc_cxx(context):
@@ -74,6 +121,6 @@ def make_compiler_config(context):
 
         config = _CONFIG_MAP.get(cxx, DefaultConfiguration)
 
-        _compiler_config = config(context)
+        _cxx_compiler_config = config(context)
 
-    return _compiler_config
+    return _cxx_compiler_config
index d9ceb1767c3894ec0e94b67df3d7ed6d437e9e02..ded43a7bd4694ccfdc8869b48577ad2d2a5e1971 100644 (file)
@@ -21,6 +21,38 @@ class GccConfiguration(Configuration):
     def __init__(self, context):
         Configuration.__init__(self, context)
 
+    # ------------------------------------------------------------
+    # Return test program to be used when checking for basic C99
+    # support in GCC.
+    # ------------------------------------------------------------
+    def _c99_test_program(self):
+        # Use the default C99 test program but enable pedantic
+        # diagnostics specific to GCC to force errors to occur if a
+        # flag is required to compile C99 code without warning or
+        # error.
+
+        from default_configuration import DefaultConfiguration
+        def_config = DefaultConfiguration(self._context)
+
+        return """
+#pragma GCC diagnostic error "-Wall"
+#pragma GCC diagnostic error "-Werror"
+#pragma GCC diagnostic error "-pedantic"
+""" + def_config._c99_test_program()
+
+    # -------------------------------------------------------------
+    # Get flags known to enable C99 support for GCC C compiler.
+    # -------------------------------------------------------------
+    def _c99_flags(self):
+        # Favor flags that do not enable GNU extensions by default,
+        # e.g. '-std=c99'.
+        return [ '-std=c99',
+                 '-std=iso9899:1999',
+                 '-std=gnu99',
+                 '-std=c9x',
+                 '-std=iso9899:199x',
+                 '-std=gnu9x' ]
+
     # ------------------------------------------------------------
     # Return test program to be used when checking for basic C++11
     # support in GCC.
index 83e9bfa749bb5f0624cc5bf232b87f89ae934bf5..84f440f87e578d0e6c65f997193d41d6efc4eb67 100755 (executable)
@@ -31,7 +31,6 @@ liboctbstack_env.PrependUnique(CPPPATH = [
 
 if target_os not in ['arduino', 'windows', 'winrt']:
        liboctbstack_env.AppendUnique(CPPDEFINES  = ['WITH_POSIX'])
-       liboctbstack_env.AppendUnique(CFLAGS = ['-std=c99'])
 
 if target_os not in ['windows', 'winrt']:
        liboctbstack_env.AppendUnique(CFLAGS = ['-Wall'])
index c7bba1591eb1907a6c9ec30957c949a120993d5b..1d1315808182e948dd8d162c36c09f2bc9f0dd42 100644 (file)
@@ -26,8 +26,7 @@ libcoap_env.PrependUnique(CPPPATH = [
                ])
 
 if target_os not in ['arduino', 'windows', 'winrt']:
-       libcoap_env.AppendUnique(CPPDEFINES = ['WITH_POSIX'])
-       libcoap_env.AppendUnique(CFLAGS = ['-std=gnu99'])
+       libcoap_env.AppendUnique(CPPDEFINES = ['WITH_POSIX', '_BSD_SOURCE'])
 
 if target_os not in ['windows', 'winrt']:
        libcoap_env.AppendUnique(CFLAGS = ['-Wall', '-ffunction-sections',
index c5e3a1585ae8a16f9b27241898515d60ffd6e0c5..17f7883d6c3e9b6974c255871b00abade3af59f8 100644 (file)
@@ -16,7 +16,6 @@ if target_os == 'android':
        liboc_logger_env.AppendUnique(LIBS = ['gnustl_shared', 'log'])
 
 if target_os not in ['arduino', 'windows', 'winrt']:
-       liboc_logger_env.AppendUnique(CFLAGS = ['-std=c99'])
        liboc_logger_env.AppendUnique(CCFLAGS = ['-Wall'])
 
 ######################################################################
index 73cce37daa7460876d4bccc6b7d76be677671c61..46e1b0825dd8c0e33664119ac2a118fded6f614c 100644 (file)
@@ -18,7 +18,7 @@ if target_os == 'android':
        examples_env.AppendUnique(LIBS = ['gnustl_shared'])
 
 if target_os not in ['arduino', 'windows', 'winrt']:
-       examples_env.AppendUnique(CFLAGS = Split('-Wall -std=c99 -Werror'))
+       examples_env.AppendUnique(CFLAGS = Split('-Wall -Werror'))
        examples_env.AppendUnique(CXXFLAGS = '-Wall')
 
 ######################################################################
index a5695c219c5ffa1c1daeb00909af3869832224f6..fc2add8eed70ab5df458dda3d211b7f881c51c12 100644 (file)
@@ -14,6 +14,8 @@ target_os = env.get('TARGET_OS')
 ######################################################################
 mosquitto_env.AppendUnique(CPPPATH = ['./'])
 if target_os not in ['windows', 'winrt']:
+       # strdup() and pselect() require specific extensions to be enabled.
+       mosquitto_env.AppendUnique(CPPDEFINES = [('_XOPEN_SOURCE', 600)])
        mosquitto_env.AppendUnique(CFLAGS = ['-Wall', '-ggdb', '-fPIC',
                        '-DWITH_TLS', '-DWITH_TLS_PSK', '-DWITH_THREADING'])
 ######################################################################
index 7f94dea40aabcefc3a9e5ec78df63d55f8fdcd69..a6dd2a7fa92b708edc7ca1954a94db2b57e2bbc9 100644 (file)
@@ -33,6 +33,7 @@ POSSIBILITY OF SUCH DAMAGE.
 #include <stdio.h>
 #include <string.h>
 #ifndef WIN32
+#include <strings.h>  /* for strcasecmp() */
 #include <sys/select.h>
 #include <sys/time.h>
 #include <unistd.h>