Last active
December 17, 2015 11:09
-
-
Save ahmadia/5600293 to your computer and use it in GitHub Desktop.
cmagic -- this is a very simple magic for compiling and importing C code with ctypes in IPython.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
"""C magic. | |
This is a very simple magic for compiling and importing C code with ctypes. | |
This derives from biteymagic.py, by Bradley Froehle: | |
https://gist.github.com/bfroehle/3458310 | |
You must provide the function names you would like exported. | |
Example usage: | |
>>> %%c foo | |
int foo(int x) | |
{ | |
return x*2; | |
} | |
>>> foo(4) | |
It doesn't do nearly as many interesting things as bitey, and could benefit | |
from integration with a parser such as: | |
https://bitbucket.org/eliben/pycparser | |
""" | |
#----------------------------------------------------------------------------- | |
# Copyright (C) 2013, Continuum Analytics | |
# | |
# Distributed under the terms of the Modified BSD License. | |
#----------------------------------------------------------------------------- | |
from __future__ import print_function | |
import ctypes | |
import imp | |
import io | |
import os | |
import pipes | |
import subprocess | |
import sys | |
from distutils.sysconfig import get_config_var, get_python_inc | |
try: | |
import hashlib | |
except ImportError: | |
import md5 as hashlib | |
from IPython.core.magic import Magics, magics_class, cell_magic | |
@magics_class | |
class CMagics(Magics): | |
"""Magics for C, a simple compile-and-import Tool""" | |
@cell_magic | |
def c(self, line, cell): | |
"""Compile single C function code and wrap/import using ctypes. | |
Usage, in cell mode:: | |
%%c <function names to export> | |
<C code> | |
The user is responsible for using ctypes to handle function calls. | |
""" | |
code = cell if cell.endswith('\n') else cell+'\n' | |
fun_names = line.split() | |
lib_dir = os.path.join(self.shell.ipython_dir, 'cmagic') | |
key = line, code, sys.version_info, sys.executable | |
if not os.path.exists(lib_dir): | |
os.makedirs(lib_dir) | |
module_name = "_c_magic_" + \ | |
hashlib.md5(str(key).encode('utf-8')).hexdigest() | |
c_name = module_name+'.c' | |
o_name = module_name+'.o' | |
# sorry Windows users :(, I don't know how to fix this default | |
lib_name = module_name + '.so' | |
c_path = os.path.join(lib_dir, c_name) | |
o_path = os.path.join(lib_dir, o_name) | |
lib_path = os.path.join(lib_dir, lib_name) | |
if not os.path.exists(c_path): | |
with io.open(c_path, 'w', encoding='utf-8') as f: | |
f.write(code) | |
if not os.path.exists(lib_path): | |
try: | |
startupinfo = None | |
if os.name == 'nt': | |
# Avoid a console window in Microsoft Windows. | |
startupinfo = subprocess.STARTUPINFO() | |
startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW | |
cc = get_config_var('CC') | |
cflags = get_config_var('CFLAGS') | |
ccshared = get_config_var('CCSHARED') | |
ldshared = get_config_var('LDSHARED') | |
python_inc = get_python_inc() | |
cmd = cc.split() + ['-c', '-I', python_inc] + \ | |
ccshared.split() + cflags.split() + [c_name] | |
subprocess.check_output(cmd, | |
stderr=subprocess.STDOUT, | |
cwd=lib_dir, | |
startupinfo=startupinfo) | |
cmd = ldshared.split() +['-o', lib_name, o_name] | |
subprocess.check_output(cmd, | |
stderr=subprocess.STDOUT, | |
cwd=lib_dir, | |
startupinfo=startupinfo) | |
except subprocess.CalledProcessError as e: | |
print(e.output, file=sys.stderr) | |
print("ERROR: command `%s` failed." % | |
' '.join(map(pipes.quote, e.cmd)), | |
file=sys.stderr) | |
return | |
lib = ctypes.CDLL(lib_path) | |
for fun_name in fun_names: | |
fun = getattr(lib, fun_name) | |
self.shell.push({fun_name:fun}) | |
_loaded = False | |
def load_ipython_extension(ip): | |
"""Load the extension in IPython.""" | |
global _loaded | |
if not _loaded: | |
ip.register_magics(CMagics) | |
_loaded = True |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment