[Python-checkins] distutils2: Building extensions from the setup.cfg

tarek.ziade python-checkins at python.org
Sun Jan 30 10:43:58 CET 2011


tarek.ziade pushed f8657bc04959 to distutils2:

http://hg.python.org/distutils2/rev/f8657bc04959
changeset:   953:f8657bc04959
parent:      927:11f13263c188
user:        Andre Espaze <andre.espaze at logilab.fr>
date:        Sat Jan 29 17:08:28 2011 +0100
summary:
  Building extensions from the setup.cfg

This changeset adds the setup.cfg syntax for building binary extensions.
Note the extension key defined by the section name is not yet
used for managing build dependencies.

files:
  distutils2/config.py
  distutils2/tests/test_config.py

diff --git a/distutils2/config.py b/distutils2/config.py
--- a/distutils2/config.py
+++ b/distutils2/config.py
@@ -3,14 +3,32 @@
     Know how to read all config files Distutils2 uses.
 """
 import os
+import re
 import sys
 from ConfigParser import RawConfigParser
 
 from distutils2 import logger
 from distutils2.util import check_environ, resolve_name
+from distutils2.compiler.extension import Extension
 from distutils2.compiler import set_compiler
 from distutils2.command import set_command
 
+
+def pop_values(values_dct, key):
+    """Remove values from the dictionary and convert them as a list"""
+    vals_str = values_dct.pop(key, None)
+    if not vals_str:
+        return
+    # Get bash options like `gcc -print-file-name=libgcc.a`
+    vals = re.search('(`.*?`)', vals_str) or []
+    if vals:
+        vals = list(vals.groups())
+        vals_str = re.sub('`.*?`', '', vals_str)
+    vals.extend(vals_str.split())
+    if vals:
+        return vals
+
+
 class Config(object):
     """Reads configuration files and work with the Distribution instance
     """
@@ -181,6 +199,34 @@
             # manifest template
             self.dist.extra_files = files.get('extra_files', [])
 
+        ext_modules = self.dist.ext_modules
+        for section_key in content:
+            labels = section_key.split('=')
+            if (len(labels) == 2) and (labels[0] == 'extension'):
+                # labels[1] not used from now but should be implemented
+                # for extension build dependency
+                values_dct = content[section_key]
+                ext_modules.append(Extension(
+                    values_dct.pop('name'),
+                    pop_values(values_dct, 'sources'),
+                    pop_values(values_dct, 'include_dirs'),
+                    pop_values(values_dct, 'define_macros'),
+                    pop_values(values_dct, 'undef_macros'),
+                    pop_values(values_dct, 'library_dirs'),
+                    pop_values(values_dct, 'libraries'),
+                    pop_values(values_dct, 'runtime_library_dirs'),
+                    pop_values(values_dct, 'extra_objects'),
+                    pop_values(values_dct, 'extra_compile_args'),
+                    pop_values(values_dct, 'extra_link_args'),
+                    pop_values(values_dct, 'export_symbols'),
+                    pop_values(values_dct, 'swig_opts'),
+                    pop_values(values_dct, 'depends'),
+                    values_dct.pop('language', None),
+                    values_dct.pop('optional', None),
+                    **values_dct
+                ))
+
+
     def parse_config_files(self, filenames=None):
         if filenames is None:
             filenames = self.find_config_files()
diff --git a/distutils2/tests/test_config.py b/distutils2/tests/test_config.py
--- a/distutils2/tests/test_config.py
+++ b/distutils2/tests/test_config.py
@@ -93,6 +93,30 @@
 sub_commands = foo
 """
 
+# Can not be merged with SETUP_CFG else install_dist
+# command will fail when trying to compile C sources
+EXT_SETUP_CFG = """
+[files]
+packages = one
+           two
+
+[extension=speed_coconuts]
+name = one.speed_coconuts
+sources = c_src/speed_coconuts.c
+extra_link_args = `gcc -print-file-name=libgcc.a` -shared
+define_macros = HAVE_CAIRO HAVE_GTK2
+
+[extension=fast_taunt]
+name = three.fast_taunt
+sources = cxx_src/utils_taunt.cxx
+          cxx_src/python_module.cxx
+include_dirs = /usr/include/gecode
+    /usr/include/blitz
+extra_compile_args = -fPIC -O2
+language = cxx
+
+"""
+
 
 class DCompiler(object):
     name = 'd'
@@ -134,7 +158,14 @@
         super(ConfigTestCase, self).setUp()
         self.addCleanup(setattr, sys, 'stdout', sys.stdout)
         self.addCleanup(setattr, sys, 'stderr', sys.stderr)
+        sys.stdout = sys.stderr = StringIO()
+
         self.addCleanup(os.chdir, os.getcwd())
+        tempdir = self.mkdtemp()
+        os.chdir(tempdir)
+        self.tempdir = tempdir
+
+        self.addCleanup(setattr, sys, 'argv', sys.argv)
 
     def write_setup(self, kwargs=None):
         opts = {'description-file': 'README', 'extra-files':''}
@@ -156,8 +187,6 @@
         return dist
 
     def test_config(self):
-        tempdir = self.mkdtemp()
-        os.chdir(tempdir)
         self.write_setup()
         self.write_file('README', 'yeah')
 
@@ -232,9 +261,6 @@
 
 
     def test_multiple_description_file(self):
-        tempdir = self.mkdtemp()
-        os.chdir(tempdir)
-
         self.write_setup({'description-file': 'README  CHANGES'})
         self.write_file('README', 'yeah')
         self.write_file('CHANGES', 'changelog2')
@@ -242,9 +268,6 @@
         self.assertEqual(dist.metadata.requires_files, ['README', 'CHANGES'])
 
     def test_multiline_description_file(self):
-        tempdir = self.mkdtemp()
-        os.chdir(tempdir)
-
         self.write_setup({'description-file': 'README\n  CHANGES'})
         self.write_file('README', 'yeah')
         self.write_file('CHANGES', 'changelog')
@@ -252,9 +275,28 @@
         self.assertEqual(dist.metadata['description'], 'yeah\nchangelog')
         self.assertEqual(dist.metadata.requires_files, ['README', 'CHANGES'])
 
+    def test_parse_extensions_in_config(self):
+        self.write_file('setup.cfg', EXT_SETUP_CFG)
+        dist = self.run_setup('--version')
+
+        ext_modules = dict((mod.name, mod) for mod in dist.ext_modules)
+        self.assertEqual(len(ext_modules), 2)
+        ext = ext_modules.get('one.speed_coconuts')
+        self.assertEqual(ext.sources, ['c_src/speed_coconuts.c'])
+        self.assertEqual(ext.define_macros, ['HAVE_CAIRO', 'HAVE_GTK2'])
+        self.assertEqual(ext.extra_link_args,
+            ['`gcc -print-file-name=libgcc.a`', '-shared'])
+
+        ext = ext_modules.get('three.fast_taunt')
+        self.assertEqual(ext.sources,
+            ['cxx_src/utils_taunt.cxx', 'cxx_src/python_module.cxx'])
+        self.assertEqual(ext.include_dirs,
+            ['/usr/include/gecode', '/usr/include/blitz'])
+        self.assertEqual(ext.extra_compile_args, ['-fPIC', '-O2'])
+        self.assertEqual(ext.language, 'cxx')
+
+
     def test_metadata_requires_description_files_missing(self):
-        tempdir = self.mkdtemp()
-        os.chdir(tempdir)
         self.write_setup({'description-file': 'README\n  README2'})
         self.write_file('README', 'yeah')
         self.write_file('README2', 'yeah')
@@ -278,8 +320,6 @@
         self.assertRaises(DistutilsFileError, cmd.make_distribution)
 
     def test_metadata_requires_description_files(self):
-        tempdir = self.mkdtemp()
-        os.chdir(tempdir)
         self.write_setup({'description-file': 'README\n  README2',
                           'extra-files':'\n  README2'})
         self.write_file('README', 'yeah')
@@ -315,8 +355,6 @@
         self.assertIn('README\nREADME2\n', open('MANIFEST').read())
 
     def test_sub_commands(self):
-        tempdir = self.mkdtemp()
-        os.chdir(tempdir)
         self.write_setup()
         self.write_file('README', 'yeah')
         self.write_file('haven.py', '#')

--
Repository URL: http://hg.python.org/distutils2


More information about the Python-checkins mailing list