| Help(''' |
| Type 'scons' to build and run all the available test cases. |
| It will automatically detect your platform and C compiler and |
| build appropriately. |
| |
| You can modify the behaviour using following options: |
| BUILDDIR Directory to build into (default "build") |
| CC Name of C compiler |
| CXX Name of C++ compiler |
| CCFLAGS Flags to pass to the C compiler |
| CXXFLAGS Flags to pass to the C++ compiler |
| LINK Name of linker (usually same as CC) |
| LINKFLAGS Flags to pass to linker |
| LINKLIBS Flags to pass to linker after object files |
| PROTOC Path to protoc binary |
| PROTOCFLAGS Arguments to pass protoc |
| NODEFARGS Do not add the default CCFLAGS |
| NOVALGRIND Do not use valgrind for memory checks |
| |
| For example, for a clang build, use: |
| scons CC=clang CXX=clang++ |
| ''') |
| |
| import os |
| import platform |
| env = Environment(ENV = os.environ) |
| |
| # Allow giving environment flags on command line. |
| list_vars = ['CCFLAGS', 'CXXFLAGS', 'LINKFLAGS', 'LINKLIBS', 'PROTOCFLAGS'] |
| for var,val in ARGUMENTS.items(): |
| if var in list_vars: |
| env.Append(**{var: val}) |
| else: |
| env.Replace(**{var: val}) |
| |
| env.SetDefault(BUILDDIR = "build") |
| env.SConsignFile(env['BUILDDIR'] + "/sconsign") |
| env.Replace(CONFIGUREDIR = env['BUILDDIR'] + "/config") |
| |
| # If a cross compilation platform is given, apply the environment settings |
| # from site_scons/platforms/X/X.py |
| if ARGUMENTS.get('PLATFORM'): |
| platform_func = platforms.get(ARGUMENTS.get('PLATFORM')) |
| if not platform_func: |
| print("Supported platforms: " + str(platforms.keys())) |
| raise Exception("Unsupported platform: " + ARGUMENTS.get('PLATFORM')) |
| else: |
| platform_func(env) |
| |
| # Load nanopb generator build rules from site_scons/site_tools/nanopb.py |
| env.Tool("nanopb") |
| |
| # Limit memory usage. This is to catch problems like issue #338 |
| try: |
| import resource |
| soft, hard = resource.getrlimit(resourse.RLIMIT_AS) |
| resource.setrlimit(resource.RLIMIT_AS, (100*1024*1024, hard)) |
| except: |
| pass |
| |
| # On Mac OS X, gcc is usually alias for clang. |
| # To avoid problem with default options, use clang directly. |
| if platform.system() == "Darwin" and 'CC' not in ARGUMENTS: |
| env.Replace(CC = "clang", CXX = "clang++") |
| |
| # Add the builders defined in site_init.py |
| add_nanopb_builders(env) |
| |
| # Path to the files shared by tests, and to the nanopb core. |
| env.Append(CPPPATH = ["#../", "$COMMON"]) |
| |
| # Path for finding nanopb.proto |
| env.Append(PROTOCPATH = '#../generator') |
| |
| # Check the compilation environment, unless we are just cleaning up. |
| if not env.GetOption('clean'): |
| def check_ccflags(context, flags, linkflags = ''): |
| '''Check if given CCFLAGS are supported''' |
| context.Message('Checking support for CCFLAGS="%s"... ' % flags) |
| oldflags = context.env['CCFLAGS'] |
| oldlinkflags = context.env['LINKFLAGS'] |
| context.env.Append(CCFLAGS = flags) |
| context.env.Append(LINKFLAGS = linkflags) |
| result = context.TryCompile("int main() {return 0;}", '.c') |
| context.env.Replace(CCFLAGS = oldflags) |
| context.env.Replace(LINKFLAGS = oldlinkflags) |
| context.Result(result) |
| return result |
| |
| def check_protocversion(context): |
| context.Display("Checking protoc version... ") |
| status, output = context.TryAction('$PROTOC --version > $TARGET') |
| if status: |
| context.Result(str(output.strip())) |
| return str(output.strip()) |
| else: |
| context.Display("error: %s\n" % output.strip()) |
| context.did_show_result = 1 |
| context.Result("unknown, assuming 3.6.1") |
| return "3.6.1" |
| |
| conf = Configure(env, custom_tests = |
| {'CheckCCFLAGS': check_ccflags, |
| 'CheckProtocVersion': check_protocversion}) |
| |
| # If the platform doesn't support C99, use our own header file instead. |
| stdbool = conf.CheckCHeader('stdbool.h') |
| stdint = conf.CheckCHeader('stdint.h') |
| stddef = conf.CheckCHeader('stddef.h') |
| string = conf.CheckCHeader('string.h') |
| stdlib = conf.CheckCHeader('stdlib.h') |
| limits = conf.CheckCHeader('limits.h') |
| if not stdbool or not stdint or not stddef or not string or not limits: |
| conf.env.Append(CPPDEFINES = {'PB_SYSTEM_HEADER': '\\"pb_syshdr.h\\"'}) |
| conf.env.Append(CPPPATH = "#../extra") |
| conf.env.Append(SYSHDR = '\\"pb_syshdr.h\\"') |
| |
| if stdbool: conf.env.Append(CPPDEFINES = {'HAVE_STDBOOL_H': 1}) |
| if stdint: conf.env.Append(CPPDEFINES = {'HAVE_STDINT_H': 1}) |
| if stddef: conf.env.Append(CPPDEFINES = {'HAVE_STDDEF_H': 1}) |
| if string: conf.env.Append(CPPDEFINES = {'HAVE_STRING_H': 1}) |
| if stdlib: conf.env.Append(CPPDEFINES = {'HAVE_STDLIB_H': 1}) |
| if limits: conf.env.Append(CPPDEFINES = {'HAVE_LIMITS_H': 1}) |
| |
| # Check protoc version |
| conf.env['PROTOC_VERSION'] = conf.CheckProtocVersion() |
| |
| # Initialize compiler arguments with defaults, unless overridden on |
| # command line. |
| if not env.get('NODEFARGS'): |
| # Check if libmudflap is available (only with GCC) |
| if 'gcc' in env['CC']: |
| if conf.CheckLib('mudflap'): |
| conf.env.Append(CCFLAGS = '-fmudflap') |
| conf.env.Append(LINKFLAGS = '-fmudflap') |
| |
| # Check if we can use extra strict warning flags (only with GCC) |
| extra = '-Wcast-qual -Wlogical-op -Wconversion' |
| extra += ' -fstrict-aliasing -Wstrict-aliasing=1' |
| extra += ' -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls' |
| extra += ' -Wstack-protector ' |
| if 'gcc' in env['CC']: |
| if conf.CheckCCFLAGS(extra): |
| conf.env.Append(CORECFLAGS = extra) |
| |
| # Check if we can use undefined behaviour sanitizer (only with clang) |
| # TODO: Fuzz test triggers the bool sanitizer, figure out whether to |
| # modify the fuzz test or to keep ignoring the check. |
| extra = '-fsanitize=undefined,integer -fno-sanitize-recover=undefined,integer ' |
| if 'clang' in env['CC']: |
| if conf.CheckCCFLAGS(extra, linkflags = extra): |
| conf.env.Append(CORECFLAGS = extra) |
| conf.env.Append(LINKFLAGS = extra) |
| |
| # End the config stuff |
| env = conf.Finish() |
| |
| if not env.get('NODEFARGS'): |
| # Initialize the CCFLAGS according to the compiler |
| if 'gcc' in env['CC']: |
| # GNU Compiler Collection |
| |
| # Debug info, warnings as errors |
| env.Append(CFLAGS = '-g -Wall -Werror ') |
| env.Append(CORECFLAGS = '-Wextra ') |
| |
| # Pedantic ANSI C. On AVR this doesn't work because we use large |
| # enums in some of the tests. |
| if env.get("EMBEDDED") != "AVR": |
| env.Append(CFLAGS = '-ansi ') |
| env.Append(CORECFLAGS = '-pedantic ') |
| |
| # Profiling and coverage |
| if not env.get("EMBEDDED"): |
| env.Append(CFLAGS = '-fprofile-arcs -ftest-coverage ') |
| env.Append(LINKFLAGS = '-g --coverage') |
| |
| |
| # We currently need uint64_t anyway, even though ANSI C90 otherwise.. |
| env.Append(CFLAGS = '-Wno-long-long') |
| elif 'clang' in env['CC']: |
| # CLang |
| env.Append(CFLAGS = '-ansi -g -Wall -Werror') |
| env.Append(CORECFLAGS = ' -Wextra -Wcast-qual -Wconversion') |
| elif 'cl' in env['CC']: |
| # Microsoft Visual C++ |
| |
| # Debug info on, warning level 2 for tests, warnings as errors |
| env.Append(CFLAGS = '/Zi /W2 /WX') |
| env.Append(LINKFLAGS = '/DEBUG') |
| |
| # More strict checks on the nanopb core |
| env.Append(CORECFLAGS = '/W4') |
| |
| # Enable C11 standard |
| env.Append(CFLAGS = ' /std:c11 ') |
| |
| # Disable warning about sizeof(union{}) construct that is used in |
| # message size macros, in e.g. multiple_files testcase. The C construct |
| # itself is valid, but quite rare, which causes Visual C++ to give a warning |
| # about it. |
| env.Append(CFLAGS = '/wd4116') |
| elif 'tcc' in env['CC']: |
| # Tiny C Compiler |
| env.Append(CFLAGS = '-Wall -Werror -g') |
| |
| if 'clang' in env['CXX']: |
| env.Append(CXXFLAGS = '-g -Wall -Werror -Wextra -Wno-missing-field-initializers') |
| elif 'g++' in env['CXX'] or 'gcc' in env['CXX']: |
| env.Append(CXXFLAGS = '-g -Wall -Werror -Wextra -Wno-missing-field-initializers -std=gnu++11') |
| elif 'cl' in env['CXX']: |
| env.Append(CXXFLAGS = '/Zi /W2 /WX /wd4116 /wd4127') |
| |
| env.SetDefault(CORECFLAGS = '') |
| |
| if not env.get("EMBEDDED") and not env.get("NOVALGRIND"): |
| valgrind = env.WhereIs('valgrind') |
| if valgrind: |
| env.SetDefault(VALGRIND = valgrind) |
| |
| # Make it possible to add commands to the end of linker line |
| env.SetDefault(LINKLIBS = '') |
| env.Replace(LINKCOM = env['LINKCOM'] + " $LINKLIBS") |
| |
| # Place build files under separate folder |
| import os.path |
| env['VARIANT_DIR'] = env['BUILDDIR'] |
| env['BUILD'] = '#' + env['VARIANT_DIR'] |
| env['COMMON'] = '#' + env['VARIANT_DIR'] + '/common' |
| |
| # Include common/SConscript first to make sure its exports are available |
| # to other SConscripts. |
| SConscript("common/SConscript", exports = 'env', variant_dir = env['VARIANT_DIR'] + '/common') |
| |
| # Now include the SConscript files from all subdirectories |
| for subdir in Glob('*/SConscript') + Glob('regression/*/SConscript'): |
| if str(subdir).startswith("common/"): continue |
| if str(subdir).startswith("common\\"): continue |
| SConscript(subdir, exports = 'env', variant_dir = env['VARIANT_DIR'] + '/' + os.path.dirname(str(subdir))) |
| |