Package mbuild :: Module env
[frames] | no frames]

Source Code for Module mbuild.env

   1  #!/usr/bin/env python 
   2  # -*- python -*- 
   3  # Mark Charney  
   4  #BEGIN_LEGAL 
   5  # 
   6  #Copyright (c) 2016 Intel Corporation 
   7  # 
   8  #  Licensed under the Apache License, Version 2.0 (the "License"); 
   9  #  you may not use this file except in compliance with the License. 
  10  #  You may obtain a copy of the License at 
  11  # 
  12  #      http://www.apache.org/licenses/LICENSE-2.0 
  13  # 
  14  #  Unless required by applicable law or agreed to in writing, software 
  15  #  distributed under the License is distributed on an "AS IS" BASIS, 
  16  #  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  17  #  See the License for the specific language governing permissions and 
  18  #  limitations under the License. 
  19  #   
  20  #END_LEGAL 
  21   
  22  """Environment support""" 
  23  import os 
  24  import sys 
  25  import re 
  26  import platform 
  27  import types 
  28  import optparse 
  29  import time 
  30  import copy 
  31   
  32  from   base import * 
  33  import util 
  34  import build_env 
  35  import plan 
  36  import msvs 
  37  import mbuild 
  38   
39 -def _remove_libname(args,env):
40 #lib = env.expand('%(LIBNAME)s') 41 lib = args[0] 42 msgb("REMOVING", lib) 43 util.remove_file(lib) 44 return (0,['REMOVED %s\n' % ( lib )])
45 46 # 2014-04-02: Intel has 2 compilers for mac: icc and icl. Intel now 47 # calls their mac llvm-based comiler "icl". This confuses thing with 48 # the name of the windows intel compiler which is also called "icl". 49 # In mbuild, we call the Intel llvm-based compiler "iclang" to 50 # disambiguate the conflict. 51
52 -class env_t(object):
53 """The is the environment for compilation. The environment 54 includes a dictionary for holding everything custom about this 55 environment. The default environment includes: 56 57 - command line options. These are also in the environment dictionary. 58 - build_dir defaultE{:} obj 59 - src_dir defaultE{:} . or path to the mfile 60 - gen_dir defaultE{:} None (default path for generated files, if set) 61 - shared defaultE{:} False (default: no shared libraries) 62 - static defaultE{:} False (default: not to statically link) 63 - opt defaultE{:} 'noopt' (could be 'noopt, 0,1,2,3) 64 - debug defaultE{:} False 65 - separate_pdb_files defaultE{:} False 66 - targets defaultE{:} [] targets to build 67 - verbose defaultE{:} 1 68 - compiler defaultE{:} 'gnu', 'ms', 'clang', 'icc', 'icl', 'iclang' 69 - extra_defines defaultE{:} '' 70 - extra_flags defaultE{:} '' (for both CXXFLAGS & CCFLAGS) 71 - extra_cxxflags defaultE{:} '' 72 - extra_ccflags defaultE{:} '' 73 - extra_linkflags defaultE{:} '' 74 - extra_libs defaultE{:} '' 75 - use_yasm defaultE{:} False 76 77 - CPPPATH defaultE{:} [] The list of include paths 78 - SYSTEMINCLUDE defaultE{:} [] The list of system include paths (Not 79 supported by MSVS). 80 - DEFINES defaultE{:} {} The dictionary of defines 81 82 83 - short names for the primary compiler toolsE{:} 84 - CXX_COMPILER cl or g++ 85 - CC_COMPILER cl or gcc 86 - ASSEMBLER ml/ml64 or gcc/gas (gcc is the default for gnu) 87 - LINKER link or g++/gcc (g++ is the default for gnu) 88 - ARCHIVER ar 89 - RANLIB_CMD ranlib 90 91 - toolchain path to the compiler tools (default is ''). If toolchain is 92 set, it should end with a trailing slash. 93 - vc_dir path to the compiler VC directory for MSVS (default is '')n 94 - icc_version 7, 8, 9, 10, ... 95 - gcc_version 2.96, 3.x.y, 4.x.y, ... 96 - msvs_version 6 (VC98), 7 (.NET 2003), 8 (Pro 2005), ... 97 98 - primary compilation toolsE{:} 99 - CC cl or gcc (with toolchain path) 100 - CXX cl or g++ (with toolchain path) 101 - AS ml,ml64 or gcc/gas (with toolchain path) 102 - LINK link or gcc/g++ (with toolchain path) 103 - AR lib or ar (with toolchain path) 104 - RANLIB ranlib (with toolchain path) 105 - flags for primary toolsE{:} 106 - CCFLAGS 107 - CXXFLAGS 108 - ASFLAGS 109 - ARFLAGS 110 - LINKFLAGS 111 - LIBS (libraries for the end of the link statement) 112 113 - preprocessor flags 114 - DOPT /D or -D 115 - ASDOPT /D or -D 116 - IOPT /I or -I 117 - OPTPOPT /O or -O 118 - DEBUGOPT /Zi or -g 119 120 - options to control compilation outputE{:} 121 - COPT /c or -c 122 - COUT /Fo or -o 123 - ASMOUT /Fo or -o 124 - LIBOUT /outE{:} or -o 125 - LINKOUT /OUTE{:} or -o 126 - DLLOPT -shared 127 128 - Override-buildersE{:} set these to a function pointer if you want 129 to replace the default builder function. 130 131 - ASSEMBLE_BUILDER if not set default is to use assemble_default() 132 - CXX_COMPILE_BUILDER if not set default is to use cxx_default() 133 - CC_COMPILE_BUILDER if not set default is to use cc_default() 134 - LINK_BUILDER if not set default is to use link_default() 135 - STATIC_LIBRARY_BUILDER if not set default is to use static_lib_default() 136 - DYNAMIC_LIBRARY_BUILDER if not set default is to use dynamic_lib_default() 137 138 - default extensionsE{:} 139 - OBJEXT .obj or .o 140 - LIBEXT .lib or .a 141 - DLLEXT .dll, .so, or .dylib 142 - EXEEXT .exe or '' 143 144 - System valuesE{:} 145 - uname standard python tuple of values from uname. 146 - system standard valuesE{:} 'Linux', 'Windows', 'Darwin', 'Microsoft', 'FreeBSD' 147 - hostname 148 - build_os standard valuesE{:} 'lin', 'win', 'mac', 'bsd' 149 - host_os standard valuesE{:} 'lin', 'win', 'mac', 'bsd' 150 - build_cpu standard valuesE{:} 'ia32', 'x86-64', 'ipf' 151 - host_cpu standard valuesE{:} 'ia32', 'x86-64', 'ipf' 152 153 """ 154 155 obj_pattern = re.compile(r'.obj$') 156 objext_pattern = re.compile(r'[%][(]OBJEXT[)]s$') 157 158 mbuild_subs_pattern = re.compile('%[(][^)]+[)]') 159 #FIXME: no backslashes in patterns! 160 assignment_pattern = re.compile(r'(?P<name>[-A-Za-z0-9_]+)[=](?P<value>.+)') 161 supplement_pattern = re.compile(r'(?P<name>[-A-Za-z0-9_]+)[+][=](?P<value>.+)') 162
163 - def version(self):
164 """Emit the version string. 165 @rtype: string 166 @return: The version string 167 """ 168 # FIXME: could put an Id in each sub-module and look at the 169 # doc strings for each one. 170 msgb("VERSION", "$Id: mbuild_env.py 44 2007-03-16 15:54:44Z mjcharne $")
171 - def __setitem__(self,k,value):
172 """Write a value to the environment dictionary""" 173 if isinstance(value,types.StringType): 174 self.env[k] = util.posix_slashes(value) 175 else: 176 self.env[k] = value
177 - def __contains__(self,k):
178 if k in self.env: 179 return True 180 return False
181
182 - def __getitem__(self,k):
183 """Read the environment dictionary. Not doing any 184 substitutions.""" 185 #return self.env[k] 186 try: 187 return self.env[k] 188 except: 189 die("env key not found: %s" % (k))
190
191 - def expand(self, command_string, newenv=None):
192 """Alias for expand_string()""" 193 return self.expand_string(command_string, newenv)
194
195 - def expand_string(self, command_string, newenv=None):
196 """Read the environment dictionary, doing recursive 197 substitutions from the environment. If no environment is 198 supplied, then the default environment is used. 199 200 @type command_string: string or list of strings 201 @param command_string: A string with %(...)s variables in it 202 @type newenv: L{env_t} 203 @param newenv: An environment within which to do the expansion. If 204 null, the default environment is used. 205 @rtype: string 206 """ 207 if newenv == None: 208 newenv = self.env 209 if isinstance(command_string, types.StringType): 210 return self._iterative_substitute(command_string, newenv) 211 if isinstance(command_string, types.ListType): 212 return map(lambda(x): self._iterative_substitute(x, newenv), command_string) 213 die("expand_string only handles substitution in strings or lists of strings")
214
215 - def expand_key(self,k, newenv=None):
216 """Read the the value of k from the environment dictionary, 217 doing recursive substitutions from the environment. If no 218 environment is supplied, then the default environment is used. 219 220 @type k: string or list of strings 221 @param k: A string (or strings) containing a single key name(s) 222 @type newenv: L{env_t} 223 @param newenv: An environment within which to do the expansion. If 224 null, the default environment is used. 225 @rtype: string 226 """ 227 if newenv == None: 228 newenv = self.env 229 if k not in newenv: 230 die("Could not find %s in the environment" % k) 231 232 233 if isinstance(newenv[k],types.ListType): 234 # We must process each string in the list and do 235 # substitutions on them. For example, CPPPATH 236 return map(lambda(x): self._iterative_substitute(x,newenv), newenv[k]) 237 if isinstance(newenv[k], types.StringType): 238 return self._iterative_substitute("%(" + k + ")s", newenv) 239 # non strings (scalars) 240 return newenv[k]
241
242 - def _mysub(self,input, keyname, newval):
243 """Replace %(keyname)s in input with newval""" 244 # only handling %(...)s replacement. Nothing fancy. 245 s = '%('+keyname+')s' 246 # simple string replacement, not regexp replacement 247 output = input.replace(s,newval) 248 return output
249 250
251 - def _iterative_substitute(self,s,dct1,debug=False):
252 """Replace all the %(...)s with values in s from the 253 dictionary dct1. Note, the dictionary can contain tuples of 254 the form (key, dict). In this case, this code uses the lookup 255 result of dct1[key] to query yet the dictionary dict. That 256 lookup can result in a string or another such tuple.""" 257 #error_msg("iterative_substitute", str(s)) 258 subs_pattern = re.compile('%[(](?P<name>[^)]+)[)]s') 259 t = s 260 m = subs_pattern.search(t) 261 while m: 262 name = m.group('name') 263 if name not in dct1: 264 die("Bad substitution for " + name) 265 #print "SUBSTITUTING %s" % name 266 v = dct1[name] 267 # repeatedly expand any tuples that show up. 268 while not isinstance(v,types.StringType): 269 if isinstance(v,types.TupleType): 270 (key, dct) = v 271 272 # look up key in the main dictionary to create a 273 # subkey for use in the 2nd level dictionary 274 275 try: 276 subkey = dct1[key] 277 except: 278 die("nested dictionary lookup error during iterative string " + 279 " expansion. key=%s" % (str(key))) 280 281 try: 282 v = dct[ subkey ] 283 except: 284 try: 285 v = dct['otherwise'] 286 except: 287 die("nested dictionary lookup error during iterative string " + 288 " expansion. key=%s subkey=%s" % (str(key),str(subkey))) 289 elif isinstance(v,types.FunctionType): 290 try: 291 v = v(dct1) 292 except: 293 die("Bad function invokation during iterative string expansion") 294 else: 295 die("Bad environment value: " + str(v) + 296 " when searching: " + s) 297 t = self._mysub(t,name,v) 298 m = subs_pattern.search(t) 299 if debug: 300 print t 301 return t
302
303 - def _dosub_old(self,s,d):
304 """Repeatedly substitute values from the dictionary d into the 305 string s while '%(...)' substrings remain in the thing we want 306 to return. If the input s is a list, then we recursively 307 expand each element of that list""" 308 309 if isinstance(s,types.ListType): 310 return map(lambda(x): self.dosub(x,d), s) 311 312 # The common case: Just expanding a simple string. 313 t = s 314 while env_t.mbuild_subs_pattern.search(t): 315 t = t % d 316 return t
317
318 - def __str__(self):
319 """Print out the environment""" 320 s = [] 321 s.append("BUILD_CPU:") 322 s.append(self.env['build_cpu']) 323 s.append("HOST_CPU:") 324 s.append(self.env['host_cpu']) 325 s.append("\nBUILD_OS: ") 326 s.append(self.env['build_os']) 327 s.append("\nHOST_OS: ") 328 s.append(self.env['host_os']) 329 s.append("\nUNAME: ") 330 s.append(str(self.env['uname'])) 331 s.append("\nHOSTNAME: ") 332 s.append(self.env['hostname']) 333 s.append("\nSYSTEM: ") 334 s.append(self.env['system']) 335 s.append("\nDICTIONARY:\n") 336 for k,v in self.env.iteritems(): 337 s.append("\t") 338 s.append(k) 339 s.append("->") 340 s.append(str(v)) 341 s.append("\n") 342 return ''.join(s)
343
344 - def verbose_startup(self):
345 if self._emitted_startup_msg: 346 return 347 self._emitted_startup_msg = True 348 if verbose(1): 349 msgb("INVOKED", " ".join(sys.argv)) 350 msgb("START TIME", self.env['start_time_str']) 351 msgb("CURRENT DIRECTORY", os.getcwd()) 352 353 msgb('UNAME', str(self.env['uname']).replace(':','_')) 354 msgb('SYSTEM', self.env['system']) 355 msgb('HOSTNAME', self.env['hostname']) 356 msgb("BUILD_OS", self.env['build_os']) 357 msgb("BUILD_CPU", self.env['build_cpu']) 358 msgb("HOST_OS", self.env['host_os']) 359 msgb("HOST_CPU", self.env['host_cpu'])
360
361 - def _check_registry_environment(self,env_var):
362 s = 'SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment' 363 try: 364 import _winreg 365 key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, s) 366 (val, typ) = _winreg.QueryValueEx(key, env_var) 367 return val 368 except: 369 mbuild.die(("Could not read windows registry for variable %s.\n" % \ 370 (env_var)) + 371 "Use win32 python and install pywin32")
372
374 375 return self._check_registry_environment('PROCESSOR_IDENTIFIER')
376 377
379 return self._check_registry_environment('NUMBER_OF_PROCESSORS')
380 381
382 - def __init__(self, init_verbose=1, default_knobs=True):
383 """Build up the environment for compilation. 384 """ 385 set_verbosity(int(init_verbose)) 386 self.env = {} 387 self.parsed_args = False 388 self.added_common_knobs=False 389 self.added_default_knobs=False 390 self.env['python'] = sys.executable 391 self.env['CPPPATH'] = [] 392 self.env['SYSTEMINCLUDE'] = [] 393 self.env['DEFINES'] = {} 394 395 self.env['LINKPATH'] = [] 396 self.env['LINKDIRS'] = '' 397 self.env['LINKFLAGS'] = ' %(LINKDIRS)s ' 398 399 self.env['targets'] = [] 400 401 # defaults for the build dir and src dir 402 self.env['build_dir'] = 'obj' 403 self.env['src_dir'] = '' # we set this accordingly 404 self.env['gen_dir'] = None # location of generated files that do not exist 405 self.env['shared'] = False 406 self.env['static'] = False 407 self.env['debug'] = False 408 self.env['separate_pdb_files'] = False 409 self.env['opt'] = 'noopt' 410 411 self.env['LIBS'] = '' # default link libraries 412 self.env['CXX_COMPILER'] = '' 413 self.env['CC_COMPILER'] = '' 414 self.env['ASSEMBLER'] = '' 415 self.env['LINKER'] = '' 416 417 418 # windows rc tool for dll resource files. 419 self.env['RC'] = '' 420 self.env['RC_CMD'] = '' 421 self.env['RCFLAGS'] = '' 422 423 # use_compiler_to_link = True if using the compiler to link. 424 # use_compiler_to_link = False if using the linker to link 425 self.env['use_compiler_to_link'] = False 426 self.env['ARCHIVER'] = '' 427 self.env['RANLIB_CMD'] = '' 428 429 self.env['CXX'] = '' 430 self.env['CC'] = '' 431 self.env['LINK'] = '' 432 self.env['AR'] = '' 433 self.env['AS'] = '' 434 self.env['RANLIB'] = '' 435 436 self.env['uname'] = platform.uname() 437 self.env['hostname'] = platform.node() 438 self.env['system'] = platform.system() # sort of like build_os 439 # distro is the empty string on mac and windows 440 if util.check_python_version(2,6): 441 (distro, distro_ver, distro_id) = platform.linux_distribution() 442 else: 443 distro = '' 444 distro_ver = '' 445 self.env['distro'] = distro.strip() 446 self.env['distro_version'] = distro_ver 447 448 449 if 'HOME' in os.environ: 450 self.env['home'] = os.environ['HOME'] 451 else: 452 self.env['home'] = 'unknown' 453 454 # the colons in the time string are replaced by underscores. 455 # The colons confused xemacs compilation mode error 456 # parsing. (emacs was fine) 457 458 self.env['start_time_str'] = re.sub(":","_",util.get_time_str()) 459 self.start_time = util.get_time() 460 461 #Old versions of mbuild used target_cpu erroneously instead of 462 #host_cpu. We do a little magic later to try to make those old 463 #uses continue to work. 464 self.env['target_cpu']=None 465 466 if self.env['system'] in [ 'Linux', 'FreeBSD']: 467 uname = platform.uname() 468 self.env['build_os'] = self._normalize_os_name(uname[0]) 469 470 self.env['build_cpu'] = \ 471 self._normalize_cpu_name(uname[4]) 472 473 elif self.env['system'] in [ 'Darwin']: 474 uname = platform.uname() 475 self.env['build_os'] = self._normalize_os_name(uname[0]) 476 x = uname[4] 477 if self._check_mac_64b(): 478 x = 'x86_64' 479 self.env['build_cpu'] = \ 480 self._normalize_cpu_name(x) 481 elif self.on_windows(): 482 self.env['build_os'] = self._normalize_os_name(os.environ['OS']) 483 if 'PROCESSOR_IDENTIFIER' in os.environ: 484 p = os.environ['PROCESSOR_IDENTIFIER'] 485 else: 486 p = self._check_processor_identifier_windows() 487 self.env['build_cpu'] = \ 488 self._normalize_cpu_name(p) 489 490 else: 491 die("Unknown platform") 492 493 # where the compiled thing runs, not where it is built 494 # but that is the starting default. 495 self.env['host_cpu'] = self.env['build_cpu'] 496 self.env['host_os'] = self.env['build_os'] 497 498 self._add_compilation_support() 499 500 501 self._emitted_startup_msg = False 502 503 mbuild_env_defaults = dict( 504 args = [], 505 mbuild_version=False, 506 jobs='4', 507 build_dir='obj', 508 src_dir='', 509 gen_dir=None, 510 verbose= -1, 511 arg_host_cpu=None, 512 arg_host_os=None, 513 compiler=self.default_compiler(), 514 debug=False, 515 shared=False, 516 static=False, 517 opt='noopt', 518 silent=False, 519 extra_defines=[], 520 extra_flags=[], 521 extra_cxxflags=[], 522 extra_ccflags=[], 523 extra_linkflags=[], 524 extra_libs=[], 525 toolchain='', 526 ignorable_files=[], # deprecated, unused 2011-10-20 527 required_files=[], 528 vc_dir='', 529 msvs_version='', 530 setup_msvc=False, 531 icc_version='', 532 gcc_version='', 533 cc='', 534 cxx='', 535 linker='', 536 ar='', 537 538 use_yasm=False, 539 cygwin_limit_jobs=True 540 ) 541 542 # as is a keyword so must set it separately 543 mbuild_env_defaults['as']='' 544 545 # store the default if we ever need them 546 self.env_defaults = mbuild_env_defaults 547 # put them in the initial environment 548 self.update_dict(mbuild_env_defaults) 549 550 self.parser = optparse.OptionParser() 551 # set the defaults in the command line option parser 552 self.parser.set_defaults(**mbuild_env_defaults) 553 554 if default_knobs: 555 self.add_common_knobs() 556 self.add_default_knobs()
557 558
559 - def add_common_knobs(self):
560 if self.added_common_knobs: 561 return 562 self.added_common_knobs=True 563 self.parser.add_option( 564 "-j", "--jobs", 565 dest="jobs", 566 action="store", 567 help="Number of concurrent worker threads to use.")
568
569 - def add_default_knobs(self):
570 if self.added_default_knobs: 571 return 572 self.added_default_knobs=True 573 self.parser.add_option( 574 "--mbuild-version", 575 dest="mbuild_version", 576 action="store_true", 577 help="Emit the version information") 578 self.parser.add_option( 579 "--build-dir", 580 dest="build_dir", 581 action="store", 582 help="Build directory, default is 'obj'") 583 self.parser.add_option( 584 "--src-dir", 585 action="store", 586 dest="src_dir", 587 help="The directory where the sources are located.") 588 self.parser.add_option( 589 "--gen-dir", 590 action="store", 591 dest="gen_dir", 592 help="The directory where generated sources are assumed" + 593 " to be located.") 594 self.parser.add_option( 595 "-v", 596 "--verbose", 597 action="store", 598 dest="verbose", 599 help="Verbosity level. Defaults to value passed to env_t()") 600 self.parser.add_option( 601 "--compiler", 602 dest="compiler", 603 action="store", 604 help="Compiler (ms,gnu,clang,icc,icl,iclang)." + 605 " Default is gnu on linux and" + 606 " ms on windows. Default is: %s" % (self.default_compiler())) 607 self.parser.add_option( 608 "--debug", 609 dest="debug", 610 action="store_true", 611 help="Debug build") 612 self.parser.add_option( 613 "--shared", 614 dest="shared", 615 action="store_true", 616 help="Shared DLL build") 617 self.parser.add_option( 618 "--static", 619 dest="static", 620 action="store_true", 621 help="Statically link executables") 622 self.parser.add_option( 623 "--opt", 624 dest="opt", 625 action="store", 626 help="Optimization level noopt, 0, 1, 2, 3") 627 self.parser.add_option( 628 "-s", 629 "--silent", 630 dest="silent", 631 action="store_true", 632 help="Silence all but the most important messages") 633 self.parser.add_option( 634 "--extra-defines", 635 dest="extra_defines", 636 action="append", 637 help="Extra preprocessor defines") 638 self.parser.add_option( 639 "--extra-flags", 640 dest="extra_flags", 641 action="append", 642 help="Extra values for CXXFLAGS and CCFLAGS") 643 self.parser.add_option( 644 "--extra-cxxflags", 645 dest="extra_cxxflags", 646 action="append", 647 help="Extra values for CXXFLAGS") 648 self.parser.add_option( 649 "--extra-ccflags", 650 dest="extra_ccflags", 651 action="append", 652 help="Extra values for CCFLAGS") 653 self.parser.add_option( 654 "--extra-linkflags", 655 dest="extra_linkflags", 656 action="append", 657 help="Extra values for LINKFLAGS") 658 self.parser.add_option( 659 "--extra-libs", 660 dest="extra_libs", 661 action="append", 662 help="Extra values for LIBS") 663 self.parser.add_option( 664 "--toolchain", 665 dest="toolchain", 666 action="store", 667 help="Compiler toolchain") 668 self.parser.add_option( 669 "--vc-dir", 670 dest="vc_dir", 671 action="store", 672 help="MSVS Compiler VC directory. For finding libraries " + 673 " and setting the toolchain") 674 self.parser.add_option( 675 '--msvs-version', 676 '--msvc-version', 677 '--msvsversion', 678 '--msvcversion', 679 dest='msvs_version', 680 action='store', 681 help="MSVS version 6=VC98, 7=VS .Net 2003, 8=VS 2005," + 682 " 9=VS 2008, 10=VS 2010/DEV10, 11=VS2012/DEV11" + 683 "This sets certain flags and idioms for quirks in some compilers.") 684 self.parser.add_option( 685 '--setup-msvc', 686 '--setup-msvs', 687 '--msvs-setup', 688 '--msvc-setup', 689 dest='setup_msvc', 690 action='store_true', 691 help="Use the value of the --msvc-version to initialize" + 692 " the MSVC configuration.") 693 self.parser.add_option( 694 '--icc-version', 695 '--iccver', 696 '--icc-ver', 697 dest='icc_version', 698 action='store', 699 help="ICC/ICL version 7, 8, 9, 10, 11") 700 self.parser.add_option( 701 '--gcc-version', 702 '--gccversion', 703 '--gcc-ver', 704 dest='gcc_version', 705 action='store', 706 help="GCC version, with dots as in 2.96, 3.4.3, 4.2.0, etc. ") 707 708 self.parser.add_option( 709 "--cc", 710 dest="cc", 711 action="store", 712 help="full path to C compiler") 713 self.parser.add_option( 714 "--cxx", 715 dest="cxx", 716 action="store", 717 help="full path to C++ compiler") 718 self.parser.add_option( 719 "--linker", 720 dest="linker", 721 action="store", 722 help="full path to linker") 723 self.parser.add_option( 724 "--ar", 725 dest="ar", 726 action="store", 727 help="full path to archiver (lib/ar)") 728 self.parser.add_option( 729 "--as", 730 dest="as", 731 action="store", 732 help="full path to assembler (gas/as/ml/ml64)") 733 734 self.parser.add_option( 735 "--yasm", 736 dest="use_yasm", 737 action="store_true", 738 help="Use yasm") 739 self.parser.add_option( 740 "--no-cygwin-limit", 741 dest="cygwin_limit_jobs", 742 action="store_false", 743 help="Do not limit cygwin to one job at a time. " + 744 " Default is to limit cygwin to one job.") 745 746 self.parser.add_option( 747 "--host-cpu", 748 dest="arg_host_cpu", 749 action="store", 750 help="Host CPU, typically ia32, intel64 or x86-64") 751 752 self.parser.add_option( 753 "--host-os", 754 dest="arg_host_os", 755 action="store", 756 help="Host OS (where the binary runs)")
757
758 - def _implied_compiler(self,dct):
759 """If one of the icc_version, gcc_version_ or msvs_version 760 variables are set, deduce the compiler variable setting.""" 761 762 # windows default is ms so no need to set that. 763 if dct['icc_version'] != '': 764 if self.on_windows(): 765 dct['compiler'] = 'icl' 766 else: 767 dct['compiler'] = 'icc' 768 if dct['gcc_version'] != '': 769 dct['compiler'] = 'gnu'
770
771 - def _check_mac_ncpu(self):
772 """How many CPUs on a mac""" 773 774 cmd = "/usr/sbin/sysctl hw.ncpu" 775 (retval,output, error_output) = util.run_command(cmd) 776 if retval == 0 and len(output)>0: 777 if re.match('hw.ncpu', output[0]): 778 n = int(re.sub('hw.ncpu: ','',output[0])) 779 return n 780 return 0
781
782 - def number_of_cpus(self):
783 """Return the number of CPUs or 0 if we don't know anything for sure""" 784 n = 0 785 if self.on_mac(): 786 n = self._check_mac_ncpu() 787 elif self.on_windows(): 788 ns = "NUMBER_OF_PROCESSORS" 789 if ns in os.environ: 790 nsv = os.environ[ns] 791 else: 792 nsv = self._check_number_of_processors_windows() 793 n = int(nsv) 794 elif self.on_freebsd(): 795 getconf = "/usr/bin/getconf" 796 if os.path.exists(getconf): 797 cmd = "%s NPROCESSORS_ONLN" % (getconf) # or NPROCESSORS_CONF 798 (retval, output, error_output) = util.run_command(cmd) 799 if retval == 0 and len(output)>0: 800 n = int(output[0]) 801 else: 802 f = '/proc/cpuinfo' 803 proc_pat= re.compile(r'proces') 804 if os.path.exists(f): 805 for line in file(f).readlines(): 806 if proc_pat.search(line): 807 n += 1 808 return n
809
810 - def update_dict(self, dct):
811 """Update the environment dictionary with another dictionary.""" 812 self.env.update(dct)
813
814 - def copy_settings(self, incoming_env, kwds, replace=False):
815 816 """Update the environment dictionary with elements of kwds 817 from the dictionary in the incoming_env. Lists are extended with the 818 incoming elements and other types of elements are assigned directly. 819 820 @type incoming_env: env_t 821 @param incoming_env: the source environment 822 823 @type kwds: list of strings 824 @param kwds: elements to copy from the source enviornment 825 826 @type replace: bool 827 @param replace: if True, replace lists in the source environment 828 """ 829 for k in kwds: 830 if k in incoming_env: 831 t = incoming_env[k] 832 if isinstance(t,types.ListType) and replace==False: 833 self.env[k].extend(t) 834 else: 835 self.env[k] = t 836 else: 837 die("copy_settings() could not read key %s from incoming environment" % k)
838
839 - def update(self, targets=None):
840 """Post process the current environment, setting targets and bindings""" 841 842 # if the dct['args'] exists, supplement the targets list with 843 # that. This is how non-command-line invocations of mbuild 844 # pass the "other stuff" 845 if targets == None: 846 targets = [] 847 848 if not isinstance(targets,types.ListType): 849 die("The 'targets' environment option must be a list") 850 851 if 'args' in self.env: 852 args = self.env['args'] 853 if isinstance(args,types.ListType): 854 targets.extend(args) 855 else: 856 die("The 'args' environment option must be a list") 857 858 # split up the targets list so we can extract the command line 859 # variable bindings 860 just_targets = [] 861 bindings = [] 862 for t in targets: 863 ap = env_t.assignment_pattern.match(t) 864 if ap: 865 msgb("BINDING", "%s --> [%s]" % 866 (ap.group('name'), ap.group('value'))) 867 bindings.append( (ap.group('name'), 868 ap.group('value'), 'equals' )) 869 continue 870 sp = env_t.supplement_pattern.match(t) 871 if ap: 872 msgb("BINDING", "%s --> [%s]" % 873 (ap.group('name'), ap.group('value'))) 874 bindings.append( (ap.group('name'), 875 ap.group('value'), 'plusequals') ) 876 continue 877 just_targets.append(t) 878 879 # add command line variable bindings to the environment 880 for (var,value, how) in bindings: 881 if how == 'equals': 882 self.env[var] = value 883 884 # early versions of mbuild used target_cpu instead of 885 # host_cpu. This next override compensates for that, 886 # compatibility with older clients. 887 if var == 'target_cpu': 888 self.env['host_cpu'] = value 889 890 elif how == 'plusequals': 891 self.add_to_var(var,value) 892 893 # give precidence to the knob for --host-cpu and --host-os 894 # over the default binding. 895 if self.env['arg_host_cpu']: 896 self.env['host_cpu'] = self.env['arg_host_cpu'] 897 if self.env['arg_host_os']: 898 self.env['host_os'] = self.env['arg_host_os'] 899 900 # make sure we understand what host cpu we are dealing 901 # with. If someone puts in an Intel64 it'll come out as 902 # x86-64. 903 904 self.env['host_cpu'] = self._normalize_cpu_name(self.env['host_cpu']) 905 self.env['host_os'] = self._normalize_os_name(self.env['host_os']) 906 self.add_to_var('targets',just_targets) 907 908 # old versions of mbuild used target_cpu. To allow them to 909 # continue to work, we copy target_cpu to host_cpu if 910 # target_cpu is non null and differs from the setting for the 911 # host_cpu and the host_cpu is the same as the build_cpu. If 912 # the host_cpu and build_cpu differ, someone must have set 913 # host_cpu so leave it alone in that case. 914 915 if self.env['target_cpu']: 916 if self.env['target_cpu'] != self.env['host_cpu']: 917 # build_cpu and host_cpu start out the same, so only 918 # change host_cpu if it has the original value. 919 if self.env['build_cpu'] == self.env['host_cpu']: 920 self.env['host_cpu'] = self.env['target_cpu']
921 922
923 - def process_user_settings(self):
924 """Set the initial derived environment settings""" 925 926 self.update() 927 928 if self.env['mbuild_version']: 929 self.version() 930 sys.exit(0) 931 932 self._implied_compiler(self.env) 933 934 if self.env['silent']: 935 set_verbosity(0) 936 else: 937 arg_verbosity = int(self.env['verbose']) 938 if arg_verbosity >= 0: 939 set_verbosity( arg_verbosity ) 940 self.verbose_startup() 941 942 # convert several of the lists to strings 943 for f in ['extra_cxxflags', 'extra_ccflags', 'extra_linkflags', 944 'extra_libs', 'extra_flags']: 945 self._flatten_list_to_string(f,self.env) 946 # distribute the "extra" flags. 947 if self.env['extra_flags']: 948 self.env['extra_cxxflags'] += ' ' + self.env['extra_flags'] 949 self.env['extra_ccflags'] += ' ' + self.env['extra_flags'] 950 951 # This starts the compilation environment off CLEAN 952 self.set_compiler_env() 953 954 # if the user did not use --src-dir, then we check the path to 955 # the mbuild script. If it there is no path, we assume we are 956 # in the right directory. If there is a path, we assume that 957 # is where the sources are, and change the option before anyone 958 # can see it. 959 if self.env['src_dir'] == '': 960 (path_to_src, this_file) = os.path.split(sys.argv[0]) 961 if path_to_src == '': 962 path_to_src = '.' 963 self.env['src_dir'] = util.posix_slashes(path_to_src) 964 965 # This works around a longstanding python-specific bug in 966 # cygwin with running multiple threads. 967 if self.on_windows(): 968 try: 969 import win32api # we don't use it. We just test for it. 970 except: 971 if self.env['cygwin_limit_jobs'] and self.on_cygwin(): 972 msgb('NOTE', 973 'Using just one worker thread to avoid' + \ 974 ' a cygwin threading problem.') 975 self.env['jobs'] = "1" 976 977 # if 0 jobs were specified, try to use 2x the number of cpus. 978 if self.env['jobs'] == '0': 979 n = self.number_of_cpus() 980 if n: 981 self.env['jobs'] = str(2*n) 982 msgb('NOTE', 983 'Setting jobs to %d, 2x the detected number of CPUs (%d)' % 984 (2*n,n)) 985 else: 986 self.env['jobs'] = "1" 987 msgb('NOTE', 988 'Setting jobs to 1 because we could not detect' + 989 ' the number of CPUs') 990 991 if verbose(1): 992 # print host_cpu here because it may be overridden for 993 # cross compilations 994 msgb("HOST_CPU", self.env['host_cpu'])
995 996 997 998
999 - def _flatten_list_to_string(self, field, dct):
1000 """See if options has a field named field. If it does and its 1001 value is a list, flatten the list, joining the substrings with 1002 spaces.""" 1003 if field in dct: 1004 v = dct[field] 1005 if isinstance(v,types.ListType): 1006 vflat = ' '.join(v) 1007 dct[field]= vflat
1008
1009 - def set_defaults(self, dct):
1010 1011 """Take the dictionary of defaults and apply to the 1012 environment. Any extra bindings and targets should be listed 1013 in the 'args' list option of the dictionary""" 1014 1015 self.parser.set_defaults(**dct) 1016 self.update_dict(dct)
1017 1018 1019
1020 - def parse_args(self, user_default_options=None):
1021 """Call this to re-initialize the environment from the command 1022 line arguments. This calls update() with the results of 1023 command line processing. 1024 @type user_default_options: dict 1025 @param user_default_options: dictionary of default options 1026 """ 1027 1028 # make parse_args() runnable only once per environment. 1029 # ("append"-mode arguments get messed up if args parsed 1030 # more than once.) 1031 if self.parsed_args: 1032 return 1033 self.parsed_args=True 1034 1035 if user_default_options: 1036 # pass a dictionary where keyword args are expected using 1037 # "**" SEE: 1038 # http://docs.python.org/tut/node6.html#SECTION006740000000000000000 1039 self.parser.set_defaults(**user_default_options) 1040 1041 (options, args) = self.parser.parse_args() 1042 dct = vars(options) 1043 dct['args'].extend(args) 1044 self.update_dict(dct) 1045 1046 self.process_user_settings()
1047 1048
1049 - def on_ipf(self):
1050 """@rtype: bool 1051 @return: True iff on IA64""" 1052 if self.env['build_cpu'] == 'ipf': 1053 return True 1054 return False
1055
1056 - def on_ia32(self):
1057 """@rtype: bool 1058 @return: True iff on IA32""" 1059 if self.env['build_cpu'] == 'ia32': 1060 return True 1061 return False
1062
1063 - def on_intel64(self):
1064 """@rtype: bool 1065 @return: True iff on Intel64""" 1066 if self.env['build_cpu'] == 'x86-64': 1067 return True 1068 return False
1069
1070 - def on_mac(self):
1071 """@rtype: bool 1072 @return: True iff on Mac OSX Darwin""" 1073 if self.env['system'] == 'Darwin': 1074 return True 1075 return False
1076
1077 - def mac_ver(self):
1078 if self.on_mac(): 1079 ver = platform.mac_ver()[0] 1080 (maj,min,rev) = ver.split('.') 1081 return (int(maj),int(min),int(rev)) 1082 return None
1083
1084 - def check_mac_ver(self, x,y,z):
1085 """@rtype: bool 1086 @return: True iff on a mac and the version is later than x.y.z""" 1087 if self.on_mac(): 1088 (maj,min,rev) = self.mac_ver() 1089 if x > maj: 1090 return False 1091 if x == maj and y > min: 1092 return False 1093 if x == maj and y == min and z > rev: 1094 return False 1095 return True 1096 return False
1097
1098 - def on_tiger(self):
1099 """@rtype: bool 1100 @return: True iff on Mac running OS X Tiger 10.4.x""" 1101 if self.check_mac_ver(10,4,0): 1102 return True 1103 return False
1104 - def on_leopard(self):
1105 """@rtype: bool 1106 @return: True iff on Mac running OS X Leopard 10.5.x""" 1107 if self.check_mac_ver(10,5,0): 1108 return True 1109 return False
1110
1111 - def on_freebsd(self):
1112 """@rtype: bool 1113 @return: True iff on freebsd""" 1114 if self.env['system'] == 'FreeBSD': 1115 return True 1116 return False
1117
1118 - def on_linux(self):
1119 """@rtype: bool 1120 @return: True iff on linux""" 1121 if self.env['system'] == 'Linux': 1122 return True 1123 return False
1124
1125 - def on_cygwin(self):
1126 """@rtype: bool 1127 @return: True iff on cygwin""" 1128 if len(self.env['system']) >= 6 and self.env['system'][0:6] == 'CYGWIN': 1129 return True 1130 return False
1131
1132 - def windows_native(self):
1133 """@rtype: bool 1134 @return: True iff on windows native -- not using cygwin""" 1135 if self.env['system'] == 'Windows' or self.env['system'] == 'Microsoft': 1136 return True 1137 return False
1138
1139 - def on_windows(self):
1140 """@rtype: bool 1141 @return: True iff on windows""" 1142 if self.windows_native(): 1143 return True 1144 return self.on_cygwin()
1145
1146 - def supports_avx(self):
1147 """Return True if system supports AVX1. Does not work 1148 on windows""" 1149 if self.on_linux(): 1150 lines = file('/proc/cpuinfo').readlines() 1151 for l in lines: 1152 if 'avx' in l: 1153 return True 1154 elif self.on_mac(): 1155 cmd = "/usr/sbin/sysctl hw.optional.avx1_0" 1156 (retval, output, error_output) = util.run_command(cmd) 1157 if retval == 0 and len(output)>0: 1158 if re.match('hw.optional.avx1_0: 1', output[0]): 1159 return True 1160 1161 # FIXME: find some way of doing this on windows 1162 return False
1163
1164 - def _check_mac_64b(self):
1165 """Check to see if a mac is 64b""" 1166 1167 cmd = "/usr/sbin/sysctl hw.optional.x86_64" 1168 (retval,output, error_output) = util.run_command(cmd) 1169 if retval == 0 and len(output)>0: 1170 if re.match('hw.optional.x86_64: 1', output[0]): 1171 return True 1172 return False
1173
1174 - def _normalize_cpu_name(self, name):
1175 """Internal function. Standardize various CPU identifiers""" 1176 if name in ['ia32', 'i386', 'i686','x86']: 1177 return 'ia32' 1178 elif name in ['ia32e', 'x86_64', 'amd64', 1179 'x86-64', 'Intel64','intel64']: 1180 return 'x86-64' 1181 elif name == 'ia64': 1182 return 'ipf' 1183 elif name[0:5] == 'EM64T': 1184 return 'x86-64' 1185 elif name[0:7] == 'Intel64': 1186 return 'x86-64' 1187 elif name == 'intel64': 1188 return 'x86-64' 1189 elif name[0:3] == 'x86': 1190 return 'ia32' 1191 else: 1192 die("Unknown cpu " + name)
1193
1194 - def _normalize_os_name(self,name):
1195 """Internal function. Standardize various O/S identifiers""" 1196 if name in ['android']: 1197 return 'android' 1198 elif name in ['lin', 'Linux']: 1199 return 'lin' 1200 elif name in ['mac', 'Darwin']: 1201 return 'mac' 1202 elif name in ['bsd', 'FreeBSD']: 1203 return 'bsd' 1204 elif name[0:6] == 'CYGWIN': 1205 return 'win' 1206 elif name in ['win', 'Windows_NT']: 1207 return 'win' 1208 else: 1209 die("Unknown os " + name)
1210
1211 - def default_compiler(self):
1212 """Default to ms on windows and gnu everywhere else. 1213 @rtype: string 1214 @returns: "ms" on windows, "clang" on mac, otherwise "gnu" 1215 """ 1216 if self.on_windows(): 1217 return "ms" 1218 if self.on_mac(): 1219 return "clang" 1220 return "gnu"
1221
1222 - def set_compiler_env(self, compiler_family=None):
1223 """Initialize the build environment based on the compiler 1224 environment variable setting. 1225 1226 Adds in the "extra" flags from the environment. 1227 1228 @type compiler_family: string 1229 @param compiler_family: an override for the default 1230 compiler family (gnu, ms, clang, icl, icc, iclang) 1231 """ 1232 1233 1234 # copy the command line version of the tool overrides to the 1235 # real ones that we use. 1236 1237 if self.env['cxx'] != '': 1238 self.env['CXX'] = self.env['cxx'] 1239 if self.env['cc'] != '': 1240 self.env['CC'] = self.env['cc'] 1241 if self.env['linker'] != '': 1242 self.env['LINK'] = self.env['linker'] 1243 if self.env['ar'] != '': 1244 self.env['AR'] = self.env['ar'] 1245 if self.env['as'] != '': 1246 self.env['AS'] = self.env['as'] 1247 1248 if compiler_family == None: 1249 if 'compiler' in self.env: 1250 self.env['compiler'] = self.env['compiler'].lower() 1251 compiler_family = self.env['compiler'] 1252 else: 1253 die("Compiler family not specified in the environment or as an argument") 1254 1255 if compiler_family == 'gnu': 1256 build_env.set_env_gnu(self) 1257 elif compiler_family == 'clang': 1258 build_env.set_env_clang(self) 1259 elif compiler_family == 'ms': 1260 build_env.set_env_ms(self) 1261 elif compiler_family == 'icc': 1262 build_env.set_env_icc(self) 1263 elif compiler_family == 'iclang': 1264 build_env.set_env_iclang(self) 1265 elif compiler_family == 'icl': 1266 build_env.set_env_icl(self) 1267 else: 1268 die("Compiler family not recognized. Need gnu or ms") 1269 1270 if self.env['use_yasm']: 1271 if verbose(1): 1272 msgb("USE YASM") 1273 build_env.yasm_support(self) 1274 1275 self.add_to_var('CXXFLAGS', self.env['extra_cxxflags']) 1276 self.add_to_var('CCFLAGS', self.env['extra_ccflags'] ) 1277 self.add_to_var('LINKFLAGS', self.env['extra_linkflags'] ) 1278 self.add_to_var('LIBS', self.env['extra_libs'] ) 1279 for d in self.env['extra_defines']: 1280 self.add_define(d)
1281
1282 - def resuffix(self, fn, newext):
1283 """Replace the suffix of single fn (or list of files) with 1284 newext. newext should supply its own dot if you want one. 1285 @type fn: string (or list of strings) 1286 @param fn: a filename 1287 @type newext: string 1288 @param newext: a new extension starting with a '.' 1289 @rtype: string 1290 @return: fn with a new suffix specified by newext 1291 """ 1292 if isinstance(fn,types.ListType): 1293 return map(lambda(x): self.resuffix(x,newext), fn) 1294 else: 1295 (root,ext) = os.path.splitext(fn) 1296 return root + newext
1297
1298 - def osenv_add_to_front(self,evar,newstring,osenv=None):
1299 """Add newstring to front of the environment variable osenv if given 1300 if not given add to os.environ """ 1301 environ = os.environ 1302 if osenv: 1303 environ = osenv 1304 1305 if self.on_windows(): 1306 sep = ';' 1307 else: 1308 sep = ':' 1309 if evar in environ: 1310 # The environment variable already exists 1311 environ[evar]= newstring + sep + environ[evar] 1312 else: 1313 # Support creation of a new environment variable 1314 environ[evar]= newstring
1315
1316 - def path_search(self,exe):
1317 path = os.environ['PATH'] 1318 if self.on_freebsd() or self.on_linux() or self.on_cygwin(): 1319 sep = ':' 1320 else: 1321 sep = ';' 1322 for p in path.split(sep): 1323 t = util.prefix_files(p,exe) 1324 if os.path.exists(t): 1325 return t 1326 return None
1327 1328
1329 - def make_obj(self,flist):
1330 """Take file or list of files and return a file or list of 1331 files with the OBJEXT extension from the environment. 1332 @type flist: string or list of strings 1333 @param flist: a filename (or list of filenames) 1334 @rtype: string 1335 @return: fn with a suffix specified %(OBJEXT)s 1336 """ 1337 return self.resuffix(flist,"%(OBJEXT)s")
1338 1339
1340 - def build_dir_join(self,files):
1341 """Make the file (or list of files) with the build 1342 directory name. 1343 1344 @type files: string or list of strings 1345 @param files: filename(s) 1346 1347 @rtype: string or list of strings 1348 @return: filenames prepended with the current build_dir 1349 """ 1350 1351 # FIXME: could do this lazily... and just prepend %(build_dir)s 1352 try: 1353 objdir = self.env['build_dir'] 1354 except: 1355 die("build_dir not defined in build_dir_join") 1356 if objdir == '': 1357 return files 1358 return util.prefix_files(objdir, files)
1359
1360 - def src_dir_join(self,files):
1361 """Prefix file (or list of files) with the src directory name. 1362 @type files: string or list of strings 1363 @param files: filename(s) 1364 1365 @rtype: string or list of strings 1366 @return: filenames prepended with the current src_dir 1367 """ 1368 # FIXME: could do this lazily... and just prepend %(src_dir)s 1369 try: 1370 srcdir = self.env['src_dir'] 1371 except: 1372 die("src_dir not defined in src_dir_join") 1373 if srcdir == '': 1374 return files 1375 return util.prefix_files(srcdir, files)
1376
1377 - def add_define(self,newdef):
1378 """Add a define or list defines to the CXXFLAGS and CCFLAGS 1379 @type newdef: string or list of strings 1380 @param newdef: string to add to the CXXFLAGS and CCFLAGS 1381 environment variables. 1382 """ 1383 self.add_cc_define(newdef) 1384 self.add_cxx_define(newdef) 1385 self.add_as_define(newdef)
1386
1387 - def _collect_defines(self, dlist):
1388 for d in dlist: 1389 if d not in self.env['DEFINES']: 1390 self.env['DEFINES'][d]=True
1391
1392 - def add_as_define(self,newdef):
1393 """Add a define or list defines to the ASFLAGS 1394 @type newdef: string or list of strings 1395 @param newdef: string to add to the ASFLAGS 1396 environment variable. 1397 """ 1398 if isinstance(newdef,types.ListType): 1399 deflist = newdef 1400 else: 1401 deflist = [ newdef ] 1402 self._collect_defines(deflist) 1403 for d in deflist: 1404 self.add_to_var('ASFLAGS', "%(ASDOPT)s" + d )
1405
1406 - def add_cc_define(self,newdef):
1407 """Add a define or list defines to the CCFLAGS 1408 @type newdef: string or list of strings 1409 @param newdef: string to add to the CCFLAGS 1410 environment variable. 1411 """ 1412 if isinstance(newdef,types.ListType): 1413 deflist = newdef 1414 else: 1415 deflist = [ newdef ] 1416 self._collect_defines(deflist) 1417 1418 for d in deflist: 1419 self.add_to_var('CCFLAGS', "%(DOPT)s" + d )
1420
1421 - def add_cxx_define(self,newdef):
1422 """Add a define or list defines to the CXXFLAGS 1423 @type newdef: string or list of strings 1424 @param newdef: string to add to the CXXFLAGS 1425 environment variable. 1426 """ 1427 if isinstance(newdef,types.ListType): 1428 deflist = newdef 1429 else: 1430 deflist = [ newdef ] 1431 self._collect_defines(deflist) 1432 for d in deflist: 1433 self.add_to_var('CXXFLAGS', "%(DOPT)s" + d )
1434 1435
1436 - def add_include_dir(self,include_dir):
1437 """Add a directory or list of directories to the CPPPATH. Just 1438 a short cut for adding things to the list of files in the 1439 env['CPPPATH'] 1440 @type include_dir: string or list of strings 1441 @param include_dir: string to add to the CPPPATH environment variable 1442 """ 1443 if isinstance(include_dir,types.ListType): 1444 lst = include_dir 1445 else: 1446 lst = [ include_dir ] 1447 for d in lst: 1448 p = util.posix_slashes(d) 1449 if p not in self.env['CPPPATH']: 1450 self.env['CPPPATH'].append(p)
1451
1452 - def add_system_include_dir(self,sys_include_dir):
1453 """Add a directory or list of directories to the SYSTEMINCLUDE. Just 1454 a short cut for adding things to the list of files in the 1455 env['SYSTEMINCLUDE'] 1456 @type sys_include_dir: string or list of strings 1457 @param sys_include_dir: string to add to the SYSTEMINCLUDE environment variable 1458 """ 1459 if isinstance(sys_include_dir,types.ListType): 1460 lst = sys_include_dir 1461 else: 1462 lst = [ sys_include_dir ] 1463 for d in lst: 1464 p = util.posix_slashes(d) 1465 if p not in self.env['SYSTEMINCLUDE']: 1466 self.env['SYSTEMINCLUDE'].append(p)
1467 1480 1481
1482 - def remove_from_var(self, var, value):
1483 """Remove a substring (or list entry) from env[var]. Opposite 1484 of add_to_var(). 1485 1486 @type var: string 1487 @param var: name of a dictionary key 1488 @type value: string 1489 @param value: the value to remove 1490 """ 1491 if var in self.env: 1492 if isinstance(self.env[var], types.ListType): 1493 try: 1494 self.env[var].remove(value) 1495 except: 1496 pass 1497 else: 1498 self.env[var] = re.sub(value,'',self.env[var])
1499 1500
1501 - def add_to_var(self, var, value):
1502 """Add or append value to the environment variable var. If the 1503 variable is not in the environment, then it is added as 1504 is. Otherwise if the variable is in the environment and is a 1505 list then value is appended. Otherwise, the value is appended 1506 as a string with a leading space. This will *NOT* do variable 1507 substitution when adding to a variable. 1508 1509 @type var: string 1510 @param var: name of a dictionary key 1511 @type value: string 1512 @param value: the value to add or append 1513 1514 """ 1515 if var not in self.env: 1516 self.env[var] = value 1517 elif isinstance(self.env[var],types.ListType): 1518 if isinstance(value, types.ListType): 1519 self.env[var].extend(value) 1520 else: 1521 self.env[var].append(value) 1522 else: 1523 self.env[var] += ' ' + value # This would do variable expansion when calling __getitem__
1524 1525 # These strings should be % env expanded. 1526 1527 # COUT should be "-o " on linux. Note the trailing space 1528 # COPT should be "-c" on linux 1529 # OBJNAME and SRCNAME should be fully qualified suffix-wise 1530 # OBJNAMES is used for the link and lib statements 1531 # EXENAME is used for link statements 1532 # LIBNAME is used for lib statements 1533 # SOLIBNAME is used for shared objects "soname" embedded names 1534 # LIBOUT, LINKOUT should be set appropriately. Trailing spaces needed on linux 1535 # DLLOPT is needed for dynamic libraries 1536 1537 # Example: 1538 # a = '%(lang)s has %(c)03d quote types.' % dict(lang='Python', c=2) 1539
1540 - def _add_c_compile(self):
1541 s = "%(CC)s %(CPPINCLUDES)s %(SYSINCLUDES)s %(CCFLAGS)s %(COPT)s %(COUT)s%(OBJNAME)s %(SRCNAME)s" 1542 return s
1543
1544 - def _add_assemble(self):
1545 s = "%(AS)s %(CPPINCLUDES)s %(SYSINCLUDES)s %(ASFLAGS)s %(ASMOUT)s%(OBJNAME)s %(SRCNAME)s" 1546 return s
1547
1548 - def _add_cxx_compile(self):
1549 s = "%(CXX)s %(CPPINCLUDES)s %(SYSINCLUDES)s %(CXXFLAGS)s %(COPT)s %(COUT)s%(OBJNAME)s %(SRCNAME)s" 1550 return s
1551 1555
1556 - def _add_static_lib(self):
1557 s = [ _remove_libname, 1558 "%(AR)s %(ARFLAGS)s %(LIBOUT)s%(LIBNAME)s %(OBJNAMES)s" ] 1559 return s
1560
1561 - def _add_dynamic_lib(self):
1562 s = "%(LINK)s %(LINKFLAGS)s %(DLLOPT)s %(LIBOUT)s%(LIBNAME)s %(OBJNAMES)s %(LIBS)s" 1563 return s
1564
1565 - def _add_cxx_shared_lib(self):
1566 s = "%(CXX)s %(LINKFLAGS)s %(DLLOPT)s %(COUT)s%(LIBNAME)s %(OBJNAMES)s %(LIBS)s" 1567 return s
1568
1569 - def _add_res_file_cmd(self):
1570 s = "%(RC)s %(RCFLAGS)s /fo%(RESNAME)s %(RCNAME)s" 1571 return s
1572
1573 - def _add_default_builders(self):
1574 """Private. Part of initialization for the environment. Sets 1575 the default builders""" 1576 1577 # Instead use default function if these are not set. 1578 self.env['ASSEMBLE_BUILDER'] = None 1579 self.env['CXX_COMPILE_BUILDER'] = None 1580 self.env['CC_COMPILE_BUILDER'] = None 1581 self.env['LINK_BUILDER'] = None 1582 self.env['STATIC_LIBRARY_BUILDER'] = None 1583 self.env['DYNAMIC_LIBRARY_BUILDER'] = None 1584 self.env['RES_FILE_BUILDER'] = None
1585
1587 """Private. Part of initialization for the environment. Sets 1588 the default templates used by the default builders""" 1589 self.env['CC_COMPILE_COMMAND'] = self._add_c_compile() 1590 self.env['CXX_COMPILE_COMMAND'] = self._add_cxx_compile() 1591 self.env['ASSEMBLE_COMMAND'] = self._add_assemble() 1592 self.env['LINK_COMMAND'] = self._add_link() 1593 self.env['STATIC_LIB_COMMAND'] = self._add_static_lib() 1594 self.env['DYNAMIC_LIB_COMMAND'] = self._add_dynamic_lib() 1595 self.env['CXX_SHARED_LIB_COMMAND'] = self._add_cxx_shared_lib() 1596 self.env['RES_FILE_COMMAND'] = self._add_res_file_cmd()
1597
1598 - def _add_compilation_support(self):
1599 """Private. Part of initialization for the environment. Sets 1600 the default builders and templates.""" 1601 self._add_default_builders() 1602 self._add_default_builder_templates()
1603
1604 - def escape_string(self,s):
1605 if self.on_windows(): 1606 return util.cond_add_quotes(s) 1607 else: 1608 t = s.replace(' ','\ ') 1609 return t
1610 - def _escape_list_of_strings(self,sl):
1611 n = [] 1612 for s in sl: 1613 n.append(self.escape_string(s)) 1614 return n
1615
1616 - def _make_cpp_include(self):
1617 s = [] 1618 1619 iopt = self.env['IOPT'] 1620 1621 for p in self.env['CPPPATH']: 1622 s.extend([iopt, self.escape_string(p), ' ']) 1623 return ''.join(s)
1624
1625 - def _make_system_include(self):
1626 s = [] 1627 iopt = self.env['ISYSOPT'] 1628 for p in self.env['SYSTEMINCLUDE']: 1629 s.extend([iopt, self.escape_string(p), ' ']) 1630 return ''.join(s)
1631 1638
1639 - def _make_cpp_flags(self):
1640 self.env['CPPINCLUDES'] = self._make_cpp_include()
1641 - def _make_sys_include_flags(self):
1642 self.env['SYSINCLUDES'] = self._make_system_include()
1645
1646 - def make_derived_flags(self):
1647 """Put together any derived flags. This is required to be 1648 called by builder functions before they do their expansion. 1649 """ 1650 1651 self._make_cpp_flags() 1652 self._make_sys_include_flags() 1653 self._make_link_flags()
1654 1655 1656
1657 - def assemble(self, source, obj=None):
1658 """Indirection function. Reads builder function from the 1659 environment variable ASSEMBLER_BUILDER. Assemble a source file 1660 to the obj file. If no obj file name is given one will be 1661 created in the build directory. 1662 @type source: string 1663 @param source: filename to assemble 1664 1665 @type obj: string 1666 @param obj: output filename. 1667 1668 @rtype: L{plan_t} 1669 @return: an input for the DAG 1670 """ 1671 # FIXME abspath breaks windows compilation under cygwin python 1672 new_source = os.path.abspath(source) 1673 1674 f= self.env['ASSEMBLE_BUILDER'] 1675 if f: 1676 return f(new_source,obj) 1677 return self._assemble_default(new_source,obj)
1678
1679 - def cxx_compile(self, source, obj=None):
1680 """Indirection function. Reads builder function from the 1681 environment variable CXX_COMPILE_BUILDER. C++-compile a source 1682 file to a file called obj. If no obj file name is given one 1683 will be created in the build directory. 1684 @type source: string 1685 @param source: filename to compile 1686 1687 @type obj: string 1688 @param obj: output filename. 1689 1690 @rtype: L{plan_t} 1691 @return: an input for the DAG 1692 """ 1693 # FIXME abspath breaks windows compilation under cygwin python 1694 new_source = os.path.abspath(source) 1695 1696 f = self.env['CXX_COMPILE_BUILDER'] 1697 if f: 1698 return f(new_source,obj) 1699 return self._cxx_compile_default(new_source,obj)
1700
1701 - def cc_compile(self, source, obj=None):
1702 """Indirection function. Reads builder function from the 1703 environment variable CC_COMPILE_BUILDER. C-compile a source 1704 file to a file named obj. If no obj file name is given one 1705 will be created in the build directory. 1706 @type source: string 1707 @param source: filename to compile 1708 1709 @type obj: string 1710 @param obj: output filename. 1711 1712 @rtype: L{plan_t} 1713 @return: an input for the DAG 1714 """ 1715 1716 # FIXME abspath breaks windows compilation under cygwin python 1717 new_source = os.path.abspath(source) 1718 1719 f = self.env['CC_COMPILE_BUILDER'] 1720 if f: 1721 return f(new_source,obj) 1722 return self._cc_compile_default(new_source,obj)
1723 1746
1747 - def static_lib(self, objs, libname, relocate=False):
1748 """Indirection function. Reads builder function from the 1749 environment variable STATIC_LIBRARY_BUILDER. Make a static 1750 library libname from objs. If relocate is True, then prefix 1751 libname with the build directory name 1752 1753 @type objs: list of strings 1754 @param objs: filenames to link 1755 1756 @type libname: string 1757 @param libname: output filename. 1758 1759 @type relocate: bool 1760 @param relocate: If true, relocate the library to the build directory. 1761 1762 @rtype: L{plan_t} 1763 @return: an input for the DAG 1764 1765 1766 """ 1767 f = self.env['STATIC_LIBRARY_BUILDER'] 1768 if f: 1769 return f(objs,libname, relocate) 1770 return self._static_lib_default(objs,libname,relocate)
1771
1772 - def compile_and_static_lib(self, dag, sources, libname):
1773 """Build all the sources by adding them to the dag. Use the 1774 suffixes to figure out how to handle the files. The dag can be 1775 passed to a work queue. See the build function. """ 1776 1777 # Compile 1778 objs = self.compile(dag, sources) 1779 1780 # Link the lib 1781 dag.add(self, self.static_lib(objs, libname, relocate=True))
1782
1783 - def dynamic_lib_name(self, base):
1784 return self.shared_lib_name(base)
1785
1786 - def shared_lib_name(self, base):
1787 if self.on_windows(): 1788 s = '{}%(DLLEXT)s'.format(base) 1789 else: 1790 s = 'lib{}%(DLLEXT)s'.format(base) 1791 return s
1792 - def static_lib_name(self, base):
1793 if self.on_windows(): 1794 s = '{}%(LIBEXT)s'.format(base) 1795 else: 1796 s = 'lib{}%(LIBEXT)s'.format(base) 1797 return s
1798
1799 - def dynamic_lib(self, objs, libname, relocate=False):
1800 """Indirection function. Reads builder function from the 1801 environment variable DYNAMIC_LIBRARY_BUILDER. Make a dynamic 1802 library libname from objs. If relocate is True, then prefix 1803 libname with the build directory name 1804 1805 @type objs: list of strings 1806 @param objs: filenames to link 1807 1808 @type libname: string 1809 @param libname: output filename. 1810 1811 @type relocate: bool 1812 @param relocate: If true, relocate the library to the build directory. 1813 1814 @rtype: L{plan_t} 1815 @return: an input for the DAG 1816 1817 """ 1818 f = self.env['DYNAMIC_LIBRARY_BUILDER'] 1819 if f: 1820 return f(objs,libname, relocate) 1821 return self._dynamic_lib_default(objs,libname,relocate)
1822 1823
1824 - def rc_file(self, rc_file, res_file=None):
1825 """Indirection function. For making RES files 1826 from RC files on windows. 1827 1828 @type rc_file: string 1829 @param rc_file: filename for RC file 1830 1831 @type res_file: string 1832 @param res_file: filename for RES file 1833 1834 """ 1835 f = self.env['RES_FILE_BUILDER'] 1836 if f: 1837 return f(rc_file, res_file) 1838 return self._res_file_builder_default(rc_file, res_file)
1839
1840 - def _escape_dict(self, d):
1841 file_name_keys = ['SRCNAME','OBJNAME', 'LIBNAME', 1842 'SOLIBNAME', 'EXENAME', 1843 'RCNAME', 'RESNAME' ] 1844 for k in file_name_keys: 1845 if k in d: 1846 d[k] = self.escape_string(d[k])
1847
1848 - def _assemble_default(self, source, obj=None):
1849 """Assemble a source file to the obj file. If no obj file name 1850 is given one will be created in the build directory.""" 1851 cmd = self.env['ASSEMBLE_COMMAND'] 1852 d = copy.copy(self) 1853 self.make_derived_flags() 1854 d['SRCNAME'] = source 1855 if obj == None: 1856 (filepath,fullfilename) = os.path.split(source) 1857 (filename,ext) = os.path.splitext(fullfilename) 1858 obj = filename + self.env['OBJEXT'] 1859 obj = self.build_dir_join(obj) 1860 d['OBJNAME'] = obj 1861 self._escape_dict(d) 1862 s = self.expand_string(cmd, d) 1863 return plan.plan_t(command=s, output=obj, input=source)
1864
1865 - def _make_pdb_file(self,obj):
1866 """If obj obj file ends in '.obj$' or '%(OBJEXT)s' replace it 1867 so it looks like: '%(PDBEXT)s'""" 1868 1869 if env_t.obj_pattern.search(obj): 1870 pdbfile = env_t.obj_pattern.sub('%(PDBEXT)s',obj) 1871 elif env_t.objext_pattern.search(obj): 1872 pdbfile = env_t.objext_pattern.sub('%(PDBEXT)s',obj) 1873 else: 1874 die("Could not make PDB file from OBJ file: %s" % obj) 1875 return pdbfile
1876
1877 - def _cxx_compile_default(self, source, obj=None):
1878 """C++-compile a source file to a file called obj. If no obj file 1879 name is given one will be created in the build directory.""" 1880 cmd = self.env['CXX_COMPILE_COMMAND'] 1881 d = copy.copy(self) 1882 self.make_derived_flags() 1883 d['SRCNAME'] = source 1884 if obj == None: 1885 (filepath,fullfilename) = os.path.split(source) 1886 (filename,ext) = os.path.splitext(fullfilename) 1887 obj = filename + self.env['OBJEXT'] 1888 obj = self.build_dir_join(obj) 1889 if d['separate_pdb_files'] and d['compiler'] == 'ms' and d['debug'] == 1: 1890 pdbfile = self._make_pdb_file(obj) 1891 d['CXXFLAGS'] += ' /Fd%s ' % pdbfile 1892 1893 d['OBJNAME'] = obj 1894 self._escape_dict(d) 1895 s = self.expand_string(cmd, d) 1896 return plan.plan_t(command=s, output=obj, input=source)
1897 1898
1899 - def _cc_compile_default(self, source, obj=None):
1900 """C-compile a source file to a file named obj. If no obj file 1901 name is given one will be created in the build directory.""" 1902 1903 cmd = self.env['CC_COMPILE_COMMAND'] 1904 d = copy.copy(self) 1905 self.make_derived_flags() 1906 d['SRCNAME'] = source 1907 if obj == None: 1908 (filepath,fullfilename) = os.path.split(source) 1909 (filename,ext) = os.path.splitext(fullfilename) 1910 obj = filename + self.env['OBJEXT'] 1911 obj = self.build_dir_join(obj) 1912 if d['separate_pdb_files'] and d['compiler'] == 'ms' and d['debug'] == 1: 1913 pdbfile = self._make_pdb_file(obj) 1914 d['CCFLAGS'] += ' /Fd%s ' % pdbfile 1915 1916 d['OBJNAME'] = obj 1917 self._escape_dict(d) 1918 s = self.expand_string(cmd, d) 1919 return plan.plan_t(command=s, output=obj, input=source)
1920
1921 - def _find_libs(self):
1922 libs = [] 1923 for lib in self.expand_string('%(LIBS)s').split(): 1924 if lib: 1925 # ignore libraries that start with "-" as in -lc -lm. I 1926 # would not know what suffix to put on them anyway 1927 # (LIBEXT,DLLEXT) without trying them all. 1928 if lib[0]=='-': 1929 continue 1930 if os.path.exists(lib): 1931 #msgb("ADDING DEPENDENCE ON LIBRARY", lib) 1932 libs.append(lib) 1933 else: 1934 for dir in self.env['LINKPATH']: 1935 t = mbuild.join(dir,lib) 1936 if os.path.exists(t): 1937 #msgb("ADDING DERIVED DEPENDENCE ON LIBRARY", t) 1938 libs.append(t) 1939 return libs
1940 1941 1960 1961
1962 - def _static_lib_default(self, objs, libname, relocate=False):
1963 """Make a static library libname from objs. If relocate is True, 1964 then prefix libname with the build directory name""" 1965 d = copy.copy(self) 1966 self.make_derived_flags() 1967 if relocate: 1968 libname = self.build_dir_join(libname) 1969 d['LIBNAME'] = libname 1970 if not isinstance(objs,types.ListType): 1971 objs = [ objs ] 1972 objs = self._escape_list_of_strings(objs) 1973 obj = " ".join(objs) 1974 1975 d['OBJNAMES'] = obj 1976 self._escape_dict(d) 1977 n = [] 1978 scmd = self.env['STATIC_LIB_COMMAND'] 1979 if not isinstance(scmd,types.ListType): 1980 scmd = [ scmd ] 1981 for cmd in scmd: 1982 if isinstance(cmd,types.StringType): 1983 n.append(self.expand_string(cmd, d)) 1984 else: 1985 n.append(cmd) 1986 # we pass args to the python scripts... Must expand now or 1987 # else suffer concurrency bugs at build time. 1988 args = [ self.expand_string('%(LIBNAME)s') ] 1989 return plan.plan_t(command=n, output=libname, 1990 args=args, 1991 input=objs, env=self)
1992 1993
1994 - def _dynamic_lib_default(self, objs, libname, relocate=False):
1995 """Make a dynamic library libname from objs. If relocate is True, 1996 then prefix libname with the build directory name""" 1997 if self.env['compiler'] in [ 'gnu','icc','clang','iclang']: 1998 cmd = self.env['CXX_SHARED_LIB_COMMAND'] 1999 else: 2000 cmd = self.env['DYNAMIC_LIB_COMMAND'] 2001 d = copy.copy(self) 2002 self.make_derived_flags() 2003 if relocate: 2004 libname = self.build_dir_join(libname) 2005 d['LIBNAME'] = libname 2006 d['SOLIBNAME'] = os.path.basename(libname) 2007 if not isinstance(objs,types.ListType): 2008 objs = [ objs ] 2009 objs = self._escape_list_of_strings(objs) 2010 obj = " ".join(objs) 2011 d['OBJNAMES'] = obj 2012 self._escape_dict(d) 2013 s = self.expand_string(cmd, d) 2014 return plan.plan_t(command=s, output=libname, 2015 input=objs + self._find_libs())
2016 2017 2018
2019 - def _res_file_builder_default(self, rc_file,res_file=None):
2020 """Make a res file from an rc file. Windows only.""" 2021 cmd = self.env['RES_FILE_COMMAND'] 2022 d = copy.copy(self) 2023 if not res_file: 2024 res_file = self.build_dir_join(self.resuffix(rc_file,'%(RESEXT)s')) 2025 d['RESNAME'] = res_file 2026 d['RCNAME'] = rc_file 2027 self._escape_dict(d) 2028 s = self.expand_string(cmd, d) 2029 return plan.plan_t(command=s, 2030 output=res_file, 2031 input=rc_file)
2032
2033 - def compile(self, dag, sources):
2034 """Build all the sources by adding them to the dag. Use the 2035 suffixes to figure out how to handle the files. The dag can be 2036 passed to a work queue. See the build function. """ 2037 2038 objs = [] 2039 for s in sources: 2040 b = os.path.basename(s) # filename component of path/filename 2041 (base,ext) = os.path.splitext(b) 2042 if ext in ['.rc' ]: 2043 obj = self.build_dir_join(self.resuffix(b,'%(RESEXT)s')) 2044 else: 2045 obj = self.build_dir_join(self.make_obj(b)) 2046 2047 if ext in ['.asm', '.s' ]: 2048 c = self.assemble( s, obj ) 2049 elif ext in ['.c']: 2050 c = self.cc_compile( s, obj ) 2051 elif ext in ['.cpp', '.C' ]: 2052 c = self.cxx_compile( s, obj ) 2053 elif ext in ['.rc' ]: 2054 c = self.rc_file( s, obj ) # obj is a res file in this case 2055 else: 2056 die("Unsupported file type %s" % (s)) 2057 cmd = dag.add(self,c) 2058 objs.append(self.expand_string(obj)) 2059 return objs
2060 2061 2076 2077
2078 - def build(self, work_queue, dag, phase='BUILD',terminate_on_errors=False):
2079 """Build everything in the work queue""" 2080 okay = work_queue.build(dag=dag, die_on_errors=False) 2081 if not okay: 2082 if terminate_on_errors: 2083 die("[%s] failed." % phase) 2084 else: 2085 msgb(phase,"failed.") 2086 return False 2087 msgb(phase, "succeeded") 2088 return True
2089