2017-11-03 14:38:42 +01:00
|
|
|
#!/usr/bin/env python
|
|
|
|
|
import logging
|
|
|
|
|
import sys
|
|
|
|
|
import re
|
|
|
|
|
import os
|
|
|
|
|
import json
|
2020-11-18 15:52:37 +00:00
|
|
|
import shutil
|
2017-11-03 14:38:42 +01:00
|
|
|
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
2020-11-18 15:52:37 +00:00
|
|
|
from setup_support import SetupApp, Config
|
2017-11-03 14:38:42 +01:00
|
|
|
|
|
|
|
|
PYTHON_DATA_SCRIPT = """
|
2024-04-04 08:05:04 +00:00
|
|
|
from distutils.sysconfig import (get_config_var, get_python_inc,
|
|
|
|
|
get_config_vars, PREFIX)
|
2017-11-03 14:38:42 +01:00
|
|
|
import json
|
|
|
|
|
result = {'config_vars': get_config_vars(),
|
2024-04-04 08:05:04 +00:00
|
|
|
'python_inc': get_python_inc(),
|
|
|
|
|
'python_inc_plat': get_python_inc(plat_specific=True),
|
|
|
|
|
'prefix': PREFIX}
|
2017-11-03 14:38:42 +01:00
|
|
|
print(json.dumps(result))
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def fetch_python_config(config):
|
|
|
|
|
logging.info('Fetch Python information...')
|
|
|
|
|
python_output = config.run(config.data['python_exec'], '-c',
|
|
|
|
|
PYTHON_DATA_SCRIPT,
|
|
|
|
|
grab=True)
|
|
|
|
|
python_data = json.loads(python_output)
|
|
|
|
|
config_vars = python_data['config_vars']
|
|
|
|
|
python_version = config_vars["VERSION"]
|
2019-11-21 12:31:40 +01:00
|
|
|
python_ldversion = config_vars.get("LDVERSION", python_version)
|
2017-11-03 14:38:42 +01:00
|
|
|
logging.info(' %-24s %s', 'Python version:', python_version)
|
|
|
|
|
|
|
|
|
|
# Current python location
|
2018-02-07 07:07:07 -05:00
|
|
|
current_prefix = python_data['prefix']
|
2017-11-03 14:38:42 +01:00
|
|
|
|
2019-11-21 12:31:40 +01:00
|
|
|
# Fetch prefix during the build process. Some paths of interest might
|
|
|
|
|
# still reference a location used during the Python build process.
|
2017-11-03 14:38:42 +01:00
|
|
|
build_prefix = ([sys.prefix] +
|
|
|
|
|
re.findall(r"'--prefix=([^']+)'",
|
|
|
|
|
config_vars.get('CONFIG_ARGS', '')))[-1]
|
|
|
|
|
|
|
|
|
|
def relocate(path):
|
|
|
|
|
if os.path.isabs(path):
|
|
|
|
|
rel_path = os.path.relpath(path, build_prefix)
|
|
|
|
|
if not rel_path.startswith(os.pardir):
|
2019-11-21 12:31:40 +01:00
|
|
|
# If the input path is relative to the original build
|
|
|
|
|
# directory, replace build prefix by the current one.
|
2017-11-03 14:38:42 +01:00
|
|
|
return os.path.join(current_prefix, rel_path)
|
|
|
|
|
else:
|
2019-11-21 12:31:40 +01:00
|
|
|
# Otherwise, return it unchanged
|
2017-11-03 14:38:42 +01:00
|
|
|
return path
|
|
|
|
|
else:
|
|
|
|
|
# The input path is relative so assume it's relative to the current
|
|
|
|
|
# python prefix.
|
|
|
|
|
return os.path.join(current_prefix, path)
|
|
|
|
|
|
|
|
|
|
# Retrieve cflags, and linker flags
|
|
|
|
|
static_dir = relocate(config_vars.get('LIBPL', 'libs'))
|
|
|
|
|
logging.info(' %-24s %s', 'Static dir', static_dir)
|
|
|
|
|
|
|
|
|
|
shared_dir = relocate(config_vars.get('LIBDIR', '.'))
|
|
|
|
|
logging.info(' %-24s %s', 'Shared dir', shared_dir)
|
|
|
|
|
|
2019-11-21 12:31:40 +01:00
|
|
|
# Add first relocated include dirs followed by non-relocated version.
|
|
|
|
|
# Indeed, when using venv and maybe virtualenv, includes are not copied.
|
2017-11-03 14:38:42 +01:00
|
|
|
cflags = "-I" + relocate(python_data['python_inc'])
|
|
|
|
|
if python_data['python_inc'] != python_data['python_inc_plat']:
|
|
|
|
|
cflags += " -I" + relocate(python_data['python_inc_plat'])
|
2019-11-21 12:31:40 +01:00
|
|
|
cflags += " -I" + python_data['python_inc_plat']
|
|
|
|
|
cflags += " -I" + python_data['python_inc']
|
|
|
|
|
|
2017-11-03 14:38:42 +01:00
|
|
|
logging.info(' %-24s %s', 'CFLAGS', cflags)
|
|
|
|
|
|
2019-11-21 12:31:40 +01:00
|
|
|
if python_version.startswith('3'):
|
|
|
|
|
# In python 3.x MODLIBS seems to drag in too many libraries
|
|
|
|
|
python_libs = [config_vars[v] for v in ("LIBS", "SYSLIBS")
|
|
|
|
|
if v in config_vars and config_vars[v]]
|
|
|
|
|
else:
|
|
|
|
|
python_libs = [config_vars[v] for v in ("LIBS", "SYSLIBS", "MODLIBS")
|
|
|
|
|
if v in config_vars and config_vars[v]]
|
2017-11-03 14:38:42 +01:00
|
|
|
python_libs = " ".join(python_libs)
|
|
|
|
|
|
|
|
|
|
python_shared_libs = "-L%s -lpython%s %s" % (shared_dir,
|
2019-11-21 12:31:40 +01:00
|
|
|
python_ldversion,
|
2017-11-03 14:38:42 +01:00
|
|
|
python_libs)
|
2020-11-18 15:52:37 +00:00
|
|
|
python_static_libs = python_libs
|
2019-11-21 12:31:40 +01:00
|
|
|
libpython_a = os.path.join(
|
|
|
|
|
static_dir,
|
|
|
|
|
config_vars.get('LIBRARY', 'libpython%s.a' % python_version))
|
|
|
|
|
|
2019-08-10 00:50:58 +02:00
|
|
|
if os.path.isfile(libpython_a):
|
2020-11-18 15:52:37 +00:00
|
|
|
config.set_data('GNATCOLL_PYTHON_STATIC_LIB',
|
|
|
|
|
libpython_a, sub='gprbuild')
|
2021-05-26 10:56:34 +01:00
|
|
|
else:
|
|
|
|
|
logging.info('static python library not found')
|
2020-11-18 15:52:37 +00:00
|
|
|
|
2017-11-03 14:38:42 +01:00
|
|
|
if sys.platform.startswith('linux'):
|
|
|
|
|
# On Linux platform, even when linking with the static libpython,
|
|
|
|
|
# symbols not used by the application itself should be exported so
|
|
|
|
|
# that shared library present in Python can use the Python C API.
|
|
|
|
|
python_static_libs += ' -export-dynamic'
|
|
|
|
|
python_shared_libs += ' -export-dynamic'
|
|
|
|
|
|
|
|
|
|
logging.info(' %-24s %s', 'Shared linker flags', python_shared_libs)
|
|
|
|
|
logging.info(' %-24s %s', 'Static linker flags', python_static_libs)
|
|
|
|
|
|
2018-02-07 15:39:00 +01:00
|
|
|
# User does not have the choice between linking with static libpython
|
2018-06-06 15:34:25 +02:00
|
|
|
# and shared libpython. If --enable-shared or --enable-framework was
|
|
|
|
|
# passed to Python's configure during Python build, then we should
|
2018-02-07 15:39:00 +01:00
|
|
|
# link with the shared libpython, otherwise with the static one.
|
|
|
|
|
# Indeed otherwise some C modules might not work as expected or even
|
2019-11-21 12:31:40 +01:00
|
|
|
# crash. On Windows always link with shared version of libpython
|
2018-02-07 15:39:00 +01:00
|
|
|
# (if the static is present, this is just an indirection to the shared)
|
|
|
|
|
if '--enable-shared' in config_vars.get('CONFIG_ARGS', '') or \
|
2018-06-06 15:34:25 +02:00
|
|
|
'--enable-framework' in config_vars.get('CONFIG_ARGS', '') or \
|
2018-02-07 15:39:00 +01:00
|
|
|
sys.platform.startswith('win'):
|
|
|
|
|
logging.info('Force link to shared python library')
|
|
|
|
|
config.set_data('GNATCOLL_PYTHON_LIBS',
|
|
|
|
|
python_shared_libs, sub='gprbuild')
|
|
|
|
|
config.set_data('GNATCOLL_LIBPYTHON_KIND', 'shared',
|
|
|
|
|
sub='gprbuild')
|
|
|
|
|
else:
|
|
|
|
|
logging.info('Force link to static python library')
|
|
|
|
|
config.set_data('GNATCOLL_PYTHON_LIBS',
|
|
|
|
|
python_static_libs, sub='gprbuild')
|
|
|
|
|
config.set_data('GNATCOLL_LIBPYTHON_KIND', 'static',
|
|
|
|
|
sub='gprbuild')
|
2017-11-03 14:38:42 +01:00
|
|
|
config.set_data('GNATCOLL_PYTHON_CFLAGS', cflags, sub='gprbuild')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class GNATCollPython(SetupApp):
|
2018-01-17 11:23:29 +01:00
|
|
|
name = 'gnatcoll_python'
|
|
|
|
|
project = 'gnatcoll_python.gpr'
|
2017-11-03 14:38:42 +01:00
|
|
|
description = 'GNATColl Python bindings'
|
|
|
|
|
|
|
|
|
|
def create(self):
|
|
|
|
|
super(GNATCollPython, self).create()
|
|
|
|
|
self.build_cmd.add_argument(
|
|
|
|
|
'--python-exec',
|
|
|
|
|
help='set python executable location',
|
|
|
|
|
metavar='PATH',
|
|
|
|
|
default=sys.executable)
|
|
|
|
|
self.build_cmd.add_argument(
|
|
|
|
|
'--debug',
|
|
|
|
|
help='build project in debug mode',
|
|
|
|
|
action="store_true",
|
|
|
|
|
default=False)
|
|
|
|
|
|
|
|
|
|
def update_config(self, config, args):
|
|
|
|
|
# Fetch python information
|
|
|
|
|
config.set_data('python_exec', args.python_exec)
|
|
|
|
|
fetch_python_config(config)
|
|
|
|
|
|
|
|
|
|
logging.info('%-26s %s',
|
|
|
|
|
'Libraries kind', ", ".join(config.data['library_types']))
|
|
|
|
|
|
|
|
|
|
# Set library version
|
|
|
|
|
with open(os.path.join(config.source_dir, '..',
|
2019-11-21 12:31:40 +01:00
|
|
|
'version_information'), 'r') as fd:
|
2017-11-03 14:38:42 +01:00
|
|
|
version = fd.read().strip()
|
|
|
|
|
config.set_data('GNATCOLL_VERSION', version, sub='gprbuild')
|
|
|
|
|
logging.info('%-26s %s', 'Version', version)
|
|
|
|
|
|
|
|
|
|
# Set build mode
|
|
|
|
|
config.set_data('BUILD', 'DEBUG' if args.debug else 'PROD',
|
|
|
|
|
sub='gprbuild')
|
|
|
|
|
logging.info('%-26s %s', 'Build mode',
|
|
|
|
|
config.data['gprbuild']['BUILD'])
|
|
|
|
|
|
|
|
|
|
# Set GNATCOLL_OS
|
|
|
|
|
if 'darwin' in config.data['canonical_target']:
|
|
|
|
|
gnatcoll_os = 'osx'
|
|
|
|
|
elif 'windows' in config.data['canonical_target']:
|
|
|
|
|
gnatcoll_os = 'windows'
|
|
|
|
|
else:
|
|
|
|
|
# Assume this is an Unix system
|
|
|
|
|
gnatcoll_os = 'unix'
|
|
|
|
|
config.set_data('GNATCOLL_OS', gnatcoll_os, sub='gprbuild')
|
|
|
|
|
|
|
|
|
|
def variants(self, config, cmd):
|
|
|
|
|
result = []
|
|
|
|
|
for library_type in config.data['library_types']:
|
|
|
|
|
gpr_vars = {'LIBRARY_TYPE': library_type,
|
2018-02-07 03:23:38 -05:00
|
|
|
'XMLADA_BUILD': library_type,
|
|
|
|
|
'GPR_BUILD': library_type}
|
2017-11-03 14:38:42 +01:00
|
|
|
if cmd == 'install':
|
|
|
|
|
result.append((['--build-name=%s' % library_type,
|
|
|
|
|
'--build-var=LIBRARY_TYPE'],
|
|
|
|
|
gpr_vars))
|
|
|
|
|
else:
|
|
|
|
|
result.append(([], gpr_vars))
|
|
|
|
|
return result
|
|
|
|
|
|
2020-11-18 15:52:37 +00:00
|
|
|
def install(self, args):
|
|
|
|
|
config = Config()
|
2021-05-26 10:56:34 +01:00
|
|
|
has_static_python = "GNATCOLL_PYTHON_STATIC_LIB" in config.data["gprbuild"]
|
|
|
|
|
if has_static_python:
|
|
|
|
|
python_la = config.data["gprbuild"]["GNATCOLL_PYTHON_STATIC_LIB"]
|
|
|
|
|
prefix = config.data["prefix"]
|
|
|
|
|
target = os.path.join(
|
|
|
|
|
"..", "..", "lib", "gnatcoll_python.static",
|
|
|
|
|
os.path.basename(python_la)
|
|
|
|
|
)
|
|
|
|
|
config.set_data("GNATCOLL_PYTHON_STATIC_LIB", target, sub='gprbuild')
|
|
|
|
|
config.save_data()
|
2020-11-18 15:52:37 +00:00
|
|
|
super(GNATCollPython, self).install(args)
|
|
|
|
|
|
2021-05-26 10:56:34 +01:00
|
|
|
if has_static_python:
|
|
|
|
|
# Copy over the libpython*.la
|
|
|
|
|
shutil.copy(
|
|
|
|
|
python_la, os.path.join(prefix, "lib", "gnatcoll_python.static"))
|
2020-11-18 15:52:37 +00:00
|
|
|
|
2018-01-17 11:23:29 +01:00
|
|
|
|
2017-11-03 14:38:42 +01:00
|
|
|
if __name__ == '__main__':
|
|
|
|
|
app = GNATCollPython()
|
|
|
|
|
sys.exit(app.run())
|