commit
1db6aa1f6e
@ -0,0 +1,7 @@ |
||||
.ipynb_checkpoints |
||||
.ccls-cache |
||||
build |
||||
pbm_modules |
||||
*.pyc |
||||
__pycache__ |
||||
pybind11 |
@ -0,0 +1,40 @@ |
||||
# pybindmagic |
||||
|
||||
An IPython kernel magic library. After `import pybindmagic` you can use the cell magic `%%cpp` |
||||
|
||||
In this cell you can write cpp code. |
||||
|
||||
## Requirements |
||||
|
||||
* pybind11 |
||||
* git |
||||
* gcc |
||||
* cmake (optional) |
||||
|
||||
## TODOS |
||||
|
||||
* [ ] add options for cmake flags |
||||
* [ ] add other compilers |
||||
* [ ] Better exception handling |
||||
* [ ] Better debugging output |
||||
|
||||
## Options |
||||
|
||||
### defs |
||||
|
||||
You need to specify all functions or classes you want to expose to python. Either by `%%cpp -f funcname` or by pybind11 syntax at the end of the cell. There is a shortcut by inserting a `defs` in the end of the cell that will add the correct module name. For an example take a look at the example notebook. |
||||
|
||||
### Compiler |
||||
|
||||
Currently only gcc is supported. The default compiler command is `c++`. You can change the compiler command with: |
||||
`pybindmagic.compiler_cmd = "gcc"` |
||||
|
||||
|
||||
### CMake |
||||
|
||||
With `%%cpp -c path/to/folder/with/CMakeList.txt/in` you can specify cmake compilation. After evaluation pybind11 will be downloaded and moved to this folder, a build folder is generated and the cell is compiled in this folder. |
||||
Makesure that you add pybind11 to your cmake file. |
||||
|
||||
### rebuild |
||||
|
||||
With the `%cpp -rebuild` flag you can enforce a complete rebuild. |
@ -0,0 +1 @@ |
||||
libigl |
@ -0,0 +1,132 @@ |
||||
import pybindmagic |
||||
import os |
||||
os.environ["PATH"] = "/home/ugo/anaconda3/bin" + os.pathsep + os.environ["PATH"] |
||||
|
||||
#%% |
||||
%%cpp -f generateMesh |
||||
#include <pybind11/eigen.h> |
||||
std::tuple<Eigen::MatrixXd,Eigen::MatrixXi> generateMesh() |
||||
{ |
||||
// Inline mesh of a cube |
||||
const Eigen::MatrixXd V = (Eigen::MatrixXd(8,3)<< |
||||
0.0,0.0,0.0, |
||||
0.0,0.0,1.0, |
||||
0.0,1.0,0.0, |
||||
0.0,1.0,1.0, |
||||
1.0,0.0,0.0, |
||||
1.0,0.0,1.0, |
||||
1.0,1.0,0.0, |
||||
1.0,1.0,1.0).finished(); |
||||
const Eigen::MatrixXi F = (Eigen::MatrixXi(12,3)<< |
||||
1,7,5, |
||||
1,3,7, |
||||
1,4,3, |
||||
1,2,4, |
||||
3,8,7, |
||||
3,4,8, |
||||
5,7,8, |
||||
5,8,6, |
||||
1,5,6, |
||||
1,6,2, |
||||
2,6,8, |
||||
2,8,4).finished().array()-1; |
||||
return std::make_tuple(V,F); |
||||
} |
||||
#%% |
||||
|
||||
V,F = generateMesh() |
||||
print("Vertices:\n",V) |
||||
print("Faces:\n",F) |
||||
|
||||
#%% |
||||
%%cpp |
||||
#include <pybind11/eigen.h> |
||||
|
||||
|
||||
std::tuple<Eigen::MatrixXd,Eigen::MatrixXi> generateMesh() |
||||
{ |
||||
// Inline mesh of a cube |
||||
const Eigen::MatrixXd V = (Eigen::MatrixXd(8,3)<< |
||||
0.0,0.0,0.0, |
||||
0.0,0.0,1.0, |
||||
0.0,1.0,0.0, |
||||
0.0,1.0,1.0, |
||||
1.0,0.0,0.0, |
||||
1.0,0.0,1.0, |
||||
1.0,1.0,0.0, |
||||
1.0,1.0,1.0).finished(); |
||||
const Eigen::MatrixXi F = (Eigen::MatrixXi(12,3)<< |
||||
1,7,5, |
||||
1,3,7, |
||||
1,4,3, |
||||
1,2,4, |
||||
3,8,7, |
||||
3,4,8, |
||||
5,7,8, |
||||
5,8,6, |
||||
1,5,6, |
||||
1,6,2, |
||||
2,6,8, |
||||
2,8,4).finished().array()-1; |
||||
return std::make_tuple(V,F); |
||||
} |
||||
|
||||
void printMesh(Eigen::MatrixXd V,Eigen::MatrixXi F) |
||||
{ |
||||
py::print("Vertices:\n", V); |
||||
py::print("Faces:\n", F); |
||||
} |
||||
|
||||
defs |
||||
m.def("generateMesh",&generateMesh); |
||||
m.def("printMesh",&printMesh); |
||||
#%% |
||||
|
||||
printMesh(*generateMesh()) |
||||
|
||||
#%% |
||||
%%cpp -c pathtocmake -f viewMesh |
||||
|
||||
#include <igl/opengl/glfw/Viewer.h> |
||||
#include <pybind11/eigen.h> |
||||
|
||||
|
||||
void viewMesh(Eigen::Matrix<double, Eigen::Dynamic, 3> V, Eigen::Matrix<int, Eigen::Dynamic, 3> F) |
||||
{ |
||||
// Plot the mesh |
||||
igl::opengl::glfw::Viewer viewer; |
||||
viewer.data().set_mesh(V, F); |
||||
viewer.data().set_face_based(true); |
||||
viewer.launch(); |
||||
} |
||||
#%% |
||||
|
||||
import numpy as np |
||||
|
||||
V = np.array([ |
||||
[0.0,0.0,0.0], |
||||
[0.0,0.0,1.0], |
||||
[0.0,1.0,0.0], |
||||
[0.0,1.0,1.0], |
||||
[1.0,0.0,0.0], |
||||
[1.0,0.0,1.0], |
||||
[1.0,1.0,0.0], |
||||
[1.0,1.0,1.0]]) |
||||
|
||||
F = np.array( |
||||
[ |
||||
[1,7,5], |
||||
[1,3,7], |
||||
[1,4,3], |
||||
[1,2,4], |
||||
[3,8,7], |
||||
[3,4,8], |
||||
[5,7,8], |
||||
[5,8,6], |
||||
[1,5,6], |
||||
[1,6,2], |
||||
[2,6,8], |
||||
[2,8,4] |
||||
], dtype=np.int32)-1 |
||||
|
||||
viewMesh(V,F) |
@ -0,0 +1,21 @@ |
||||
cmake_minimum_required(VERSION 3.1) |
||||
|
||||
project({name} LANGUAGES CXX) |
||||
|
||||
find_package(Python COMPONENTS Interpreter Development REQUIRED) |
||||
add_subdirectory(pybind11) |
||||
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) |
||||
|
||||
# libigl |
||||
option(LIBIGL_WITH_OPENGL "Use OpenGL" ON) |
||||
option(LIBIGL_WITH_OPENGL_GLFW "Use GLFW" ON) |
||||
|
||||
find_package(LIBIGL REQUIRED QUIET) |
||||
|
||||
# Add your project files |
||||
file(GLOB SRCFILES *.cpp) |
||||
# add_executable(${PROJECT_NAME} ${SRCFILES}) |
||||
pybind11_add_module(${PROJECT_NAME} ${SRCFILES}) |
||||
target_link_libraries(${PROJECT_NAME} PRIVATE igl::core igl::opengl_glfw) |
@ -0,0 +1,34 @@ |
||||
# - Try to find the LIBIGL library |
||||
# Once done this will define |
||||
# |
||||
# LIBIGL_FOUND - system has LIBIGL |
||||
# LIBIGL_INCLUDE_DIR - **the** LIBIGL include directory |
||||
if(LIBIGL_FOUND) |
||||
return() |
||||
endif() |
||||
|
||||
find_path(LIBIGL_INCLUDE_DIR igl/readOBJ.h |
||||
HINTS |
||||
${LIBIGL_DIR} |
||||
ENV LIBIGL_DIR |
||||
PATHS |
||||
${CMAKE_SOURCE_DIR}/../.. |
||||
${CMAKE_SOURCE_DIR}/.. |
||||
${CMAKE_SOURCE_DIR} |
||||
${CMAKE_SOURCE_DIR}/libigl |
||||
${CMAKE_SOURCE_DIR}/../libigl |
||||
${CMAKE_SOURCE_DIR}/../../libigl |
||||
/usr |
||||
/usr/local |
||||
/usr/local/igl/libigl |
||||
PATH_SUFFIXES include |
||||
) |
||||
|
||||
include(FindPackageHandleStandardArgs) |
||||
find_package_handle_standard_args(LIBIGL |
||||
"\nlibigl not found --- You can download it using:\n\tgit clone https://github.com/libigl/libigl.git ${CMAKE_SOURCE_DIR}/../libigl" |
||||
LIBIGL_INCLUDE_DIR) |
||||
mark_as_advanced(LIBIGL_INCLUDE_DIR) |
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${LIBIGL_INCLUDE_DIR}/../cmake") |
||||
include(libigl) |
@ -0,0 +1,409 @@ |
||||
{ |
||||
"cells": [ |
||||
{ |
||||
"cell_type": "code", |
||||
"execution_count": 1, |
||||
"metadata": {}, |
||||
"outputs": [], |
||||
"source": [ |
||||
"import pybindmagic" |
||||
] |
||||
}, |
||||
{ |
||||
"cell_type": "code", |
||||
"execution_count": 2, |
||||
"metadata": {}, |
||||
"outputs": [], |
||||
"source": [ |
||||
"%%cpp -f generateMesh\n", |
||||
"#include <pybind11/eigen.h>\n", |
||||
"\n", |
||||
"\n", |
||||
"std::tuple<Eigen::MatrixXd,Eigen::MatrixXi> generateMesh()\n", |
||||
"{\n", |
||||
" // Inline mesh of a cube\n", |
||||
" const Eigen::MatrixXd V = (Eigen::MatrixXd(8,3)<<\n", |
||||
" 0.0,0.0,0.0,\n", |
||||
" 0.0,0.0,1.0,\n", |
||||
" 0.0,1.0,0.0,\n", |
||||
" 0.0,1.0,1.0,\n", |
||||
" 1.0,0.0,0.0,\n", |
||||
" 1.0,0.0,1.0,\n", |
||||
" 1.0,1.0,0.0,\n", |
||||
" 1.0,1.0,1.0).finished();\n", |
||||
" const Eigen::MatrixXi F = (Eigen::MatrixXi(12,3)<<\n", |
||||
" 1,7,5,\n", |
||||
" 1,3,7,\n", |
||||
" 1,4,3,\n", |
||||
" 1,2,4,\n", |
||||
" 3,8,7,\n", |
||||
" 3,4,8,\n", |
||||
" 5,7,8,\n", |
||||
" 5,8,6,\n", |
||||
" 1,5,6,\n", |
||||
" 1,6,2,\n", |
||||
" 2,6,8,\n", |
||||
" 2,8,4).finished().array()-1;\n", |
||||
" return std::make_tuple(V,F);\n", |
||||
"}" |
||||
] |
||||
}, |
||||
{ |
||||
"cell_type": "code", |
||||
"execution_count": 3, |
||||
"metadata": {}, |
||||
"outputs": [ |
||||
{ |
||||
"name": "stdout", |
||||
"output_type": "stream", |
||||
"text": [ |
||||
"Vertices:\n", |
||||
" [[0. 0. 0.]\n", |
||||
" [0. 0. 1.]\n", |
||||
" [0. 1. 0.]\n", |
||||
" [0. 1. 1.]\n", |
||||
" [1. 0. 0.]\n", |
||||
" [1. 0. 1.]\n", |
||||
" [1. 1. 0.]\n", |
||||
" [1. 1. 1.]]\n", |
||||
"Faces:\n", |
||||
" [[0 6 4]\n", |
||||
" [0 2 6]\n", |
||||
" [0 3 2]\n", |
||||
" [0 1 3]\n", |
||||
" [2 7 6]\n", |
||||
" [2 3 7]\n", |
||||
" [4 6 7]\n", |
||||
" [4 7 5]\n", |
||||
" [0 4 5]\n", |
||||
" [0 5 1]\n", |
||||
" [1 5 7]\n", |
||||
" [1 7 3]]\n" |
||||
] |
||||
} |
||||
], |
||||
"source": [ |
||||
"V,F = generateMesh()\n", |
||||
"print(\"Vertices:\\n\",V)\n", |
||||
"print(\"Faces:\\n\",F)" |
||||
] |
||||
}, |
||||
{ |
||||
"cell_type": "code", |
||||
"execution_count": 4, |
||||
"metadata": {}, |
||||
"outputs": [], |
||||
"source": [ |
||||
"%%cpp\n", |
||||
"#include <pybind11/eigen.h>\n", |
||||
"\n", |
||||
"\n", |
||||
"std::tuple<Eigen::MatrixXd,Eigen::MatrixXi> generateMesh()\n", |
||||
"{\n", |
||||
" // Inline mesh of a cube\n", |
||||
" const Eigen::MatrixXd V = (Eigen::MatrixXd(8,3)<<\n", |
||||
" 0.0,0.0,0.0,\n", |
||||
" 0.0,0.0,1.0,\n", |
||||
" 0.0,1.0,0.0,\n", |
||||
" 0.0,1.0,1.0,\n", |
||||
" 1.0,0.0,0.0,\n", |
||||
" 1.0,0.0,1.0,\n", |
||||
" 1.0,1.0,0.0,\n", |
||||
" 1.0,1.0,1.0).finished();\n", |
||||
" const Eigen::MatrixXi F = (Eigen::MatrixXi(12,3)<<\n", |
||||
" 1,7,5,\n", |
||||
" 1,3,7,\n", |
||||
" 1,4,3,\n", |
||||
" 1,2,4,\n", |
||||
" 3,8,7,\n", |
||||
" 3,4,8,\n", |
||||
" 5,7,8,\n", |
||||
" 5,8,6,\n", |
||||
" 1,5,6,\n", |
||||
" 1,6,2,\n", |
||||
" 2,6,8,\n", |
||||
" 2,8,4).finished().array()-1;\n", |
||||
" return std::make_tuple(V,F);\n", |
||||
"}\n", |
||||
"\n", |
||||
"void printMesh(Eigen::MatrixXd V,Eigen::MatrixXi F)\n", |
||||
"{\n", |
||||
" py::print(\"Vertices:\\n\", V);\n", |
||||
" py::print(\"Faces:\\n\", F);\n", |
||||
"}\n", |
||||
"\n", |
||||
"defs\n", |
||||
" m.def(\"generateMesh\",&generateMesh);\n", |
||||
" m.def(\"printMesh\",&printMesh);" |
||||
] |
||||
}, |
||||
{ |
||||
"cell_type": "code", |
||||
"execution_count": 5, |
||||
"metadata": {}, |
||||
"outputs": [ |
||||
{ |
||||
"name": "stdout", |
||||
"output_type": "stream", |
||||
"text": [ |
||||
"Vertices:\n", |
||||
" [[0. 0. 0.]\n", |
||||
" [0. 0. 1.]\n", |
||||
" [0. 1. 0.]\n", |
||||
" [0. 1. 1.]\n", |
||||
" [1. 0. 0.]\n", |
||||
" [1. 0. 1.]\n", |
||||
" [1. 1. 0.]\n", |
||||
" [1. 1. 1.]]\n", |
||||
"Faces:\n", |
||||
" [[0 6 4]\n", |
||||
" [0 2 6]\n", |
||||
" [0 3 2]\n", |
||||
" [0 1 3]\n", |
||||
" [2 7 6]\n", |
||||
" [2 3 7]\n", |
||||
" [4 6 7]\n", |
||||
" [4 7 5]\n", |
||||
" [0 4 5]\n", |
||||
" [0 5 1]\n", |
||||
" [1 5 7]\n", |
||||
" [1 7 3]]\n" |
||||
] |
||||
} |
||||
], |
||||
"source": [ |
||||
"printMesh(*generateMesh())" |
||||
] |
||||
}, |
||||
{ |
||||
"cell_type": "markdown", |
||||
"metadata": {}, |
||||
"source": [ |
||||
"# CMAKE example\n", |
||||
"\n", |
||||
"Take a look at _pathtocmake/CMAKEList.txt_. Its a template cmake file. Make sure that the following lines are present:\n", |
||||
"\n", |
||||
"```\n", |
||||
"project({name} LANGUAGES CXX)\n", |
||||
"\n", |
||||
"find_package(Python COMPONENTS Interpreter Development REQUIRED)\n", |
||||
"add_subdirectory(pybind11)\n", |
||||
"pybind11_add_module(${PROJECT_NAME} ${SRCFILES})\n", |
||||
"```\n", |
||||
"\n", |
||||
"This example needs libigl in the pathtocmake folder. Clone it using:\n", |
||||
"\n", |
||||
"`git clone https://github.com/libigl/libigl.git`" |
||||
] |
||||
}, |
||||
{ |
||||
"cell_type": "code", |
||||
"execution_count": 7, |
||||
"metadata": {}, |
||||
"outputs": [ |
||||
{ |
||||
"name": "stdout", |
||||
"output_type": "stream", |
||||
"text": [ |
||||
"cmake:\n", |
||||
"-- The CXX compiler identification is GNU 9.3.0\n", |
||||
"-- Check for working CXX compiler: /usr/bin/c++\n", |
||||
"-- Check for working CXX compiler: /usr/bin/c++ -- works\n", |
||||
"-- Detecting CXX compiler ABI info\n", |
||||
"-- Detecting CXX compiler ABI info - done\n", |
||||
"-- Detecting CXX compile features\n", |
||||
"-- Detecting CXX compile features - done\n", |
||||
"-- Found Python: /home/ugo/anaconda3/bin/python3.7 (found version \"3.7.6\") found components: Interpreter Development \n", |
||||
"-- pybind11 v2.6.3 dev1\n", |
||||
"-- Performing Test HAS_FLTO\n", |
||||
"-- Performing Test HAS_FLTO - Success\n", |
||||
"-- Looking for C++ include pthread.h\n", |
||||
"-- Looking for C++ include pthread.h - found\n", |
||||
"-- Performing Test CMAKE_HAVE_LIBC_PTHREAD\n", |
||||
"-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Failed\n", |
||||
"-- Looking for pthread_create in pthreads\n", |
||||
"-- Looking for pthread_create in pthreads - not found\n", |
||||
"-- Looking for pthread_create in pthread\n", |
||||
"-- Looking for pthread_create in pthread - found\n", |
||||
"-- Found Threads: TRUE \n", |
||||
"-- Creating target: igl::core (igl)\n", |
||||
"-- Creating target: igl::opengl (igl_opengl)\n", |
||||
"-- Found OpenGL: /usr/lib/x86_64-linux-gnu/libOpenGL.so found components: OpenGL \n", |
||||
"-- The C compiler identification is GNU 9.3.0\n", |
||||
"-- Check for working C compiler: /usr/bin/cc\n", |
||||
"-- Check for working C compiler: /usr/bin/cc -- works\n", |
||||
"-- Detecting C compiler ABI info\n", |
||||
"-- Detecting C compiler ABI info - done\n", |
||||
"-- Detecting C compile features\n", |
||||
"-- Detecting C compile features - done\n", |
||||
"-- Creating target: igl::opengl_glfw (igl_opengl_glfw)\n", |
||||
"-- Using X11 for window creation\n", |
||||
"-- Found X11: /usr/include \n", |
||||
"-- Looking for XOpenDisplay in /usr/lib/x86_64-linux-gnu/libX11.so;/usr/lib/x86_64-linux-gnu/libXext.so\n", |
||||
"-- Looking for XOpenDisplay in /usr/lib/x86_64-linux-gnu/libX11.so;/usr/lib/x86_64-linux-gnu/libXext.so - found\n", |
||||
"-- Looking for gethostbyname\n", |
||||
"-- Looking for gethostbyname - found\n", |
||||
"-- Looking for connect\n", |
||||
"-- Looking for connect - found\n", |
||||
"-- Looking for remove\n", |
||||
"-- Looking for remove - found\n", |
||||
"-- Looking for shmat\n", |
||||
"-- Looking for shmat - found\n", |
||||
"-- Looking for IceConnectionNumber in ICE\n", |
||||
"-- Looking for IceConnectionNumber in ICE - found\n", |
||||
"-- Configuring done\n", |
||||
"-- Generating done\n", |
||||
"-- Build files have been written to: /home/ugo/work/pybindipynb/examples/pathtocmake/build\n", |
||||
"\n", |
||||
"make:\n", |
||||
"Scanning dependencies of target glad\n", |
||||
"[ 4%] Building C object glad/CMakeFiles/glad.dir/src/glad.c.o\n", |
||||
"[ 9%] Linking C static library libglad.a\n", |
||||
"[ 9%] Built target glad\n", |
||||
"Scanning dependencies of target glfw\n", |
||||
"[ 14%] Building C object glfw/src/CMakeFiles/glfw.dir/context.c.o\n", |
||||
"[ 19%] Building C object glfw/src/CMakeFiles/glfw.dir/init.c.o\n", |
||||
"[ 23%] Building C object glfw/src/CMakeFiles/glfw.dir/input.c.o\n", |
||||
"[ 28%] Building C object glfw/src/CMakeFiles/glfw.dir/monitor.c.o\n", |
||||
"[ 33%] Building C object glfw/src/CMakeFiles/glfw.dir/vulkan.c.o\n", |
||||
"[ 38%] Building C object glfw/src/CMakeFiles/glfw.dir/window.c.o\n", |
||||
"[ 42%] Building C object glfw/src/CMakeFiles/glfw.dir/x11_init.c.o\n", |
||||
"[ 47%] Building C object glfw/src/CMakeFiles/glfw.dir/x11_monitor.c.o\n", |
||||
"[ 52%] Building C object glfw/src/CMakeFiles/glfw.dir/x11_window.c.o\n", |
||||
"[ 57%] Building C object glfw/src/CMakeFiles/glfw.dir/xkb_unicode.c.o\n", |
||||
"[ 61%] Building C object glfw/src/CMakeFiles/glfw.dir/posix_time.c.o\n", |
||||
"[ 66%] Building C object glfw/src/CMakeFiles/glfw.dir/posix_thread.c.o\n", |
||||
"[ 71%] Building C object glfw/src/CMakeFiles/glfw.dir/glx_context.c.o\n", |
||||
"[ 76%] Building C object glfw/src/CMakeFiles/glfw.dir/egl_context.c.o\n", |
||||
"[ 80%] Building C object glfw/src/CMakeFiles/glfw.dir/osmesa_context.c.o\n", |
||||
"[ 85%] Building C object glfw/src/CMakeFiles/glfw.dir/linux_joystick.c.o\n", |
||||
"[ 90%] Linking C static library libglfw3.a\n", |
||||
"[ 90%] Built target glfw\n", |
||||
"Scanning dependencies of target cpp_magic_5329071abe\n", |
||||
"[ 95%] Building CXX object CMakeFiles/cpp_magic_5329071abe.dir/cpp_magic_5329071abe.cpp.o\n", |
||||
"[100%] Linking CXX shared module cpp_magic_5329071abe.cpython-37m-x86_64-linux-gnu.so\n", |
||||
"[100%] Built target cpp_magic_5329071abe\n", |
||||
"\n" |
||||
] |
||||
} |
||||
], |
||||
"source": [ |
||||
"%%cpp -c pathtocmake -f viewMesh -rebuild\n", |
||||
"\n", |
||||
"#include <igl/opengl/glfw/Viewer.h>\n", |
||||
"#include <pybind11/eigen.h>\n", |
||||
"\n", |
||||
"\n", |
||||
"void viewMesh(Eigen::Matrix<double, Eigen::Dynamic, 3> V, Eigen::Matrix<int, Eigen::Dynamic, 3> F)\n", |
||||
"{\n", |
||||
" // Plot the mesh\n", |
||||
" igl::opengl::glfw::Viewer viewer;\n", |
||||
" viewer.data().set_mesh(V, F);\n", |
||||
" viewer.data().set_face_based(true);\n", |
||||
" viewer.launch();\n", |
||||
"}" |
||||
] |
||||
}, |
||||
{ |
||||
"cell_type": "code", |
||||
"execution_count": 5, |
||||
"metadata": {}, |
||||
"outputs": [ |
||||
{ |
||||
"ename": "ImportError", |
||||
"evalue": "dynamic module does not define module export function (PyInit_cpp_magic_f96b7fce74)", |
||||
"output_type": "error", |
||||
"traceback": [ |
||||
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", |
||||
"\u001b[0;31mImportError\u001b[0m Traceback (most recent call last)", |
||||
"\u001b[0;32m<ipython-input-5-d51271ddbf06>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mimport\u001b[0m \u001b[0mcpp_magic_f96b7fce74\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0;31m#viewMesh(V,F)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", |
||||
"\u001b[0;31mImportError\u001b[0m: dynamic module does not define module export function (PyInit_cpp_magic_f96b7fce74)" |
||||
] |
||||
} |
||||
], |
||||
"source": [ |
||||
"import cpp_magic_f96b7fce74\n", |
||||
"#viewMesh(V,F)" |
||||
] |
||||
}, |
||||
{ |
||||
"cell_type": "code", |
||||
"execution_count": 11, |
||||
"metadata": {}, |
||||
"outputs": [], |
||||
"source": [ |
||||
"import numpy as np\n", |
||||
"\n", |
||||
"V = np.array([\n", |
||||
" [0.0,0.0,0.0],\n", |
||||
" [0.0,0.0,1.0],\n", |
||||
" [0.0,1.0,0.0],\n", |
||||
" [0.0,1.0,1.0],\n", |
||||
" [1.0,0.0,0.0],\n", |
||||
" [1.0,0.0,1.0],\n", |
||||
" [1.0,1.0,0.0],\n", |
||||
" [1.0,1.0,1.0]])\n", |
||||
"\n", |
||||
"F = np.array(\n", |
||||
" [\n", |
||||
" [1,7,5],\n", |
||||
" [1,3,7],\n", |
||||
" [1,4,3],\n", |
||||
" [1,2,4],\n", |
||||
" [3,8,7],\n", |
||||
" [3,4,8],\n", |
||||
" [5,7,8],\n", |
||||
" [5,8,6],\n", |
||||
" [1,5,6],\n", |
||||
" [1,6,2],\n", |
||||
" [2,6,8],\n", |
||||
" [2,8,4]\n", |
||||
" ], dtype=np.int32)-1\n", |
||||
"viewMesh(V,F)" |
||||
] |
||||
} |
||||
], |
||||
"metadata": { |
||||
"@webio": { |
||||
"lastCommId": null, |
||||
"lastKernelId": null |
||||
}, |
||||
"kernelspec": { |
||||
"display_name": "Python 3", |
||||
"language": "python", |
||||
"name": "python3" |
||||
}, |
||||
"language_info": { |
||||
"codemirror_mode": { |
||||
"name": "ipython", |
||||
"version": 3 |
||||
}, |
||||
"file_extension": ".py", |
||||
"mimetype": "text/x-python", |
||||
"name": "python", |
||||
"nbconvert_exporter": "python", |
||||
"pygments_lexer": "ipython3", |
||||
"version": "3.7.6" |
||||
}, |
||||
"latex_envs": { |
||||
"LaTeX_envs_menu_present": true, |
||||
"autoclose": false, |
||||
"autocomplete": true, |
||||
"bibliofile": "biblio.bib", |
||||
"cite_by": "apalike", |
||||
"current_citInitial": 1, |
||||
"eqLabelWithNumbers": true, |
||||
"eqNumInitial": 1, |
||||
"hotkeys": { |
||||
"equation": "Ctrl-E", |
||||
"itemize": "Ctrl-I" |
||||
}, |
||||
"labels_anchors": false, |
||||
"latex_user_defs": false, |
||||
"report_style_numbering": false, |
||||
"user_envs_cfg": false |
||||
} |
||||
}, |
||||
"nbformat": 4, |
||||
"nbformat_minor": 2 |
||||
} |
@ -0,0 +1,184 @@ |
||||
from IPython.core.magic import register_cell_magic, needs_local_scope |
||||
|
||||
import importlib |
||||
import glob |
||||
import sys, os |
||||
import random |
||||
import string |
||||
import hashlib |
||||
import shutil |
||||
import subprocess |
||||
|
||||
compiler_cmd = "c++" |
||||
|
||||
cmd_flags = ["$(pkg-config --cflags eigen3)"] |
||||
|
||||
template = """ |
||||
#include <pybind11/pybind11.h> |
||||
namespace py = pybind11; |
||||
|
||||
{cell_code} |
||||
|
||||
PYBIND11_MODULE({name}, m) |
||||
{defs} |
||||
""" |
||||
|
||||
def_template = '\nm.def("{function}", &{function});\n' |
||||
|
||||
tmp_path = "pbm_modules" |
||||
|
||||
# Make sure the correct python executeable is used using cmake |
||||
os.environ["PATH"] = os.path.dirname(sys.executable) + os.pathsep + os.environ["PATH"] |
||||
|
||||
def exec_command(cmd, cwd=None,**kwargs): |
||||
try: |
||||
output = subprocess.check_output(cmd,cwd=cwd,stderr=subprocess.STDOUT,**kwargs) |
||||
if isinstance(output,bytes): |
||||
return False, output.decode("utf-8") |
||||
return False, output |
||||
except subprocess.CalledProcessError as e: |
||||
if isinstance(e.output,bytes): |
||||
return True, e.output.decode("utf-8") |
||||
return True, e.output |
||||
|
||||
|
||||
|
||||
def ensure_tmp_folder(): |
||||
path = os.path.join(os.getcwd(), tmp_path) |
||||
if not os.path.exists(path): |
||||
os.makedirs(path) |
||||
if not path in sys.path: |
||||
sys.path.append(path) |
||||
|
||||
def ensure_pybind(path, force=False): |
||||
path = os.path.join(path,"pybind11") |
||||
exists = os.path.exists(path) |
||||
if exists and force: |
||||
shutil.rmtree(os.path.join(path,"pybind11")) |
||||
if not exists: |
||||
err, output = exec_command(["git", "clone","https://github.com/pybind/pybind11.git",path]) |
||||
|
||||
def ensure_build_dir(path, clear=False): |
||||
path = os.path.join(path, "build") |
||||
exists = os.path.exists(path) |
||||
if exists and clear: |
||||
shutil.rmtree(path) |
||||
if not exists or clear: |
||||
os.makedirs(path) |
||||
return exists and not clear |
||||
|
||||
@register_cell_magic |
||||
def cpp(line, cell, *what): |
||||
"""Compile, execute C++ code wrapped with pybind11 and import it""" |
||||
args = line.split(" ") |
||||
rebuild = False |
||||
cmake_path = None |
||||
function = "" |
||||
run_cmake = False |
||||
# TODO: Add full argument parser |
||||
for i,arg in enumerate(args): |
||||
if arg == "-c": |
||||
cmake_path = args[i+1].strip() |
||||
if arg == "-f": |
||||
function = args[i+1].strip() |
||||
if arg == "-rebuild": |
||||
rebuild = True |
||||
|
||||
|
||||
# We first retrieve the current IPython interpreter |
||||
# instance. |
||||
ip = get_ipython() |
||||
|
||||
cmake = "" |
||||
if cmake_path is not None: |
||||
with open(os.path.join(cmake_path,"CMakeLists.txt"), 'r') as f: |
||||
cmake = f.read() |
||||
# name = ''.join(random.choices(string.ascii_lowercase, k=10)) |
||||
hash_object = hashlib.sha256((cmake+" ".join(line)+function+cell).encode()) |
||||
name = "cpp_magic_"+hash_object.hexdigest()[:10] |
||||
if cmake_path is None: |
||||
ensure_tmp_folder() |
||||
else: |
||||
run_cmake = not ensure_build_dir(cmake_path, clear=rebuild) |
||||
p = os.path.abspath(os.path.join(cmake_path,"build")) |
||||
if p not in sys.path: |
||||
sys.path.append(p) |
||||
ensure_pybind(cmake_path) |
||||
|
||||
if cmake_path is not None: |
||||
path = cmake_path |
||||
else: |
||||
path = tmp_path |
||||
|
||||
# We define the source and executable filenames. |
||||
try: |
||||
try: |
||||
if rebuild: |
||||
raise Exception() |
||||
mdl = importlib.import_module(name) |
||||
except: |
||||
exe = sys.executable |
||||
split = cell.split("defs") |
||||
if len(split) == 1 and function == "": |
||||
raise Exception("You have to name a function as argument ('%%cpp -f <functionname>') or manual set defs") |
||||
split.append("") |
||||
|
||||
curr_defs = split[1] |
||||
if function != "": |
||||
curr_defs += def_template.format(function=function) |
||||
|
||||
|
||||
# We write the code to the C++ file. |
||||
with open(os.path.join(path,f"{name}.cpp"), 'w') as f: |
||||
f.write(template.format(cell_code=split[0],name=name,defs="{"+curr_defs+"}")) |
||||
|
||||
|
||||
if cmake_path is None: |
||||
# We compile the C++ code into an executable. |
||||
command = f"{compiler_cmd} {' '.join(cmd_flags)} -O3 -Wall -shared -std=c++11 -fPIC $({exe} -m pybind11 --includes) {tmp_path}/{name}.cpp -o {tmp_path}/{name}.so" |
||||
compile = ip.getoutput(command) |
||||
if len(compile) != 0: |
||||
raise Exception("\n".join(compile)) |
||||
else: |
||||
with open(os.path.join(cmake_path,"CMakeLists.txt"), 'w') as f: |
||||
f.write(cmake.replace("{name}",name)) |
||||
# TODO: Add option to add cmake flags |
||||
if run_cmake: |
||||
command = ["cmake", ".."] |
||||
print("cmake:") |
||||
err, output = exec_command(command, cwd=os.path.join(cmake_path, "build")) |
||||
if err: |
||||
raise Exception(output) |
||||
print(output) |
||||
command = ["make"] |
||||
print("make:") |
||||
err, output = exec_command(command, cwd=os.path.join(cmake_path, "build")) |
||||
if err: |
||||
raise Exception(output) |
||||
print(output) |
||||
with open(os.path.join(cmake_path,"CMakeLists.txt"), 'w') as f: |
||||
f.write(cmake) |
||||
|
||||
|
||||
# We execute the executable and return the output. |
||||
# get a handle on the module |
||||
mdl = importlib.import_module(name) |
||||
|
||||
if os.path.exists(os.path.join(path,f"{name}.cpp")): |
||||
os.remove(os.path.join(path,f"{name}.cpp")) |
||||
|
||||
# is there an __all__? if so respect it |
||||
if "__all__" in mdl.__dict__: |
||||
names = mdl.__dict__["__all__"] |
||||
else: |
||||
# otherwise we import all names that don't begin with _ |
||||
names = [x for x in mdl.__dict__ if not x.startswith("_")] |
||||
except Exception as e: |
||||
with open(os.path.join(cmake_path,"CMakeLists.txt"), 'w') as f: |
||||
f.write(cmake) |
||||
if os.path.exists(os.path.join(path,f"{name}.cpp")): |
||||
os.remove(os.path.join(path,f"{name}.cpp")) |
||||
raise e |
||||
|
||||
# now drag them in |
||||
ip.push({k: getattr(mdl, k) for k in names}) |
@ -0,0 +1,35 @@ |
||||
from setuptools import setup, find_packages |
||||
import os |
||||
|
||||
# Utility function to read the README file. |
||||
# Used for the long_description. It's nice, because now 1) we have a top level |
||||
# README file and 2) it's easier to type in the README file than to put a raw |
||||
# string in below ... |
||||
def read(fname): |
||||
return open(os.path.join(os.path.dirname(__file__), fname)).read() |
||||
|
||||
setup( |
||||
name="pybindmagic", |
||||
version="0.1", |
||||
packages=find_packages(), |
||||
# requires=['pybind11'], |
||||
# scripts=['say_hello.py'], |
||||
# install_requires=['python_version>=3.5'], |
||||
|
||||
# metadata to display on PyPI |
||||
author="Ugo Finnendahl", |
||||
author_email="finnendahl@tu-berlin.de", |
||||
description="This is a simple pybind11 wrapper as ipython cellmagic.", |
||||
keywords="ipython, jupyter, cpp, c++, cell_magic", |
||||
# url="http://example.com/HelloWorld/", # project home page, if any |
||||
# project_urls={ |
||||
# "Bug Tracker": "https://bugs.example.com/HelloWorld/", |
||||
# "Documentation": "https://docs.example.com/HelloWorld/", |
||||
# "Source Code": "https://code.example.com/HelloWorld/", |
||||
# }, |
||||
# classifiers=[ |
||||
# 'License :: OSI Approved :: Python Software Foundation License' |
||||
# ], |
||||
python_requires=">=3.5", |
||||
long_description=read('README.md') |
||||
) |
Loading…
Reference in new issue