Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Tree: 4088a72eab
Fetching contributors…

Cannot retrieve contributors at this time

121 lines (91 sloc) 4.533 kB
#!/bin/env python
"Implements a new distutils 'build_exe' command to build the executable stubs used by Kelvin."
# distutils is a nasty hack. It hardcodes a lot of assumptions and requires an amazing amount
# of monkey patching to extend. This project wants to do two simple things:
#
# 1) The build command should also build some executables we'll need at runtime.
# 2) The install command should copy the EXEs to the install directory.
#
# To do this, we need to:
#
# * subclass the Distribution class just to add some attributes (very un-Pythonic design)
# * write our own build_exe class which duplicates most of build_ext
# * poke build_ext into the build command using something very ugly
import sys, os, re
from distutils.core import Command, Distribution
from distutils.ccompiler import new_compiler
from distutils import sysconfig
from distutils.ccompiler import CCompiler
from distutils.util import get_platform
from os.path import join
from distutils.command.build import build
# Honestly, how did the distutils "designers" expect people to add subcommands?
def _has_exes(self):
return bool(getattr(self.distribution, 'exe_modules', 0))
build.sub_commands.append(('build_exe', _has_exes))
assert os.name == 'nt', 'Only Windows is supported at this time.'
# This is practically a duplicate of build_ext, unfortunatley. This is only used *internally* by Kelvin, which is
# limited to Windows at this time, so this is not full featured.
# The distutils package is a collection of ugly hacks... Extra keywords to setup are ignored
# if they are not already attributes of Distribution. Sigh.
#
# To use this, you must use the Distribution2 class which adds an exe_modules attribute to
# Distribution, like ext_modules. Set this to an array of Executable objects.
#
# To use it, pass "distclass=Distribution2" to the setup function.
class Distribution2(Distribution):
def __init__ (self, attrs=None):
self.exe_modules = None
Distribution.__init__(self, attrs)
class Executable(object):
def __init__(self, name,
subsystem,
sources,
include_dirs=None,
define_macros=None,
libraries=None,
):
self.name = name
self.subsystem = subsystem
self.sources = sources
self.include_dirs = include_dirs or []
self.define_macros = define_macros or []
self.libraries = libraries or []
class BuildExeCommand(Command):
description = "builds executable"
user_options = []
def __init__(self, dist):
Command.__init__(self, dist)
def initialize_options(self):
self.build_temp = None
self.build_lib = None
def finalize_options(self):
self.set_undefined_options('build_ext',
('build_temp', 'build_temp'))
if not self.build_lib:
self.build_lib = self._get_build_lib()
def _get_build_lib(self):
# More distutils hackishness. The build.build_lib changes depending on whether
# ext_modules is empty or not. For us, obviously it is empty. Therefore we had to
# duplicate it.
return join('build', 'lib.{}-{}'.format(get_platform(), sys.version[0:3]))
def run(self):
for exe in self.distribution.exe_modules:
exe.include_dirs.append(sysconfig.get_python_inc())
compiler = new_compiler()
compiler.set_include_dirs(exe.include_dirs)
for (name, value) in exe.define_macros:
compiler.define_macro(name, value)
objects = compiler.compile(exe.sources, output_dir = self.build_temp)
# This is a hack copied from distutils.commands.build_exe (where it is also called
# a hack).
self._build_objects = objects[:]
library_dirs = [ os.path.join(sys.exec_prefix, 'libs') ]
exe_path = join(self.build_lib, exe.name.split('.')[-1] + '.exe')
compiler.link(CCompiler.EXECUTABLE,
extra_preargs = ['/SUBSYSTEM:{}'.format(exe.subsystem).upper()],
objects = objects,
output_filename = exe_path,
library_dirs = library_dirs,
libraries = exe.libraries
)
Jump to Line
Something went wrong with that request. Please try again.