setup.py changes for MSVC builds

- Using "Library" rather than "Extension" for building shared libs
  (does not try to export extension-specific symbols)
- Linking against import libs
- Using os.path.join consistently for backslash/slash difference
This commit is contained in:
klayoutmatthias 2018-10-18 09:41:38 +02:00
parent 8ab4868d76
commit e452a4305c
1 changed files with 118 additions and 77 deletions

195
setup.py
View File

@ -54,7 +54,8 @@ and won't find them. So we need to take away the path with
"-Wl,-soname" on Linux (see Config.link_args). "-Wl,-soname" on Linux (see Config.link_args).
""" """
from setuptools import setup, Extension, Distribution from setuptools import setup, Distribution
from setuptools.extension import Extension, Library
import glob import glob
import os import os
import platform import platform
@ -137,6 +138,13 @@ class Config(object):
build_cmd = Distribution().get_command_obj('build') build_cmd = Distribution().get_command_obj('build')
build_cmd.finalize_options() build_cmd.finalize_options()
self.build_platlib = build_cmd.build_platlib self.build_platlib = build_cmd.build_platlib
self.build_temp = build_cmd.build_temp
if platform.system() == "Windows":
# Windows uses separate temp build folders for debug and release
if build_cmd.debug:
self.build_temp = os.path.join(self.build_temp, "Debug")
else:
self.build_temp = os.path.join(self.build_temp, "Release")
self.ext_suffix = sysconfig.get_config_var("EXT_SUFFIX") self.ext_suffix = sysconfig.get_config_var("EXT_SUFFIX")
@ -155,18 +163,30 @@ class Config(object):
ext_suffix = ext_suffix.replace('.so', '.dylib') ext_suffix = ext_suffix.replace('.so', '.dylib')
return mod + ext_suffix return mod + ext_suffix
def path_of(self, mod): def path_of(self, mod, mod_src_path):
""" """
Returns the build path of the library for a given module Returns the build path of the library for a given module
""" """
return os.path.join(self.build_platlib, self.root, self.libname_of(mod)) if platform.system() == "Windows":
# On Windows, the library to link is the import library
(dll_name, dll_ext) = os.path.splitext(self.libname_of(mod))
return os.path.join(self.build_temp, mod_src_path, dll_name + ".lib")
else:
return os.path.join(self.build_platlib, self.root, self.libname_of(mod))
def compile_args(self, mod): def compile_args(self, mod):
""" """
Gets additional compiler arguments Gets additional compiler arguments
""" """
if platform.system() == "Windows": if platform.system() == "Windows":
return [] bits = os.getenv("KLAYOUT_BITS")
if bits:
return ["\"-I" + os.path.join(bits, "zlib", "include") + "\"",
"\"-I" + os.path.join(bits, "ptw", "include") + "\"",
"\"-I" + os.path.join(bits, "expat", "include") + "\"",
"\"-I" + os.path.join(bits, "curl", "include") + "\""]
else:
return []
elif platform.system() == "Darwin": elif platform.system() == "Darwin":
return [] return []
else: else:
@ -174,12 +194,31 @@ class Config(object):
"-std=c++11", # because we use unordered_map/unordered_set "-std=c++11", # because we use unordered_map/unordered_set
] ]
def libraries(self, mod):
"""
Gets the libraries to add
"""
if platform.system() == "Windows":
if mod == "_tl":
return [ "libcurl", "expat", "pthreadVCE2", "zlib", "wsock32" ]
else:
if mod == "_tl":
['curl', 'expat'],
return []
def link_args(self, mod): def link_args(self, mod):
""" """
Gets additional linker arguments Gets additional linker arguments
""" """
if platform.system() == "Windows": if platform.system() == "Windows":
return [] args = ["/DLL"]
bits = os.getenv("KLAYOUT_BITS")
if bits:
args += ["\"/LIBPATH:" + os.path.join(bits, "zlib", "libraries") + "\"",
"\"/LIBPATH:" + os.path.join(bits, "ptw", "libraries") + "\"",
"\"/LIBPATH:" + os.path.join(bits, "expat", "libraries") + "\"",
"\"/LIBPATH:" + os.path.join(bits, "curl", "libraries") + "\""]
return args
elif platform.system() == "Darwin": elif platform.system() == "Darwin":
# For the dependency modules, make sure we produce a dylib. # For the dependency modules, make sure we produce a dylib.
# We can only link against such, but the bundles produced otherwise. # We can only link against such, but the bundles produced otherwise.
@ -222,7 +261,6 @@ config = Config()
# _tl dependency library # _tl dependency library
_tl_path = os.path.join("src", "tl", "tl") _tl_path = os.path.join("src", "tl", "tl")
_tl_sources = set(glob.glob(os.path.join(_tl_path, "*.cc"))) _tl_sources = set(glob.glob(os.path.join(_tl_path, "*.cc")))
# Exclude sources which are compatible with Qt only # Exclude sources which are compatible with Qt only
@ -233,41 +271,43 @@ _tl_sources.discard(os.path.join(_tl_path, "tlHttpStreamNoQt.cc"))
_tl_sources.discard(os.path.join(_tl_path, "tlFileSystemWatcher.cc")) _tl_sources.discard(os.path.join(_tl_path, "tlFileSystemWatcher.cc"))
_tl_sources.discard(os.path.join(_tl_path, "tlDeferredExecutionQt.cc")) _tl_sources.discard(os.path.join(_tl_path, "tlDeferredExecutionQt.cc"))
_tl = Extension(config.root + '._tl', _tl = Library(config.root + '._tl',
define_macros=config.macros() + [('MAKE_TL_LIBRARY', 1)], define_macros=config.macros() + [('MAKE_TL_LIBRARY', 1)],
language='c++', language='c++',
libraries=['curl', 'expat'], libraries=config.libraries('_tl'),
extra_link_args=config.link_args('_tl'), extra_link_args=config.link_args('_tl'),
extra_compile_args=config.compile_args('_tl'), extra_compile_args=config.compile_args('_tl'),
sources=list(_tl_sources)) sources=list(_tl_sources))
# ------------------------------------------------------------------ # ------------------------------------------------------------------
# _gsi dependency library # _gsi dependency library
_gsi_sources = glob.glob("src/gsi/gsi/*.cc") _gsi_path = os.path.join("src", "gsi", "gsi")
_gsi_sources = set(glob.glob(os.path.join(_gsi_path, "*.cc")))
_gsi = Extension(config.root + '._gsi', _gsi = Library(config.root + '._gsi',
define_macros=config.macros() + [('MAKE_GSI_LIBRARY', 1)], define_macros=config.macros() + [('MAKE_GSI_LIBRARY', 1)],
include_dirs=['src/tl/tl'], include_dirs=[_tl_path],
extra_objects=[config.path_of('_tl')], extra_objects=[config.path_of('_tl', _tl_path)],
language='c++', language='c++',
extra_link_args=config.link_args('_gsi'), extra_link_args=config.link_args('_gsi'),
extra_compile_args=config.compile_args('_gsi'), extra_compile_args=config.compile_args('_gsi'),
sources=_gsi_sources) sources=list(_gsi_sources))
# ------------------------------------------------------------------ # ------------------------------------------------------------------
# _pya dependency library # _pya dependency library
_pya_sources = glob.glob("src/pya/pya/*.cc") _pya_path = os.path.join("src", "pya", "pya")
_pya_sources = set(glob.glob(os.path.join(_pya_path, "*.cc")))
_pya = Extension(config.root + '._pya', _pya = Library(config.root + '._pya',
define_macros=config.macros() + [('MAKE_PYA_LIBRARY', 1)], define_macros=config.macros() + [('MAKE_PYA_LIBRARY', 1)],
include_dirs=['src/tl/tl', 'src/gsi/gsi'], include_dirs=[_tl_path, _gsi_path],
extra_objects=[config.path_of('_tl'), config.path_of('_gsi')], extra_objects=[config.path_of('_tl', _tl_path), config.path_of('_gsi', _gsi_path)],
language='c++', language='c++',
extra_link_args=config.link_args('_pya'), extra_link_args=config.link_args('_pya'),
extra_compile_args=config.compile_args('_pya'), extra_compile_args=config.compile_args('_pya'),
sources=_pya_sources) sources=list(_pya_sources))
# ------------------------------------------------------------------ # ------------------------------------------------------------------
# _db dependency library # _db dependency library
@ -280,93 +320,94 @@ _db_sources = set(glob.glob(os.path.join(_db_path, "*.cc")))
# not exist. So we need an error-free discard method instead of list's remove. # not exist. So we need an error-free discard method instead of list's remove.
_db_sources.discard(os.path.join(_db_path, "fonts.cc")) _db_sources.discard(os.path.join(_db_path, "fonts.cc"))
_db = Extension(config.root + '._db', _db = Library(config.root + '._db',
define_macros=config.macros() + [('MAKE_DB_LIBRARY', 1)], define_macros=config.macros() + [('MAKE_DB_LIBRARY', 1)],
include_dirs=['src/tl/tl', 'src/gsi/gsi', 'src/db/db'], include_dirs=[_tl_path, _gsi_path, _db_path],
extra_objects=[config.path_of('_tl'), config.path_of('_gsi')], extra_objects=[config.path_of('_tl', _tl_path), config.path_of('_gsi', _gsi_path)],
language='c++', language='c++',
extra_link_args=config.link_args('_db'), extra_link_args=config.link_args('_db'),
extra_compile_args=config.compile_args('_db'), extra_compile_args=config.compile_args('_db'),
sources=list(_db_sources)) sources=list(_db_sources))
# ------------------------------------------------------------------ # ------------------------------------------------------------------
# _rdb dependency library # _rdb dependency library
_rdb_sources = glob.glob("src/rdb/rdb/*.cc") _rdb_path = os.path.join("src", "rdb", "rdb")
_rdb_sources = set(glob.glob(os.path.join(_rdb_path, "*.cc")))
_rdb = Extension(config.root + '._rdb', _rdb = Library(config.root + '._rdb',
define_macros=config.macros() + [('MAKE_RDB_LIBRARY', 1)], define_macros=config.macros() + [('MAKE_RDB_LIBRARY', 1)],
include_dirs=['src/db/db', 'src/tl/tl', 'src/gsi/gsi'], include_dirs=[_db_path, _tl_path, _gsi_path],
extra_objects=[config.path_of('_tl'), config.path_of( extra_objects=[config.path_of('_tl', _tl_path), config.path_of('_gsi', _gsi_path), config.path_of('_db', _db_path)],
'_gsi'), config.path_of('_db')], language='c++',
language='c++', extra_link_args=config.link_args('_rdb'),
extra_link_args=config.link_args('_rdb'), extra_compile_args=config.compile_args('_rdb'),
extra_compile_args=config.compile_args('_rdb'), sources=list(_rdb_sources))
sources=_rdb_sources)
# ------------------------------------------------------------------ # ------------------------------------------------------------------
# dependency libraries from db_plugins # dependency libraries from db_plugins
db_plugins = [] db_plugins = []
for pi in glob.glob("src/plugins/*/db_plugin") + glob.glob("src/plugins/*/*/db_plugin"): dbpi_dirs = glob.glob(os.path.join("src", "plugins", "*", "db_plugin"))
dbpi_dirs += glob.glob(os.path.join("src", "plugins", "*", "*", "db_plugin"))
for pi in dbpi_dirs:
mod_name = "_" + os.path.split(os.path.split(pi)[-2])[-1] + "_dbpi" mod_name = "_" + os.path.split(os.path.split(pi)[-2])[-1] + "_dbpi"
pi_sources = glob.glob(pi + "/*.cc") pi_sources = glob.glob(os.path.join(pi, "*.cc"))
pi_ext = Extension(config.root + '.db_plugins.' + mod_name, pi_ext = Library(config.root + '.db_plugins.' + mod_name,
define_macros=config.macros() + [('MAKE_DB_PLUGIN_LIBRARY', 1)], define_macros=config.macros() + [('MAKE_DB_PLUGIN_LIBRARY', 1)],
include_dirs=['src/plugins/common', include_dirs=[os.path.join("src", "plugins", "common"),
'src/db/db', 'src/tl/tl', 'src/gsi/gsi'], _db_path, _tl_path, _gsi_path],
extra_objects=[config.path_of('_tl'), config.path_of( extra_objects=[config.path_of('_tl', _tl_path), config.path_of('_gsi', _gsi_path), config.path_of('_db', _db_path)],
'_gsi'), config.path_of('_db')], language='c++',
language='c++', extra_link_args=config.link_args(mod_name),
extra_link_args=config.link_args(mod_name), extra_compile_args=config.compile_args(mod_name),
extra_compile_args=config.compile_args(mod_name), sources=pi_sources)
sources=pi_sources)
db_plugins.append(pi_ext) db_plugins.append(pi_ext)
# ------------------------------------------------------------------ # ------------------------------------------------------------------
# tl extension library # tl extension library
tl_sources = glob.glob("src/pymod/tl/*.cc") tl_path = os.path.join("src", "pymod", "tl")
tl_sources = set(glob.glob(os.path.join(tl_path, "*.cc")))
tl = Extension(config.root + '.tl', tl = Extension(config.root + '.tl',
define_macros=config.macros(), define_macros=config.macros(),
include_dirs=['src/tl/tl', 'src/gsi/gsi', 'src/pya/pya'], include_dirs=[_tl_path, _gsi_path, _pya_path],
extra_objects=[config.path_of('_tl'), config.path_of( extra_objects=[config.path_of('_tl', _tl_path), config.path_of('_gsi', _gsi_path), config.path_of('_pya', _pya_path)],
'_gsi'), config.path_of('_pya')],
extra_link_args=config.link_args('tl'), extra_link_args=config.link_args('tl'),
sources=tl_sources) sources=list(tl_sources))
# ------------------------------------------------------------------ # ------------------------------------------------------------------
# db extension library # db extension library
db_sources = glob.glob("src/pymod/db/*.cc") db_path = os.path.join("src", "pymod", "db")
db_sources = set(glob.glob(os.path.join(db_path, "*.cc")))
db = Extension(config.root + '.db', db = Extension(config.root + '.db',
define_macros=config.macros(), define_macros=config.macros(),
include_dirs=['src/db/db', 'src/tl/tl', 'src/gsi/gsi', 'src/pya/pya'], include_dirs=[_db_path, _tl_path, _gsi_path, _pya_path],
extra_objects=[config.path_of('_db'), config.path_of( extra_objects=[config.path_of('_db', _db_path), config.path_of('_tl', _tl_path), config.path_of('_gsi', _gsi_path), config.path_of('_pya', _pya_path)],
'_tl'), config.path_of('_gsi'), config.path_of('_pya')],
extra_link_args=config.link_args('db'), extra_link_args=config.link_args('db'),
sources=db_sources) sources=list(db_sources))
# ------------------------------------------------------------------ # ------------------------------------------------------------------
# rdb extension library # rdb extension library
rdb_sources = glob.glob("src/pymod/rdb/*.cc") rdb_path = os.path.join("src", "pymod", "rdb")
rdb_sources = set(glob.glob(os.path.join(rdb_path, "*.cc")))
rdb = Extension(config.root + '.rdb', rdb = Extension(config.root + '.rdb',
define_macros=config.macros(), define_macros=config.macros(),
include_dirs=['src/rdb/rdb', 'src/db/db', include_dirs=[_rdb_path, _db_path, _tl_path, _gsi_path, _pya_path],
'src/tl/tl', 'src/gsi/gsi', 'src/pya/pya'], extra_objects=[config.path_of('_rdb', _rdb_path), config.path_of('_tl', _tl_path), config.path_of('_gsi', _gsi_path), config.path_of('_pya', _pya_path)],
extra_objects=[config.path_of('_rdb'), config.path_of(
'_gsi'), config.path_of('_pya')],
extra_link_args=config.link_args('rdb'), extra_link_args=config.link_args('rdb'),
sources=rdb_sources) sources=list(rdb_sources))
# ------------------------------------------------------------------ # ------------------------------------------------------------------
# Core setup function # Core setup function