"""
Setup script for building clr.pyd and dependencies using mono and into
an egg or wheel.
"""
from setuptools import setup, Extension
from distutils.command.build_ext import build_ext
from distutils.command.build_scripts import build_scripts
from distutils.command.install_lib import install_lib
from distutils.sysconfig import get_config_vars
from platform import architecture
from subprocess import Popen, CalledProcessError, PIPE, check_call
from glob import glob
import shutil
import sys
import os
CONFIG = "Release" # Release or Debug
DEVTOOLS = "MsDev" if sys.platform == "win32" else "Mono"
VERBOSITY = "minimal" # quiet, minimal, normal, detailed, diagnostic
PLATFORM = "x64" if architecture()[0] == "64bit" else "x86"
def _find_msbuild_path():
"""Return full path to msbuild.exe"""
import _winreg
hreg = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE)
try:
keys_to_check = [
r"SOFTWARE\Microsoft\MSBuild\ToolsVersions\12.0",
r"SOFTWARE\Microsoft\MSBuild\ToolsVersions\4.0",
r"SOFTWARE\Microsoft\MSBuild\ToolsVersions\3.5",
r"SOFTWARE\Microsoft\MSBuild\ToolsVersions\2.0"
]
hkey = None
for key in keys_to_check:
try:
hkey = _winreg.OpenKey(hreg, key)
break
except WindowsError:
pass
if hkey is None:
raise RuntimeError("msbuild.exe could not be found")
try:
val, type_ = _winreg.QueryValueEx(hkey, "MSBuildToolsPath")
if type_ != _winreg.REG_SZ:
raise RuntimeError("msbuild.exe could not be found")
finally:
hkey.Close()
finally:
hreg.Close()
msbuildpath = os.path.join(val, "msbuild.exe")
return msbuildpath
if DEVTOOLS == "MsDev":
_xbuild = "\"%s\"" % _find_msbuild_path()
_defines_sep = ";"
_config = "%sWin" % CONFIG
_npython_exe = "nPython.exe"
elif DEVTOOLS == "Mono":
_xbuild = "xbuild"
_defines_sep = ","
_config = "%sMono" % CONFIG
_npython_exe = "npython"
else:
raise NotImplementedError("DevTools %s not supported (use MsDev or Mono)" % DEVTOOLS)
class PythonNET_BuildExt(build_ext):
def build_extension(self, ext):
"""
Builds the .pyd file using msbuild or xbuild.
"""
if ext.name != "clr":
return build_ext.build_extension(self, ext)
# install packages using nuget
self._install_packages()
dest_file = self.get_ext_fullpath(ext.name)
dest_dir = os.path.dirname(dest_file)
if not os.path.exists(dest_dir):
os.makedirs(dest_dir)
defines = [
"PYTHON%d%s" % (sys.version_info[:2]),
"UCS2" if sys.maxunicode < 0x10FFFF else "UCS4",
]
if CONFIG == "Debug":
defines.extend(["DEBUG", "TRACE"])
cmd = [
_xbuild,
"pythonnet.sln",
"/p:Configuration=%s" % _config,
"/p:Platform=%s" % PLATFORM,
"/p:DefineConstants=\"%s\"" % _defines_sep.join(defines),
"/p:PythonBuildDir=%s" % os.path.abspath(dest_dir),
"/verbosity:%s" % VERBOSITY,
]
self.announce("Building: %s" % " ".join(cmd))
use_shell = True if DEVTOOLS == "Mono" else False
check_call(" ".join(cmd + ["/t:Clean"]), shell=use_shell)
check_call(" ".join(cmd + ["/t:Build"]), shell=use_shell)
if DEVTOOLS == "Mono":
self._build_monoclr(ext)
def _build_monoclr(self, ext):
mono_libs = _check_output("pkg-config --libs mono-2", shell=True)
mono_cflags = _check_output("pkg-config --cflags mono-2", shell=True)
glib_libs = _check_output("pkg-config --libs glib-2.0", shell=True)
glib_cflags = _check_output("pkg-config --cflags glib-2.0", shell=True)
cflags = mono_cflags.strip() + " " + glib_cflags.strip()
libs = mono_libs.strip() + " " + glib_libs.strip()
# build the clr python module
clr_ext = Extension("clr",
sources=[
"src/monoclr/pynetinit.c",
"src/monoclr/clrmod.c"
],
extra_compile_args=cflags.split(" "),
extra_link_args=libs.split(" "))
build_ext.build_extension(self, clr_ext)
# build the clr python executable
sources = [
"src/monoclr/pynetinit.c",
"src/monoclr/python.c",
]
macros = ext.define_macros[:]
for undef in ext.undef_macros:
macros.append((undef,))
objects = self.compiler.compile(sources,
output_dir=self.build_temp,
macros=macros,
include_dirs=ext.include_dirs,
debug=self.debug,
extra_postargs=cflags.split(" "),
depends=ext.depends)
output_dir = os.path.dirname(self.get_ext_fullpath(ext.name))
py_libs = get_config_vars("BLDLIBRARY")[0]
libs += " " + py_libs
self.compiler.link_executable(objects,
_npython_exe,
output_dir=output_dir,
libraries=self.get_libraries(ext),
library_dirs=ext.library_dirs,
runtime_library_dirs=ext.runtime_library_dirs,
extra_postargs=libs.split(" "),
debug=self.debug)
def _install_packages(self):
"""install packages using nuget"""
nuget = os.path.join("tools", "nuget", "nuget.exe")
use_shell = False
if DEVTOOLS == "Mono":
nuget = "mono %s" % nuget
use_shell = True
cmd = "%s restore pythonnet.sln -o packages" % nuget
self.announce("Installing packages: %s" % cmd)
check_call(cmd, shell=use_shell)
class PythonNET_InstallLib(install_lib):
def install(self):
if not os.path.isdir(self.build_dir):
self.warn("'%s' does not exist -- no Python modules to install" %
self.build_dir)
return
if not os.path.exists(self.install_dir):
self.mkpath(self.install_dir)
# only copy clr.pyd and its dependencies
for pattern in ("clr.*", "Python.Runtime.*"):
for srcfile in glob(os.path.join(self.build_dir, pattern)):
destfile = os.path.join(self.install_dir, os.path.basename(srcfile))
self.copy_file(srcfile, destfile)
class PythonNET_BuildScripts(build_scripts):
def finalize_options(self):
build_scripts.finalize_options(self)
# fixup scripts to look in the build_ext output folder
if self.scripts:
build_ext = self.get_finalized_command("build_ext")
output_dir = os.path.dirname(build_ext.get_ext_fullpath("clr"))
scripts = []
for script in self.scripts:
if os.path.exists(os.path.join(output_dir, script)):
script = os.path.join(output_dir, script)
scripts.append(script)
self.scripts = scripts
def _check_output(*popenargs, **kwargs):
"""subprocess.check_output from python 2.7.
Added here to support building for earlier versions
of Python.
"""
process = Popen(stdout=PIPE, *popenargs, **kwargs)
output, unused_err = process.communicate()
retcode = process.poll()
if retcode:
cmd = kwargs.get("args")
if cmd is None:
cmd = popenargs[0]
raise CalledProcessError(retcode, cmd, output=output)
return output
if __name__ == "__main__":
setup(
name="pythonnet",
version="2.0.0.dev1",
description=".Net and Mono integration for Python",
url='http://pythonnet.github.io/',
author="Python for .Net developers",
classifiers=[
'Development Status :: 3 - Alpha',
'Intended Audience :: Developers'],
ext_modules=[
Extension("clr", sources=[])
],
scripts=[_npython_exe],
zip_safe=False,
cmdclass={
"build_ext" : PythonNET_BuildExt,
"build_scripts" : PythonNET_BuildScripts,
"install_lib" : PythonNET_InstallLib
}
)