| 72 | | DCompiler.__init__(self, *args, **kwargs) |
|---|
| 73 | | self._initialized = False |
|---|
| 74 | | |
|---|
| 75 | | |
|---|
| 76 | | def _initialize(self, debug): |
|---|
| 77 | | # Would like to determine whether optimization was requested in a more |
|---|
| 78 | | # proper manner (by checking the 'optimize' attribute of the Command |
|---|
| 79 | | # object under which we're operating), but can't figure out how to get |
|---|
| 80 | | # a reference to that Command object without burdening client |
|---|
| 81 | | # programmers by forcing them to pass a cmd_class argument to setup(). |
|---|
| 82 | | args = [a.lower() for a in sys.argv[1:]] |
|---|
| 83 | | optimize = ('-o' in args or '--optimize' in args) |
|---|
| 84 | | |
|---|
| 85 | | dmdExeFilename = (_isPlatWin and 'dmd.exe') or 'dmd' |
|---|
| 86 | | |
|---|
| 87 | | # Require environment variable D_ROOT: |
|---|
| | 57 | cc.CCompiler.__init__(self, *args, **kwargs) |
|---|
| | 58 | # Get DMD/GDC specific info |
|---|
| | 59 | self._initialize() |
|---|
| | 60 | # _binpath |
|---|
| 97 | | exampleDMDPath = '/opt/d/dmd/bin/' + dmdExeFilename |
|---|
| 98 | | |
|---|
| 99 | | raise DistutilsFileError('You must set the D_ROOT environment' |
|---|
| 100 | | ' variable to the great-grandparent directory of the dmd' |
|---|
| 101 | | ' executable.' |
|---|
| 102 | | '\n(If the dmd executable were at\n "%s", D_ROOT should be' |
|---|
| 103 | | '\n "%s".)' |
|---|
| 104 | | % (exampleDMDPath, |
|---|
| 105 | | os.path.dirname(os.path.dirname( |
|---|
| 106 | | os.path.dirname(exampleDMDPath) |
|---|
| 107 | | )) |
|---|
| 108 | | ) |
|---|
| 109 | | ) |
|---|
| 110 | | |
|---|
| 111 | | # Find the DMD executable: |
|---|
| 112 | | dmdExePath = _findInPath(dmdExeFilename, |
|---|
| 113 | | startIn=os.path.join(dRoot, 'dmd', 'bin') |
|---|
| 114 | | ) |
|---|
| 115 | | if not dmdExePath: |
|---|
| 116 | | dmdExeSubPath = os.path.join('dmd', 'bin', |
|---|
| 117 | | 'dmd' + ((_isPlatWin and '.exe') or '') |
|---|
| 118 | | ) |
|---|
| 119 | | dmdExePath = os.path.join(dRoot, dmdExeSubPath) |
|---|
| 120 | | if not os.path.isfile(dmdExePath): |
|---|
| 121 | | dmdExePathRepr = os.path.join( |
|---|
| 122 | | ((_isPlatWin and '%D_ROOT%') or '$D_ROOT'), |
|---|
| 123 | | dmdExeSubPath |
|---|
| 124 | | ) |
|---|
| 125 | | raise DistutilsFileError('Could not find dmd executable. It' |
|---|
| 126 | | ' should be located at "%s".' % dmdExePathRepr |
|---|
| 127 | | ) |
|---|
| 128 | | |
|---|
| 129 | | # Store in instance variables the info we'll need later: |
|---|
| 130 | | self._dRoot = dRoot |
|---|
| 131 | | self._dmdExePath = dmdExePath |
|---|
| 132 | | self._unicodeOpt = ('-version=Python_Unicode_UCS' |
|---|
| 133 | | + ((sys.maxunicode == 0xFFFF and '2') or '4') |
|---|
| 134 | | ) |
|---|
| 135 | | |
|---|
| 136 | | # Set optimization-versus-safety options (conservatively by default; |
|---|
| 137 | | # as aggressively optimized as possible when the user specifies |
|---|
| 138 | | # 'python setup.py build -O'). |
|---|
| 139 | | conservativeOpts = ['-debug', '-unittest'] |
|---|
| 140 | | if debug: |
|---|
| 141 | | # Conservative checking AND symbolic debugging information: |
|---|
| 142 | | self._optimizationOpts = conservativeOpts + ['-g'] |
|---|
| 143 | | elif optimize: |
|---|
| 144 | | self._optimizationOpts = ['-version=Optimized', |
|---|
| 145 | | '-release', '-O', '-inline', |
|---|
| 146 | | ] |
|---|
| 147 | | else: |
|---|
| 148 | | # The default is conservative in that it generates validation code, |
|---|
| 149 | | # but it does not include symbolic debugging information: |
|---|
| 150 | | self._optimizationOpts = conservativeOpts |
|---|
| 151 | | |
|---|
| 152 | | |
|---|
| 153 | | self._initialized = True |
|---|
| 154 | | |
|---|
| | 79 | # Just run it via the PATH directly in Linux |
|---|
| | 80 | dBin = self.compiler_type |
|---|
| | 81 | self._binpath = dBin |
|---|
| | 82 | # _unicodeOpt |
|---|
| | 83 | self._unicodeOpt = self._versionOpt % ('Python_Unicode_UCS' + ((sys.maxunicode == 0xFFFF and '2') or '4')) |
|---|
| | 84 | |
|---|
| | 85 | def _initialize(self): |
|---|
| | 86 | # It is intended that this method be implemented by subclasses. |
|---|
| | 87 | raise NotImplementedError, "Cannot initialize DCompiler, use DMDDCompiler or GDCDCompiler instead." |
|---|
| | 88 | |
|---|
| | 89 | def _def_file(self, output_dir, output_filename): |
|---|
| | 90 | """A list of options used to tell the linker how to make a dll/so. In |
|---|
| | 91 | DMD, it is the .def file. In GDC, it is |
|---|
| | 92 | ['-shared', '-Wl,-soname,blah.so'] or similar.""" |
|---|
| | 93 | raise NotImplementedError, "Cannot initialize DCompiler, use DMDDCompiler or GDCDCompiler instead." |
|---|
| | 94 | |
|---|
| | 95 | def _lib_file(self, libraries): |
|---|
| | 96 | return '' |
|---|
| | 97 | |
|---|
| | 98 | def find_library_file(self, dirs, lib, debug=0): |
|---|
| | 99 | shared_f = self.library_filename(lib, lib_type='shared') |
|---|
| | 100 | static_f = self.library_filename(lib, lib_type='static') |
|---|
| | 101 | |
|---|
| | 102 | for dir in dirs: |
|---|
| | 103 | shared = os.path.join(dir, shared_f) |
|---|
| | 104 | static = os.path.join(dir, static_f) |
|---|
| | 105 | |
|---|
| | 106 | if os.path.exists(shared): |
|---|
| | 107 | return shared |
|---|
| | 108 | elif os.path.exists(static): |
|---|
| | 109 | return static |
|---|
| | 110 | |
|---|
| | 111 | return None |
|---|
| 229 | | pythonVersionOpt = '-version=Python_%d_%d_Or_Later' % sys.version_info[:2] |
|---|
| 230 | | |
|---|
| 231 | | # Generate a complete list of all command-line arguments, excluding any |
|---|
| 232 | | # that turned out to be blank: |
|---|
| 233 | | cmdElements = ([dmdExeOpt] + extra_preargs |
|---|
| 234 | | + [compileOnlyOpt, pythonVersionOpt, self._unicodeOpt] |
|---|
| 235 | | + self._optimizationOpts + [outputDirOpt] |
|---|
| 236 | | + userVersionAndDebugOpts + quotedSourceFiles + extra_postargs |
|---|
| 237 | | ) |
|---|
| | 189 | pythonVersionOpt = self._versionOpt % ('Python_%d_%d_Or_Later' % sys.version_info[:2]) |
|---|
| | 190 | |
|---|
| | 191 | # Optimization opts |
|---|
| | 192 | args = [a.lower() for a in sys.argv[1:]] |
|---|
| | 193 | optimize = ('-o' in args or '--optimize' in args) |
|---|
| | 194 | if debug: |
|---|
| | 195 | optimizationOpts = self._debugOptimizeOpts |
|---|
| | 196 | elif optimize: |
|---|
| | 197 | optimizationOpts = self._releaseOptimizeOpts |
|---|
| | 198 | else: |
|---|
| | 199 | optimizationOpts = self._defaultOptimizeOpts |
|---|
| | 200 | |
|---|
| | 201 | #for source in sources: |
|---|
| | 202 | #outOpts = outputOpts[:] |
|---|
| | 203 | #objName = self.object_filenames([os.path.split(source)[1]], 0, output_dir)[0] |
|---|
| | 204 | #outOpts[-1] = outOpts[-1] % _qp(objName) |
|---|
| | 205 | #cmdElements = ( |
|---|
| | 206 | # [binpath] + extra_preargs + compileOpts + |
|---|
| | 207 | # [pythonVersionOpt, self._unicodeOpt] + optimizationOpts + |
|---|
| | 208 | # includePathOpts + outOpts + userVersionAndDebugOpts + |
|---|
| | 209 | # [_qp(source)] + extra_postargs |
|---|
| | 210 | #) |
|---|
| | 211 | # gdc/gcc doesn't support the idea of an output directory, so we |
|---|
| | 212 | # compile from the destination |
|---|
| | 213 | sources = [_qp(os.path.abspath(s)) for s in sources] |
|---|
| | 214 | cwd = os.getcwd() |
|---|
| | 215 | os.chdir(output_dir) |
|---|
| | 216 | cmdElements = ( |
|---|
| | 217 | [binpath] + extra_preargs + compileOpts + |
|---|
| | 218 | [pythonVersionOpt, self._unicodeOpt] + optimizationOpts + |
|---|
| | 219 | includePathOpts + userVersionAndDebugOpts + |
|---|
| | 220 | sources + extra_postargs |
|---|
| | 221 | ) |
|---|
| | 286 | # The .def file (on Windows) or -shared and -soname (on Linux) |
|---|
| | 287 | sharedOpts = self._def_file(build_temp, output_filename) |
|---|
| | 288 | |
|---|
| | 289 | # The python .lib file, if needed |
|---|
| | 290 | pythonLibOpt = self._lib_file(libraries) |
|---|
| | 291 | if pythonLibOpt: |
|---|
| | 292 | pythonLibOpt = _qp(pythonLibOpt) |
|---|
| | 293 | |
|---|
| | 294 | if target_desc != cc.CCompiler.SHARED_OBJECT: |
|---|
| | 295 | raise LinkError('This CCompiler implementation does not know' |
|---|
| | 296 | ' how to link anything except an extension module (that is, a' |
|---|
| | 297 | ' shared object file).' |
|---|
| | 298 | ) |
|---|
| | 299 | |
|---|
| | 300 | # Library linkage options |
|---|
| | 301 | print "library_dirs:", library_dirs |
|---|
| | 302 | print "runtime_library_dirs:", runtime_library_dirs |
|---|
| | 303 | print "libraries:", libraries |
|---|
| | 304 | libOpts = gen_lib_options(self, library_dirs, runtime_library_dirs, libraries) |
|---|
| | 305 | |
|---|
| | 306 | # Optimization opts |
|---|
| | 307 | args = [a.lower() for a in sys.argv[1:]] |
|---|
| | 308 | optimize = ('-o' in args or '--optimize' in args) |
|---|
| | 309 | if debug: |
|---|
| | 310 | optimizationOpts = self._debugOptimizeOpts |
|---|
| | 311 | elif optimize: |
|---|
| | 312 | optimizationOpts = self._releaseOptimizeOpts |
|---|
| | 313 | else: |
|---|
| | 314 | optimizationOpts = self._defaultOptimizeOpts |
|---|
| | 315 | |
|---|
| | 316 | cmdElements = ( |
|---|
| | 317 | [binpath] + extra_preargs + self._linkOpts + optimizationOpts + |
|---|
| | 318 | outputOpts + [pythonLibOpt] + objectOpts + libOpts + sharedOpts + |
|---|
| | 319 | extra_postargs |
|---|
| | 320 | ) |
|---|
| | 321 | cmdElements = [el for el in cmdElements if el] |
|---|
| | 322 | |
|---|
| | 323 | try: |
|---|
| | 324 | self.spawn(cmdElements) |
|---|
| | 325 | except DistutilsExecError, msg: |
|---|
| | 326 | raise CompileError(msg) |
|---|
| | 327 | |
|---|
| | 328 | class DMDDCompiler(DCompiler): |
|---|
| | 329 | compiler_type = 'dmd' |
|---|
| | 330 | |
|---|
| | 331 | executables = { |
|---|
| | 332 | 'preprocessor' : None, |
|---|
| | 333 | 'compiler' : ['dmd'], |
|---|
| | 334 | 'compiler_so' : ['dmd'], |
|---|
| | 335 | 'linker_so' : ['dmd'], |
|---|
| | 336 | 'linker_exe' : ['dmd'], |
|---|
| | 337 | } |
|---|
| | 338 | |
|---|
| | 339 | _env_var = 'DMD_BIN' |
|---|
| | 340 | |
|---|
| | 341 | def _initialize(self): |
|---|
| | 342 | # _compileOpts |
|---|
| | 343 | self._compileOpts = ['-c'] |
|---|
| | 344 | # _outputOpts |
|---|
| | 345 | self._outputOpts = ['-of%s'] |
|---|
| | 346 | # _linkOpts |
|---|
| | 347 | self._linkOpts = [] |
|---|
| | 348 | # _includeOpts |
|---|
| | 349 | self._includeOpts = ['-I%s'] |
|---|
| | 350 | # _versionOpt |
|---|
| | 351 | self._versionOpt = '-version=%s' |
|---|
| | 352 | # _debugOpt |
|---|
| | 353 | self._debugOpt = '-debug=%s' |
|---|
| | 354 | # _defaultOptimizeOpts |
|---|
| | 355 | self._defaultOptimizeOpts = ['-debug', '-unittest'] |
|---|
| | 356 | # _debugOptimizeOpts |
|---|
| | 357 | self._debugOptimizeOpts = self._defaultOptimizeOpts + ['-g'] |
|---|
| | 358 | # _releaseOptimizeOpts |
|---|
| | 359 | self._releaseOptimizeOpts = ['-version=Optimized', '-release', '-O', '-inline'] |
|---|
| | 360 | |
|---|
| | 361 | #def link_opts(self, |
|---|
| | 362 | |
|---|
| | 363 | def _def_file(self, output_dir, output_filename): |
|---|
| 374 | | |
|---|
| 375 | | # Find the paths of any requested library files: |
|---|
| 376 | | explicitLibOpts = [] |
|---|
| 377 | | if libraries: |
|---|
| 378 | | if not _isPlatWin: |
|---|
| 379 | | # Pass through library requests to the GNU linker via DMD's -L |
|---|
| 380 | | # option. |
|---|
| 381 | | explicitLibOpts.extend('-L-l' + libName for libName in libraries) |
|---|
| 382 | | else: |
|---|
| 383 | | # On Windows, the linker that DMD uses doesn't seem to have an |
|---|
| 384 | | # equivalent of GCC's -LsearchDirectory and -llibraryName |
|---|
| 385 | | # arguments, so we try to find the exact paths for the |
|---|
| 386 | | # libraries mentioned and pass those paths to DMD. |
|---|
| 387 | | # XXX: What about OptLink's /scanlib option and the LIB env var? |
|---|
| 388 | | explicitLibFilenames = [ |
|---|
| 389 | | libName + DMDDCompiler.static_lib_extension |
|---|
| 390 | | for libName in libraries |
|---|
| 391 | | ] |
|---|
| 392 | | if not library_dirs: |
|---|
| 393 | | explicitLibOpts.extend(explicitLibFilenames) |
|---|
| 394 | | else: |
|---|
| 395 | | curDir = os.path.abspath(os.curdir) |
|---|
| 396 | | if curDir not in library_dirs: |
|---|
| 397 | | library_dirs.insert(0, curDir) |
|---|
| 398 | | |
|---|
| 399 | | libFound = [False] * len(libraries) |
|---|
| 400 | | for libIndex, libFilename in enumerate(explicitLibFilenames): |
|---|
| 401 | | for libDir in library_dirs: |
|---|
| 402 | | probeLibPath = os.path.join(libDir, libFilename) |
|---|
| 403 | | if os.path.isfile(probeLibPath): |
|---|
| 404 | | explicitLibOpts.append(_qp(probeLibPath)) |
|---|
| 405 | | libFound[libIndex] = True |
|---|
| 406 | | break |
|---|
| 407 | | |
|---|
| 408 | | libsNotFound = [] |
|---|
| 409 | | for libIndex, found in enumerate(libFound): |
|---|
| 410 | | if not found: |
|---|
| 411 | | libsNotFound.append( |
|---|
| 412 | | (libraries[libIndex], explicitLibFilenames[libIndex]) |
|---|
| 413 | | ) |
|---|
| 414 | | if libsNotFound: |
|---|
| 415 | | raise LinkError('Unable to find the following libraries' |
|---|
| 416 | | ' in the specified library search directories:\n ' |
|---|
| 417 | | + '\n '.join( |
|---|
| 418 | | '%s (filename "%s")' % (libName, libFilename) |
|---|
| 419 | | for (libName, libFilename) in libsNotFound |
|---|
| 420 | | ) |
|---|
| 421 | | + '\nSearched the following directories:\n ' |
|---|
| 422 | | + '\n '.join(library_dirs) |
|---|
| 423 | | ) |
|---|
| 424 | | |
|---|
| 425 | | # Generate a complete list of all command-line arguments, excluding any |
|---|
| 426 | | # that turned out to be blank: |
|---|
| 427 | | cmdElements = ([dmdExeOpt] + extra_preargs + self._optimizationOpts |
|---|
| 428 | | + [outputDirOpt, outputObjOpt, pythonLibOpt, self._unicodeOpt] |
|---|
| 429 | | + inputObjectOpts + explicitLibOpts + extra_postargs |
|---|
| 430 | | ) |
|---|
| 431 | | cmdElements = [el for el in cmdElements if el] |
|---|
| 432 | | |
|---|
| 433 | | # Invoke the linker indirectly by calling the compiler: |
|---|
| 434 | | try: |
|---|
| 435 | | self.spawn(cmdElements) |
|---|
| 436 | | except DistutilsExecError, msg: |
|---|
| 437 | | raise CompileError(msg) |
|---|
| 438 | | |
|---|
| | 422 | return pythonLibOpt |
|---|
| | 423 | else: |
|---|
| | 424 | return '' |
|---|
| | 425 | |
|---|
| | 426 | def library_dir_option(self, dir): |
|---|
| | 427 | self.warn("Don't know how to set library search path for DMD.") |
|---|
| | 428 | #raise DistutilsPlatformError, "Don't know how to set library search path for DMD." |
|---|
| | 429 | |
|---|
| | 430 | def runtime_library_dir_option(self, dir): |
|---|
| | 431 | self.warn("Don't know how to set runtime library search path for DMD.") |
|---|
| | 432 | #raise DistutilsPlayformError, "Don't know how to set runtime library search path for DMD." |
|---|
| | 433 | |
|---|
| | 434 | def library_option(self, lib): |
|---|
| | 435 | if _isPlatWin: |
|---|
| | 436 | return self.library_filename(lib) |
|---|
| | 437 | else: |
|---|
| | 438 | return '-L-l' + lib |
|---|
| | 439 | |
|---|
| | 440 | class GDCDCompiler(DCompiler): |
|---|
| | 441 | compiler_type = 'gdc' |
|---|
| | 442 | |
|---|
| | 443 | executables = { |
|---|
| | 444 | 'preprocessor' : None, |
|---|
| | 445 | 'compiler' : ['gdc'], |
|---|
| | 446 | 'compiler_so' : ['gdc'], |
|---|
| | 447 | 'linker_so' : ['gdc'], |
|---|
| | 448 | 'linker_exe' : ['gdc'], |
|---|
| | 449 | } |
|---|
| | 450 | |
|---|
| | 451 | _env_var = 'GDC_BIN' |
|---|
| | 452 | |
|---|
| | 453 | def _initialize(self): |
|---|
| | 454 | # _compileOpts |
|---|
| | 455 | self._compileOpts = ['-fPIC', '-c'] |
|---|
| | 456 | # _outputOpts |
|---|
| | 457 | self._outputOpts = ['-o', '%s'] |
|---|
| | 458 | # _linkOpts |
|---|
| | 459 | self._linkOpts = ['-fPIC', '-nostartfiles', '-shared'] |
|---|
| | 460 | # _includeOpts |
|---|
| | 461 | self._includeOpts = ['-I', '%s'] |
|---|
| | 462 | # _versionOpt |
|---|
| | 463 | self._versionOpt = '-fversion=%s' |
|---|
| | 464 | # _debugOpt |
|---|
| | 465 | self._debugOpt = '-fdebug=%s' |
|---|
| | 466 | # _defaultOptimizeOpts |
|---|
| | 467 | self._defaultOptimizeOpts = ['-fdebug', '-funittest'] |
|---|
| | 468 | # _debugOptimizeOpts |
|---|
| | 469 | self._debugOptimizeOpts = self._defaultOptimizeOpts + ['-g'] |
|---|
| | 470 | # _releaseOptimizeOpts |
|---|
| | 471 | self._releaseOptimizeOpts = ['-fversion=Optimized', '-frelease', '-O3', '-finline-functions'] |
|---|
| | 472 | |
|---|
| | 473 | def _def_file(self, output_dir, output_filename): |
|---|
| | 474 | return ['-Wl,-soname,' + os.path.basename(output_filename)] |
|---|
| | 475 | |
|---|
| | 476 | def library_dir_option(self, dir): |
|---|
| | 477 | return '-L' + dir |
|---|
| | 478 | |
|---|
| | 479 | def runtime_library_dir_option(self, dir): |
|---|
| | 480 | return '-Wl,-R' + dir |
|---|
| | 481 | |
|---|
| | 482 | def library_option(self, lib): |
|---|
| | 483 | return '-l' + lib |
|---|