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 behavious 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"... ' % flags) 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 # Check protoc version 126 conf.env['PROTOC_VERSION'] = conf.CheckProtocVersion() 127 128 # Initialize compiler arguments with defaults, unless overridden on 129 # command line. 130 if not env.get('NODEFARGS'): 131 # Check if libmudflap is available (only with GCC) 132 if 'gcc' in env['CC']: 133 if conf.CheckLib('mudflap'): 134 conf.env.Append(CCFLAGS = '-fmudflap') 135 conf.env.Append(LINKFLAGS = '-fmudflap') 136 137 # Check if we can use extra strict warning flags (only with GCC) 138 extra = '-Wcast-qual -Wlogical-op -Wconversion' 139 extra += ' -fstrict-aliasing -Wstrict-aliasing=1' 140 extra += ' -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls' 141 extra += ' -Wstack-protector ' 142 if 'gcc' in env['CC']: 143 if conf.CheckCCFLAGS(extra): 144 conf.env.Append(CORECFLAGS = extra) 145 146 # Check if we can use undefined behaviour sanitizer (only with clang) 147 # TODO: Fuzz test triggers the bool sanitizer, figure out whether to 148 # modify the fuzz test or to keep ignoring the check. 149 extra = '-fsanitize=undefined,integer -fno-sanitize-recover=undefined,integer ' 150 if 'clang' in env['CC']: 151 if conf.CheckCCFLAGS(extra, linkflags = extra): 152 conf.env.Append(CORECFLAGS = extra) 153 conf.env.Append(LINKFLAGS = extra) 154 155 # End the config stuff 156 env = conf.Finish() 157 158if not env.get('NODEFARGS'): 159 # Initialize the CCFLAGS according to the compiler 160 if 'gcc' in env['CC']: 161 # GNU Compiler Collection 162 163 # Debug info, warnings as errors 164 env.Append(CFLAGS = '-g -Wall -Werror ') 165 env.Append(CORECFLAGS = '-Wextra') 166 167 # Pedantic ANSI C. On AVR this doesn't work because we use large 168 # enums in some of the tests. 169 if env.get("EMBEDDED") != "AVR": 170 env.Append(CFLAGS = '-ansi -pedantic') 171 172 # Profiling and coverage 173 if not env.get("EMBEDDED"): 174 env.Append(CFLAGS = '-fprofile-arcs -ftest-coverage ') 175 env.Append(LINKFLAGS = '-g --coverage') 176 177 178 # We currently need uint64_t anyway, even though ANSI C90 otherwise.. 179 env.Append(CFLAGS = '-Wno-long-long') 180 elif 'clang' in env['CC']: 181 # CLang 182 env.Append(CFLAGS = '-ansi -g -Wall -Werror') 183 env.Append(CORECFLAGS = ' -Wextra -Wcast-qual -Wconversion') 184 elif 'cl' in env['CC']: 185 # Microsoft Visual C++ 186 187 # Debug info on, warning level 2 for tests, warnings as errors 188 env.Append(CFLAGS = '/Zi /W2 /WX') 189 env.Append(LINKFLAGS = '/DEBUG') 190 191 # More strict checks on the nanopb core 192 env.Append(CORECFLAGS = '/W4') 193 194 # Disable warning about sizeof(union{}) construct that is used in 195 # message size macros, in e.g. multiple_files testcase. The C construct 196 # itself is valid, but quite rare, which causes Visual C++ to give a warning 197 # about it. 198 env.Append(CFLAGS = '/wd4116') 199 elif 'tcc' in env['CC']: 200 # Tiny C Compiler 201 env.Append(CFLAGS = '-Wall -Werror -g') 202 203 if 'clang' in env['CXX']: 204 env.Append(CXXFLAGS = '-g -Wall -Werror -Wextra -Wno-missing-field-initializers') 205 elif 'g++' in env['CXX'] or 'gcc' in env['CXX']: 206 env.Append(CXXFLAGS = '-g -Wall -Werror -Wextra -Wno-missing-field-initializers') 207 elif 'cl' in env['CXX']: 208 env.Append(CXXFLAGS = '/Zi /W2 /WX /wd4116 /wd4127') 209 210env.SetDefault(CORECFLAGS = '') 211 212if not env.get("EMBEDDED") and not env.get("NOVALGRIND"): 213 valgrind = env.WhereIs('valgrind') 214 if valgrind: 215 env.SetDefault(VALGRIND = valgrind) 216 217# Make it possible to add commands to the end of linker line 218env.SetDefault(LINKLIBS = '') 219env.Replace(LINKCOM = env['LINKCOM'] + " $LINKLIBS") 220 221# Place build files under separate folder 222import os.path 223env['VARIANT_DIR'] = env['BUILDDIR'] 224env['BUILD'] = '#' + env['VARIANT_DIR'] 225env['COMMON'] = '#' + env['VARIANT_DIR'] + '/common' 226 227# Include common/SConscript first to make sure its exports are available 228# to other SConscripts. 229SConscript("common/SConscript", exports = 'env', variant_dir = env['VARIANT_DIR'] + '/common') 230 231# Now include the SConscript files from all subdirectories 232for subdir in Glob('*/SConscript') + Glob('regression/*/SConscript'): 233 if str(subdir).startswith("common/"): continue 234 if str(subdir).startswith("common\\"): continue 235 SConscript(subdir, exports = 'env', variant_dir = env['VARIANT_DIR'] + '/' + os.path.dirname(str(subdir))) 236 237