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