1from waflib import Logs 2from waflib import Options 3from waflib import Utils 4 5 6class CompilerTraits(object): 7 def get_warnings_flags(self, level): 8 """get_warnings_flags(level) -> list of cflags""" 9 raise NotImplementedError 10 11 def get_optimization_flags(self, level): 12 """get_optimization_flags(level) -> list of cflags""" 13 raise NotImplementedError 14 15 def get_debug_flags(self, level): 16 """get_debug_flags(level) -> (list of cflags, list of cppdefines)""" 17 raise NotImplementedError 18 19 20class GccTraits(CompilerTraits): 21 def __init__(self): 22 super(GccTraits, self).__init__() 23 # cumulative list of warnings per level 24 self.warnings_flags = [['-Wall'], ['-Werror'], ['-Wextra']] 25 26 def get_warnings_flags(self, level): 27 warnings = [] 28 for l in range(level): 29 if l < len(self.warnings_flags): 30 warnings.extend(self.warnings_flags[l]) 31 else: 32 break 33 return warnings 34 35 def get_optimization_flags(self, level): 36 if level == 0: 37 return ['-O0'] 38 elif level == 1: 39 return ['-O'] 40 elif level == 2: 41 return ['-O2'] 42 elif level == 3: 43 return ['-O3'] 44 45 def get_debug_flags(self, level): 46 if level == 0: 47 return (['-g0'], ['NDEBUG']) 48 elif level == 1: 49 return (['-g'], []) 50 elif level >= 2: 51 return (['-ggdb', '-g3'], ['_DEBUG']) 52 53 54class IccTraits(CompilerTraits): 55 def __init__(self): 56 super(IccTraits, self).__init__() 57 # cumulative list of warnings per level 58 # icc is _very_ verbose with -Wall, -Werror is barely achievable 59 self.warnings_flags = [[], [], ['-Wall']] 60 61 def get_warnings_flags(self, level): 62 warnings = [] 63 for l in range(level): 64 if l < len(self.warnings_flags): 65 warnings.extend(self.warnings_flags[l]) 66 else: 67 break 68 return warnings 69 70 def get_optimization_flags(self, level): 71 if level == 0: 72 return ['-O0'] 73 elif level == 1: 74 return ['-O'] 75 elif level == 2: 76 return ['-O2'] 77 elif level == 3: 78 return ['-O3'] 79 80 def get_debug_flags(self, level): 81 if level == 0: 82 return (['-g0'], ['NDEBUG']) 83 elif level == 1: 84 return (['-g'], []) 85 elif level >= 2: 86 return (['-ggdb', '-g3'], ['_DEBUG']) 87 88 89 90class MsvcTraits(CompilerTraits): 91 def __init__(self): 92 super(MsvcTraits, self).__init__() 93 # cumulative list of warnings per level 94 self.warnings_flags = [['/W2'], ['/WX'], ['/Wall']] 95 96 def get_warnings_flags(self, level): 97 warnings = [] 98 for l in range(level): 99 if l < len(self.warnings_flags): 100 warnings.extend(self.warnings_flags[l]) 101 else: 102 break 103 return warnings 104 105 def get_optimization_flags(self, level): 106 if level == 0: 107 return ['/Od'] 108 elif level == 1: 109 return [] 110 elif level == 2: 111 return ['/O2'] 112 elif level == 3: 113 return ['/Ox'] 114 115 def get_debug_flags(self, level): 116 if level == 0: 117 return ([], ['NDEBUG']) 118 elif level == 1: 119 return (['/ZI', '/RTC1'], []) 120 elif level >= 2: 121 return (['/ZI', '/RTC1'], ['_DEBUG']) 122 123 124gcc = GccTraits() 125icc = IccTraits() 126msvc = MsvcTraits() 127 128# how to map env['COMPILER_CC'] or env['COMPILER_CXX'] into a traits object 129compiler_mapping = { 130 'gcc': gcc, 131 'g++': gcc, 132 'msvc': msvc, 133 'icc': icc, 134 'icpc': icc, 135} 136 137profiles = { 138 # profile name: [optimization_level, warnings_level, debug_level] 139 'default': [2, 1, 1], 140 'debug': [0, 2, 3], 141 'release': [3, 1, 0], 142 } 143 144default_profile = 'default' 145 146def options(opt): 147 assert default_profile in profiles 148 opt.add_option('-d', '--build-profile', 149 action='store', 150 default=default_profile, 151 help=("Specify the build profile. " 152 "Build profiles control the default compilation flags" 153 " used for C/C++ programs, if CCFLAGS/CXXFLAGS are not" 154 " set set in the environment. [Allowed Values: %s]" 155 % ", ".join([repr(p) for p in list(profiles.keys())])), 156 choices=list(profiles.keys()), 157 dest='build_profile') 158 159def configure(conf): 160 cc = conf.env['COMPILER_CC'] or None 161 cxx = conf.env['COMPILER_CXX'] or None 162 if not (cc or cxx): 163 raise Utils.WafError("neither COMPILER_CC nor COMPILER_CXX are defined; " 164 "maybe the compiler_cc or compiler_cxx tool has not been configured yet?") 165 166 try: 167 compiler = compiler_mapping[cc] 168 except KeyError: 169 try: 170 compiler = compiler_mapping[cxx] 171 except KeyError: 172 Logs.warn("No compiler flags support for compiler %r or %r" 173 % (cc, cxx)) 174 return 175 176 opt_level, warn_level, dbg_level = profiles[Options.options.build_profile] 177 178 optimizations = compiler.get_optimization_flags(opt_level) 179 debug, debug_defs = compiler.get_debug_flags(dbg_level) 180 warnings = compiler.get_warnings_flags(warn_level) 181 182 if cc and not conf.env['CCFLAGS']: 183 conf.env.append_value('CCFLAGS', optimizations) 184 conf.env.append_value('CCFLAGS', debug) 185 conf.env.append_value('CCFLAGS', warnings) 186 conf.env.append_value('CCDEFINES', debug_defs) 187 if cxx and not conf.env['CXXFLAGS']: 188 conf.env.append_value('CXXFLAGS', optimizations) 189 conf.env.append_value('CXXFLAGS', debug) 190 conf.env.append_value('CXXFLAGS', warnings) 191 conf.env.append_value('CXXDEFINES', debug_defs) 192