pytalloc patches

Petr Viktorin pviktori at redhat.com
Fri Apr 24 10:58:57 MDT 2015


On 04/24/2015 02:37 AM, Jelmer Vernooij wrote:
> On Thu, Apr 23, 2015 at 08:08:29AM +0200, Andreas Schneider wrote:
>> On Wednesday 22 April 2015 13:33:00 Petr Viktorin wrote:
>>> Anything I can do to help hove this forward?
>>
>> Attached is the patchset with my RB+. One patch is missing Jelmer his RB. 
>> Jelmer please check and push.
> Thanks, pushed.


Thank you both for your time!

The rest of the patches need a slight rebase, so I'm including them here.

-- 
Petr Viktorin

-------------- next part --------------
From 1fb68ffd353e2bba1f3b70d6e30b41603fd61900 Mon Sep 17 00:00:00 2001
From: Petr Viktorin <pviktori at redhat.com>
Date: Fri, 16 Jan 2015 13:02:37 +0100
Subject: [PATCH 01/10] buildtools: Use 'pyfeature' instead of pyembed and
 pyext arguments

This will allow defining other Python-related features, which will be
passed through the stack the same way as the existing two.

Signed-off-by: Petr Viktorin <pviktori at redhat.com>
---
 buildtools/wafsamba/samba_python.py |  2 +-
 buildtools/wafsamba/wafsamba.py     | 37 +++++++++++++++++--------------------
 lib/ldb/wscript                     |  2 +-
 lib/talloc/wscript                  |  2 +-
 python/wscript_build                |  4 ++--
 source4/lib/policy/wscript_build    |  2 +-
 source4/librpc/wscript_build        |  2 +-
 source4/param/wscript_build         |  4 ++--
 source4/smbd/wscript_build          |  2 +-
 source4/torture/wscript_build       |  2 +-
 source4/utils/wscript_build         |  2 +-
 source4/web_server/wscript_build    |  4 ++--
 testsuite/headers/wscript_build     |  2 +-
 13 files changed, 32 insertions(+), 35 deletions(-)

diff --git a/buildtools/wafsamba/samba_python.py b/buildtools/wafsamba/samba_python.py
index a371b43..f53ac90 100644
--- a/buildtools/wafsamba/samba_python.py
+++ b/buildtools/wafsamba/samba_python.py
@@ -60,7 +60,7 @@ def SAMBA_PYTHON(bld, name,
                       vars=vars,
                       realname=realname,
                       link_name=link_name,
-                      pyext=True,
+                      pyfeature='pyext',
                       target_type='PYTHON',
                       install_path='${PYTHONARCHDIR}',
                       allow_undefined_symbols=True,
diff --git a/buildtools/wafsamba/wafsamba.py b/buildtools/wafsamba/wafsamba.py
index d7e482c..07fc2ac 100644
--- a/buildtools/wafsamba/wafsamba.py
+++ b/buildtools/wafsamba/wafsamba.py
@@ -126,8 +126,7 @@ def SAMBA_LIBRARY(bld, libname, source,
                   subdir=None,
                   install_path=None,
                   install=True,
-                  pyembed=False,
-                  pyext=False,
+                  pyfeature=None,
                   target_type='LIBRARY',
                   bundled_extension=False,
                   bundled_name=None,
@@ -193,8 +192,7 @@ def SAMBA_LIBRARY(bld, libname, source,
                         depends_on     = depends_on,
                         hide_symbols   = hide_symbols,
                         allow_warnings = allow_warnings,
-                        pyembed        = pyembed,
-                        pyext          = pyext,
+                        pyfeature      = pyfeature,
                         local_include  = local_include,
                         global_include = global_include)
 
@@ -241,10 +239,8 @@ def SAMBA_LIBRARY(bld, libname, source,
     ldflags = TO_LIST(ldflags)
 
     features = 'cc cshlib symlink_lib install_lib'
-    if pyext:
-        features += ' pyext'
-    if pyembed:
-        features += ' pyembed'
+    if pyfeature:
+        features += ' ' + pyfeature
 
     if abi_directory:
         features += ' abi_check'
@@ -336,7 +332,7 @@ def SAMBA_BINARY(bld, binname, source,
                  local_include=True,
                  global_include=True,
                  subsystem_name=None,
-                 pyembed=False,
+                 pyfeature=None,
                  vars=None,
                  subdir=None,
                  install=True,
@@ -352,8 +348,8 @@ def SAMBA_BINARY(bld, binname, source,
         return
 
     features = 'cc cprogram symlink_bin install_bin'
-    if pyembed:
-        features += ' pyembed'
+    if pyfeature:
+        features += ' ' + pyfeature
 
     obj_target = binname + '.objlist'
 
@@ -379,6 +375,10 @@ def SAMBA_BINARY(bld, binname, source,
     # first create a target for building the object files for this binary
     # by separating in this way, we avoid recompiling the C files
     # separately for the install binary and the build binary
+    if pyfeature == 'pyembed':
+        subsystem_pyfeature = 'pyext'
+    else:
+        subsystem_pyfeature = None
     bld.SAMBA_SUBSYSTEM(obj_target,
                         source         = source,
                         deps           = deps,
@@ -390,7 +390,7 @@ def SAMBA_BINARY(bld, binname, source,
                         local_include  = local_include,
                         global_include = global_include,
                         use_hostcc     = use_hostcc,
-                        pyext          = pyembed,
+                        pyfeature      = subsystem_pyfeature,
                         use_global_deps= use_global_deps)
 
     bld.SET_BUILD_GROUP(group)
@@ -438,7 +438,7 @@ def SAMBA_MODULE(bld, modname, source,
                  vars=None,
                  subdir=None,
                  enabled=True,
-                 pyembed=False,
+                 pyfeature=None,
                  manpages=None,
                  allow_undefined_symbols=False,
                  allow_warnings=False
@@ -508,7 +508,7 @@ def SAMBA_MODULE(bld, modname, source,
                       bundled_name=build_name,
                       link_name=build_link_name,
                       install_path="${MODULESDIR}/%s" % subsystem,
-                      pyembed=pyembed,
+                      pyfeature=pyfeature,
                       manpages=manpages,
                       allow_undefined_symbols=allow_undefined_symbols,
                       allow_warnings=allow_warnings
@@ -544,8 +544,7 @@ def SAMBA_SUBSYSTEM(bld, modname, source,
                     subdir=None,
                     hide_symbols=False,
                     allow_warnings=False,
-                    pyext=False,
-                    pyembed=False):
+                    pyfeature=None):
     '''define a Samba subsystem'''
 
     if not enabled:
@@ -576,10 +575,8 @@ def SAMBA_SUBSYSTEM(bld, modname, source,
     bld.SET_BUILD_GROUP(group)
 
     features = 'cc'
-    if pyext:
-        features += ' pyext'
-    if pyembed:
-        features += ' pyembed'
+    if pyfeature:
+        features += ' ' + pyfeature
 
     t = bld(
         features       = features,
diff --git a/lib/ldb/wscript b/lib/ldb/wscript
index 65a6843..d02ad87 100755
--- a/lib/ldb/wscript
+++ b/lib/ldb/wscript
@@ -129,7 +129,7 @@ def build(bld):
                           vnum=VERSION,
                           private_library=private_library,
                           pc_files='pyldb-util.pc',
-                          pyembed=True,
+                          pyfeature='pyembed',
                           abi_directory='ABI',
                           abi_match='pyldb_*')
 
diff --git a/lib/talloc/wscript b/lib/talloc/wscript
index 1367988..d449609 100644
--- a/lib/talloc/wscript
+++ b/lib/talloc/wscript
@@ -121,7 +121,7 @@ def build(bld):
         bld.SAMBA_LIBRARY('pytalloc-util',
             source='pytalloc_util.c',
             public_deps='talloc',
-            pyembed=True,
+            pyfeature='pyembed',
             vnum=VERSION,
             hide_symbols=True,
             abi_directory='ABI',
diff --git a/python/wscript_build b/python/wscript_build
index a40b583..56d671e 100644
--- a/python/wscript_build
+++ b/python/wscript_build
@@ -5,14 +5,14 @@ bld.SAMBA_LIBRARY('samba_python',
 	deps='LIBPYTHON pytalloc-util pyrpc_util',
 	grouping_library=True,
 	private_library=True,
-	pyembed=True)
+	pyfeature='pyembed')
 
 bld.SAMBA_SUBSYSTEM('LIBPYTHON',
 	source='modules.c',
 	public_deps='',
 	init_function_sentinel='{NULL,NULL}',
 	deps='talloc',
-	pyext=True,
+	pyfeature='pyext',
 	)
 
 
diff --git a/source4/lib/policy/wscript_build b/source4/lib/policy/wscript_build
index b8ba638..8d5ea59 100644
--- a/source4/lib/policy/wscript_build
+++ b/source4/lib/policy/wscript_build
@@ -5,7 +5,7 @@ bld.SAMBA_LIBRARY('samba-policy',
 	pc_files='samba-policy.pc',
 	public_deps='ldb samba-net',
 	vnum='0.0.1',
-	pyembed=True,
+	pyfeature='pyembed',
 	public_headers='policy.h'
 	)
 
diff --git a/source4/librpc/wscript_build b/source4/librpc/wscript_build
index 781611e..dbb420a 100755
--- a/source4/librpc/wscript_build
+++ b/source4/librpc/wscript_build
@@ -143,7 +143,7 @@ bld.SAMBA_LIBRARY('dcerpc',
 bld.SAMBA_SUBSYSTEM('pyrpc_util',
 	source='rpc/pyrpc_util.c',
 	public_deps='pytalloc-util pyparam_util dcerpc MESSAGING',
-	pyext=True,
+	pyfeature='pyext',
 	)
 
 
diff --git a/source4/param/wscript_build b/source4/param/wscript_build
index 4585a83..87f2eee 100644
--- a/source4/param/wscript_build
+++ b/source4/param/wscript_build
@@ -3,7 +3,7 @@
 bld.SAMBA_SUBSYSTEM('PROVISION',
 	source='provision.c pyparam.c',
 	deps='LIBPYTHON pyparam_util ldb pytalloc-util pyldb-util',
-	pyext=True,
+	pyfeature='pyext',
 	)
 
 
@@ -50,7 +50,7 @@ bld.SAMBA_SUBSYSTEM('param_options',
 bld.SAMBA_SUBSYSTEM('pyparam_util',
 	source='pyparam_util.c',
 	deps='LIBPYTHON samba-hostconfig',
-	pyext=True,
+	pyfeature='pyext',
 	)
 
 bld.SAMBA_LIBRARY('shares',
diff --git a/source4/smbd/wscript_build b/source4/smbd/wscript_build
index 12d842b..2ae9f9b 100644
--- a/source4/smbd/wscript_build
+++ b/source4/smbd/wscript_build
@@ -22,7 +22,7 @@ bld.SAMBA_BINARY('samba',
 	subsystem_name='service',
 	deps='''events process_model service samba-hostconfig samba-util POPT_SAMBA
                 popt gensec registry ntptr ntvfs share cluster COMMON_SCHANNEL SECRETS''',
-	pyembed=True,
+	pyfeature='pyembed',
 	install_path='${SBINDIR}',
 	enabled=bld.AD_DC_BUILD_IS_ENABLED()
 	)
diff --git a/source4/torture/wscript_build b/source4/torture/wscript_build
index b80e827..55e2bb6 100755
--- a/source4/torture/wscript_build
+++ b/source4/torture/wscript_build
@@ -169,7 +169,7 @@ bld.SAMBA_BINARY('smbtorture',
                  manpages='man/smbtorture.1',
                  public_headers='smbtorture.h',
                  deps='torturemain torture popt POPT_SAMBA POPT_CREDENTIALS dcerpc LIBCLI_SMB SMBREADLINE ' + TORTURE_MODULES,
-                 pyembed=True
+                 pyfeature='pyembed',
                  )
 
 bld.SAMBA_BINARY('gentest',
diff --git a/source4/utils/wscript_build b/source4/utils/wscript_build
index 046e237..cd12da3 100644
--- a/source4/utils/wscript_build
+++ b/source4/utils/wscript_build
@@ -6,7 +6,7 @@ bld.SAMBA_BINARY('ntlm_auth4',
                  deps='''samba-hostconfig samba-util popt
                  POPT_SAMBA POPT_CREDENTIALS gensec LIBCLI_RESOLVE
                  auth4 NTLMSSP_COMMON MESSAGING events service''',
-                 pyembed=True,
+                 pyfeature='pyembed',
                  install=False
 	)
 
diff --git a/source4/web_server/wscript_build b/source4/web_server/wscript_build
index b845067..1c44785 100644
--- a/source4/web_server/wscript_build
+++ b/source4/web_server/wscript_build
@@ -3,7 +3,7 @@
 
 bld.SAMBA_SUBSYSTEM('WEB_WSGI',
 		source='wsgi.c',
-		pyext=True,
+		pyfeature='pyext',
 		deps='talloc LIBTSOCKET',
 		enabled=bld.AD_DC_BUILD_IS_ENABLED()
 		)
@@ -14,7 +14,7 @@ bld.SAMBA_MODULE('service_web',
 		subsystem='service',
 		init_function='server_service_web_init',
 		deps='LIBTLS process_model LIBPYTHON WEB_WSGI',
-		pyembed=True,
+		pyfeature='pyembed',
 		internal_module=False,
 		enabled=bld.AD_DC_BUILD_IS_ENABLED()
 		)
diff --git a/testsuite/headers/wscript_build b/testsuite/headers/wscript_build
index f612ad9..f201b05 100644
--- a/testsuite/headers/wscript_build
+++ b/testsuite/headers/wscript_build
@@ -41,7 +41,7 @@ if bld.env.DEVELOPER_MODE:
     bld.SAMBA_BINARY('test_headers',
                      source='test_headers.c',
                      includes="#include/public",
-                     pyembed=True,
+                     pyfeature='pyembed',
                      cflags=cflags,
                      local_include=True,
                      global_include=False,
-- 
2.1.0


From 85e002498d29f61bdfb4f0141aa953960c919fb1 Mon Sep 17 00:00:00 2001
From: Petr Viktorin <pviktori at redhat.com>
Date: Thu, 15 Jan 2015 14:22:22 +0100
Subject: [PATCH 02/10] buildtools: Add --extra-python configure option

This will allow building Python support for two different Python versions
at the same time.

Signed-off-by: Petr Viktorin <pviktori at redhat.com>
---
 buildtools/wafsamba/samba_python.py | 4 ++++
 buildtools/wafsamba/wscript         | 8 ++++++++
 2 files changed, 12 insertions(+)

diff --git a/buildtools/wafsamba/samba_python.py b/buildtools/wafsamba/samba_python.py
index f53ac90..831a5a7 100644
--- a/buildtools/wafsamba/samba_python.py
+++ b/buildtools/wafsamba/samba_python.py
@@ -20,6 +20,10 @@ def SAMBA_CHECK_PYTHON_HEADERS(conf, mandatory=True):
     if conf.env["python_headers_checked"] == []:
         conf.check_python_headers(mandatory)
         conf.env["python_headers_checked"] = "yes"
+
+        if conf.env['EXTRAPYTHON_VERSION'] == conf.env['PYTHON_VERSION']:
+            raise Utils.WafError("extrapython %s is same as main python %s" % (
+                conf.env['EXTRAPYTHON_VERSION'], conf.env['PYTHON_VERSION']))
     else:
         conf.msg("python headers", "using cache")
 
diff --git a/buildtools/wafsamba/wscript b/buildtools/wafsamba/wscript
index 694147e..d6bb688 100755
--- a/buildtools/wafsamba/wscript
+++ b/buildtools/wafsamba/wscript
@@ -195,6 +195,12 @@ def set_options(opt):
                    help='tag release in git at the same time',
                    type='string', action='store', dest='TAG_RELEASE')
 
+    opt.add_option('--extra-python', type=str,
+                    help=("build selected libraries for the specified "
+                          "additional version of Python "
+                          "(example: --extra-python=/usr/bin/python3)"),
+                    metavar="PYTHON", dest='EXTRA_PYTHON', default=None)
+
 
 @wafsamba.runonce
 def configure(conf):
@@ -266,6 +272,8 @@ def configure(conf):
     conf.env.AUTOCONF_HOST  = Options.options.AUTOCONF_HOST
     conf.env.AUTOCONF_PROGRAM_PREFIX = Options.options.AUTOCONF_PROGRAM_PREFIX
 
+    conf.env.EXTRA_PYTHON = Options.options.EXTRA_PYTHON
+
     if (conf.env.AUTOCONF_HOST and
         conf.env.AUTOCONF_BUILD and
         conf.env.AUTOCONF_BUILD != conf.env.AUTOCONF_HOST):
-- 
2.1.0


From b384083559f5b8c070e54f4904a5a0b507f9afc6 Mon Sep 17 00:00:00 2001
From: Petr Viktorin <pviktori at redhat.com>
Date: Thu, 15 Jan 2015 17:25:07 +0100
Subject: [PATCH 03/10] buildtools: Store separate configuration for extra
 python

For extrapython, we store config in a separate set of env variables.
During the configure step we swap these with the normal *PYTHON* equivalents,
use waf's regular Python tool, and then switch them all back.

Signed-off-by: Petr Viktorin <pviktori at redhat.com>
---
 buildtools/wafsamba/samba_python.py | 88 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 87 insertions(+), 1 deletion(-)

diff --git a/buildtools/wafsamba/samba_python.py b/buildtools/wafsamba/samba_python.py
index 831a5a7..15ebf93 100644
--- a/buildtools/wafsamba/samba_python.py
+++ b/buildtools/wafsamba/samba_python.py
@@ -1,23 +1,109 @@
-# waf build tool for building IDL files with pidl
+import contextlib
 
 import Build
 from samba_utils import *
 from samba_autoconf import *
+from Logs import warn
 
 from Configure import conf
 
+# For extrapython, we store config in a separate set of env variables.
+# During the configure step we swap these with the normal *PYTHON* equivalents,
+# use waf's regular Python tool, and then switch them all back.
+EXTRAPYTHON_ENV_KEYS = (
+    ('PYTHON', 'EXTRAPYTHON'),
+    ('PYTHONDIR', 'EXTRAPYTHONDIR'),
+    ('PYTHONARCHDIR', 'EXTRAPYTHONARCHDIR'),
+    ('PYTHON_VERSION', 'EXTRAPYTHON_VERSION'),
+
+    ('CCFLAGS_PYEXT', 'CCFLAGS_EXTRAPYEXT'),
+    ('CCFLAGS_PYEMBED', 'CCFLAGS_EXTRAPYEMBED'),
+
+    ('LIBPATH_PYEXT', 'LIBPATH_EXTRAPYEXT'),
+    ('LIBPATH_PYEMBED', 'LIBPATH_EXTRAPYEMBED'),
+
+    ('LIB_PYEXT', 'LIB_EXTRAPYEXT'),
+    ('LIB_PYEMBED', 'LIB_EXTRAPYEMBED'),
+
+    ('CPPPATH_PYEXT', 'CPPPATH_EXTRAPYEXT'),
+    ('CPPPATH_PYEMBED', 'CPPPATH_EXTRAPYEMBED'),
+
+    ('LINKFLAGS_PYEXT', 'LINKFLAGS_EXTRAPYEXT'),
+    ('LINKFLAGS_PYEMBED', 'LINKFLAGS_EXTRAPYEMBED'),
+
+    ('HAVE_PYTHON_H', 'EXTRAPY_HAVE_PYTHON_H'),
+
+    ('PYTHON_CONFIG', 'EXTRAPYTHON_CONFIG'),
+
+    ('pyext_PATTERN', 'extrapyext_PATTERN'),
+    ('PYCMD', 'EXTRAPYCMD'),
+    ('PYFLAGS', 'EXTRAPYFLAGS'),
+    ('PYFLAGS_OPT', 'EXTRAPYFLAGS_OPT'),
+)
+EXTRAPYTHON_DEFINES_KEYS = (
+    ('PYTHONDIR', 'EXTRAPYTHONDIR'),
+    ('PYTHONARCHDIR', 'EXTRAPYTHONARCHDIR'),
+    ('HAVE_PYTHON_H', 'EXTRAPY_HAVE_PYTHON_H'),
+)
+
+
+ at contextlib.contextmanager
+def extrapython_map(env, keys):
+    saved = {}
+    for key, extrakey in keys:
+        if key in env:
+            saved[key] = env[key]
+        if extrakey in env:
+            env[key] = env[extrakey]
+        else:
+            env.pop(key, None)
+    yield
+    for key, extrakey in keys:
+        if key in env:
+            env[extrakey] = env[key]
+        else:
+            env.pop(extrakey, None)
+        if key in saved:
+            env[key] = saved[key]
+        else:
+            env.pop(key, None)
+
+
+ at contextlib.contextmanager
+def extrapython_env(env):
+    with extrapython_map(env, EXTRAPYTHON_ENV_KEYS):
+        with extrapython_map(env['defines'], EXTRAPYTHON_DEFINES_KEYS):
+            yield
+
+
 @conf
 def SAMBA_CHECK_PYTHON(conf, mandatory=True, version=(2,4,2)):
     # enable tool to build python extensions
+    if conf.env['EXTRA_PYTHON']:
+        with extrapython_env(conf.env):
+            conf.env['PYTHON'] = conf.env['EXTRA_PYTHON']
+            conf.find_program('python', var='PYTHON', mandatory=True)
+            conf.check_tool('python')
+            try:
+                conf.check_python_version((3, 3, 0))
+            except Exception:
+                warn('extra-python needs to be Python 3.3 or later')
+                raise
+
     conf.find_program('python', var='PYTHON', mandatory=mandatory)
     conf.check_tool('python')
     path_python = conf.find_program('python')
     conf.env.PYTHON_SPECIFIED = (conf.env.PYTHON != path_python)
     conf.check_python_version(version)
 
+
 @conf
 def SAMBA_CHECK_PYTHON_HEADERS(conf, mandatory=True):
     if conf.env["python_headers_checked"] == []:
+        pre_dict = conf.env.get_merged_dict()
+        if conf.env['EXTRA_PYTHON']:
+            with extrapython_env(conf.env):
+                conf.check_python_headers(mandatory=True)
         conf.check_python_headers(mandatory)
         conf.env["python_headers_checked"] = "yes"
 
-- 
2.1.0


From d79e954b7813a25bc7299e6d698d58b7888c1998 Mon Sep 17 00:00:00 2001
From: Petr Viktorin <pviktori at redhat.com>
Date: Fri, 16 Jan 2015 14:52:26 +0100
Subject: [PATCH 04/10] buildtools: Add features and type for extra-python
 support

This allows support for an additional version of Python to be built.
Two additional features (extrapyext & extrapyembed), and a target type
(EXTRAPYTHON) are added.
They work the same way as the "non-extra" variants, but use configuration
specific to the extra-python version.

Signed-off-by: Petr Viktorin <pviktori at redhat.com>
---
 buildtools/wafsamba/samba_deps.py    | 28 +++++++++++-----------
 buildtools/wafsamba/samba_install.py |  8 ++++---
 buildtools/wafsamba/samba_python.py  | 45 ++++++++++++++++++++++++++++++++----
 buildtools/wafsamba/samba_utils.py   | 17 +++++++++-----
 buildtools/wafsamba/stale_files.py   |  2 ++
 buildtools/wafsamba/symbols.py       | 19 +++++++++++----
 buildtools/wafsamba/wafsamba.py      | 11 +++++----
 7 files changed, 95 insertions(+), 35 deletions(-)

diff --git a/buildtools/wafsamba/samba_deps.py b/buildtools/wafsamba/samba_deps.py
index 3be9956..6948d65 100644
--- a/buildtools/wafsamba/samba_deps.py
+++ b/buildtools/wafsamba/samba_deps.py
@@ -72,7 +72,7 @@ def build_dependencies(self):
     the full dependency list for a target until we have all of the targets declared.
     '''
 
-    if self.samba_type in ['LIBRARY', 'BINARY', 'PYTHON']:
+    if self.samba_type in ['LIBRARY', 'BINARY', 'PYTHON', 'EXTRAPYTHON']:
         self.uselib        = list(self.final_syslibs)
         self.uselib_local  = list(self.final_libs)
         self.add_objects   = list(self.final_objects)
@@ -279,7 +279,7 @@ def check_duplicate_sources(bld, tgt_list):
     # build a list of targets that each source file is part of
     for t in tgt_list:
         sources = []
-        if not targets[t.sname] in [ 'LIBRARY', 'BINARY', 'PYTHON' ]:
+        if not targets[t.sname] in [ 'LIBRARY', 'BINARY', 'PYTHON', 'EXTRAPYTHON' ]:
             continue
         for obj in t.add_objects:
             t2 = t.bld.name_to_obj(obj, bld.env)
@@ -312,7 +312,7 @@ def check_orphaned_targets(bld, tgt_list):
         if getattr(t, 'samba_used', False):
             continue
         type = target_dict[t.sname]
-        if not type in ['BINARY', 'LIBRARY', 'MODULE', 'ET', 'PYTHON']:
+        if not type in ['BINARY', 'LIBRARY', 'MODULE', 'ET', 'PYTHON', 'EXTRAPYTHON']:
             if re.search('^PIDL_', t.sname) is None:
                 Logs.warn("Target %s of type %s is unused by any other target" % (t.sname, type))
 
@@ -366,7 +366,7 @@ def show_final_deps(bld, tgt_list):
     targets = LOCAL_CACHE(bld, 'TARGET_TYPE')
 
     for t in tgt_list:
-        if not targets[t.sname] in ['LIBRARY', 'BINARY', 'PYTHON', 'SUBSYSTEM']:
+        if not targets[t.sname] in ['LIBRARY', 'BINARY', 'PYTHON', 'EXTRAPYTHON', 'SUBSYSTEM']:
             continue
         debug('deps: final dependencies for target %s: uselib=%s uselib_local=%s add_objects=%s',
               t.sname, t.uselib, getattr(t, 'uselib_local', []), getattr(t, 'add_objects', []))
@@ -449,7 +449,9 @@ def build_direct_deps(bld, tgt_list):
                 sys.exit(1)
             if targets[d] in [ 'EMPTY', 'DISABLED' ]:
                 continue
-            if targets[d] == 'PYTHON' and targets[t.sname] != 'PYTHON' and t.sname.find('.objlist') == -1:
+            if (targets[d] in ('PYTHON', 'EXTRAPYTHON') and
+                    targets[t.sname] not in ('PYTHON', 'EXTRAPYTHON') and
+                    t.sname.find('.objlist') == -1):
                 # this check should be more restrictive, but for now we have pidl-generated python
                 # code that directly depends on other python modules
                 Logs.error('ERROR: Target %s has dependency on python module %s' % (t.sname, d))
@@ -475,7 +477,7 @@ def build_direct_deps(bld, tgt_list):
                 sys.exit(1)
             if t2.samba_type in [ 'LIBRARY', 'MODULE' ]:
                 t.direct_libs.add(d)
-            elif t2.samba_type in [ 'SUBSYSTEM', 'ASN1', 'PYTHON' ]:
+            elif t2.samba_type in [ 'SUBSYSTEM', 'ASN1', 'PYTHON', 'EXTRAPYTHON' ]:
                 t.direct_objects.add(d)
     debug('deps: built direct dependencies')
 
@@ -669,7 +671,7 @@ def break_dependency_loops(bld, tgt_list):
         if t.samba_type in ['SUBSYSTEM']:
             loops[loop] = loops[loop].union(t.indirect_objects)
             loops[loop] = loops[loop].union(t.direct_objects)
-        if t.samba_type in ['LIBRARY','PYTHON']:
+        if t.samba_type in ['LIBRARY','PYTHON','EXTRAPYTHON']:
             loops[loop] = loops[loop].union(t.indirect_libs)
             loops[loop] = loops[loop].union(t.direct_libs)
         if loop in loops[loop]:
@@ -717,7 +719,7 @@ def reduce_objects(bld, tgt_list):
 
     changed = False
 
-    for type in ['BINARY', 'PYTHON', 'LIBRARY']:
+    for type in ['BINARY', 'PYTHON', 'EXTRAPYTHON', 'LIBRARY']:
         for t in tgt_list:
             if t.samba_type != type: continue
             # if we will indirectly link to a target then we don't need it
@@ -817,7 +819,7 @@ def calculate_final_deps(bld, tgt_list, loops):
 
     # find any library loops
     for t in tgt_list:
-        if t.samba_type in ['LIBRARY', 'PYTHON']:
+        if t.samba_type in ['LIBRARY', 'PYTHON', 'EXTRAPYTHON']:
             for l in t.final_libs.copy():
                 t2 = bld.name_to_obj(l, bld.env)
                 if t.sname in t2.final_libs:
@@ -841,7 +843,7 @@ def calculate_final_deps(bld, tgt_list, loops):
     # we now need to make corrections for any library loops we broke up
     # any target that depended on the target of the loop and doesn't
     # depend on the source of the loop needs to get the loop source added
-    for type in ['BINARY','PYTHON','LIBRARY','BINARY']:
+    for type in ['BINARY','PYTHON','EXTRAPYTHON','LIBRARY','BINARY']:
         for t in tgt_list:
             if t.samba_type != type: continue
             for loop in loops:
@@ -874,7 +876,7 @@ def calculate_final_deps(bld, tgt_list, loops):
 
     # add in any syslib dependencies
     for t in tgt_list:
-        if not t.samba_type in ['BINARY','PYTHON','LIBRARY','SUBSYSTEM']:
+        if not t.samba_type in ['BINARY','PYTHON','EXTRAPYTHON','LIBRARY','SUBSYSTEM']:
             continue
         syslibs = set()
         for d in t.final_objects:
@@ -891,7 +893,7 @@ def calculate_final_deps(bld, tgt_list, loops):
     # find any unresolved library loops
     lib_loop_error = False
     for t in tgt_list:
-        if t.samba_type in ['LIBRARY', 'PYTHON']:
+        if t.samba_type in ['LIBRARY', 'PYTHON', 'EXTRAPYTHON']:
             for l in t.final_libs.copy():
                 t2 = bld.name_to_obj(l, bld.env)
                 if t.sname in t2.final_libs:
@@ -935,7 +937,7 @@ def show_object_duplicates(bld, tgt_list):
     Logs.info("showing duplicate objects")
 
     for t in tgt_list:
-        if not targets[t.sname] in [ 'LIBRARY', 'PYTHON' ]:
+        if not targets[t.sname] in [ 'LIBRARY', 'PYTHON', 'EXTRAPYTHON' ]:
             continue
         for n in getattr(t, 'final_objects', set()):
             t2 = bld.name_to_obj(n, bld.env)
diff --git a/buildtools/wafsamba/samba_install.py b/buildtools/wafsamba/samba_install.py
index aa7f143..4a5780b 100644
--- a/buildtools/wafsamba/samba_install.py
+++ b/buildtools/wafsamba/samba_install.py
@@ -105,10 +105,12 @@ def install_library(self):
         install_link = None
         if getattr(self, 'soname', ''):
             install_link = self.soname
-        if getattr(self, 'samba_type', None) == 'PYTHON':
-            inst_name    = bld.make_libname(t.target, nolibprefix=True, python=True)
+        samba_type = getattr(self, 'samba_type', None)
+        if samba_type in ('PYTHON', 'EXTRAPYTHON'):
+            inst_name = bld.make_libname(t.target, nolibprefix=True,
+                                         target_type=samba_type)
         else:
-            inst_name    = bld.make_libname(t.target)
+            inst_name = bld.make_libname(t.target)
     elif self.vnum:
         vnum_base    = self.vnum.split('.')[0]
         install_name = bld.make_libname(target_name, version=self.vnum)
diff --git a/buildtools/wafsamba/samba_python.py b/buildtools/wafsamba/samba_python.py
index 15ebf93..e6c0c6f 100644
--- a/buildtools/wafsamba/samba_python.py
+++ b/buildtools/wafsamba/samba_python.py
@@ -4,9 +4,37 @@ import Build
 from samba_utils import *
 from samba_autoconf import *
 from Logs import warn
+from TaskGen import extension, before, after, feature
 
 from Configure import conf
 
+
+ at feature('extrapyext')
+ at before('apply_incpaths', 'apply_lib_vars', 'apply_type_vars', 'apply_bundle')
+ at after('vars_target_cshlib')
+def init_extrapyext(self):
+    self.default_install_path = '${PYTHONARCHDIR}'
+    self.uselib = self.to_list(getattr(self, 'uselib', ''))
+    if not 'EXTRAPYEXT' in self.uselib:
+        self.uselib.append('EXTRAPYEXT')
+
+
+ at before('apply_link', 'apply_lib_vars', 'apply_type_vars')
+ at after('apply_bundle')
+ at feature('extrapyext')
+def extrapyext_shlib_ext(self):
+    # override shlib_PATTERN set by the osx module
+    self.env['shlib_PATTERN'] = self.env['extrapyext_PATTERN']
+
+
+ at before('apply_incpaths', 'apply_lib_vars', 'apply_type_vars')
+ at feature('extrapyembed')
+def init_extrapyembed(self):
+    self.uselib = self.to_list(getattr(self, 'uselib', ''))
+    if not 'EXTRAPYEMBED' in self.uselib:
+        self.uselib.append('EXTRAPYEMBED')
+
+
 # For extrapython, we store config in a separate set of env variables.
 # During the configure step we swap these with the normal *PYTHON* equivalents,
 # use waf's regular Python tool, and then switch them all back.
@@ -125,7 +153,8 @@ def SAMBA_PYTHON(bld, name,
                  local_include=True,
                  vars=None,
                  install=True,
-                 enabled=True):
+                 enabled=True,
+                 extra_python=False):
     '''build a python extension for Samba'''
 
     # when we support static python modules we'll need to gather
@@ -140,6 +169,14 @@ def SAMBA_PYTHON(bld, name,
     else:
         link_name = None
 
+    if extra_python:
+        pyfeature = 'extrapyext'
+        target_type = 'EXTRAPYTHON'
+        install_path = '${EXTRAPYTHONARCHDIR}'
+    else:
+        pyfeature = 'pyext'
+        target_type = 'PYTHON'
+        install_path = '${PYTHONARCHDIR}'
     bld.SAMBA_LIBRARY(name,
                       source=source,
                       deps=deps,
@@ -150,9 +187,9 @@ def SAMBA_PYTHON(bld, name,
                       vars=vars,
                       realname=realname,
                       link_name=link_name,
-                      pyfeature='pyext',
-                      target_type='PYTHON',
-                      install_path='${PYTHONARCHDIR}',
+                      pyfeature=pyfeature,
+                      target_type=target_type,
+                      install_path=install_path,
                       allow_undefined_symbols=True,
                       allow_warnings=True,
                       install=install,
diff --git a/buildtools/wafsamba/samba_utils.py b/buildtools/wafsamba/samba_utils.py
index e8bc0f3..fd04a49 100644
--- a/buildtools/wafsamba/samba_utils.py
+++ b/buildtools/wafsamba/samba_utils.py
@@ -568,7 +568,7 @@ def reconfigure(ctx):
     Scripting.check_configured(bld)
 
 
-def map_shlib_extension(ctx, name, python=False):
+def map_shlib_extension(ctx, name, target_type=None):
     '''map a filename with a shared library extension of .so to the real shlib name'''
     if name is None:
         return None
@@ -576,8 +576,10 @@ def map_shlib_extension(ctx, name, python=False):
         # some libraries have specified versions in the wscript rule
         return name
     (root1, ext1) = os.path.splitext(name)
-    if python:
+    if target_type == 'PYTHON':
         return ctx.env.pyext_PATTERN % root1
+    elif target_type == 'EXTRAPYTHON':
+        return ctx.env.extrapyext_PATTERN % root1
     else:
         (root2, ext2) = os.path.splitext(ctx.env.shlib_PATTERN)
     return root1+ext2
@@ -591,15 +593,18 @@ def apply_pattern(filename, pattern):
     basename = os.path.basename(filename)
     return os.path.join(dirname, pattern % basename)
 
-def make_libname(ctx, name, nolibprefix=False, version=None, python=False):
+def make_libname(ctx, name, nolibprefix=False, version=None, target_type=None):
     """make a library filename
          Options:
               nolibprefix: don't include the lib prefix
               version    : add a version number
-              python     : if we should use python module name conventions"""
+              target_type: 'PYTHON' or 'EXTRAPYTHON' if we should use python module name conventions
+    """
 
-    if python:
+    if target_type == 'PYTHON':
         libname = apply_pattern(name, ctx.env.pyext_PATTERN)
+    elif target_type == 'EXTRAPYTHON':
+        libname = apply_pattern(name, ctx.env.extrapyext_PATTERN)
     else:
         libname = apply_pattern(name, ctx.env.shlib_PATTERN)
     if nolibprefix and libname[0:3] == 'lib':
@@ -626,7 +631,7 @@ def get_tgt_list(bld):
     tgt_list = []
     for tgt in targets:
         type = targets[tgt]
-        if not type in ['SUBSYSTEM', 'MODULE', 'BINARY', 'LIBRARY', 'ASN1', 'PYTHON']:
+        if not type in ['SUBSYSTEM', 'MODULE', 'BINARY', 'LIBRARY', 'ASN1', 'PYTHON', 'EXTRAPYTHON']:
             continue
         t = bld.name_to_obj(tgt, bld.env)
         if t is None:
diff --git a/buildtools/wafsamba/stale_files.py b/buildtools/wafsamba/stale_files.py
index 2dd08e1..8c5d5ee 100644
--- a/buildtools/wafsamba/stale_files.py
+++ b/buildtools/wafsamba/stale_files.py
@@ -71,6 +71,8 @@ def replace_refill_task_list(self):
                             t = samba_utils.apply_pattern(t, bld.env.shlib_PATTERN)
                         if ttype == 'PYTHON':
                             t = samba_utils.apply_pattern(t, bld.env.pyext_PATTERN)
+                        elif ttype == 'EXTRAPYTHON':
+                            t = samba_utils.apply_pattern(t, bld.env.extrapyext_PATTERN)
                         p = os.path.join(x.path.abspath(bld.env), t)
                         p = os.path.normpath(p)
                         expected.append(p)
diff --git a/buildtools/wafsamba/symbols.py b/buildtools/wafsamba/symbols.py
index daa18b9..6750a8a 100644
--- a/buildtools/wafsamba/symbols.py
+++ b/buildtools/wafsamba/symbols.py
@@ -278,7 +278,7 @@ def build_library_dict(bld, tgt_list):
     bld.env.library_dict = {}
 
     for t in tgt_list:
-        if t.samba_type in [ 'LIBRARY', 'PYTHON' ]:
+        if t.samba_type in [ 'LIBRARY', 'PYTHON', 'EXTRAPYTHON' ]:
             linkpath = os.path.realpath(t.link_task.outputs[0].abspath(bld.env))
             bld.env.library_dict[linkpath] = t.sname
 
@@ -293,10 +293,12 @@ def build_syslib_sets(bld, tgt_list):
     syslibs = {}
     objmap = {}
     for t in tgt_list:
-        if getattr(t, 'uselib', []) and t.samba_type in [ 'LIBRARY', 'BINARY', 'PYTHON' ]:
+        if getattr(t, 'uselib', []) and t.samba_type in [ 'LIBRARY', 'BINARY', 'PYTHON', 'EXTRAPYTHON' ]:
             for lib in t.uselib:
                 if lib in ['PYEMBED', 'PYEXT']:
                     lib = "python"
+                elif lib in ['EXTRAPYEMBED', 'EXTRAPYEXT']:
+                    lib = "python" + bld.env.EXTRAPYTHON_VERSION
                 if not lib in syslibs:
                     syslibs[lib] = []
                 syslibs[lib].append(t)
@@ -356,7 +358,8 @@ def build_autodeps(bld, t):
             if t.in_library == depname:
                 # no need to depend on the library we are part of
                 continue
-            if depname[0] in ['c', 'python']:
+            if depname[0] in ['c', 'python',
+                              'python' + bld.env.EXTRAPYTHON_VERSION]:
                 # these don't go into autodeps
                 continue
             if targets[depname[0]] in [ 'SYSLIB' ]:
@@ -484,8 +487,14 @@ def check_syslib_dependencies(bld, t):
 
     features = TO_LIST(t.features)
     if 'pyembed' in features or 'pyext' in features:
-        if 'python' in bld.env.public_symbols:
-            t.unsatisfied_symbols = t.unsatisfied_symbols.difference(bld.env.public_symbols['python'])
+        python_libname = 'python'
+    elif 'extrapyembed' in features or 'extrapyext' in features:
+        python_libname = 'python' + bld.env.EXTRAPYTHON_VERSION
+    else:
+        python_libname = None
+    if python_libname and python_libname in bld.env.public_symbols:
+        py_symbols = bld.env.public_symbols[python_libname]
+        t.unsatisfied_symbols = t.unsatisfied_symbols.difference(py_symbols)
 
     needed = {}
     for sym in t.unsatisfied_symbols:
diff --git a/buildtools/wafsamba/wafsamba.py b/buildtools/wafsamba/wafsamba.py
index 07fc2ac..0d66813 100644
--- a/buildtools/wafsamba/wafsamba.py
+++ b/buildtools/wafsamba/wafsamba.py
@@ -207,11 +207,12 @@ def SAMBA_LIBRARY(bld, libname, source,
     deps = TO_LIST(deps)
     deps.append(obj_target)
 
-    realname = bld.map_shlib_extension(realname, python=(target_type=='PYTHON'))
-    link_name = bld.map_shlib_extension(link_name, python=(target_type=='PYTHON'))
+    realname = bld.map_shlib_extension(realname, target_type=target_type)
+    link_name = bld.map_shlib_extension(link_name, target_type=target_type)
 
     # we don't want any public libraries without version numbers
-    if (not private_library and target_type != 'PYTHON' and not realname):
+    if (not private_library and not realname and
+            target_type not in ('PYTHON', 'EXTRAPYTHON')):
         if vnum is None and soname is None:
             raise Utils.WafError("public library '%s' must have a vnum" %
                     libname)
@@ -224,7 +225,7 @@ def SAMBA_LIBRARY(bld, libname, source,
 
     if bundled_name is not None:
         pass
-    elif target_type == 'PYTHON' or realname or not private_library:
+    elif target_type in ('PYTHON', 'EXTRAPYTHON') or realname or not private_library:
         if keep_underscore:
             bundled_name = libname
         else:
@@ -377,6 +378,8 @@ def SAMBA_BINARY(bld, binname, source,
     # separately for the install binary and the build binary
     if pyfeature == 'pyembed':
         subsystem_pyfeature = 'pyext'
+    elif pyfeature == 'extrapyembed':
+        subsystem_pyfeature = 'extrapyext'
     else:
         subsystem_pyfeature = None
     bld.SAMBA_SUBSYSTEM(obj_target,
-- 
2.1.0


From f44a4fc92e2953116c52c54a483b50b8cd68d5c4 Mon Sep 17 00:00:00 2001
From: Petr Viktorin <pviktori at redhat.com>
Date: Fri, 23 Jan 2015 16:32:21 +0100
Subject: [PATCH 05/10] buildtools: Don't require pkgconfig file or headers for
 extrapython

For system configuration one should use the system version of Python,
not extrapython.
Public headers should be the same for all versions, so the ones for
the main Python version should be used.

Signed-off-by: Petr Viktorin <pviktori at redhat.com>
---
 buildtools/wafsamba/wafsamba.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/buildtools/wafsamba/wafsamba.py b/buildtools/wafsamba/wafsamba.py
index 0d66813..57fb4d9 100644
--- a/buildtools/wafsamba/wafsamba.py
+++ b/buildtools/wafsamba/wafsamba.py
@@ -216,10 +216,10 @@ def SAMBA_LIBRARY(bld, libname, source,
         if vnum is None and soname is None:
             raise Utils.WafError("public library '%s' must have a vnum" %
                     libname)
-        if pc_files is None:
+        if pc_files is None and pyfeature != 'extrapyembed':
             raise Utils.WafError("public library '%s' must have pkg-config file" %
                        libname)
-        if public_headers is None:
+        if public_headers is None and pyfeature != 'extrapyembed':
             raise Utils.WafError("public library '%s' must have header files" %
                        libname)
 
-- 
2.1.0


From 9fe10ed8669e8786dc2193cb72b1e01b3c37b578 Mon Sep 17 00:00:00 2001
From: Petr Viktorin <pviktori at redhat.com>
Date: Fri, 23 Jan 2015 17:02:55 +0100
Subject: [PATCH 06/10] buildtools: Enable adding ABI flags to Python utilities

This allows shared libraries to be named, for example,
"libpytalloc-util.cpython-34m.so". The ABI flag enables
libraries for several Python versions to co-exist on
a single system.

Signed-off-by: Petr Viktorin <pviktori at redhat.com>
---
 buildtools/wafsamba/samba_python.py | 28 ++++++++++++++++++++++++++--
 1 file changed, 26 insertions(+), 2 deletions(-)

diff --git a/buildtools/wafsamba/samba_python.py b/buildtools/wafsamba/samba_python.py
index e6c0c6f..878df38 100644
--- a/buildtools/wafsamba/samba_python.py
+++ b/buildtools/wafsamba/samba_python.py
@@ -1,3 +1,4 @@
+import os
 import contextlib
 
 import Build
@@ -67,6 +68,8 @@ EXTRAPYTHON_ENV_KEYS = (
     ('PYCMD', 'EXTRAPYCMD'),
     ('PYFLAGS', 'EXTRAPYFLAGS'),
     ('PYFLAGS_OPT', 'EXTRAPYFLAGS_OPT'),
+
+    ('PYTHON_SO_ABI_FLAG', 'EXTRAPYTHON_SO_ABI_FLAG'),
 )
 EXTRAPYTHON_DEFINES_KEYS = (
     ('PYTHONDIR', 'EXTRAPYTHONDIR'),
@@ -125,14 +128,24 @@ def SAMBA_CHECK_PYTHON(conf, mandatory=True, version=(2,4,2)):
     conf.check_python_version(version)
 
 
+def check_python_headers(conf, mandatory):
+    conf.check_python_headers(mandatory=mandatory)
+
+    if conf.env['PYTHON_VERSION'] > '3':
+        abi_pattern = os.path.splitext(conf.env['pyext_PATTERN'])[0]
+        conf.env['PYTHON_SO_ABI_FLAG'] = abi_pattern % ''
+    else:
+        conf.env['PYTHON_SO_ABI_FLAG'] = ''
+
+
 @conf
 def SAMBA_CHECK_PYTHON_HEADERS(conf, mandatory=True):
     if conf.env["python_headers_checked"] == []:
         pre_dict = conf.env.get_merged_dict()
         if conf.env['EXTRA_PYTHON']:
             with extrapython_env(conf.env):
-                conf.check_python_headers(mandatory=True)
-        conf.check_python_headers(mandatory)
+                check_python_headers(conf, mandatory=True)
+        check_python_headers(conf, mandatory=mandatory)
         conf.env["python_headers_checked"] = "yes"
 
         if conf.env['EXTRAPYTHON_VERSION'] == conf.env['PYTHON_VERSION']:
@@ -196,3 +209,14 @@ def SAMBA_PYTHON(bld, name,
                       enabled=enabled)
 
 Build.BuildContext.SAMBA_PYTHON = SAMBA_PYTHON
+
+
+def pyembed_libname(bld, name, extrapython=False):
+    if extrapython:
+        return name + bld.env['EXTRAPYTHON_SO_ABI_FLAG']
+    else:
+        return name + bld.env['PYTHON_SO_ABI_FLAG']
+
+    return name
+
+Build.BuildContext.pyembed_libname = pyembed_libname
-- 
2.1.0


From 7c7346e4f9d49fcd049e0f996edf977edacbe19a Mon Sep 17 00:00:00 2001
From: Petr Viktorin <pviktori at redhat.com>
Date: Tue, 10 Mar 2015 18:19:14 +0100
Subject: [PATCH 07/10] buildtools: Add a helper for running Python tests

Add the function samba_utils.RUN_PYTHON_TESTS for running a Python
test. When building for multiple Python versions, all are tested.

Also, add the list of configured Python interpreters to build config.

Signed-off-by: Petr Viktorin <pviktori at redhat.com>
---
 buildtools/wafsamba/samba_python.py |  6 ++++++
 buildtools/wafsamba/samba_utils.py  | 16 ++++++++++++++++
 2 files changed, 22 insertions(+)

diff --git a/buildtools/wafsamba/samba_python.py b/buildtools/wafsamba/samba_python.py
index 878df38..e07d33f 100644
--- a/buildtools/wafsamba/samba_python.py
+++ b/buildtools/wafsamba/samba_python.py
@@ -110,6 +110,8 @@ def extrapython_env(env):
 @conf
 def SAMBA_CHECK_PYTHON(conf, mandatory=True, version=(2,4,2)):
     # enable tool to build python extensions
+    interpreters = []
+
     if conf.env['EXTRA_PYTHON']:
         with extrapython_env(conf.env):
             conf.env['PYTHON'] = conf.env['EXTRA_PYTHON']
@@ -120,6 +122,7 @@ def SAMBA_CHECK_PYTHON(conf, mandatory=True, version=(2,4,2)):
             except Exception:
                 warn('extra-python needs to be Python 3.3 or later')
                 raise
+        interpreters.append(conf.env['EXTRA_PYTHON'])
 
     conf.find_program('python', var='PYTHON', mandatory=mandatory)
     conf.check_tool('python')
@@ -127,6 +130,9 @@ def SAMBA_CHECK_PYTHON(conf, mandatory=True, version=(2,4,2)):
     conf.env.PYTHON_SPECIFIED = (conf.env.PYTHON != path_python)
     conf.check_python_version(version)
 
+    interpreters.append(conf.env['PYTHON'])
+    conf.env.python_interpreters = interpreters
+
 
 def check_python_headers(conf, mandatory):
     conf.check_python_headers(mandatory=mandatory)
diff --git a/buildtools/wafsamba/samba_utils.py b/buildtools/wafsamba/samba_utils.py
index fd04a49..4c56bae 100644
--- a/buildtools/wafsamba/samba_utils.py
+++ b/buildtools/wafsamba/samba_utils.py
@@ -386,6 +386,22 @@ def RUN_COMMAND(cmd,
     return -1
 
 
+def RUN_PYTHON_TESTS(testfiles, pythonpath=None):
+    env = LOAD_ENVIRONMENT()
+    if pythonpath is None:
+        pythonpath = os.path.join(Utils.g_module.blddir, 'python')
+    result = 0
+    for interp in env.python_interpreters:
+        for testfile in testfiles:
+            cmd = "PYTHONPATH=%s %s %s" % (pythonpath, interp, testfile)
+            print('Running Python test with %s: %s' % (interp, testfile))
+            ret = RUN_COMMAND(cmd)
+            if ret:
+                print('Python test failed: %s' % cmd)
+                result = ret
+    return result
+
+
 # make sure we have md5. some systems don't have it
 try:
     from hashlib import md5
-- 
2.1.0


From 07b3067e6fcebcc685927bdad920e8f73b878ac2 Mon Sep 17 00:00:00 2001
From: Petr Viktorin <pviktori at redhat.com>
Date: Thu, 15 Jan 2015 14:07:09 +0100
Subject: [PATCH 08/10] talloc build: Use SAMBA_CHECK_PYTHON for finding Python

Previously the code repeated most of SAMBA_CHECK_PYTHON explicitly.

Signed-off-by: Petr Viktorin <pviktori at redhat.com>
---
 lib/talloc/wscript | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/lib/talloc/wscript b/lib/talloc/wscript
index d449609..de8c27d 100644
--- a/lib/talloc/wscript
+++ b/lib/talloc/wscript
@@ -60,9 +60,7 @@ def configure(conf):
 
     if not conf.env.disable_python:
         # also disable if we don't have the python libs installed
-        conf.find_program('python', var='PYTHON')
-        conf.check_tool('python')
-        conf.check_python_version((2,4,2))
+        conf.SAMBA_CHECK_PYTHON(mandatory=False, version=(2,4,2))
         conf.SAMBA_CHECK_PYTHON_HEADERS(mandatory=False)
         if not conf.env.HAVE_PYTHON_H:
             Logs.warn('Disabling pytalloc-util as python devel libs not found')
-- 
2.1.0


From 0bf319d7236a37d77cd2fe2ca56da1f9103d3204 Mon Sep 17 00:00:00 2001
From: Petr Viktorin <pviktori at redhat.com>
Date: Tue, 10 Mar 2015 16:40:48 +0100
Subject: [PATCH 09/10] pytalloc: Port to Python 3

- Use native string for repr

- Use rich comparison
  Removes the deprecated tp_compare in favor of tp_richcompare.
  Disparate types cannot be compared (except for == and !=),
  and True or False objects are returned explicitly.

- Use Py_TYPE instead of ob_type
  This changed to conform to C aliasing rules,
  see http://legacy.python.org/dev/peps/pep-3123/

- Don't provide CObject creation function
  A PyCapsule based replacement would be possible,
  but might not be necessary considering the function is
  not used much.

- Use new-style module initialization

Signed-off-by: Petr Viktorin <pviktori at redhat.com>
---
 lib/talloc/pytalloc.c       | 87 ++++++++++++++++++++++++++++++++++++++++-----
 lib/talloc/pytalloc_util.c  |  4 +++
 lib/talloc/test_pytalloc.c  | 41 ++++++++++++++++++---
 lib/talloc/test_pytalloc.py |  3 ++
 4 files changed, 122 insertions(+), 13 deletions(-)

diff --git a/lib/talloc/pytalloc.c b/lib/talloc/pytalloc.c
index ac4fe0f..3afae9c 100644
--- a/lib/talloc/pytalloc.c
+++ b/lib/talloc/pytalloc.c
@@ -21,7 +21,13 @@
 #include <talloc.h>
 #include <pytalloc.h>
 
-void inittalloc(void);
+static PyTypeObject TallocObject_Type;
+
+#if PY_MAJOR_VERSION >= 3
+#define PyStr_FromFormat PyUnicode_FromFormat
+#else
+#define PyStr_FromFormat PyString_FromFormat
+#endif
 
 /* print a talloc tree report for a talloc python object */
 static PyObject *pytalloc_report_full(PyObject *self, PyObject *args)
@@ -79,8 +85,8 @@ static PyObject *pytalloc_default_repr(PyObject *obj)
 	pytalloc_Object *talloc_obj = (pytalloc_Object *)obj;
 	PyTypeObject *type = (PyTypeObject*)PyObject_Type(obj);
 
-	return PyString_FromFormat("<%s talloc object at 0x%p>", 
-				   type->tp_name, talloc_obj->ptr);
+	return PyStr_FromFormat("<%s talloc object at 0x%p>",
+				type->tp_name, talloc_obj->ptr);
 }
 
 /**
@@ -97,6 +103,35 @@ static void pytalloc_dealloc(PyObject* self)
 /**
  * Default (but only slightly more useful than the default) implementation of cmp.
  */
+#if PY_MAJOR_VERSION >= 3
+static PyObject *pytalloc_default_richcmp(PyObject *obj1, PyObject *obj2, int op)
+{
+	void *ptr1;
+	void *ptr2;
+	if (Py_TYPE(obj1) == Py_TYPE(obj2)) {
+		/* When types match, compare pointers */
+		ptr1 = pytalloc_get_ptr(obj1);
+		ptr2 = pytalloc_get_ptr(obj2);
+	} else if (PyObject_TypeCheck(obj2, &TallocObject_Type)) {
+		/* Otherwise, compare types */
+		ptr1 = Py_TYPE(obj1);
+		ptr2 = Py_TYPE(obj2);
+	} else {
+		Py_INCREF(Py_NotImplemented);
+		return Py_NotImplemented;
+	}
+	switch (op) {
+		case Py_EQ: return PyBool_FromLong(ptr1 == ptr2);
+		case Py_NE: return PyBool_FromLong(ptr1 != ptr2);
+		case Py_LT: return PyBool_FromLong(ptr1 < ptr2);
+		case Py_GT: return PyBool_FromLong(ptr1 > ptr2);
+		case Py_LE: return PyBool_FromLong(ptr1 <= ptr2);
+		case Py_GE: return PyBool_FromLong(ptr1 >= ptr2);
+	}
+	Py_INCREF(Py_NotImplemented);
+	return Py_NotImplemented;
+}
+#else
 static int pytalloc_default_cmp(PyObject *_obj1, PyObject *_obj2)
 {
 	pytalloc_Object *obj1 = (pytalloc_Object *)_obj1,
@@ -106,6 +141,7 @@ static int pytalloc_default_cmp(PyObject *_obj1, PyObject *_obj2)
 
 	return ((char *)pytalloc_get_ptr(obj1) - (char *)pytalloc_get_ptr(obj2));
 }
+#endif
 
 static PyTypeObject TallocObject_Type = {
 	.tp_name = "talloc.Object",
@@ -114,21 +150,56 @@ static PyTypeObject TallocObject_Type = {
 	.tp_dealloc = (destructor)pytalloc_dealloc,
 	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
 	.tp_repr = pytalloc_default_repr,
+#if PY_MAJOR_VERSION >= 3
+	.tp_richcompare = pytalloc_default_richcmp,
+#else
 	.tp_compare = pytalloc_default_cmp,
+#endif
 };
 
-void inittalloc(void)
+#define MODULE_DOC PyDoc_STR("Python wrapping of talloc-maintained objects.")
+
+#if PY_MAJOR_VERSION >= 3
+static struct PyModuleDef moduledef = {
+    PyModuleDef_HEAD_INIT,
+    .m_name = "talloc",
+    .m_doc = MODULE_DOC,
+    .m_size = -1,
+    .m_methods = talloc_methods,
+};
+#endif
+
+static PyObject *module_init(void);
+static PyObject *module_init(void)
 {
 	PyObject *m;
 
 	if (PyType_Ready(&TallocObject_Type) < 0)
-		return;
+		return NULL;
 
-	m = Py_InitModule3("talloc", talloc_methods,
-					   "Python wrapping of talloc-maintained objects.");
+#if PY_MAJOR_VERSION >= 3
+	m = PyModule_Create(&moduledef);
+#else
+	m = Py_InitModule3("talloc", talloc_methods, MODULE_DOC);
+#endif
 	if (m == NULL)
-		return;
+		return NULL;
 
 	Py_INCREF(&TallocObject_Type);
 	PyModule_AddObject(m, "Object", (PyObject *)&TallocObject_Type);
+	return m;
+}
+
+#if PY_MAJOR_VERSION >= 3
+PyMODINIT_FUNC PyInit_talloc(void);
+PyMODINIT_FUNC PyInit_talloc(void)
+{
+	return module_init();
+}
+#else
+void inittalloc(void);
+void inittalloc(void)
+{
+	module_init();
 }
+#endif
diff --git a/lib/talloc/pytalloc_util.c b/lib/talloc/pytalloc_util.c
index 89a093b..0af7c05 100644
--- a/lib/talloc/pytalloc_util.c
+++ b/lib/talloc/pytalloc_util.c
@@ -97,6 +97,8 @@ _PUBLIC_ PyObject *pytalloc_reference_ex(PyTypeObject *py_type, TALLOC_CTX *mem_
 	return (PyObject *)ret;
 }
 
+#if PY_MAJOR_VERSION < 3
+
 static void py_cobject_talloc_free(void *ptr)
 {
 	talloc_free(ptr);
@@ -110,6 +112,8 @@ _PUBLIC_ PyObject *pytalloc_CObject_FromTallocPtr(void *ptr)
 	return PyCObject_FromVoidPtr(ptr, py_cobject_talloc_free);
 }
 
+#endif
+
 _PUBLIC_ int pytalloc_Check(PyObject *obj)
 {
 	PyTypeObject *tp = pytalloc_GetObjectType();
diff --git a/lib/talloc/test_pytalloc.c b/lib/talloc/test_pytalloc.c
index 2eaa7c3..f66b4e5 100644
--- a/lib/talloc/test_pytalloc.c
+++ b/lib/talloc/test_pytalloc.c
@@ -104,25 +104,56 @@ static PyTypeObject DObject_Type = {
 	.tp_doc = "test talloc object that calls a function when underlying data is freed\n",
 };
 
-#define MODULE_DOC "Test utility module for pytalloc"
+#define MODULE_DOC PyDoc_STR("Test utility module for pytalloc")
+
+#if PY_MAJOR_VERSION >= 3
+static struct PyModuleDef moduledef = {
+    PyModuleDef_HEAD_INIT,
+    .m_name = "_test_pytalloc",
+    .m_doc = PyDoc_STR("Test utility module for pytalloc"),
+    .m_size = -1,
+    .m_methods = test_talloc_methods,
+};
+#endif
 
-void init_test_pytalloc(void);
-void init_test_pytalloc(void)
+static PyObject *module_init(void);
+static PyObject *module_init(void)
 {
 	PyObject *m;
 
 	DObject_Type.tp_base = pytalloc_GetObjectType();
 	if (PyType_Ready(&DObject_Type) < 0) {
-		return;
+		return NULL;
 	}
 
+#if PY_MAJOR_VERSION >= 3
+	m = PyModule_Create(&moduledef);
+#else
 	m = Py_InitModule3("_test_pytalloc", test_talloc_methods, MODULE_DOC);
+#endif
 
 	if (m == NULL) {
-		return;
+		return NULL;
 	}
 
 	Py_INCREF(&DObject_Type);
 	Py_INCREF(DObject_Type.tp_base);
 	PyModule_AddObject(m, "DObject", (PyObject *)&DObject_Type);
+
+	return m;
+}
+
+
+#if PY_MAJOR_VERSION >= 3
+PyMODINIT_FUNC PyInit__test_pytalloc(void);
+PyMODINIT_FUNC PyInit__test_pytalloc(void)
+{
+	return module_init();
+}
+#else
+void init_test_pytalloc(void);
+void init_test_pytalloc(void)
+{
+	module_init();
 }
+#endif
diff --git a/lib/talloc/test_pytalloc.py b/lib/talloc/test_pytalloc.py
index 961bfcb..a613373 100644
--- a/lib/talloc/test_pytalloc.py
+++ b/lib/talloc/test_pytalloc.py
@@ -78,6 +78,9 @@ class TallocComparisonTests(unittest.TestCase):
 
     def test_compare_different_types(self):
         # object comparison falls back to comparing types
+        if sys.version_info >= (3, 0):
+            # In Python 3, types are unorderable -- nothing to test
+            return
         if talloc.Object < _test_pytalloc.DObject:
             obj1 = _test_pytalloc.new()
             obj2 = _test_pytalloc.DObject(dummy_func)
-- 
2.1.0


From 0fc82a797565b4271a2dc0f4ade8c7c1ac62f69a Mon Sep 17 00:00:00 2001
From: Petr Viktorin <pviktori at redhat.com>
Date: Wed, 19 Nov 2014 14:50:07 +0100
Subject: [PATCH 10/10] pytalloc: Build for Python 3/extrapython

This enables building, installing & testing two versions for pytalloc,
for two versions of Python, at the same time.

Signed-off-by: Petr Viktorin <pviktori at redhat.com>
---
 lib/talloc/pytalloc-util.pc.in |  2 +-
 lib/talloc/pytalloc_guide.txt  |  8 +++++++
 lib/talloc/wscript             | 50 +++++++++++++++++++++++++++++-------------
 3 files changed, 44 insertions(+), 16 deletions(-)

diff --git a/lib/talloc/pytalloc-util.pc.in b/lib/talloc/pytalloc-util.pc.in
index b7426bb..b87c94e 100644
--- a/lib/talloc/pytalloc-util.pc.in
+++ b/lib/talloc/pytalloc-util.pc.in
@@ -6,6 +6,6 @@ includedir=@includedir@
 Name: pytalloc-util
 Description: Utility functions for using talloc objects with Python
 Version: @TALLOC_VERSION@
-Libs: @LIB_RPATH@ -L${libdir} -lpytalloc-util
+Libs: @LIB_RPATH@ -L${libdir} -lpytalloc-util at PYTHON_SO_ABI_FLAG@
 Cflags: -I${includedir}
 URL: http://talloc.samba.org/
diff --git a/lib/talloc/pytalloc_guide.txt b/lib/talloc/pytalloc_guide.txt
index 755a52b..80968e0 100644
--- a/lib/talloc/pytalloc_guide.txt
+++ b/lib/talloc/pytalloc_guide.txt
@@ -20,6 +20,14 @@ for objects that wrap talloc-maintained memory in C. It won't write your
 bindings for you but it will make it easier to write C bindings that involve
 talloc, and take away some of the boiler plate.
 
+Python 3
+--------
+
+pytalloc can be used with Python 3. Usage from Python extension remains
+the same, but for the C utilities, the library to link to is tagged with
+Python's PEP3149 ABI tag, for example "pytalloc.cpython34m".
+To make a build for Python 3, configure with PYTHON=/usr/bin/python3.
+.
 =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 pytalloc_Object
 
diff --git a/lib/talloc/wscript b/lib/talloc/wscript
index de8c27d..05f1daf 100644
--- a/lib/talloc/wscript
+++ b/lib/talloc/wscript
@@ -116,21 +116,26 @@ def build(bld):
                           manpages='man/talloc.3')
 
     if not bld.CONFIG_SET('USING_SYSTEM_PYTALLOC_UTIL') and not bld.env.disable_python:
-        bld.SAMBA_LIBRARY('pytalloc-util',
+        name = bld.pyembed_libname('pytalloc-util')
+        options = dict(
             source='pytalloc_util.c',
             public_deps='talloc',
-            pyfeature='pyembed',
             vnum=VERSION,
             hide_symbols=True,
             abi_directory='ABI',
-            abi_match='pytalloc_*',
             private_library=private_library,
-            public_headers='pytalloc.h',
-            pc_files='pytalloc-util.pc'
+            abi_match='pytalloc_*',
             )
+
+        name = bld.pyembed_libname('pytalloc-util')
+        bld.SAMBA_LIBRARY(name,
+            pyfeature='pyembed',
+            pc_files='pytalloc-util.pc',
+            public_headers='pytalloc.h',
+            **options)
         bld.SAMBA_PYTHON('pytalloc',
                          'pytalloc.c',
-                         deps='talloc pytalloc-util',
+                         deps='talloc ' + name,
                          enabled=True,
                          realname='talloc.so')
 
@@ -141,21 +146,36 @@ def build(bld):
                          realname='_test_pytalloc.so',
                          install=False)
 
+        if bld.env['EXTRA_PYTHON']:
+            name = bld.pyembed_libname('pytalloc-util', extrapython=True)
+            bld.SAMBA_LIBRARY(name,
+                pyfeature='extrapyembed',
+                pc_files=None,
+                **options)
+
+            bld.SAMBA_PYTHON('extra-pytalloc',
+                            'pytalloc.c',
+                            deps='talloc ' + name,
+                            enabled=True,
+                            realname='talloc.so',
+                            extra_python=True)
+
+            bld.SAMBA_PYTHON('extra-test_pytalloc',
+                             'test_pytalloc.c',
+                             deps='pytalloc',
+                             enabled=True,
+                             realname='_test_pytalloc.so',
+                             install=False,
+                             extra_python=True)
+
+
 def test(ctx):
     '''run talloc testsuite'''
     import Utils, samba_utils
-    env = samba_utils.LOAD_ENVIRONMENT()
     cmd = os.path.join(Utils.g_module.blddir, 'talloc_testsuite')
     ret = samba_utils.RUN_COMMAND(cmd)
     print("testsuite returned %d" % ret)
-    if 'USING_SYSTEM_PYTALLOC_UTIL' not in env.defines and not env.disable_python:
-        cmd = "PYTHONPATH=%s %s test_pytalloc.py" % (
-            os.path.join(Utils.g_module.blddir, 'python'),
-            env['PYTHON'],
-        )
-        pyret = samba_utils.RUN_COMMAND(cmd)
-    else:
-        pyret = 0
+    pyret = samba_utils.RUN_PYTHON_TESTS(['test_pytalloc.py'])
     print("python testsuite returned %d" % pyret)
     sys.exit(ret or pyret)
 
-- 
2.1.0


More information about the samba-technical mailing list