def check_python_headers(conf, features='pyembed pyext'):
    """
	Check for headers and libraries necessary to extend or embed python by using the module *distutils*.
	On success the environment variables xxx_PYEXT and xxx_PYEMBED are added:

	* PYEXT: for compiling python extensions
	* PYEMBED: for embedding a python interpreter
	"""
    features = Utils.to_list(features)
    assert ('pyembed' in features) or (
        'pyext' in features
    ), "check_python_headers features must include 'pyembed' and/or 'pyext'"
    env = conf.env
    if not env.CC_NAME and not env.CXX_NAME:
        conf.fatal('load a compiler first (gcc, g++, ..)')

    # bypass all the code below for cross-compilation
    if conf.python_cross_compile(features):
        return

    if not env.PYTHON_VERSION:
        conf.check_python_version()

    pybin = env.PYTHON
    if not pybin:
        conf.fatal('Could not find the python executable')

    # so we actually do all this for compatibility reasons and for obtaining pyext_PATTERN below
    v = 'prefix SO LDFLAGS LIBDIR LIBPL INCLUDEPY Py_ENABLE_SHARED MACOSX_DEPLOYMENT_TARGET LDSHARED CFLAGS LDVERSION'.split(
    )
    try:
        lst = conf.get_python_variables(
            ["get_config_var('%s') or ''" % x for x in v])
    except RuntimeError:
        conf.fatal("Python development headers not found (-v for details).")

    vals = ['%s = %r' % (x, y) for (x, y) in zip(v, lst)]
    conf.to_log("Configuration returned from %r:\n%s\n" %
                (pybin, '\n'.join(vals)))

    dct = dict(zip(v, lst))
    x = 'MACOSX_DEPLOYMENT_TARGET'
    if dct[x]:
        env[x] = conf.environ[x] = dct[x]
    env.pyext_PATTERN = '%s' + dct['SO']  # not a mistake

    # Try to get pythonX.Y-config
    num = '.'.join(env.PYTHON_VERSION.split('.')[:2])
    conf.find_program([
        ''.join(pybin) + '-config',
        'python%s-config' % num,
        'python-config-%s' % num,
        'python%sm-config' % num
    ],
                      var='PYTHON_CONFIG',
                      msg="python-config",
                      mandatory=False)

    if env.PYTHON_CONFIG:
        # python2.6-config requires 3 runs
        all_flags = [['--cflags', '--libs', '--ldflags']]
        if sys.hexversion < 0x2070000:
            all_flags = [[k] for k in all_flags[0]]

        xx = env.CXX_NAME and 'cxx' or 'c'

        if 'pyembed' in features:
            for flags in all_flags:
                conf.check_cfg(
                    msg='Asking python-config for pyembed %r flags' %
                    ' '.join(flags),
                    path=env.PYTHON_CONFIG,
                    package='',
                    uselib_store='PYEMBED',
                    args=flags)

            try:
                conf.test_pyembed(xx)
            except conf.errors.ConfigurationError:
                # python bug 7352
                if dct['Py_ENABLE_SHARED'] and dct['LIBDIR']:
                    env.append_unique('LIBPATH_PYEMBED', [dct['LIBDIR']])
                    conf.test_pyembed(xx)
                else:
                    raise

        if 'pyext' in features:
            for flags in all_flags:
                conf.check_cfg(msg='Asking python-config for pyext %r flags' %
                               ' '.join(flags),
                               path=env.PYTHON_CONFIG,
                               package='',
                               uselib_store='PYEXT',
                               args=flags)

            try:
                conf.test_pyext(xx)
            except conf.errors.ConfigurationError:
                # python bug 7352
                if dct['Py_ENABLE_SHARED'] and dct['LIBDIR']:
                    env.append_unique('LIBPATH_PYEXT', [dct['LIBDIR']])
                    conf.test_pyext(xx)
                else:
                    raise

        conf.define('HAVE_PYTHON_H', 1)
        return

    # No python-config, do something else on windows systems
    all_flags = dct['LDFLAGS'] + ' ' + dct['CFLAGS']
    conf.parse_flags(all_flags, 'PYEMBED')

    all_flags = dct['LDFLAGS'] + ' ' + dct['LDSHARED'] + ' ' + dct['CFLAGS']
    conf.parse_flags(all_flags, 'PYEXT')

    result = None
    if not dct["LDVERSION"]:
        dct["LDVERSION"] = env.PYTHON_VERSION

    # further simplification will be complicated
    for name in ('python' + dct['LDVERSION'],
                 'python' + env.PYTHON_VERSION + 'm',
                 'python' + env.PYTHON_VERSION.replace('.', '')):

        # LIBPATH_PYEMBED is already set; see if it works.
        if not result and env.LIBPATH_PYEMBED:
            path = env.LIBPATH_PYEMBED
            conf.to_log("\n\n# Trying default LIBPATH_PYEMBED: %r\n" % path)
            result = conf.check(
                lib=name,
                uselib='PYEMBED',
                libpath=path,
                mandatory=False,
                msg='Checking for library %s in LIBPATH_PYEMBED' % name)

        if not result and dct['LIBDIR']:
            path = [dct['LIBDIR']]
            conf.to_log("\n\n# try again with -L$python_LIBDIR: %r\n" % path)
            result = conf.check(lib=name,
                                uselib='PYEMBED',
                                libpath=path,
                                mandatory=False,
                                msg='Checking for library %s in LIBDIR' % name)

        if not result and dct['LIBPL']:
            path = [dct['LIBPL']]
            conf.to_log(
                "\n\n# try again with -L$python_LIBPL (some systems don't install the python library in $prefix/lib)\n"
            )
            result = conf.check(lib=name,
                                uselib='PYEMBED',
                                libpath=path,
                                mandatory=False,
                                msg='Checking for library %s in python_LIBPL' %
                                name)

        if not result:
            path = [os.path.join(dct['prefix'], "libs")]
            conf.to_log(
                "\n\n# try again with -L$prefix/libs, and pythonXY name rather than pythonX.Y (win32)\n"
            )
            result = conf.check(lib=name,
                                uselib='PYEMBED',
                                libpath=path,
                                mandatory=False,
                                msg='Checking for library %s in $prefix/libs' %
                                name)

        if result:
            break  # do not forget to set LIBPATH_PYEMBED

    if result:
        env.LIBPATH_PYEMBED = path
        env.append_value('LIB_PYEMBED', [name])
    else:
        conf.to_log("\n\n### LIB NOT FOUND\n")

    # under certain conditions, python extensions must link to
    # python libraries, not just python embedding programs.
    if Utils.is_win32 or dct['Py_ENABLE_SHARED']:
        env.LIBPATH_PYEXT = env.LIBPATH_PYEMBED
        env.LIB_PYEXT = env.LIB_PYEMBED

    conf.to_log(
        "Include path for Python extensions (found via distutils module): %r\n"
        % (dct['INCLUDEPY'], ))
    env.INCLUDES_PYEXT = [dct['INCLUDEPY']]
    env.INCLUDES_PYEMBED = [dct['INCLUDEPY']]

    # Code using the Python API needs to be compiled with -fno-strict-aliasing
    if env.CC_NAME == 'gcc':
        env.append_value('CFLAGS_PYEMBED', ['-fno-strict-aliasing'])
        env.append_value('CFLAGS_PYEXT', ['-fno-strict-aliasing'])
    if env.CXX_NAME == 'gcc':
        env.append_value('CXXFLAGS_PYEMBED', ['-fno-strict-aliasing'])
        env.append_value('CXXFLAGS_PYEXT', ['-fno-strict-aliasing'])

    if env.CC_NAME == "msvc":
        from distutils.msvccompiler import MSVCCompiler
        dist_compiler = MSVCCompiler()
        dist_compiler.initialize()
        env.append_value('CFLAGS_PYEXT', dist_compiler.compile_options)
        env.append_value('CXXFLAGS_PYEXT', dist_compiler.compile_options)
        env.append_value('LINKFLAGS_PYEXT', dist_compiler.ldflags_shared)

    # See if it compiles
    conf.check(
        header_name='Python.h',
        define_name='HAVE_PYTHON_H',
        uselib='PYEMBED',
        fragment=FRAG,
        errmsg=
        'Distutils not installed? Broken python installation? Get python-config now!'
    )
Exemple #2
0
def check_python_headers(conf, features='pyembed pyext'):
	"""
	Check for headers and libraries necessary to extend or embed python by using the module *distutils*.
	On success the environment variables xxx_PYEXT and xxx_PYEMBED are added:

	* PYEXT: for compiling python extensions
	* PYEMBED: for embedding a python interpreter
	"""
	features = Utils.to_list(features)
	assert ('pyembed' in features) or ('pyext' in features), "check_python_headers features must include 'pyembed' and/or 'pyext'"
	env = conf.env
	if not env.CC_NAME and not env.CXX_NAME:
		conf.fatal('load a compiler first (gcc, g++, ..)')

	# bypass all the code below for cross-compilation
	if conf.python_cross_compile(features):
		return

	if not env.PYTHON_VERSION:
		conf.check_python_version()

	pybin = env.PYTHON
	if not pybin:
		conf.fatal('Could not find the python executable')

	# so we actually do all this for compatibility reasons and for obtaining pyext_PATTERN below
	v = 'prefix SO LDFLAGS LIBDIR LIBPL INCLUDEPY Py_ENABLE_SHARED MACOSX_DEPLOYMENT_TARGET LDSHARED CFLAGS LDVERSION'.split()
	try:
		lst = conf.get_python_variables(["get_config_var('%s') or ''" % x for x in v])
	except RuntimeError:
		conf.fatal("Python development headers not found (-v for details).")

	vals = ['%s = %r' % (x, y) for (x, y) in zip(v, lst)]
	conf.to_log("Configuration returned from %r:\n%s\n" % (pybin, '\n'.join(vals)))

	dct = dict(zip(v, lst))
	x = 'MACOSX_DEPLOYMENT_TARGET'
	if dct[x]:
		env[x] = conf.environ[x] = dct[x]
	env.pyext_PATTERN = '%s' + dct['SO'] # not a mistake


	# Try to get pythonX.Y-config
	num = '.'.join(env.PYTHON_VERSION.split('.')[:2])
	conf.find_program([''.join(pybin) + '-config', 'python%s-config' % num, 'python-config-%s' % num, 'python%sm-config' % num], var='PYTHON_CONFIG', msg="python-config", mandatory=False)

	if env.PYTHON_CONFIG:
		# python2.6-config requires 3 runs
		all_flags = [['--cflags', '--libs', '--ldflags']]
		if sys.hexversion < 0x2070000:
			all_flags = [[k] for k in all_flags[0]]

		xx = env.CXX_NAME and 'cxx' or 'c'

		if 'pyembed' in features:
			for flags in all_flags:
				conf.check_cfg(msg='Asking python-config for pyembed %r flags' % ' '.join(flags), path=env.PYTHON_CONFIG, package='', uselib_store='PYEMBED', args=flags)

			try:
				conf.test_pyembed(xx)
			except conf.errors.ConfigurationError:
				# python bug 7352
				if dct['Py_ENABLE_SHARED'] and dct['LIBDIR']:
					env.append_unique('LIBPATH_PYEMBED', [dct['LIBDIR']])
					conf.test_pyembed(xx)
				else:
					raise

		if 'pyext' in features:
			for flags in all_flags:
				conf.check_cfg(msg='Asking python-config for pyext %r flags' % ' '.join(flags), path=env.PYTHON_CONFIG, package='', uselib_store='PYEXT', args=flags)

			try:
				conf.test_pyext(xx)
			except conf.errors.ConfigurationError:
				# python bug 7352
				if dct['Py_ENABLE_SHARED'] and dct['LIBDIR']:
					env.append_unique('LIBPATH_PYEXT', [dct['LIBDIR']])
					conf.test_pyext(xx)
				else:
					raise

		conf.define('HAVE_PYTHON_H', 1)
		return

	# No python-config, do something else on windows systems
	all_flags = dct['LDFLAGS'] + ' ' + dct['CFLAGS']
	conf.parse_flags(all_flags, 'PYEMBED')

	all_flags = dct['LDFLAGS'] + ' ' + dct['LDSHARED'] + ' ' + dct['CFLAGS']
	conf.parse_flags(all_flags, 'PYEXT')

	result = None
	if not dct["LDVERSION"]:
		dct["LDVERSION"] = env.PYTHON_VERSION

	# further simplification will be complicated
	for name in ('python' + dct['LDVERSION'], 'python' + env.PYTHON_VERSION + 'm', 'python' + env.PYTHON_VERSION.replace('.', '')):

		# LIBPATH_PYEMBED is already set; see if it works.
		if not result and env.LIBPATH_PYEMBED:
			path = env.LIBPATH_PYEMBED
			conf.to_log("\n\n# Trying default LIBPATH_PYEMBED: %r\n" % path)
			result = conf.check(lib=name, uselib='PYEMBED', libpath=path, mandatory=False, msg='Checking for library %s in LIBPATH_PYEMBED' % name)

		if not result and dct['LIBDIR']:
			path = [dct['LIBDIR']]
			conf.to_log("\n\n# try again with -L$python_LIBDIR: %r\n" % path)
			result = conf.check(lib=name, uselib='PYEMBED', libpath=path, mandatory=False, msg='Checking for library %s in LIBDIR' % name)

		if not result and dct['LIBPL']:
			path = [dct['LIBPL']]
			conf.to_log("\n\n# try again with -L$python_LIBPL (some systems don't install the python library in $prefix/lib)\n")
			result = conf.check(lib=name, uselib='PYEMBED', libpath=path, mandatory=False, msg='Checking for library %s in python_LIBPL' % name)

		if not result:
			path = [os.path.join(dct['prefix'], "libs")]
			conf.to_log("\n\n# try again with -L$prefix/libs, and pythonXY name rather than pythonX.Y (win32)\n")
			result = conf.check(lib=name, uselib='PYEMBED', libpath=path, mandatory=False, msg='Checking for library %s in $prefix/libs' % name)

		if result:
			break # do not forget to set LIBPATH_PYEMBED

	if result:
		env.LIBPATH_PYEMBED = path
		env.append_value('LIB_PYEMBED', [name])
	else:
		conf.to_log("\n\n### LIB NOT FOUND\n")

	# under certain conditions, python extensions must link to
	# python libraries, not just python embedding programs.
	if Utils.is_win32 or dct['Py_ENABLE_SHARED']:
		env.LIBPATH_PYEXT = env.LIBPATH_PYEMBED
		env.LIB_PYEXT = env.LIB_PYEMBED

	conf.to_log("Include path for Python extensions (found via distutils module): %r\n" % (dct['INCLUDEPY'],))
	env.INCLUDES_PYEXT = [dct['INCLUDEPY']]
	env.INCLUDES_PYEMBED = [dct['INCLUDEPY']]

	# Code using the Python API needs to be compiled with -fno-strict-aliasing
	if env.CC_NAME == 'gcc':
		env.append_value('CFLAGS_PYEMBED', ['-fno-strict-aliasing'])
		env.append_value('CFLAGS_PYEXT', ['-fno-strict-aliasing'])
	if env.CXX_NAME == 'gcc':
		env.append_value('CXXFLAGS_PYEMBED', ['-fno-strict-aliasing'])
		env.append_value('CXXFLAGS_PYEXT', ['-fno-strict-aliasing'])

	if env.CC_NAME == "msvc":
		from distutils.msvccompiler import MSVCCompiler
		dist_compiler = MSVCCompiler()
		dist_compiler.initialize()
		env.append_value('CFLAGS_PYEXT', dist_compiler.compile_options)
		env.append_value('CXXFLAGS_PYEXT', dist_compiler.compile_options)
		env.append_value('LINKFLAGS_PYEXT', dist_compiler.ldflags_shared)

	# See if it compiles
	conf.check(header_name='Python.h', define_name='HAVE_PYTHON_H', uselib='PYEMBED', fragment=FRAG, errmsg='Distutils not installed? Broken python installation? Get python-config now!')
Exemple #3
0
def check_python_headers(conf, features='pyembed pyext'):
    features = Utils.to_list(features)
    assert ('pyembed' in features) or (
        'pyext' in features
    ), "check_python_headers features must include 'pyembed' and/or 'pyext'"
    env = conf.env
    if not env['CC_NAME'] and not env['CXX_NAME']:
        conf.fatal('load a compiler first (gcc, g++, ..)')
    if conf.python_cross_compile(features):
        return
    if not env['PYTHON_VERSION']:
        conf.check_python_version()
    pybin = env.PYTHON
    if not pybin:
        conf.fatal('Could not find the python executable')
    v = 'prefix SO LDFLAGS LIBDIR LIBPL INCLUDEPY Py_ENABLE_SHARED MACOSX_DEPLOYMENT_TARGET LDSHARED CFLAGS LDVERSION'.split(
    )
    try:
        lst = conf.get_python_variables(
            ["get_config_var('%s') or ''" % x for x in v])
    except RuntimeError:
        conf.fatal("Python development headers not found (-v for details).")
    vals = ['%s = %r' % (x, y) for (x, y) in zip(v, lst)]
    conf.to_log("Configuration returned from %r:\n%s\n" %
                (pybin, '\n'.join(vals)))
    dct = dict(zip(v, lst))
    x = 'MACOSX_DEPLOYMENT_TARGET'
    if dct[x]:
        env[x] = conf.environ[x] = dct[x]
    env['pyext_PATTERN'] = '%s' + dct['SO']
    num = '.'.join(env['PYTHON_VERSION'].split('.')[:2])
    conf.find_program([
        ''.join(pybin) + '-config',
        'python%s-config' % num,
        'python-config-%s' % num,
        'python%sm-config' % num
    ],
                      var='PYTHON_CONFIG',
                      msg="python-config",
                      mandatory=False)
    if env.PYTHON_CONFIG:
        all_flags = [['--cflags', '--libs', '--ldflags']]
        if sys.hexversion < 0x2070000:
            all_flags = [[k] for k in all_flags[0]]
        xx = env.CXX_NAME and 'cxx' or 'c'
        if 'pyembed' in features:
            for flags in all_flags:
                conf.check_cfg(
                    msg='Asking python-config for pyembed %r flags' %
                    ' '.join(flags),
                    path=env.PYTHON_CONFIG,
                    package='',
                    uselib_store='PYEMBED',
                    args=flags)
            try:
                conf.test_pyembed(xx)
            except conf.errors.ConfigurationError:
                if dct['Py_ENABLE_SHARED'] and dct['LIBDIR']:
                    env.append_unique('LIBPATH_PYEMBED', [dct['LIBDIR']])
                    conf.test_pyembed(xx)
                else:
                    raise
        if 'pyext' in features:
            for flags in all_flags:
                conf.check_cfg(msg='Asking python-config for pyext %r flags' %
                               ' '.join(flags),
                               path=env.PYTHON_CONFIG,
                               package='',
                               uselib_store='PYEXT',
                               args=flags)
            try:
                conf.test_pyext(xx)
            except conf.errors.ConfigurationError:
                if dct['Py_ENABLE_SHARED'] and dct['LIBDIR']:
                    env.append_unique('LIBPATH_PYEXT', [dct['LIBDIR']])
                    conf.test_pyext(xx)
                else:
                    raise
        conf.define('HAVE_PYTHON_H', 1)
        return
    all_flags = dct['LDFLAGS'] + ' ' + dct['CFLAGS']
    conf.parse_flags(all_flags, 'PYEMBED')
    all_flags = dct['LDFLAGS'] + ' ' + dct['LDSHARED'] + ' ' + dct['CFLAGS']
    conf.parse_flags(all_flags, 'PYEXT')
    result = None
    if not dct["LDVERSION"]:
        dct["LDVERSION"] = env['PYTHON_VERSION']
    for name in ('python' + dct['LDVERSION'],
                 'python' + env['PYTHON_VERSION'] + 'm',
                 'python' + env['PYTHON_VERSION'].replace('.', '')):
        if not result and env['LIBPATH_PYEMBED']:
            path = env['LIBPATH_PYEMBED']
            conf.to_log("\n\n# Trying default LIBPATH_PYEMBED: %r\n" % path)
            result = conf.check(
                lib=name,
                uselib='PYEMBED',
                libpath=path,
                mandatory=False,
                msg='Checking for library %s in LIBPATH_PYEMBED' % name)
        if not result and dct['LIBDIR']:
            path = [dct['LIBDIR']]
            conf.to_log("\n\n# try again with -L$python_LIBDIR: %r\n" % path)
            result = conf.check(lib=name,
                                uselib='PYEMBED',
                                libpath=path,
                                mandatory=False,
                                msg='Checking for library %s in LIBDIR' % name)
        if not result and dct['LIBPL']:
            path = [dct['LIBPL']]
            conf.to_log(
                "\n\n# try again with -L$python_LIBPL (some systems don't install the python library in $prefix/lib)\n"
            )
            result = conf.check(lib=name,
                                uselib='PYEMBED',
                                libpath=path,
                                mandatory=False,
                                msg='Checking for library %s in python_LIBPL' %
                                name)
        if not result:
            path = [os.path.join(dct['prefix'], "libs")]
            conf.to_log(
                "\n\n# try again with -L$prefix/libs, and pythonXY name rather than pythonX.Y (win32)\n"
            )
            result = conf.check(lib=name,
                                uselib='PYEMBED',
                                libpath=path,
                                mandatory=False,
                                msg='Checking for library %s in $prefix/libs' %
                                name)
        if result:
            break
    if result:
        env['LIBPATH_PYEMBED'] = path
        env.append_value('LIB_PYEMBED', [name])
    else:
        conf.to_log("\n\n### LIB NOT FOUND\n")
    if Utils.is_win32 or dct['Py_ENABLE_SHARED']:
        env['LIBPATH_PYEXT'] = env['LIBPATH_PYEMBED']
        env['LIB_PYEXT'] = env['LIB_PYEMBED']
    conf.to_log(
        "Include path for Python extensions (found via distutils module): %r\n"
        % (dct['INCLUDEPY'], ))
    env['INCLUDES_PYEXT'] = [dct['INCLUDEPY']]
    env['INCLUDES_PYEMBED'] = [dct['INCLUDEPY']]
    if env['CC_NAME'] == 'gcc':
        env.append_value('CFLAGS_PYEMBED', ['-fno-strict-aliasing'])
        env.append_value('CFLAGS_PYEXT', ['-fno-strict-aliasing'])
    if env['CXX_NAME'] == 'gcc':
        env.append_value('CXXFLAGS_PYEMBED', ['-fno-strict-aliasing'])
        env.append_value('CXXFLAGS_PYEXT', ['-fno-strict-aliasing'])
    if env.CC_NAME == "msvc":
        from distutils.msvccompiler import MSVCCompiler
        dist_compiler = MSVCCompiler()
        dist_compiler.initialize()
        env.append_value('CFLAGS_PYEXT', dist_compiler.compile_options)
        env.append_value('CXXFLAGS_PYEXT', dist_compiler.compile_options)
        env.append_value('LINKFLAGS_PYEXT', dist_compiler.ldflags_shared)
    conf.check(
        header_name='Python.h',
        define_name='HAVE_PYTHON_H',
        uselib='PYEMBED',
        fragment=FRAG,
        errmsg=
        'Distutils not installed? Broken python installation? Get python-config now!'
    )
def check_python_headers(conf, features="pyembed pyext"):
    """
    Check for headers and libraries necessary to extend or embed python by using the module *distutils*.
    On success the environment variables xxx_PYEXT and xxx_PYEMBED are added:

    * PYEXT: for compiling python extensions
    * PYEMBED: for embedding a python interpreter
    """
    features = Utils.to_list(features)
    assert ("pyembed" in features) or (
        "pyext" in features
    ), "check_python_headers features must include 'pyembed' and/or 'pyext'"
    env = conf.env
    if not env.CC_NAME and not env.CXX_NAME:
        conf.fatal("load a compiler first (gcc, g++, ..)")

    # bypass all the code below for cross-compilation
    if conf.python_cross_compile(features):
        return

    if not env.PYTHON_VERSION:
        conf.check_python_version()

    pybin = env.PYTHON
    if not pybin:
        conf.fatal("Could not find the python executable")

    # so we actually do all this for compatibility reasons and for obtaining pyext_PATTERN below
    v = "prefix SO LDFLAGS LIBDIR LIBPL INCLUDEPY Py_ENABLE_SHARED MACOSX_DEPLOYMENT_TARGET LDSHARED CFLAGS LDVERSION".split()
    try:
        lst = conf.get_python_variables(["get_config_var('%s') or ''" % x for x in v])
    except RuntimeError:
        conf.fatal("Python development headers not found (-v for details).")

    vals = [f"{x} = {y!r}" for (x, y) in zip(v, lst)]
    conf.to_log(
        "Configuration returned from {!r}:\n{}\n".format(pybin, "\n".join(vals))
    )

    dct = dict(zip(v, lst))
    x = "MACOSX_DEPLOYMENT_TARGET"
    if dct[x]:
        env[x] = conf.environ[x] = dct[x]
    env.pyext_PATTERN = "%s" + dct["SO"]  # not a mistake

    # Try to get pythonX.Y-config
    num = ".".join(env.PYTHON_VERSION.split(".")[:2])
    conf.find_program(
        [
            "".join(pybin) + "-config",
            "python%s-config" % num,
            "python-config-%s" % num,
            "python%sm-config" % num,
        ],
        var="PYTHON_CONFIG",
        msg="python-config",
        mandatory=False,
    )

    if env.PYTHON_CONFIG:
        # python2.6-config requires 3 runs
        all_flags = [["--cflags", "--libs", "--ldflags"]]
        if sys.hexversion < 0x2070000:
            all_flags = [[k] for k in all_flags[0]]

        xx = env.CXX_NAME and "cxx" or "c"

        if "pyembed" in features:
            for flags in all_flags:
                conf.check_cfg(
                    msg="Asking python-config for pyembed %r flags" % " ".join(flags),
                    path=env.PYTHON_CONFIG,
                    package="",
                    uselib_store="PYEMBED",
                    args=flags,
                )

            try:
                conf.test_pyembed(xx)
            except conf.errors.ConfigurationError:
                # python bug 7352
                if dct["Py_ENABLE_SHARED"] and dct["LIBDIR"]:
                    env.append_unique("LIBPATH_PYEMBED", [dct["LIBDIR"]])
                    conf.test_pyembed(xx)
                else:
                    raise

        if "pyext" in features:
            for flags in all_flags:
                conf.check_cfg(
                    msg="Asking python-config for pyext %r flags" % " ".join(flags),
                    path=env.PYTHON_CONFIG,
                    package="",
                    uselib_store="PYEXT",
                    args=flags,
                )

            try:
                conf.test_pyext(xx)
            except conf.errors.ConfigurationError:
                # python bug 7352
                if dct["Py_ENABLE_SHARED"] and dct["LIBDIR"]:
                    env.append_unique("LIBPATH_PYEXT", [dct["LIBDIR"]])
                    conf.test_pyext(xx)
                else:
                    raise

        conf.define("HAVE_PYTHON_H", 1)
        return

    # No python-config, do something else on windows systems
    all_flags = dct["LDFLAGS"] + " " + dct["CFLAGS"]
    conf.parse_flags(all_flags, "PYEMBED")

    all_flags = dct["LDFLAGS"] + " " + dct["LDSHARED"] + " " + dct["CFLAGS"]
    conf.parse_flags(all_flags, "PYEXT")

    result = None
    if not dct["LDVERSION"]:
        dct["LDVERSION"] = env.PYTHON_VERSION

    # further simplification will be complicated
    for name in (
        "python" + dct["LDVERSION"],
        "python" + env.PYTHON_VERSION + "m",
        "python" + env.PYTHON_VERSION.replace(".", ""),
    ):

        # LIBPATH_PYEMBED is already set; see if it works.
        if not result and env.LIBPATH_PYEMBED:
            path = env.LIBPATH_PYEMBED
            conf.to_log("\n\n# Trying default LIBPATH_PYEMBED: %r\n" % path)
            result = conf.check(
                lib=name,
                uselib="PYEMBED",
                libpath=path,
                mandatory=False,
                msg="Checking for library %s in LIBPATH_PYEMBED" % name,
            )

        if not result and dct["LIBDIR"]:
            path = [dct["LIBDIR"]]
            conf.to_log("\n\n# try again with -L$python_LIBDIR: %r\n" % path)
            result = conf.check(
                lib=name,
                uselib="PYEMBED",
                libpath=path,
                mandatory=False,
                msg="Checking for library %s in LIBDIR" % name,
            )

        if not result and dct["LIBPL"]:
            path = [dct["LIBPL"]]
            conf.to_log(
                "\n\n# try again with -L$python_LIBPL (some systems don't install the python library in $prefix/lib)\n"
            )
            result = conf.check(
                lib=name,
                uselib="PYEMBED",
                libpath=path,
                mandatory=False,
                msg="Checking for library %s in python_LIBPL" % name,
            )

        if not result:
            path = [os.path.join(dct["prefix"], "libs")]
            conf.to_log(
                "\n\n# try again with -L$prefix/libs, and pythonXY name rather than pythonX.Y (win32)\n"
            )
            result = conf.check(
                lib=name,
                uselib="PYEMBED",
                libpath=path,
                mandatory=False,
                msg="Checking for library %s in $prefix/libs" % name,
            )

        if result:
            break  # do not forget to set LIBPATH_PYEMBED

    if result:
        env.LIBPATH_PYEMBED = path
        env.append_value("LIB_PYEMBED", [name])
    else:
        conf.to_log("\n\n### LIB NOT FOUND\n")

    # under certain conditions, python extensions must link to
    # python libraries, not just python embedding programs.
    if Utils.is_win32 or dct["Py_ENABLE_SHARED"]:
        env.LIBPATH_PYEXT = env.LIBPATH_PYEMBED
        env.LIB_PYEXT = env.LIB_PYEMBED

    conf.to_log(
        "Include path for Python extensions (found via distutils module): {!r}\n".format(
            dct["INCLUDEPY"]
        )
    )
    env.INCLUDES_PYEXT = [dct["INCLUDEPY"]]
    env.INCLUDES_PYEMBED = [dct["INCLUDEPY"]]

    # Code using the Python API needs to be compiled with -fno-strict-aliasing
    if env.CC_NAME == "gcc":
        env.append_value("CFLAGS_PYEMBED", ["-fno-strict-aliasing"])
        env.append_value("CFLAGS_PYEXT", ["-fno-strict-aliasing"])
    if env.CXX_NAME == "gcc":
        env.append_value("CXXFLAGS_PYEMBED", ["-fno-strict-aliasing"])
        env.append_value("CXXFLAGS_PYEXT", ["-fno-strict-aliasing"])

    if env.CC_NAME == "msvc":
        from distutils.msvccompiler import MSVCCompiler

        dist_compiler = MSVCCompiler()
        dist_compiler.initialize()
        env.append_value("CFLAGS_PYEXT", dist_compiler.compile_options)
        env.append_value("CXXFLAGS_PYEXT", dist_compiler.compile_options)
        env.append_value("LINKFLAGS_PYEXT", dist_compiler.ldflags_shared)

    # See if it compiles
    conf.check(
        header_name="Python.h",
        define_name="HAVE_PYTHON_H",
        uselib="PYEMBED",
        fragment=FRAG,
        errmsg="Distutils not installed? Broken python installation? Get python-config now!",
    )
Exemple #5
0
def check_python_headers(conf, features="pyembed pyext"):
    """
	Check for headers and libraries necessary to extend or embed python by using the module *distutils*.
	On success the environment variables xxx_PYEXT and xxx_PYEMBED are added:

	* PYEXT: for compiling python extensions
	* PYEMBED: for embedding a python interpreter
	"""
    features = Utils.to_list(features)
    assert ("pyembed" in features) or (
        "pyext" in features
    ), "check_python_headers features must include 'pyembed' and/or 'pyext'"
    env = conf.env
    if not env["CC_NAME"] and not env["CXX_NAME"]:
        conf.fatal("load a compiler first (gcc, g++, ..)")

        # bypass all the code below for cross-compilation
    if conf.python_cross_compile(features):
        return

    if not env["PYTHON_VERSION"]:
        conf.check_python_version()

    pybin = env.PYTHON
    if not pybin:
        conf.fatal("Could not find the python executable")

        # so we actually do all this for compatibility reasons and for obtaining pyext_PATTERN below
    v = "prefix SO LDFLAGS LIBDIR LIBPL INCLUDEPY Py_ENABLE_SHARED MACOSX_DEPLOYMENT_TARGET LDSHARED CFLAGS LDVERSION".split()
    try:
        lst = conf.get_python_variables(["get_config_var('%s') or ''" % x for x in v])
    except RuntimeError:
        conf.fatal("Python development headers not found (-v for details).")

    vals = ["%s = %r" % (x, y) for (x, y) in zip(v, lst)]
    conf.to_log("Configuration returned from %r:\n%s\n" % (pybin, "\n".join(vals)))

    dct = dict(zip(v, lst))
    x = "MACOSX_DEPLOYMENT_TARGET"
    if dct[x]:
        env[x] = conf.environ[x] = dct[x]
    env["pyext_PATTERN"] = "%s" + dct["SO"]  # not a mistake

    # Try to get pythonX.Y-config
    num = ".".join(env["PYTHON_VERSION"].split(".")[:2])
    conf.find_program(
        ["".join(pybin) + "-config", "python%s-config" % num, "python-config-%s" % num, "python%sm-config" % num],
        var="PYTHON_CONFIG",
        msg="python-config",
        mandatory=False,
    )

    if env.PYTHON_CONFIG:
        # python2.6-config requires 3 runs
        all_flags = [["--cflags", "--libs", "--ldflags"]]
        if sys.hexversion < 0x2070000:
            all_flags = [[k] for k in all_flags[0]]

        xx = env.CXX_NAME and "cxx" or "c"

        if "pyembed" in features:
            for flags in all_flags:
                conf.check_cfg(
                    msg="Asking python-config for pyembed %r flags" % " ".join(flags),
                    path=env.PYTHON_CONFIG,
                    package="",
                    uselib_store="PYEMBED",
                    args=flags,
                )

            try:
                conf.test_pyembed(xx)
            except conf.errors.ConfigurationError:
                # python bug 7352
                if dct["Py_ENABLE_SHARED"] and dct["LIBDIR"]:
                    env.append_unique("LIBPATH_PYEMBED", [dct["LIBDIR"]])
                    conf.test_pyembed(xx)
                else:
                    raise

        if "pyext" in features:
            for flags in all_flags:
                conf.check_cfg(
                    msg="Asking python-config for pyext %r flags" % " ".join(flags),
                    path=env.PYTHON_CONFIG,
                    package="",
                    uselib_store="PYEXT",
                    args=flags,
                )

            try:
                conf.test_pyext(xx)
            except conf.errors.ConfigurationError:
                # python bug 7352
                if dct["Py_ENABLE_SHARED"] and dct["LIBDIR"]:
                    env.append_unique("LIBPATH_PYEXT", [dct["LIBDIR"]])
                    conf.test_pyext(xx)
                else:
                    raise

        conf.define("HAVE_PYTHON_H", 1)
        return

        # No python-config, do something else on windows systems
    all_flags = dct["LDFLAGS"] + " " + dct["CFLAGS"]
    conf.parse_flags(all_flags, "PYEMBED")

    all_flags = dct["LDFLAGS"] + " " + dct["LDSHARED"] + " " + dct["CFLAGS"]
    conf.parse_flags(all_flags, "PYEXT")

    result = None
    if not dct["LDVERSION"]:
        dct["LDVERSION"] = env["PYTHON_VERSION"]

        # further simplification will be complicated
    for name in (
        "python" + dct["LDVERSION"],
        "python" + env["PYTHON_VERSION"] + "m",
        "python" + env["PYTHON_VERSION"].replace(".", ""),
    ):

        # LIBPATH_PYEMBED is already set; see if it works.
        if not result and env["LIBPATH_PYEMBED"]:
            path = env["LIBPATH_PYEMBED"]
            conf.to_log("\n\n# Trying default LIBPATH_PYEMBED: %r\n" % path)
            result = conf.check(
                lib=name,
                uselib="PYEMBED",
                libpath=path,
                mandatory=False,
                msg="Checking for library %s in LIBPATH_PYEMBED" % name,
            )

        if not result and dct["LIBDIR"]:
            path = [dct["LIBDIR"]]
            conf.to_log("\n\n# try again with -L$python_LIBDIR: %r\n" % path)
            result = conf.check(
                lib=name,
                uselib="PYEMBED",
                libpath=path,
                mandatory=False,
                msg="Checking for library %s in LIBDIR" % name,
            )

        if not result and dct["LIBPL"]:
            path = [dct["LIBPL"]]
            conf.to_log(
                "\n\n# try again with -L$python_LIBPL (some systems don't install the python library in $prefix/lib)\n"
            )
            result = conf.check(
                lib=name,
                uselib="PYEMBED",
                libpath=path,
                mandatory=False,
                msg="Checking for library %s in python_LIBPL" % name,
            )

        if not result:
            path = [os.path.join(dct["prefix"], "libs")]
            conf.to_log("\n\n# try again with -L$prefix/libs, and pythonXY name rather than pythonX.Y (win32)\n")
            result = conf.check(
                lib=name,
                uselib="PYEMBED",
                libpath=path,
                mandatory=False,
                msg="Checking for library %s in $prefix/libs" % name,
            )

        if result:
            break  # do not forget to set LIBPATH_PYEMBED

    if result:
        env["LIBPATH_PYEMBED"] = path
        env.append_value("LIB_PYEMBED", [name])
    else:
        conf.to_log("\n\n### LIB NOT FOUND\n")

        # under certain conditions, python extensions must link to
        # python libraries, not just python embedding programs.
    if Utils.is_win32 or dct["Py_ENABLE_SHARED"]:
        env["LIBPATH_PYEXT"] = env["LIBPATH_PYEMBED"]
        env["LIB_PYEXT"] = env["LIB_PYEMBED"]

    conf.to_log("Include path for Python extensions (found via distutils module): %r\n" % (dct["INCLUDEPY"],))
    env["INCLUDES_PYEXT"] = [dct["INCLUDEPY"]]
    env["INCLUDES_PYEMBED"] = [dct["INCLUDEPY"]]

    # Code using the Python API needs to be compiled with -fno-strict-aliasing
    if env["CC_NAME"] == "gcc":
        env.append_value("CFLAGS_PYEMBED", ["-fno-strict-aliasing"])
        env.append_value("CFLAGS_PYEXT", ["-fno-strict-aliasing"])
    if env["CXX_NAME"] == "gcc":
        env.append_value("CXXFLAGS_PYEMBED", ["-fno-strict-aliasing"])
        env.append_value("CXXFLAGS_PYEXT", ["-fno-strict-aliasing"])

    if env.CC_NAME == "msvc":
        from distutils.msvccompiler import MSVCCompiler

        dist_compiler = MSVCCompiler()
        dist_compiler.initialize()
        env.append_value("CFLAGS_PYEXT", dist_compiler.compile_options)
        env.append_value("CXXFLAGS_PYEXT", dist_compiler.compile_options)
        env.append_value("LINKFLAGS_PYEXT", dist_compiler.ldflags_shared)

        # See if it compiles
    conf.check(
        header_name="Python.h",
        define_name="HAVE_PYTHON_H",
        uselib="PYEMBED",
        fragment=FRAG,
        errmsg="Distutils not installed? Broken python installation? Get python-config now!",
    )
Exemple #6
0
def check_python_headers(conf,features='pyembed pyext'):
	features=Utils.to_list(features)
	assert('pyembed'in features)or('pyext'in features),"check_python_headers features must include 'pyembed' and/or 'pyext'"
	env=conf.env
	if not env['CC_NAME']and not env['CXX_NAME']:
		conf.fatal('load a compiler first (gcc, g++, ..)')
	if conf.python_cross_compile(features):
		return
	if not env['PYTHON_VERSION']:
		conf.check_python_version()
	pybin=env.PYTHON
	if not pybin:
		conf.fatal('Could not find the python executable')
	v='prefix SO LDFLAGS LIBDIR LIBPL INCLUDEPY Py_ENABLE_SHARED MACOSX_DEPLOYMENT_TARGET LDSHARED CFLAGS LDVERSION'.split()
	try:
		lst=conf.get_python_variables(["get_config_var('%s') or ''"%x for x in v])
	except RuntimeError:
		conf.fatal("Python development headers not found (-v for details).")
	vals=['%s = %r'%(x,y)for(x,y)in zip(v,lst)]
	conf.to_log("Configuration returned from %r:\n%s\n"%(pybin,'\n'.join(vals)))
	dct=dict(zip(v,lst))
	x='MACOSX_DEPLOYMENT_TARGET'
	if dct[x]:
		env[x]=conf.environ[x]=dct[x]
	env['pyext_PATTERN']='%s'+dct['SO']
	num='.'.join(env['PYTHON_VERSION'].split('.')[:2])
	conf.find_program([''.join(pybin)+'-config','python%s-config'%num,'python-config-%s'%num,'python%sm-config'%num],var='PYTHON_CONFIG',msg="python-config",mandatory=False)
	if env.PYTHON_CONFIG:
		all_flags=[['--cflags','--libs','--ldflags']]
		if sys.hexversion<0x2070000:
			all_flags=[[k]for k in all_flags[0]]
		xx=env.CXX_NAME and'cxx'or'c'
		if'pyembed'in features:
			for flags in all_flags:
				conf.check_cfg(msg='Asking python-config for pyembed %r flags'%' '.join(flags),path=env.PYTHON_CONFIG,package='',uselib_store='PYEMBED',args=flags)
			try:
				conf.test_pyembed(xx)
			except conf.errors.ConfigurationError:
				if dct['Py_ENABLE_SHARED']and dct['LIBDIR']:
					env.append_unique('LIBPATH_PYEMBED',[dct['LIBDIR']])
					conf.test_pyembed(xx)
				else:
					raise
		if'pyext'in features:
			for flags in all_flags:
				conf.check_cfg(msg='Asking python-config for pyext %r flags'%' '.join(flags),path=env.PYTHON_CONFIG,package='',uselib_store='PYEXT',args=flags)
			try:
				conf.test_pyext(xx)
			except conf.errors.ConfigurationError:
				if dct['Py_ENABLE_SHARED']and dct['LIBDIR']:
					env.append_unique('LIBPATH_PYEXT',[dct['LIBDIR']])
					conf.test_pyext(xx)
				else:
					raise
		conf.define('HAVE_PYTHON_H',1)
		return
	all_flags=dct['LDFLAGS']+' '+dct['CFLAGS']
	conf.parse_flags(all_flags,'PYEMBED')
	all_flags=dct['LDFLAGS']+' '+dct['LDSHARED']+' '+dct['CFLAGS']
	conf.parse_flags(all_flags,'PYEXT')
	result=None
	if not dct["LDVERSION"]:
		dct["LDVERSION"]=env['PYTHON_VERSION']
	for name in('python'+dct['LDVERSION'],'python'+env['PYTHON_VERSION']+'m','python'+env['PYTHON_VERSION'].replace('.','')):
		if not result and env['LIBPATH_PYEMBED']:
			path=env['LIBPATH_PYEMBED']
			conf.to_log("\n\n# Trying default LIBPATH_PYEMBED: %r\n"%path)
			result=conf.check(lib=name,uselib='PYEMBED',libpath=path,mandatory=False,msg='Checking for library %s in LIBPATH_PYEMBED'%name)
		if not result and dct['LIBDIR']:
			path=[dct['LIBDIR']]
			conf.to_log("\n\n# try again with -L$python_LIBDIR: %r\n"%path)
			result=conf.check(lib=name,uselib='PYEMBED',libpath=path,mandatory=False,msg='Checking for library %s in LIBDIR'%name)
		if not result and dct['LIBPL']:
			path=[dct['LIBPL']]
			conf.to_log("\n\n# try again with -L$python_LIBPL (some systems don't install the python library in $prefix/lib)\n")
			result=conf.check(lib=name,uselib='PYEMBED',libpath=path,mandatory=False,msg='Checking for library %s in python_LIBPL'%name)
		if not result:
			path=[os.path.join(dct['prefix'],"libs")]
			conf.to_log("\n\n# try again with -L$prefix/libs, and pythonXY name rather than pythonX.Y (win32)\n")
			result=conf.check(lib=name,uselib='PYEMBED',libpath=path,mandatory=False,msg='Checking for library %s in $prefix/libs'%name)
		if result:
			break
	if result:
		env['LIBPATH_PYEMBED']=path
		env.append_value('LIB_PYEMBED',[name])
	else:
		conf.to_log("\n\n### LIB NOT FOUND\n")
	if Utils.is_win32 or dct['Py_ENABLE_SHARED']:
		env['LIBPATH_PYEXT']=env['LIBPATH_PYEMBED']
		env['LIB_PYEXT']=env['LIB_PYEMBED']
	conf.to_log("Include path for Python extensions (found via distutils module): %r\n"%(dct['INCLUDEPY'],))
	env['INCLUDES_PYEXT']=[dct['INCLUDEPY']]
	env['INCLUDES_PYEMBED']=[dct['INCLUDEPY']]
	if env['CC_NAME']=='gcc':
		env.append_value('CFLAGS_PYEMBED',['-fno-strict-aliasing'])
		env.append_value('CFLAGS_PYEXT',['-fno-strict-aliasing'])
	if env['CXX_NAME']=='gcc':
		env.append_value('CXXFLAGS_PYEMBED',['-fno-strict-aliasing'])
		env.append_value('CXXFLAGS_PYEXT',['-fno-strict-aliasing'])
	if env.CC_NAME=="msvc":
		from distutils.msvccompiler import MSVCCompiler
		dist_compiler=MSVCCompiler()
		dist_compiler.initialize()
		env.append_value('CFLAGS_PYEXT',dist_compiler.compile_options)
		env.append_value('CXXFLAGS_PYEXT',dist_compiler.compile_options)
		env.append_value('LINKFLAGS_PYEXT',dist_compiler.ldflags_shared)
	conf.check(header_name='Python.h',define_name='HAVE_PYTHON_H',uselib='PYEMBED',fragment=FRAG,errmsg='Distutils not installed? Broken python installation? Get python-config now!')