WIP start runtime Python bindings.
Project: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/repo Commit: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/commit/2245230b Tree: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/tree/2245230b Diff: http://git-wip-us.apache.org/repos/asf/lucy-clownfish/diff/2245230b Branch: refs/heads/py_exp1 Commit: 2245230bc12aae3980c211f68096465cb42b283d Parents: f5f21ac Author: Marvin Humphrey <[email protected]> Authored: Tue Dec 16 16:30:56 2014 -0800 Committer: Marvin Humphrey <[email protected]> Committed: Tue Dec 16 16:30:56 2014 -0800 ---------------------------------------------------------------------- runtime/python/cfext/clownfish.c | 222 +++++++++++++++++++++++++++++ runtime/python/clownfish/_clownfish.c | 35 +++++ runtime/python/setup.py | 176 +++++++++++++++++++++++ 3 files changed, 433 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/2245230b/runtime/python/cfext/clownfish.c ---------------------------------------------------------------------- diff --git a/runtime/python/cfext/clownfish.c b/runtime/python/cfext/clownfish.c new file mode 100644 index 0000000..e631426 --- /dev/null +++ b/runtime/python/cfext/clownfish.c @@ -0,0 +1,222 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define CFISH_USE_SHORT_NAMES +#define C_CFISH_OBJ +#define C_CFISH_CLASS +#define C_CFISH_METHOD +#define C_CFISH_ERR +#define C_CFISH_LOCKFREEREGISTRY + +#include <stdio.h> +#include <stdlib.h> + +#include "charmony.h" + +#include "Clownfish/Obj.h" +#include "Clownfish/Class.h" +#include "Clownfish/Method.h" +#include "Clownfish/Err.h" +#include "Clownfish/Util/Memory.h" +#include "Clownfish/String.h" +#include "Clownfish/VArray.h" +#include "Clownfish/LockFreeRegistry.h" + +/******************************** Obj **************************************/ + +uint32_t +Obj_Get_RefCount_IMP(Obj *self) { + return self->refcount; +} + +Obj* +Obj_Inc_RefCount_IMP(Obj *self) { + self->refcount++; + return self; +} + +uint32_t +Obj_Dec_RefCount_IMP(Obj *self) { + uint32_t modified_refcount = INT32_MAX; + switch (self->refcount) { + case 0: + THROW(ERR, "Illegal refcount of 0"); + break; // useless + case 1: + modified_refcount = 0; + Obj_Destroy(self); + break; + default: + modified_refcount = --self->refcount; + break; + } + return modified_refcount; +} + +void* +Obj_To_Host_IMP(Obj *self) { + UNUSED_VAR(self); + THROW(ERR, "TODO"); + UNREACHABLE_RETURN(void*); +} + +/******************************* Class *************************************/ + +Obj* +Class_Make_Obj_IMP(Class *self) { + Obj *obj = (Obj*)Memory_wrapped_calloc(self->obj_alloc_size, 1); + obj->klass = self; + obj->refcount = 1; + return obj; +} + +Obj* +Class_Init_Obj_IMP(Class *self, void *allocation) { + Obj *obj = (Obj*)allocation; + obj->klass = self; + obj->refcount = 1; + return obj; +} + +Obj* +Class_Foster_Obj_IMP(Class *self, void *host_obj) { + UNUSED_VAR(self); + UNUSED_VAR(host_obj); + THROW(ERR, "TODO"); + UNREACHABLE_RETURN(Obj*); +} + +void +Class_register_with_host(Class *singleton, Class *parent) { + UNUSED_VAR(singleton); + UNUSED_VAR(parent); +} + +VArray* +Class_fresh_host_methods(String *class_name) { + UNUSED_VAR(class_name); + return VA_new(0); +} + +String* +Class_find_parent_class(String *class_name) { + UNUSED_VAR(class_name); + THROW(ERR, "TODO"); + UNREACHABLE_RETURN(String*); +} + +void* +Class_To_Host_IMP(Class *self) { + UNUSED_VAR(self); + THROW(ERR, "TODO"); + UNREACHABLE_RETURN(void*); +} + +/******************************* Method ************************************/ + +String* +Method_Host_Name_IMP(Method *self) { + return (String*)INCREF(self->name); +} + +/******************************** Err **************************************/ + +/* TODO: Thread safety */ +static Err *current_error; +static Err *thrown_error; +static jmp_buf *current_env; + +void +Err_init_class(void) { +} + +Err* +Err_get_error() { + return current_error; +} + +void +Err_set_error(Err *error) { + if (current_error) { + DECREF(current_error); + } + current_error = error; +} + +void +Err_do_throw(Err *error) { + if (current_env) { + thrown_error = error; + longjmp(*current_env, 1); + } + else { + String *message = Err_Get_Mess(error); + char *utf8 = Str_To_Utf8(message); + fprintf(stderr, "%s", utf8); + FREEMEM(utf8); + exit(EXIT_FAILURE); + } +} + +void* +Err_To_Host_IMP(Err *self) { + UNUSED_VAR(self); + THROW(ERR, "TODO"); + UNREACHABLE_RETURN(void*); +} + +void +Err_throw_mess(Class *klass, String *message) { + UNUSED_VAR(klass); + Err *err = Err_new(message); + Err_do_throw(err); +} + +void +Err_warn_mess(String *message) { + char *utf8 = Str_To_Utf8(message); + fprintf(stderr, "%s", utf8); + FREEMEM(utf8); + DECREF(message); +} + +Err* +Err_trap(Err_Attempt_t routine, void *context) { + jmp_buf env; + jmp_buf *prev_env = current_env; + current_env = &env; + + if (!setjmp(env)) { + routine(context); + } + + current_env = prev_env; + + Err *error = thrown_error; + thrown_error = NULL; + return error; +} + +/************************** LockFreeRegistry *******************************/ + +void* +LFReg_To_Host_IMP(LockFreeRegistry *self) { + UNUSED_VAR(self); + THROW(ERR, "TODO"); + UNREACHABLE_RETURN(void*); +} + + http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/2245230b/runtime/python/clownfish/_clownfish.c ---------------------------------------------------------------------- diff --git a/runtime/python/clownfish/_clownfish.c b/runtime/python/clownfish/_clownfish.c new file mode 100644 index 0000000..15d1873 --- /dev/null +++ b/runtime/python/clownfish/_clownfish.c @@ -0,0 +1,35 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Python.h" +#include "Clownfish/Obj.h" + +static PyModuleDef clownfish_module_def = { + PyModuleDef_HEAD_INIT, + "clownfish", + "Clownfish runtime", + -1, + NULL, NULL, NULL, NULL, NULL +}; + +PyMODINIT_FUNC +PyInit__clownfish(void) { + cfish_bootstrap_parcel(); + PyObject *cfc_module = PyModule_Create(&clownfish_module_def); + return cfc_module; +} + + http://git-wip-us.apache.org/repos/asf/lucy-clownfish/blob/2245230b/runtime/python/setup.py ---------------------------------------------------------------------- diff --git a/runtime/python/setup.py b/runtime/python/setup.py new file mode 100644 index 0000000..b5e2a35 --- /dev/null +++ b/runtime/python/setup.py @@ -0,0 +1,176 @@ +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You under the Apache License, Version 2.0 +# (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from distutils.core import setup, Extension +from distutils.command.build import build as _build +from distutils.command.clean import clean as _clean +from distutils.cmd import Command as _Command +from distutils.dep_util import newer_group +import distutils.ccompiler +import os +import glob +import platform +import re +import shutil +import subprocess +import sysconfig +import sys +import unittest + +def ext_build_dir(base): + """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(base, 'build', dirname) + +# Get a compiler object and and strings representing the compiler type and +# CFLAGS. +compiler = distutils.ccompiler.new_compiler() +cflags = sysconfig.get_config_var('CFLAGS') +compiler_type = distutils.ccompiler.get_default_compiler() + +# There's no public way to get a string representing the compiler executable +# 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)) +PARENT_DIR = os.path.abspath(os.pardir) +CORE_SOURCE_DIR = os.path.join(PARENT_DIR, 'src') +CFEXT_DIR = 'cfext' +COMMON_SOURCE_DIR = os.path.join(PARENT_DIR, 'common') +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' +LIBCLOWNFISH_NAME = 'libclownfish.a' # TODO portability +LIBCLOWNFISH_PATH = os.path.abspath(os.path.join(os.curdir, LIBCLOWNFISH_NAME)) +CFC_DIR = os.path.join(BASE_DIR, 'compiler', 'python') +CFC_BUILD_DIR = ext_build_dir(os.path.join(CFC_DIR)) + +c_filepaths = [os.path.join('clownfish', '_clownfish.c')] +paths_to_clean = [ + CHARMONIZER_EXE_PATH, + CHARMONY_H_PATH, + '_charm*', +] + +def _quotify(text): + text = text.replace('\\', '\\\\') + text = text.replace('"', '\\"') + return '"' + text + '"' + +class charmony(_Command): + description = "Build and run charmonizer" + user_options = [] + def initialize_options(self): + pass + def finalize_options(self): + pass + def run(self): + # Compile charmonizer. + if newer_group([CHARMONIZER_C], CHARMONIZER_EXE_PATH): + command = [compiler_name] + if compiler_type == 'msvc': + command.append('/Fe' + CHARMONIZER_EXE_PATH) + else: + command.extend(['-o', CHARMONIZER_EXE_PATH]) + command.append(CHARMONIZER_C) + print(" ".join(command)) + subprocess.check_call(command) + + # Run charmonizer. + if newer_group([CHARMONIZER_EXE_PATH], CHARMONY_H_PATH): + command = [ + CHARMONIZER_EXE_PATH, + '--cc=' + _quotify(compiler_name), + '--enable-c', + '--host=python', + '--enable-makefile', + '--', + cflags + ] + if 'CHARM_VALGRIND' in os.environ: + command[0:0] = "valgrind", "--leak-check=yes"; + print(" ".join(command)) + subprocess.check_call(command) + +class libclownfish(_Command): + description = "Build the Clownfish runtime core as a static archive." + user_options = [] + def initialize_options(self): + pass + def finalize_options(self): + pass + + def run(self): + self.run_command('charmony') + self.run_cfc() + subprocess.check_call([make_command, '-j', 'static']) + + def run_cfc(self): + from pprint import pprint + sys.path.append(CFC_DIR) + sys.path.append(CFC_BUILD_DIR) + pprint(sys.path) + import clownfish.cfc as cfc + hierarchy = cfc.model.Hierarchy(dest="autogen") + hierarchy.add_source_dir(CORE_SOURCE_DIR) + hierarchy.build() + +class my_clean(_clean): + def run(self): + _clean.run(self) + subprocess.check_call([make_command, 'distclean']) + for elem in paths_to_clean: + for path in glob.glob(elem): + print("removing " + path) + if os.path.isdir(path): + shutil.rmtree(path) + else: + os.unlink(path) + +class my_build(_build): + def run(self): + self.run_command('charmony') + self.run_command('libclownfish') + _build.run(self) + +clownfish_extension = Extension('clownfish._clownfish', + include_dirs = [ + CORE_SOURCE_DIR, + os.curdir, + ], + libraries = [LIBCLOWNFISH_PATH], + sources = c_filepaths) + +setup(name = 'clownfish', + version = '0.4.0', + description = 'Clownfish runtime', + author = 'Apache Lucy Project', + author_email = 'dev at lucy dot apache dot org', + url = 'http://lucy.apache.org', + packages = ['clownfish', + ], + cmdclass = { + 'build': my_build, + 'clean': my_clean, + 'charmony': charmony, + 'libclownfish': libclownfish, + }, + ext_modules = [clownfish_extension]) +
