1Help(''' 2Type 'scons' to build and run all the available test cases. 3It will automatically detect your platform and C compiler and 4build appropriately. 5 6You can modify the behaviour using following options: 7BUILDDIR Directory to build into (default "build") 8CC Name of C compiler 9CXX Name of C++ compiler 10CCFLAGS Flags to pass to the C compiler 11CXXFLAGS Flags to pass to the C++ compiler 12LINK Name of linker (usually same as CC) 13LINKFLAGS Flags to pass to linker 14LINKLIBS Flags to pass to linker after object files 15PROTOC Path to protoc binary 16PROTOCFLAGS Arguments to pass protoc 17NODEFARGS Do not add the default CCFLAGS 18NOVALGRIND Do not use valgrind for memory checks 19 20For example, for a clang build, use: 21scons CC=clang CXX=clang++ 22''') 23 24import os 25import platform 26env = Environment(ENV = os.environ) 27 28# Allow giving environment flags on command line. 29list_vars = ['CCFLAGS', 'CXXFLAGS', 'LINKFLAGS', 'LINKLIBS', 'PROTOCFLAGS'] 30for var,val in ARGUMENTS.items(): 31 if var in list_vars: 32 env.Append(**{var: val}) 33 else: 34 env.Replace(**{var: val}) 35 36env.SetDefault(BUILDDIR = "build") 37env.SConsignFile(env['BUILDDIR'] + "/sconsign") 38env.Replace(CONFIGUREDIR = env['BUILDDIR'] + "/config") 39 40# If a cross compilation platform is given, apply the environment settings 41# from site_scons/platforms/X/X.py 42if ARGUMENTS.get('PLATFORM'): 43 platform_func = platforms.get(ARGUMENTS.get('PLATFORM')) 44 if not platform_func: 45 print("Supported platforms: " + str(platforms.keys())) 46 raise Exception("Unsupported platform: " + ARGUMENTS.get('PLATFORM')) 47 else: 48 platform_func(env) 49 50# Load nanopb generator build rules from site_scons/site_tools/nanopb.py 51env.Tool("nanopb") 52 53# Limit memory usage. This is to catch problems like issue #338 54try: 55 import resource 56 soft, hard = resource.getrlimit(resourse.RLIMIT_AS) 57 resource.setrlimit(resource.RLIMIT_AS, (100*1024*1024, hard)) 58except: 59 pass 60 61# On Mac OS X, gcc is usually alias for clang. 62# To avoid problem with default options, use clang directly. 63if platform.system() == "Darwin" and 'CC' not in ARGUMENTS: 64 env.Replace(CC = "clang", CXX = "clang++") 65 66# Add the builders defined in site_init.py 67add_nanopb_builders(env) 68 69# Path to the files shared by tests, and to the nanopb core. 70env.Append(CPPPATH = ["#../", "$COMMON"]) 71 72# Path for finding nanopb.proto 73env.Append(PROTOCPATH = '#../generator') 74 75# Check the compilation environment, unless we are just cleaning up. 76if not env.GetOption('clean'): 77 def check_ccflags(context, flags, linkflags = ''): 78 '''Check if given CCFLAGS are supported''' 79 context.Message('Checking support for CCFLAGS="%s" LINKFLAGS="%s"... ' % (flags, linkflags)) 80 oldflags = context.env['CCFLAGS'] 81 oldlinkflags = context.env['LINKFLAGS'] 82 context.env.Append(CCFLAGS = flags) 83 context.env.Append(LINKFLAGS = linkflags) 84 result = context.TryCompile("int main() {return 0;}", '.c') 85 context.env.Replace(CCFLAGS = oldflags) 86 context.env.Replace(LINKFLAGS = oldlinkflags) 87 context.Result(result) 88 return result 89 90 def check_protocversion(context): 91 context.Display("Checking protoc version... ") 92 status, output = context.TryAction('$PROTOC --version > $TARGET') 93 if status: 94 context.Result(str(output.strip())) 95 return str(output.strip()) 96 else: 97 context.Display("error: %s\n" % output.strip()) 98 context.did_show_result = 1 99 context.Result("unknown, assuming 3.6.1") 100 return "3.6.1" 101 102 conf = Configure(env, custom_tests = 103 {'CheckCCFLAGS': check_ccflags, 104 'CheckProtocVersion': check_protocversion}) 105 106 # If the platform doesn't support C99, use our own header file instead. 107 stdbool = conf.CheckCHeader('stdbool.h') 108 stdint = conf.CheckCHeader('stdint.h') 109 stddef = conf.CheckCHeader('stddef.h') 110 string = conf.CheckCHeader('string.h') 111 stdlib = conf.CheckCHeader('stdlib.h') 112 limits = conf.CheckCHeader('limits.h') 113 if not stdbool or not stdint or not stddef or not string or not limits: 114 conf.env.Append(CPPDEFINES = {'PB_SYSTEM_HEADER': '\\"pb_syshdr.h\\"'}) 115 conf.env.Append(CPPPATH = "#../extra") 116 conf.env.Append(SYSHDR = '\\"pb_syshdr.h\\"') 117 118 if stdbool: conf.env.Append(CPPDEFINES = {'HAVE_STDBOOL_H': 1}) 119 if stdint: conf.env.Append(CPPDEFINES = {'HAVE_STDINT_H': 1}) 120 if stddef: conf.env.Append(CPPDEFINES = {'HAVE_STDDEF_H': 1}) 121 if string: conf.env.Append(CPPDEFINES = {'HAVE_STRING_H': 1}) 122 if stdlib: conf.env.Append(CPPDEFINES = {'HAVE_STDLIB_H': 1}) 123 if limits: conf.env.Append(CPPDEFINES = {'HAVE_LIMITS_H': 1}) 124 125 # Some platforms need libm for isnan() 126 if conf.CheckCCFLAGS('', linkflags = '-lm'): 127 conf.env.Append(LINKFLAGS = '-lm') 128 129 # Check protoc version 130 conf.env['PROTOC_VERSION'] = conf.CheckProtocVersion() 131 132 # Initialize compiler arguments with defaults, unless overridden on 133 # command line. 134 if not env.get('NODEFARGS'): 135 # Check if libmudflap is available (only with GCC) 136 if 'gcc' in env['CC']: 137 if conf.CheckLib('mudflap'): 138 conf.env.Append(CCFLAGS = '-fmudflap') 139 conf.env.Append(LINKFLAGS = '-fmudflap') 140 141 # Check if we can use extra strict warning flags (only with GCC) 142 extra = '-Wcast-qual -Wlogical-op -Wconversion' 143 extra += ' -fstrict-aliasing -Wstrict-aliasing=1' 144 extra += ' -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls' 145 extra += ' -Wstack-protector ' 146 if 'gcc' in env['CC']: 147 if conf.CheckCCFLAGS(extra): 148 conf.env.Append(CORECFLAGS = extra) 149 150 # Check if we can use undefined behaviour sanitizer (only with clang) 151 # TODO: Fuzz test triggers the bool sanitizer, figure out whether to 152 # modify the fuzz test or to keep ignoring the check. 153 extra = '-fsanitize=undefined,integer -fno-sanitize-recover=undefined,integer ' 154 if 'clang' in env['CC']: 155 if conf.CheckCCFLAGS(extra, linkflags = extra): 156 conf.env.Append(CORECFLAGS = extra) 157 conf.env.Append(LINKFLAGS = extra) 158 159 # End the config stuff 160 env = conf.Finish() 161 162if not env.get('NODEFARGS'): 163 # Initialize the CCFLAGS according to the compiler 164 if 'gcc' in env['CC']: 165 # GNU Compiler Collection 166 167 # Debug info, warnings as errors 168 env.Append(CFLAGS = '-g -Wall -Werror ') 169 env.Append(CORECFLAGS = '-Wextra ') 170 171 # Pedantic ANSI C. On AVR this doesn't work because we use large 172 # enums in some of the tests. 173 if env.get("EMBEDDED") != "AVR": 174 env.Append(CFLAGS = '-ansi ') 175 env.Append(CORECFLAGS = '-pedantic ') 176 177 # Profiling and coverage 178 if not env.get("EMBEDDED"): 179 env.Append(CFLAGS = '-fprofile-arcs -ftest-coverage ') 180 env.Append(LINKFLAGS = '-g --coverage') 181 182 183 # We currently need uint64_t anyway, even though ANSI C90 otherwise.. 184 env.Append(CFLAGS = '-Wno-long-long') 185 elif 'clang' in env['CC']: 186 # CLang 187 env.Append(CFLAGS = '-ansi -g -Wall -Werror') 188 env.Append(CORECFLAGS = ' -Wextra -Wcast-qual -Wconversion') 189 elif 'cl' in env['CC']: 190 # Microsoft Visual C++ 191 192 # Debug info on, warning level 2 for tests, warnings as errors 193 env.Append(CFLAGS = '/Zi /W2 /WX') 194 env.Append(LINKFLAGS = '/DEBUG') 195 196 # More strict checks on the nanopb core 197 env.Append(CORECFLAGS = '/W4') 198 199 # Enable C11 standard 200 env.Append(CFLAGS = ' /std:c11 ') 201 202 # Disable warning about sizeof(union{}) construct that is used in 203 # message size macros, in e.g. multiple_files testcase. The C construct 204 # itself is valid, but quite rare, which causes Visual C++ to give a warning 205 # about it. 206 env.Append(CFLAGS = '/wd4116') 207 elif 'tcc' in env['CC']: 208 # Tiny C Compiler 209 env.Append(CFLAGS = '-Wall -Werror -g') 210 211 if 'clang' in env['CXX']: 212 env.Append(CXXFLAGS = '-g -Wall -Werror -Wextra -Wno-missing-field-initializers') 213 elif 'g++' in env['CXX'] or 'gcc' in env['CXX']: 214 env.Append(CXXFLAGS = '-g -Wall -Werror -Wextra -Wno-missing-field-initializers -std=gnu++11') 215 elif 'cl' in env['CXX']: 216 env.Append(CXXFLAGS = '/Zi /W2 /WX /wd4116 /wd4127') 217 218env.SetDefault(CORECFLAGS = '') 219 220if not env.get("EMBEDDED") and not env.get("NOVALGRIND"): 221 valgrind = env.WhereIs('valgrind') 222 if valgrind: 223 env.SetDefault(VALGRIND = valgrind) 224 225# Make it possible to add commands to the end of linker line 226env.SetDefault(LINKLIBS = '') 227env.Replace(LINKCOM = env['LINKCOM'] + " $LINKLIBS") 228 229# Place build files under separate folder 230import os.path 231env['VARIANT_DIR'] = env['BUILDDIR'] 232env['BUILD'] = '#' + env['VARIANT_DIR'] 233env['COMMON'] = '#' + env['VARIANT_DIR'] + '/common' 234 235# Include common/SConscript first to make sure its exports are available 236# to other SConscripts. 237SConscript("common/SConscript", exports = 'env', variant_dir = env['VARIANT_DIR'] + '/common') 238 239# Now include the SConscript files from all subdirectories 240for subdir in Glob('*/SConscript') + Glob('regression/*/SConscript'): 241 if str(subdir).startswith("common/"): continue 242 if str(subdir).startswith("common\\"): continue 243 SConscript(subdir, exports = 'env', variant_dir = env['VARIANT_DIR'] + '/' + os.path.dirname(str(subdir))) 244 245