diff --git a/pixie/cli.py b/pixie/cli.py index 024c93a..127d94e 100644 --- a/pixie/cli.py +++ b/pixie/cli.py @@ -1,6 +1,7 @@ import argparse import pathlib import os +import json from pixie import ( PIXIECompiler, @@ -20,6 +21,7 @@ def _generate_parser(descr): help="optimization level", default=3,) parser.add_argument("-o", metavar="", help="output library") parser.add_argument("files", help="input source files", nargs="+") + parser.add_argument("-C", "--config", help="Configuration JSON file") return parser @@ -78,6 +80,12 @@ def pixie_cc(): compiler.compile() +def load_config(config_file): + with open(config_file, 'r') as f: + config = json.load(f) + return config + + def pixie_cythonize(): parser = _generate_parser("pixie-cythonize") args = vars(parser.parse_args()) @@ -85,15 +93,49 @@ def pixie_cythonize(): opt_flags, clang_flags, library_name = \ _translate_common_options(parser, args) - # cythonize the source - inps = args["files"] - tus = [] - for inp in inps: - path = pathlib.Path(inp) - tus.append(TranslationUnit.from_cython_source(str(path), - extra_clang_flags=clang_flags)) + if args["config"] is not None: + config = load_config(args.config) + assert 'export_config' in config + assert 'translation_unit' in config + + export_config = ExportConfiguration() + assert 'symbols' in config['export_config'] + for symbol in config['export_config']['symbols']: + assert 'python_name' in symbol + assert 'symbol_name' in symbol + assert 'signature' in symbol + export_config.add_symbol(**symbol) + + tus = [] + for tu in config['translation_unit']: + assert 'name' in tu + if 'source' in tu: + tus.append( + TranslationUnit(**tu) + ) + elif 'path' in tu: + file_path = tu.pop('path') + file_type = file_path.split('.')[-1] + if file_type == 'c': + tus.append( + TranslationUnit.from_c_source(file_path, **tu) + ) + elif file_type == 'pyx': + tus.append( + TranslationUnit.from_cython_source(file_path, **tu) + ) + else: + raise ValueError("Invalid file type provided in path") + else: + # cythonize the source + inps = args["files"] + tus = [] + for inp in inps: + path = pathlib.Path(inp) + tus.append(TranslationUnit.from_cython_source(str(path), + extra_clang_flags=clang_flags)) + export_config = ExportConfiguration() - export_config = ExportConfiguration() target_description = targets.get_default_configuration() compiler = PIXIECompiler( library_name=library_name, diff --git a/pixie/tests/test_cli.py b/pixie/tests/test_cli.py index 012cc25..d109a5b 100644 --- a/pixie/tests/test_cli.py +++ b/pixie/tests/test_cli.py @@ -5,6 +5,32 @@ from pixie.tests.support import PixieTestCase +example_config = """ +{ + "translation_unit": [ + { + "name": "llvm_foo_double_double", + "source": "int _Z3fooPdS_(double* a, double* b, double* c) { + *c = *a + *b; + }" + }, + { + "name": "llvm_foo_float_float", + "path": "llvm_foo_float_float.c", + "extra_flags": [] + }, + ], + "export_config": { + "symbols": [ + { + "python_name": "foo", + "symbol_name": "_Z3fooPdS_", + "signature": "void(double*, double*, double*)" + } + ] + } +}""" + class TestCLI(PixieTestCase): @@ -28,6 +54,41 @@ def test_pixie_cc_basic(self): self.assertEqual(files[0], cfile_name) self.assertTrue(files[1].startswith(testlib_name)) + def test_pixie_cc_config(self): + cfile_name = "test.c" + cfile_source = textwrap.dedent( + """ + int f(x) { + return x + 1; + } + """) + json_file_name = "config.json" + json_file_source = example_config + tu_cfile_name = "llvm_foo_float_float.c" + tu_cfile_source = textwrap.dedent( + """ + int foo(float* a, float* b, float* c) { *c = *a + *b; } + """) + with TemporaryDirectory(prefix=self.tmpdir.name) as tmpdir: + cfile_path = os.path.join(tmpdir, cfile_name) + with open(cfile_path, "wt") as f: + f.write(cfile_source) + json_file_path = os.path.join(tmpdir, json_file_name) + with open(json_file_path, "wt") as f: + f.write(json_file_source) + with open(os.path.join(tmpdir, tu_cfile_name), "wt") as f: + f.write(tu_cfile_source) + testlib_name = "testclib" + command = ["pixie-cc", cfile_name, "-g", "-O0", "-o", + testlib_name, "-C", json_file_name] + subprocess.run(command, check=True, cwd=tmpdir) + files = sorted(os.listdir(tmpdir)) + self.assertEqual(4, len(files)) + self.assertEqual(files[0], json_file_name) + self.assertEqual(files[1], tu_cfile_name) + self.assertEqual(files[2], cfile_name) + self.assertTrue(files[3].startswith(testlib_name)) + def test_pixie_cc_two_files(self): cfile1_name = "test1.c" cfile1_source = textwrap.dedent(