forked from bartvdbraak/blender
Experimental option to build blender as a python module, rather then blender embedding python.
CMake build option WITH_PYTHON_MODULE, will build ./bin/bpy.so This allows 'bpy' to be imported from python or other applications/IDE's which embed python, eg: python -c "import bpy ; bpy.ops.render.render(write_still=True)" This runs in background mode and has similar restrictions to running a script: blender --background --python test.py TODO: - install to site-packages with blender scripts - add support for imp.reload()
This commit is contained in:
parent
55a0e21a03
commit
c30149991c
@ -69,6 +69,7 @@ get_blender_version()
|
|||||||
# Blender internal features
|
# Blender internal features
|
||||||
option(WITH_INTERNATIONAL "Enable I18N (International fonts and text)" ON)
|
option(WITH_INTERNATIONAL "Enable I18N (International fonts and text)" ON)
|
||||||
option(WITH_PYTHON "Enable Embedded Python API" ON)
|
option(WITH_PYTHON "Enable Embedded Python API" ON)
|
||||||
|
option(WITH_PYTHON_MODULE "Enable building as a python module (experemental)" OFF)
|
||||||
option(WITH_BUILDINFO "Include extra build details" ON)
|
option(WITH_BUILDINFO "Include extra build details" ON)
|
||||||
option(WITH_IK_ITASC "Enable ITASC IK solver" ON)
|
option(WITH_IK_ITASC "Enable ITASC IK solver" ON)
|
||||||
option(WITH_FFTW3 "Enable FFTW3 support (Used for smoke and audio effects)" OFF)
|
option(WITH_FFTW3 "Enable FFTW3 support (Used for smoke and audio effects)" OFF)
|
||||||
@ -1038,6 +1039,9 @@ endif()
|
|||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${PLATFORM_CFLAGS} ${C_WARNINGS}")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${PLATFORM_CFLAGS} ${C_WARNINGS}")
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${PLATFORM_CFLAGS} ${CXX_WARNINGS}")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${PLATFORM_CFLAGS} ${CXX_WARNINGS}")
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------------
|
||||||
|
# Global Defines
|
||||||
|
|
||||||
# better not define flags here but this is a debugging option thats off by default.
|
# better not define flags here but this is a debugging option thats off by default.
|
||||||
if(WITH_CXX_GUARDEDALLOC)
|
if(WITH_CXX_GUARDEDALLOC)
|
||||||
set(CMAKE_CXX_FLAGS " -DWITH_CXX_GUARDEDALLOC -I${CMAKE_SOURCE_DIR}/intern/guardedalloc ${CMAKE_CXX_FLAGS}")
|
set(CMAKE_CXX_FLAGS " -DWITH_CXX_GUARDEDALLOC -I${CMAKE_SOURCE_DIR}/intern/guardedalloc ${CMAKE_CXX_FLAGS}")
|
||||||
|
@ -66,7 +66,7 @@ macro(SETUP_LIBDIRS)
|
|||||||
|
|
||||||
link_directories(${JPEG_LIBPATH} ${PNG_LIBPATH} ${ZLIB_LIBPATH} ${FREETYPE_LIBPATH})
|
link_directories(${JPEG_LIBPATH} ${PNG_LIBPATH} ${ZLIB_LIBPATH} ${FREETYPE_LIBPATH})
|
||||||
|
|
||||||
if(WITH_PYTHON)
|
if(WITH_PYTHON AND NOT WITH_PYTHON_MODULE)
|
||||||
link_directories(${PYTHON_LIBPATH})
|
link_directories(${PYTHON_LIBPATH})
|
||||||
endif()
|
endif()
|
||||||
if(WITH_INTERNATIONAL)
|
if(WITH_INTERNATIONAL)
|
||||||
@ -127,7 +127,7 @@ macro(setup_liblinks
|
|||||||
target_link_libraries(${target} ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} ${JPEG_LIBRARIES} ${PNG_LIBRARIES} ${ZLIB_LIBRARIES} ${LLIBS})
|
target_link_libraries(${target} ${OPENGL_gl_LIBRARY} ${OPENGL_glu_LIBRARY} ${JPEG_LIBRARIES} ${PNG_LIBRARIES} ${ZLIB_LIBRARIES} ${LLIBS})
|
||||||
|
|
||||||
# since we are using the local libs for python when compiling msvc projects, we need to add _d when compiling debug versions
|
# since we are using the local libs for python when compiling msvc projects, we need to add _d when compiling debug versions
|
||||||
if(WITH_PYTHON)
|
if(WITH_PYTHON AND NOT WITH_PYTHON_MODULE)
|
||||||
target_link_libraries(${target} ${PYTHON_LINKFLAGS})
|
target_link_libraries(${target} ${PYTHON_LINKFLAGS})
|
||||||
|
|
||||||
if(WIN32 AND NOT UNIX)
|
if(WIN32 AND NOT UNIX)
|
||||||
|
@ -800,7 +800,7 @@ void RENDER_OT_render(wmOperatorType *ot)
|
|||||||
ot->modal= screen_render_modal;
|
ot->modal= screen_render_modal;
|
||||||
ot->exec= screen_render_exec;
|
ot->exec= screen_render_exec;
|
||||||
|
|
||||||
ot->poll= ED_operator_screenactive;
|
/*ot->poll= ED_operator_screenactive;*/ /* this isnt needed, causes failer in background mode */
|
||||||
|
|
||||||
RNA_def_boolean(ot->srna, "animation", 0, "Animation", "Render files from the animation range of this scene");
|
RNA_def_boolean(ot->srna, "animation", 0, "Animation", "Render files from the animation range of this scene");
|
||||||
RNA_def_boolean(ot->srna, "write_still", 0, "Write Image", "Save rendered the image to the output path (used only when animation is disabled)");
|
RNA_def_boolean(ot->srna, "write_still", 0, "Write Image", "Save rendered the image to the output path (used only when animation is disabled)");
|
||||||
|
@ -67,4 +67,8 @@ if(WITH_BUILDINFO)
|
|||||||
add_definitions(-DBUILD_DATE)
|
add_definitions(-DBUILD_DATE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(WITH_PYTHON_MODULE)
|
||||||
|
add_definitions(-DWITH_PYTHON_MODULE)
|
||||||
|
endif()
|
||||||
|
|
||||||
blender_add_lib(bf_python "${SRC}" "${INC}")
|
blender_add_lib(bf_python "${SRC}" "${INC}")
|
||||||
|
@ -53,6 +53,8 @@
|
|||||||
|
|
||||||
#include "AUD_PyInit.h"
|
#include "AUD_PyInit.h"
|
||||||
|
|
||||||
|
PyObject *bpy_package_py= NULL;
|
||||||
|
|
||||||
static char bpy_script_paths_doc[] =
|
static char bpy_script_paths_doc[] =
|
||||||
".. function:: script_paths()\n"
|
".. function:: script_paths()\n"
|
||||||
"\n"
|
"\n"
|
||||||
@ -161,7 +163,7 @@ static PyMethodDef meth_bpy_script_paths = {"script_paths", (PyCFunction)bpy_scr
|
|||||||
static PyMethodDef meth_bpy_blend_paths = {"blend_paths", (PyCFunction)bpy_blend_paths, METH_VARARGS|METH_KEYWORDS, bpy_blend_paths_doc};
|
static PyMethodDef meth_bpy_blend_paths = {"blend_paths", (PyCFunction)bpy_blend_paths, METH_VARARGS|METH_KEYWORDS, bpy_blend_paths_doc};
|
||||||
static PyMethodDef meth_bpy_user_resource = {"user_resource", (PyCFunction)bpy_user_resource, METH_VARARGS|METH_KEYWORDS, NULL};
|
static PyMethodDef meth_bpy_user_resource = {"user_resource", (PyCFunction)bpy_user_resource, METH_VARARGS|METH_KEYWORDS, NULL};
|
||||||
|
|
||||||
static void bpy_import_test(const char *modname)
|
static PyObject *bpy_import_test(const char *modname)
|
||||||
{
|
{
|
||||||
PyObject *mod= PyImport_ImportModuleLevel((char *)modname, NULL, NULL, NULL, 0);
|
PyObject *mod= PyImport_ImportModuleLevel((char *)modname, NULL, NULL, NULL, 0);
|
||||||
if(mod) {
|
if(mod) {
|
||||||
@ -171,6 +173,8 @@ static void bpy_import_test(const char *modname)
|
|||||||
PyErr_Print();
|
PyErr_Print();
|
||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return mod;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
@ -235,5 +239,5 @@ void BPy_init_modules( void )
|
|||||||
PyModule_AddObject(mod, meth_bpy_unregister_class.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_unregister_class, NULL));
|
PyModule_AddObject(mod, meth_bpy_unregister_class.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_unregister_class, NULL));
|
||||||
|
|
||||||
/* add our own modules dir, this is a python package */
|
/* add our own modules dir, this is a python package */
|
||||||
bpy_import_test("bpy");
|
bpy_package_py= bpy_import_test("bpy");
|
||||||
}
|
}
|
||||||
|
@ -22,4 +22,4 @@
|
|||||||
* ***** END GPL LICENSE BLOCK ***** */
|
* ***** END GPL LICENSE BLOCK ***** */
|
||||||
|
|
||||||
void BPy_init_modules( void );
|
void BPy_init_modules( void );
|
||||||
|
extern PyObject *bpy_package_py;
|
||||||
|
@ -157,6 +157,7 @@ void BPY_modules_update(bContext *C)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* must be called before Py_Initialize */
|
/* must be called before Py_Initialize */
|
||||||
|
#ifndef WITH_PYTHON_MODULE
|
||||||
static void bpy_python_start_path(void)
|
static void bpy_python_start_path(void)
|
||||||
{
|
{
|
||||||
char *py_path_bundle= BLI_get_folder(BLENDER_PYTHON, NULL);
|
char *py_path_bundle= BLI_get_folder(BLENDER_PYTHON, NULL);
|
||||||
@ -195,8 +196,7 @@ static void bpy_python_start_path(void)
|
|||||||
// printf("found python (wchar_t) '%ls'\n", py_path_bundle_wchar);
|
// printf("found python (wchar_t) '%ls'\n", py_path_bundle_wchar);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
void BPY_context_set(bContext *C)
|
void BPY_context_set(bContext *C)
|
||||||
{
|
{
|
||||||
@ -219,6 +219,7 @@ static struct _inittab bpy_internal_modules[]= {
|
|||||||
/* call BPY_context_set first */
|
/* call BPY_context_set first */
|
||||||
void BPY_python_start(int argc, const char **argv)
|
void BPY_python_start(int argc, const char **argv)
|
||||||
{
|
{
|
||||||
|
#ifndef WITH_PYTHON_MODULE
|
||||||
PyThreadState *py_tstate = NULL;
|
PyThreadState *py_tstate = NULL;
|
||||||
|
|
||||||
/* not essential but nice to set our name */
|
/* not essential but nice to set our name */
|
||||||
@ -252,7 +253,12 @@ void BPY_python_start(int argc, const char **argv)
|
|||||||
|
|
||||||
/* Initialize thread support (also acquires lock) */
|
/* Initialize thread support (also acquires lock) */
|
||||||
PyEval_InitThreads();
|
PyEval_InitThreads();
|
||||||
|
#else
|
||||||
|
(void)argc;
|
||||||
|
(void)argv;
|
||||||
|
|
||||||
|
PyImport_ExtendInittab(bpy_internal_modules);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* bpy.* and lets us import it */
|
/* bpy.* and lets us import it */
|
||||||
BPy_init_modules();
|
BPy_init_modules();
|
||||||
@ -281,8 +287,10 @@ void BPY_python_start(int argc, const char **argv)
|
|||||||
|
|
||||||
pyrna_alloc_types();
|
pyrna_alloc_types();
|
||||||
|
|
||||||
|
#ifndef WITH_PYTHON_MODULE
|
||||||
py_tstate = PyGILState_GetThisThreadState();
|
py_tstate = PyGILState_GetThisThreadState();
|
||||||
PyEval_ReleaseThread(py_tstate);
|
PyEval_ReleaseThread(py_tstate);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void BPY_python_end(void)
|
void BPY_python_end(void)
|
||||||
@ -659,3 +667,51 @@ int BPY_context_member_get(bContext *C, const char *member, bContextDataResult *
|
|||||||
return done;
|
return done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef WITH_PYTHON_MODULE
|
||||||
|
/* TODO, reloading the module isnt functional at the moment. */
|
||||||
|
|
||||||
|
extern int main_python(int argc, const char **argv);
|
||||||
|
static struct PyModuleDef bpy_proxy_def = {
|
||||||
|
PyModuleDef_HEAD_INIT,
|
||||||
|
"bpy", /* m_name */
|
||||||
|
NULL, /* m_doc */
|
||||||
|
0, /* m_size */
|
||||||
|
NULL, /* m_methods */
|
||||||
|
NULL, /* m_reload */
|
||||||
|
NULL, /* m_traverse */
|
||||||
|
NULL, /* m_clear */
|
||||||
|
NULL, /* m_free */
|
||||||
|
};
|
||||||
|
|
||||||
|
PyMODINIT_FUNC
|
||||||
|
PyInit_bpy(void)
|
||||||
|
{
|
||||||
|
int argc= 0;
|
||||||
|
const char *argv[]={NULL};
|
||||||
|
|
||||||
|
main_python(argc, argv);
|
||||||
|
|
||||||
|
/* initialized in BPy_init_modules() */
|
||||||
|
if(bpy_package_py) {
|
||||||
|
/* Problem:
|
||||||
|
* 1) this init function is expected to have a private member defined - 'md_def'
|
||||||
|
* but this is only set for C defined modules (not py packages)
|
||||||
|
* so we cant return 'bpy_package_py' as is.
|
||||||
|
*
|
||||||
|
* 2) there is a 'bpy' C module for python to load which is basically all of blender,
|
||||||
|
* and there is scripts/bpy/__init__.py,
|
||||||
|
* we may end up having to rename this module so there is no naming conflict here eg:
|
||||||
|
* 'from blender import bpy' */
|
||||||
|
PyObject *bpy_proxy= PyModule_Create(&bpy_proxy_def);
|
||||||
|
PyDict_Update(PyModule_GetDict(bpy_proxy), PyModule_GetDict(bpy_package_py));
|
||||||
|
return bpy_proxy;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "could not import internal bpy package");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
@ -127,8 +127,21 @@ if(WITH_BUILDINFO)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
# message(STATUS "Configuring blender")
|
# message(STATUS "Configuring blender")
|
||||||
|
if(WITH_PYTHON_MODULE)
|
||||||
|
add_definitions(-DWITH_PYTHON_MODULE)
|
||||||
|
|
||||||
add_executable(blender ${EXETYPE} ${SRC})
|
# creates ./bin/bpy.so which can be imported as a python module.
|
||||||
|
add_library(blender SHARED ${SRC})
|
||||||
|
set_target_properties(
|
||||||
|
blender
|
||||||
|
PROPERTIES
|
||||||
|
PREFIX ""
|
||||||
|
OUTPUT_NAME bpy
|
||||||
|
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin/
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
add_executable(blender ${EXETYPE} ${SRC})
|
||||||
|
endif()
|
||||||
|
|
||||||
# Post build steps for bundling/packaging.
|
# Post build steps for bundling/packaging.
|
||||||
|
|
||||||
|
@ -154,6 +154,7 @@ static void fpe_handler(int UNUSED(sig))
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef WITH_PYTHON_MODULE
|
||||||
/* handling ctrl-c event in console */
|
/* handling ctrl-c event in console */
|
||||||
static void blender_esc(int sig)
|
static void blender_esc(int sig)
|
||||||
{
|
{
|
||||||
@ -170,6 +171,7 @@ static void blender_esc(int sig)
|
|||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* buildinfo can have quotes */
|
/* buildinfo can have quotes */
|
||||||
#ifdef BUILD_DATE
|
#ifdef BUILD_DATE
|
||||||
@ -1111,12 +1113,21 @@ static void setupArguments(bContext *C, bArgs *ba, SYS_SystemHandle *syshandle)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
#ifdef WITH_PYTHON_MODULE
|
||||||
|
/* allow python module to call main */
|
||||||
|
#define main main_python
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int main(int argc, const char **argv)
|
||||||
{
|
{
|
||||||
SYS_SystemHandle syshandle;
|
SYS_SystemHandle syshandle;
|
||||||
bContext *C= CTX_create();
|
bContext *C= CTX_create();
|
||||||
bArgs *ba;
|
bArgs *ba;
|
||||||
|
|
||||||
|
#ifdef WITH_PYTHON_MODULE
|
||||||
|
#undef main
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef WITH_BINRELOC
|
#ifdef WITH_BINRELOC
|
||||||
br_init( NULL );
|
br_init( NULL );
|
||||||
#endif
|
#endif
|
||||||
@ -1192,9 +1203,12 @@ int main(int argc, char **argv)
|
|||||||
setuid(getuid()); /* end superuser */
|
setuid(getuid()); /* end superuser */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef WITH_PYTHON_MODULE
|
||||||
|
G.background= 1; /* python module mode ALWAYS runs in background mode (for now) */
|
||||||
|
#else
|
||||||
/* for all platforms, even windos has it! */
|
/* for all platforms, even windos has it! */
|
||||||
if(G.background) signal(SIGINT, blender_esc); /* ctrl c out bg render */
|
if(G.background) signal(SIGINT, blender_esc); /* ctrl c out bg render */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* background render uses this font too */
|
/* background render uses this font too */
|
||||||
BKE_font_register_builtin(datatoc_Bfont, datatoc_Bfont_size);
|
BKE_font_register_builtin(datatoc_Bfont, datatoc_Bfont_size);
|
||||||
@ -1248,6 +1262,10 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
BLI_argsFree(ba);
|
BLI_argsFree(ba);
|
||||||
|
|
||||||
|
#ifdef WITH_PYTHON_MODULE
|
||||||
|
return 0; /* keep blender in background mode running */
|
||||||
|
#endif
|
||||||
|
|
||||||
if(G.background) {
|
if(G.background) {
|
||||||
/* actually incorrect, but works for now (ton) */
|
/* actually incorrect, but works for now (ton) */
|
||||||
WM_exit(C);
|
WM_exit(C);
|
||||||
|
Loading…
Reference in New Issue
Block a user