WIP refactor compiler setup.py for static archive.

Project: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/commit/f5f21ac8
Tree: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/tree/f5f21ac8
Diff: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/diff/f5f21ac8

Branch: refs/heads/py_exp1
Commit: f5f21ac8ce1ab45e81c06d28ad0170ef706e4c34
Parents: 99e208e
Author: Marvin Humphrey <[email protected]>
Authored: Sun Dec 14 10:41:39 2014 -0800
Committer: Marvin Humphrey <[email protected]>
Committed: Tue Dec 16 09:57:40 2014 -0800

----------------------------------------------------------------------
 compiler/python/setup.py | 108 ++++++++++++++++++------------------------
 1 file changed, 45 insertions(+), 63 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/f5f21ac8/compiler/python/setup.py
----------------------------------------------------------------------
diff --git a/compiler/python/setup.py b/compiler/python/setup.py
index b5d5c10..68d6fed 100644
--- a/compiler/python/setup.py
+++ b/compiler/python/setup.py
@@ -26,6 +26,8 @@ import re
 import shutil
 import subprocess
 import sysconfig
+import sys
+import unittest
 
 # Get a compiler object and and strings representing the compiler type and
 # CFLAGS.
@@ -37,8 +39,9 @@ compiler_type = distutils.ccompiler.get_default_compiler()
 # out of distutils, but the member variable has been in the same place for a
 # long time, so violating encapsulation may be ok.
 compiler_name = " ".join(compiler.compiler)
+make_command = "make"
 
-BASE_DIR = os.path.abspath(os.path.join(os.pardir, os.pardir, os.pardir))
+BASE_DIR        = os.path.abspath(os.path.join(os.pardir, os.pardir))
 PARENT_DIR      = os.path.abspath(os.pardir)
 CFC_SOURCE_DIR  = os.path.join(PARENT_DIR, 'src')
 CFC_INCLUDE_DIR = os.path.join(PARENT_DIR, 'include')
@@ -47,57 +50,21 @@ CHARMONIZER_C        = os.path.join(COMMON_SOURCE_DIR, 
'charmonizer.c')
 CHARMONIZER_EXE_NAME = compiler.executable_filename('charmonizer')
 CHARMONIZER_EXE_PATH = os.path.join(os.curdir, CHARMONIZER_EXE_NAME)
 CHARMONY_H_PATH      = 'charmony.h'
-LEMON_DIR = os.path.join(BASE_DIR, 'lemon')
-LEMON_EXE_NAME = compiler.executable_filename('lemon')
-LEMON_EXE_PATH = os.path.join(LEMON_DIR, LEMON_EXE_NAME)
+LIBCFC_NAME          = 'libcfc.a' # TODO portability
+LIBCFC_PATH          = os.path.abspath(os.path.join(os.curdir, LIBCFC_NAME))
 
-# Accumulate lists of source files and target files.
-c_filepaths = []
-y_filepaths = []
+c_filepaths = [os.path.join('clownfish', '_cfc.c')]
 paths_to_clean = [
     CHARMONIZER_EXE_PATH,
     CHARMONY_H_PATH,
     '_charm*',
 ]
-c_filepaths.append(os.path.join('clownfish', '_cfc.c'))
-for (dirpath, dirnames, files) in os.walk(CFC_SOURCE_DIR):
-    for filename in files:
-        if filename.endswith('.y'):
-            path = os.path.join(dirpath, filename)
-            y_filepaths.append(path)
-            path = re.sub(r'y$', 'h', path)
-            paths_to_clean.append(path)
-            path = re.sub(r'h$', 'c', path)
-            paths_to_clean.append(path)
-            c_filepaths.append(path)
-            path = compiler.object_filenames([path])[0]
-            paths_to_clean.append(path)
-        if filename.endswith('.c'):
-            path = os.path.join(dirpath, filename)
-            c_filepaths.append(path)
-            path = compiler.object_filenames([path])[0]
-            paths_to_clean.append(path)
 
 def _quotify(text):
     text = text.replace('\\', '\\\\')
     text = text.replace('"', '\\"')
     return '"' + text + '"'
 
-def _run_make(command=[], directory=None):
-    current_directory = os.getcwd();
-    if (directory != None):
-        os.chdir(directory)
-    if (compiler_type == 'msvc'):
-        command.insert(0, 'Makefile.MSVC')
-        command.insert(0, '-f')
-    elif (platform.system() == 'Windows'):
-        command.insert(0, 'Makefile.MinGW')
-        command.insert(0, '-f')
-    command.insert(0, "make")
-    subprocess.check_call(command)
-    if (directory != None):
-        os.chdir(current_directory)
-
 class charmony(_Command):
     description = "Build and run charmonizer"
     user_options = []
@@ -123,6 +90,8 @@ class charmony(_Command):
                 CHARMONIZER_EXE_PATH,
                 '--cc=' + _quotify(compiler_name),
                 '--enable-c',
+                '--host=python',
+                '--enable-makefile',
                 '--',
                 cflags
             ]
@@ -131,35 +100,21 @@ class charmony(_Command):
             print(" ".join(command))
             subprocess.check_call(command)
 
-class lemon(_Command):
-    description = "Compile the Lemon parser generator"
-    user_options = []
-    def initialize_options(self):
-        pass
-    def finalize_options(self):
-        pass
-    def run(self):
-        if not os.path.exists(LEMON_EXE_PATH):
-            _run_make(['CC=' + _quotify(compiler_name)], directory=LEMON_DIR)
-
-class parsers(_Command):
-    description = "Run .y files through lemon"
+class libcfc(_Command):
+    description = "Build CFC as a static archive."
     user_options = []
     def initialize_options(self):
         pass
     def finalize_options(self):
         pass
     def run(self):
-        for y_path in y_filepaths:
-            target = re.sub(r'y$', 'c', y_path)
-            if newer_group([y_path], target):
-                command = [LEMON_EXE_PATH, '-c', y_path]
-                subprocess.check_call(command)
+        self.run_command('charmony')
+        subprocess.check_call([make_command, '-j', 'static'])
 
 class my_clean(_clean):
     def run(self):
         _clean.run(self)
-        _run_make(command=['clean'], directory=LEMON_DIR)
+        subprocess.check_call([make_command, 'distclean'])
         for elem in paths_to_clean:
             for path in glob.glob(elem):
                 print("removing " + path)
@@ -171,10 +126,36 @@ class my_clean(_clean):
 class my_build(_build):
     def run(self):
         self.run_command('charmony')
-        self.run_command('lemon')
-        self.run_command('parsers')
+        self.run_command('libcfc')
         _build.run(self)
 
+class test(_Command):
+    description = "Run unit tests."
+    user_options = []
+    def initialize_options(self):
+        pass
+    def finalize_options(self):
+        pass
+    def ext_build_dir(self):
+        """Returns the build directory for compiled extensions"""
+        pattern = "lib.{platform}-{version[0]}.{version[1]}"
+        dirname = pattern.format(platform=sysconfig.get_platform(),
+                                 version=sys.version_info)
+        return os.path.join('build', dirname)
+
+    def run(self):
+        orig_sys_path = sys.path[:]
+        sys.path.append(self.ext_build_dir())
+
+        loader = unittest.TestLoader()
+        tests = loader.discover("test")
+        test_runner = unittest.runner.TextTestRunner()
+        test_runner.run(tests)
+
+        # restore sys.path
+        sys.path = orig_sys_path
+
+
 cfc_extension = Extension('clownfish._cfc',
                           define_macros = [('CFCPYTHON', None)],
                           include_dirs = [
@@ -182,6 +163,7 @@ cfc_extension = Extension('clownfish._cfc',
                               CFC_SOURCE_DIR,
                               os.curdir,
                           ],
+                          extra_link_args = [LIBCFC_PATH],
                           sources = c_filepaths)
 
 setup(name = 'clownfish-cfc',
@@ -195,9 +177,9 @@ setup(name = 'clownfish-cfc',
       cmdclass = {
           'build': my_build,
           'clean': my_clean,
-          'lemon': lemon,
           'charmony': charmony,
-          'parsers': parsers,
+          'test': test,
+          'libcfc': libcfc,
       },
       ext_modules = [cfc_extension])
 

Reply via email to