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])
