def get_rsdl_compilation_info(): if sys.platform == 'darwin': eci = ExternalCompilationInfo( includes=[ 'SDL.h', #'Init.h', #'SDLMain.m' #'SDLMain.h'*/ ], include_dirs=[ '/Library/Frameworks/SDL.framework/Versions/A/Headers', #str(py.magic.autopath().dirpath().join('macosx-sdl-main')) ], link_extra=[ str(py.magic.autopath().dirpath().join( 'macosx-sdl-main/SDLMain.m')), #'macosx-sdl-main/SDLMain.m', '-I', '/Library/Frameworks/SDL.framework/Versions/A/Headers', ], frameworks=['SDL', 'Cocoa']) else: eci = ExternalCompilationInfo(includes=['SDL.h'], ) eci = eci.merge(ExternalCompilationInfo.from_config_tool('sdl-config')) return eci
def test_merge2(self): e1 = ExternalCompilationInfo(pre_include_bits=['1'], ) e2 = ExternalCompilationInfo(pre_include_bits=['2'], ) e3 = ExternalCompilationInfo(pre_include_bits=['3'], ) e = e1.merge(e2) e = e.merge(e3, e3) assert e.pre_include_bits == ('1', '2', '3')
def test_platforms(self): eci = ExternalCompilationInfo(platform='xxx') eci2 = ExternalCompilationInfo() assert eci != eci2 assert hash(eci) != hash(eci2) py.test.raises(Exception, eci2.merge, eci) assert eci.merge(eci).platform == 'xxx'
def llexternal_use_eci(compilation_info): """Return a dummy function that, if called in a RPython program, adds the given ExternalCompilationInfo to it.""" eci = ExternalCompilationInfo(post_include_bits=['#define PYPY_NO_OP()']) eci = eci.merge(compilation_info) return llexternal('PYPY_NO_OP', [], lltype.Void, compilation_info=eci, sandboxsafe=True, _nowrapper=True, _callable=lambda: None)
def get_eci(self): from distutils import sysconfig python_inc = sysconfig.get_python_inc() eci = ExternalCompilationInfo( include_dirs=[python_inc], includes=["Python.h", ], ) return eci.merge(CBuilder.get_eci(self))
def get_eci(self): from distutils import sysconfig python_inc = sysconfig.get_python_inc() eci = ExternalCompilationInfo( include_dirs=[python_inc], includes=[ "Python.h", ], ) return eci.merge(CBuilder.get_eci(self))
def test_merge(self): e1 = ExternalCompilationInfo(pre_include_bits=['1'], includes=['x.h'], post_include_bits=['p1']) e2 = ExternalCompilationInfo( pre_include_bits=['2'], includes=['x.h', 'y.h'], post_include_bits=['p2'], ) e3 = ExternalCompilationInfo(pre_include_bits=['3'], includes=['y.h', 'z.h'], post_include_bits=['p1', 'p3']) e = e1.merge(e2, e3) assert e.pre_include_bits == ('1', '2', '3') assert e.includes == ('x.h', 'y.h', 'z.h') assert e.post_include_bits == ('p1', 'p2', 'p3')
def get_rsdl_compilation_info(): if sys.platform == 'darwin': eci = ExternalCompilationInfo( includes = ['SDL.h'], include_dirs = ['/Library/Frameworks/SDL.framework/Headers'], link_files = [ str(py.magic.autopath().dirpath().join('macosx-sdl-main/SDLMain.m')), ], frameworks = ['SDL', 'Cocoa'] ) else: eci = ExternalCompilationInfo( includes=['SDL.h'], ) eci = eci.merge(ExternalCompilationInfo.from_config_tool('sdl-config')) return eci
def test_merge2(self): e1 = ExternalCompilationInfo( pre_include_bits = ['1'], link_files = ['1.c'] ) e2 = ExternalCompilationInfo( pre_include_bits = ['2'], link_files = ['1.c', '2.c'] ) e3 = ExternalCompilationInfo( pre_include_bits = ['3'], link_files = ['1.c', '2.c', '3.c'] ) e = e1.merge(e2) e = e.merge(e3, e3) assert e.pre_include_bits == ('1', '2', '3') assert e.link_files == ('1.c', '2.c', '3.c')
def test_platforms(self): from pypy.translator.platform import Platform class Maemo(Platform): def __init__(self, cc=None): self.cc = cc eci = ExternalCompilationInfo(platform=Maemo()) eci2 = ExternalCompilationInfo() assert eci != eci2 assert hash(eci) != hash(eci2) assert repr(eci) != repr(eci2) py.test.raises(Exception, eci2.merge, eci) assert eci.merge(eci).platform == Maemo() assert (ExternalCompilationInfo(platform=Maemo(cc='xxx')) != ExternalCompilationInfo(platform=Maemo(cc='yyy'))) assert (repr(ExternalCompilationInfo(platform=Maemo(cc='xxx'))) != repr(ExternalCompilationInfo(platform=Maemo(cc='yyy'))))
def test_merge(self): e1 = ExternalCompilationInfo( pre_include_bits = ['1'], includes = ['x.h'], post_include_bits = ['p1'] ) e2 = ExternalCompilationInfo( pre_include_bits = ['2'], includes = ['x.h', 'y.h'], post_include_bits = ['p2'], ) e3 = ExternalCompilationInfo( pre_include_bits = ['3'], includes = ['y.h', 'z.h'], post_include_bits = ['p1', 'p3'] ) e = e1.merge(e2, e3) assert e.pre_include_bits == ('1', '2', '3') assert e.includes == ('x.h', 'y.h', 'z.h') assert e.post_include_bits == ('p1', 'p2', 'p3')
def configure_external_library(name, eci, configurations, symbol=None, _cache={}): """try to find the external library. On Unix, this simply tests and returns the given eci. On Windows, various configurations may be tried to compile the given eci object. These configurations are a list of dicts, containing: - prefix: if an absolute path, will prefix each include and library directories. If a relative path, the external directory is searched for directories which names start with the prefix. The last one in alphabetical order chosen, and becomes the prefix. - include_dir: prefix + include_dir is added to the include directories - library_dir: prefix + library_dir is added to the library directories """ if sys.platform != 'win32': configurations = [] key = (name, eci) try: return _cache[key] except KeyError: last_error = None # Always try the default configuration if {} not in configurations: configurations.append({}) for configuration in configurations: prefix = configuration.get('prefix', '') include_dir = configuration.get('include_dir', '') library_dir = configuration.get('library_dir', '') if prefix and not os.path.isabs(prefix): import glob # XXX make this a global option? from pypy.tool.autopath import pypydir external_dir = py.path.local(pypydir).join('..', '..') entries = glob.glob(str(external_dir.join(prefix + '*'))) if entries: # Get last version prefix = sorted(entries)[-1] else: continue include_dir = os.path.join(prefix, include_dir) library_dir = os.path.join(prefix, library_dir) eci_lib = ExternalCompilationInfo( include_dirs=include_dir and [include_dir] or [], library_dirs=library_dir and [library_dir] or [], ) eci_lib = eci_lib.merge(eci) # verify that this eci can be compiled try: verify_eci(eci_lib) except CompilationError, e: last_error = e else: _cache[key] = eci_lib return eci_lib # Nothing found if last_error: raise last_error else: raise CompilationError("Library %s is not installed" % (name, ))
from pypy.rpython.lltypesystem import lltype, rffi from pypy.rpython.tool import rffi_platform as platform from pypy.translator.tool.cbuild import ExternalCompilationInfo from pypy.rlib.rsdl import RSDL eci = ExternalCompilationInfo( includes=['SDL_image.h'], libraries=['SDL_image'], ) eci = eci.merge(RSDL.eci) def external(name, args, result): return rffi.llexternal(name, args, result, compilation_info=eci) Load = external('IMG_Load', [rffi.CCHARP], RSDL.SurfacePtr)
class CBuilder(object): c_source_filename = None _compiled = False modulename = None def __init__(self, translator, entrypoint, config, gcpolicy=None): self.translator = translator self.entrypoint = entrypoint self.entrypoint_name = self.entrypoint.func_name self.originalentrypoint = entrypoint self.config = config self.gcpolicy = gcpolicy # for tests only, e.g. rpython/memory/ if gcpolicy is not None and gcpolicy.requires_stackless: config.translation.stackless = True self.eci = ExternalCompilationInfo() def build_database(self): translator = self.translator gcpolicyclass = self.get_gcpolicyclass() if self.config.translation.gcrootfinder == "asmgcc": if not self.standalone: raise NotImplementedError("--gcrootfinder=asmgcc requires standalone") if self.config.translation.stackless: if not self.standalone: raise Exception("stackless: only for stand-alone builds") from pypy.translator.stackless.transform import StacklessTransformer stacklesstransformer = StacklessTransformer( translator, self.originalentrypoint, stackless_gc=gcpolicyclass.requires_stackless) self.entrypoint = stacklesstransformer.slp_entry_point else: stacklesstransformer = None db = LowLevelDatabase(translator, standalone=self.standalone, gcpolicyclass=gcpolicyclass, stacklesstransformer=stacklesstransformer, thread_enabled=self.config.translation.thread, sandbox=self.config.translation.sandbox) self.db = db # give the gc a chance to register interest in the start-up functions it # need (we call this for its side-effects of db.get()) list(db.gcpolicy.gc_startup_code()) # build entrypoint and eventually other things to expose pf = self.getentrypointptr() pfname = db.get(pf) self.c_entrypoint_name = pfname db.complete() self.collect_compilation_info(db) return db have___thread = None def collect_compilation_info(self, db): # we need a concrete gcpolicy to do this self.eci = self.eci.merge(ExternalCompilationInfo( libraries=db.gcpolicy.gc_libraries())) all = [] for node in self.db.globalcontainers(): eci = getattr(node, 'compilation_info', None) if eci: all.append(eci) self.eci = self.eci.merge(*all) def get_gcpolicyclass(self): if self.gcpolicy is None: name = self.config.translation.gctransformer if self.config.translation.gcrootfinder == "stackless": name = "%s+stacklessgc" % (name,) elif self.config.translation.gcrootfinder == "llvmgc": name = "%s+llvmgcroot" % (name,) elif self.config.translation.gcrootfinder == "asmgcc": name = "%s+asmgcroot" % (name,) return gc.name_to_gcpolicy[name] return self.gcpolicy # use generate_source(defines=DEBUG_DEFINES) to force the #definition # of the macros that enable debugging assertions DEBUG_DEFINES = {'RPY_ASSERT': 1, 'RPY_LL_ASSERT': 1} def generate_source(self, db=None, defines={}): assert self.c_source_filename is None translator = self.translator if db is None: db = self.build_database() pf = self.getentrypointptr() pfname = db.get(pf) if self.modulename is None: self.modulename = uniquemodulename('testing') modulename = self.modulename targetdir = udir.ensure(modulename, dir=1) self.targetdir = targetdir defines = defines.copy() if self.config.translation.countmallocs: defines['COUNT_OP_MALLOCS'] = 1 if self.config.translation.sandbox: defines['RPY_SANDBOXED'] = 1 if CBuilder.have___thread is None: CBuilder.have___thread = check_under_under_thread() if not self.standalone: assert not self.config.translation.instrument cfile, extra = gen_source(db, modulename, targetdir, self.eci, defines = defines) else: if self.config.translation.instrument: defines['INSTRUMENT'] = 1 if CBuilder.have___thread: if not self.config.translation.no__thread: defines['USE___THREAD'] = 1 # explicitely include python.h and exceptions.h # XXX for now, we always include Python.h from distutils import sysconfig python_inc = sysconfig.get_python_inc() pypy_include_dir = autopath.this_dir self.eci = self.eci.merge(ExternalCompilationInfo( include_dirs=[python_inc, pypy_include_dir], )) cfile, extra = gen_source_standalone(db, modulename, targetdir, self.eci, entrypointname = pfname, defines = defines) self.c_source_filename = py.path.local(cfile) self.extrafiles = extra if self.standalone: self.gen_makefile(targetdir) return cfile def generate_graphs_for_llinterp(self, db=None): # prepare the graphs as when the source is generated, but without # actually generating the source. if db is None: db = self.build_database() graphs = db.all_graphs() db.gctransformer.prepare_inline_helpers(graphs) for node in db.containerlist: if isinstance(node, FuncNode): for funcgen in node.funcgens: funcgen.patch_graph(copy_graph=False) return db
def configure_external_library(name, eci, configurations, symbol=None, _cache={}): """try to find the external library. On Unix, this simply tests and returns the given eci. On Windows, various configurations may be tried to compile the given eci object. These configurations are a list of dicts, containing: - prefix: if an absolute path, will prefix each include and library directories. If a relative path, the external directory is searched for directories which names start with the prefix. The last one in alphabetical order chosen, and becomes the prefix. - include_dir: prefix + include_dir is added to the include directories - library_dir: prefix + library_dir is added to the library directories """ if sys.platform != 'win32': configurations = [] key = (name, eci) try: return _cache[key] except KeyError: last_error = None # Always try the default configuration if {} not in configurations: configurations.append({}) for configuration in configurations: prefix = configuration.get('prefix', '') include_dir = configuration.get('include_dir', '') library_dir = configuration.get('library_dir', '') if prefix and not os.path.isabs(prefix): import glob entries = glob.glob(str(PYPY_EXTERNAL_DIR.join(prefix + '*'))) if entries: # Get last version prefix = sorted(entries)[-1] else: continue include_dir = os.path.join(prefix, include_dir) library_dir = os.path.join(prefix, library_dir) eci_lib = ExternalCompilationInfo( include_dirs=include_dir and [include_dir] or [], library_dirs=library_dir and [library_dir] or [], ) eci_lib = eci_lib.merge(eci) # verify that this eci can be compiled try: verify_eci(eci_lib) except CompilationError, e: last_error = e else: _cache[key] = eci_lib return eci_lib # Nothing found if last_error: raise last_error else: raise CompilationError("Library %s is not installed" % (name,))
from pypy.rlib.rsdl import RSDL if sys.platform == 'darwin': eci = ExternalCompilationInfo( includes = ['SDL_mixer.h'], frameworks = ['SDL_mixer'], include_dirs = ['/Library/Frameworks/SDL_Mixer.framework/Headers'] ) else: eci = ExternalCompilationInfo( includes=['SDL_mixer.h'], libraries=['SDL_mixer'], ) eci = eci.merge(RSDL.eci) eci = eci.merge(eci) eci = eci.merge(eci) ChunkPtr = lltype.Ptr(lltype.ForwardReference()) class CConfig: _compilation_info_ = eci Chunk = platform.Struct('Mix_Chunk', [('allocated', rffi.INT), ('abuf', RSDL.Uint8P), ('alen', RSDL.Uint32), ('volume', RSDL.Uint8)]) globals().update(platform.configure(CConfig))
class GenLLVM(object): # see create_codewriter() below function_count = {} def __init__(self, translator, standalone): # reset counters Node.nodename_count = {} self.eci = ExternalCompilationInfo() self.standalone = standalone self.translator = translator self.config = translator.config def gen_source(self, func): self._checkpoint("before gen source") codewriter = self.setup(func) codewriter.header_comment("Extern code") codewriter.write_lines(self.llcode) codewriter.header_comment("Type declarations") for typ_decl in self.db.gettypedefnodes(): typ_decl.writetypedef(codewriter) codewriter.header_comment("Function prototypes") for node in self.db.getnodes(): if hasattr(node, 'writedecl'): node.writedecl(codewriter) codewriter.header_comment("Prebuilt constants") for node in self.db.getnodes(): # XXX tmp if hasattr(node, "writeglobalconstants"): node.writeglobalconstants(codewriter) self._checkpoint("before definitions") codewriter.header_comment('Suppport definitions') codewriter.write_lines(extfunctions, patch=True) codewriter.header_comment('Startup definition') self.write_startup_impl(codewriter) codewriter.header_comment("Function definitions") for node in self.db.getnodes(): if hasattr(node, 'writeimpl'): node.writeimpl(codewriter) self._debug(codewriter) codewriter.comment("End of file") codewriter.close() self._checkpoint('done') return self.filename def setup(self, func): """ setup all nodes create c file for externs create ll file for c file create codewriter """ if self.standalone: func = augment_entrypoint(self.translator, func) # XXX please dont ask! from pypy.translator.c.genc import CStandaloneBuilder cbuild = CStandaloneBuilder(self.translator, func, config=self.config) c_db = cbuild.generate_graphs_for_llinterp() self.db = Database(self, self.translator) self.db.gcpolicy = GcPolicy.new(self.db, self.config) self.db.gctransformer = c_db.gctransformer # get entry point entry_point = self.get_entry_point(func) self._checkpoint('get_entry_point') # set up all nodes self.db.setup_all() self.entrynode = self.db.set_entrynode(entry_point) self._checkpoint('setup_all all nodes') # set up externs nodes self.setup_externs(c_db, self.db) self.db.setup_all() self._checkpoint('setup_all externs') self._print_node_stats() # open file & create codewriter codewriter, self.filename = self.create_codewriter() self._checkpoint('open file and create codewriter') # create ll file from c code self.generate_ll_externs(codewriter) return codewriter def setup_externs(self, c_db, db): # XXX this should be done via augmenting entrypoint exctransformer = c_db.exctransformer for obj in [ exctransformer.rpyexc_occured_ptr.value, exctransformer.rpyexc_fetch_type_ptr.value, exctransformer.rpyexc_clear_ptr.value ]: db.prepare_constant(lltype.typeOf(obj), obj) def get_entry_point(self, func): assert func is not None self.entrypoint = func bk = self.translator.annotator.bookkeeper ptr = getfunctionptr(bk.getdesc(func).getuniquegraph()) c = inputconst(lltype.typeOf(ptr), ptr) self.db.prepare_arg(c) # ensure unqiue entry node name for testing entry_node = self.db.obj2node[c.value._obj] name = entry_node.name if name in self.function_count: self.function_count[name] += 1 Node.nodename_count[name] = self.function_count[name] + 1 name += '_%d' % self.function_count[name] entry_node.name = name else: self.function_count[name] = 1 self.entry_name = name[6:] return c.value._obj def generate_ll_externs(self, codewriter): all = [] for node in self.db.getnodes(): eci = getattr(node, 'compilation_info', None) if eci: all.append(eci) self.eci = self.eci.merge(*all) ccode = generate_c(self.db, self.entrynode, self.eci, self.standalone) self.llcode = generate_ll(ccode, self.eci) self.eci = self.eci.convert_sources_to_files(being_main=True) def create_codewriter(self): # prevent running the same function twice in a test filename = udir.join(self.entry_name).new(ext='.ll') f = open(str(filename), 'w') if self.standalone: return CodeWriter(f, self.db), filename else: return CodeWriter(f, self.db, linkage=''), filename def write_startup_impl(self, codewriter): open_decl = "i8* @LLVM_RPython_StartupCode()" codewriter.openfunc(open_decl) for node in self.db.getnodes(): node.writesetupcode(codewriter) codewriter.ret("i8*", "null") codewriter.closefunc() def compile_module(self): assert not self.standalone modname, dirpath = buildllvm.Builder(self).make_module() mod, wrap_fun = self.get_module(modname, dirpath) return mod, wrap_fun def get_module(self, modname, dirpath): if self.config.translation.llvm.isolate: mod = Isolate((dirpath, modname)) else: from pypy.translator.tool.cbuild import import_module_from_directory mod = import_module_from_directory(dirpath, modname) wrap_fun = getattr(mod, 'entrypoint') return mod, wrap_fun def compile_standalone(self, exe_name): assert self.standalone return buildllvm.Builder(self).make_standalone(exe_name) def _checkpoint(self, msg=None): if not self.config.translation.llvm.logging: return if msg: t = (time.time() - self.starttime) log('\t%s took %02dm%02ds' % (msg, t / 60, t % 60)) else: log('GenLLVM:') self.starttime = time.time() def _print_node_stats(self): # disable node stats output if not self.config.translation.llvm.logging: return nodecount = {} for node in self.db.getnodes(): typ = type(node) try: nodecount[typ] += 1 except: nodecount[typ] = 1 stats = [(count, str(typ)) for typ, count in nodecount.iteritems()] stats.sort() for s in stats: log('STATS %s' % str(s)) def _debug(self, codewriter): if self.config.translation.llvm.debug: if self.db.debugstringnodes: codewriter.header_comment("Debug string") for node in self.db.debugstringnodes: node.writeglobalconstants(codewriter) print "Start" print self.db.dump_pbcs() print "End"