├── 00_hello_world ├── CMakeLists.txt ├── hello_world.cpp └── hello_world.hpp ├── 01_threads ├── CMakeLists.txt ├── threads.cpp └── threads.hpp ├── 02_embed_python ├── CMakeLists.txt ├── embed_python.cpp └── embed_python.hpp ├── 03_python_callins ├── CMakeLists.txt ├── python_callins.cpp └── python_callins.hpp ├── 04_thread_safe ├── CMakeLists.txt ├── thread_safe.cpp └── thread_safe.hpp ├── CMakeLists.txt ├── README └── cmake ├── FindPythonLibsEx.cmake └── SetMultiThread.cmake /00_hello_world/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | 3 | PROJECT(00_hello_world) 4 | 5 | 6 | SET(SOURCE_FILES 7 | hello_world.cpp 8 | ) 9 | 10 | IF(WIN32) 11 | SET(SOURCE_FILES ${SOURCE_FILES} 12 | hello_world.hpp 13 | ) 14 | ENDIF(WIN32) 15 | 16 | add_executable(hello_world ${SOURCE_FILES}) 17 | target_link_libraries(hello_world) 18 | -------------------------------------------------------------------------------- /00_hello_world/hello_world.cpp: -------------------------------------------------------------------------------- 1 | #include "hello_world.hpp" 2 | 3 | int MAIN(int argc, const unicode_char* argv[]) { 4 | 5 | std::cout << "Hello World" << std::endl; 6 | } 7 | 8 | -------------------------------------------------------------------------------- /00_hello_world/hello_world.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #ifdef WIN32 6 | #define MAIN wmain 7 | typedef wchar_t unicode_char; 8 | #else 9 | #define MAIN main 10 | typedef char unicode_char; 11 | #endif 12 | -------------------------------------------------------------------------------- /01_threads/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | CMAKE_MINIMUM_REQUIRED(VERSION 2.6) 2 | 3 | PROJECT(01_threads) 4 | 5 | SET(SOURCE_FILES 6 | threads.cpp 7 | ) 8 | 9 | IF(WIN32) 10 | SET(SOURCE_FILES ${SOURCE_FILES} 11 | threads.hpp 12 | ) 13 | ENDIF(WIN32) 14 | 15 | ADD_EXECUTABLE(threads ${SOURCE_FILES}) 16 | TARGET_LINK_LIBRARIES(threads ${Boost_THREAD_LIBRARY}) 17 | -------------------------------------------------------------------------------- /01_threads/threads.cpp: -------------------------------------------------------------------------------- 1 | #include "threads.hpp" 2 | 3 | #include 4 | 5 | 6 | class logger { 7 | boost::recursive_mutex cout_guard; 8 | public: 9 | template 10 | logger & operator << (const T & data){ 11 | boost::lock_guard lock(cout_guard); 12 | std::cout << data; 13 | return *this; 14 | } 15 | }; 16 | logger safe_cout; 17 | 18 | static int delay = 100; 19 | static int thread_count = 100; 20 | static int thread_loops = 10; 21 | 22 | void thread_proc(const int id, const int delay) { 23 | for (int i=0;i>> proc: " << id << "\n"; 27 | safe_cout << ss.str(); 28 | boost::this_thread::sleep(time_to_sleep); 29 | } 30 | } 31 | 32 | int MAIN(int argc, const unicode_char* argv[]) { 33 | boost::thread_group threads; 34 | 35 | for (int i=0;i 4 | 5 | #ifdef WIN32 6 | #define MAIN wmain 7 | typedef wchar_t unicode_char; 8 | #else 9 | #define MAIN main 10 | typedef char unicode_char; 11 | #endif 12 | -------------------------------------------------------------------------------- /02_embed_python/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | CMAKE_MINIMUM_REQUIRED(VERSION 2.6) 2 | 3 | PROJECT(02_embed_python) 4 | 5 | SET(SOURCE_FILES 6 | embed_python.cpp 7 | ) 8 | 9 | IF(WIN32) 10 | SET(SOURCE_FILES ${SOURCE_FILES} 11 | embed_python.hpp 12 | ) 13 | ENDIF(WIN32) 14 | 15 | ADD_DEFINITIONS(-DBOOST_PYTHON_STATIC_LIB) 16 | 17 | ADD_EXECUTABLE(embed_python ${SOURCE_FILES}) 18 | TARGET_LINK_LIBRARIES(embed_python ${Boost_PYTHON_LIBRARY} ${PYTHON_LIBRARIES}) 19 | -------------------------------------------------------------------------------- /02_embed_python/embed_python.cpp: -------------------------------------------------------------------------------- 1 | #include "embed_python.hpp" 2 | 3 | #include 4 | 5 | namespace bp = boost::python; 6 | 7 | 8 | void hello(int id) { 9 | std::cout << "hello_cpp(" << id << ")\n"; 10 | } 11 | 12 | BOOST_PYTHON_MODULE(TEST) 13 | { 14 | bp::def("hello_cpp", hello); 15 | } 16 | 17 | void print_py_error() { 18 | try { 19 | PyErr_Print(); 20 | bp::object sys(bp::handle<>(PyImport_ImportModule("sys"))); 21 | bp::object err = sys.attr("stderr"); 22 | std::string err_text = bp::extract(err.attr("getvalue")()); 23 | std::cout << err_text << "\n"; 24 | } catch (...) { 25 | std::cout << "Failed to parse python error\n"; 26 | } 27 | PyErr_Clear(); 28 | } 29 | 30 | int MAIN(int argc, const unicode_char* argv[]) { 31 | Py_Initialize(); 32 | initTEST(); 33 | 34 | try { 35 | bp::object main_module = bp::import("__main__"); 36 | bp::dict globalDict = bp::extract(main_module.attr("__dict__")); 37 | bp::dict localDict = globalDict.copy(); 38 | 39 | bp::object ignored = bp::exec( 40 | "from TEST import hello_cpp\n" 41 | "\n" 42 | "hello_cpp(1234)\n" 43 | "\n" 44 | , localDict, localDict); 45 | 46 | } catch(const bp::error_already_set &e) { 47 | std::cout << "Exception in script: "; 48 | print_py_error(); 49 | } catch(const std::exception &e) { 50 | std::cout << "Exception in script: " << e.what() << "\n"; 51 | } catch(...) { 52 | std::cout << "Exception in script: UNKNOWN\n"; 53 | } 54 | } 55 | 56 | -------------------------------------------------------------------------------- /02_embed_python/embed_python.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #ifdef WIN32 6 | #define MAIN wmain 7 | typedef wchar_t unicode_char; 8 | #else 9 | #define MAIN main 10 | typedef char unicode_char; 11 | #endif 12 | -------------------------------------------------------------------------------- /03_python_callins/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | CMAKE_MINIMUM_REQUIRED(VERSION 2.6) 2 | 3 | PROJECT(03_python_callins) 4 | 5 | SET(SOURCE_FILES 6 | python_callins.cpp 7 | ) 8 | 9 | IF(WIN32) 10 | SET(SOURCE_FILES ${SOURCE_FILES} 11 | python_callins.hpp 12 | ) 13 | ENDIF(WIN32) 14 | 15 | ADD_DEFINITIONS(-DBOOST_PYTHON_STATIC_LIB) 16 | 17 | ADD_EXECUTABLE(python_callins ${SOURCE_FILES}) 18 | TARGET_LINK_LIBRARIES(python_callins ${Boost_PYTHON_LIBRARY} ${PYTHON_LIBRARIES}) 19 | -------------------------------------------------------------------------------- /03_python_callins/python_callins.cpp: -------------------------------------------------------------------------------- 1 | #include "python_callins.hpp" 2 | 3 | #include 4 | 5 | namespace bp = boost::python; 6 | 7 | 8 | void hello(int id) { 9 | std::cout << "hello_cpp(" << id << ")\n"; 10 | } 11 | 12 | BOOST_PYTHON_MODULE(TEST) 13 | { 14 | bp::def("hello_cpp", hello); 15 | } 16 | 17 | void print_py_error() { 18 | try { 19 | PyErr_Print(); 20 | bp::object sys(bp::handle<>(PyImport_ImportModule("sys"))); 21 | bp::object err = sys.attr("stderr"); 22 | std::string err_text = bp::extract(err.attr("getvalue")()); 23 | std::cout << err_text << "\n"; 24 | } catch (...) { 25 | std::cout << "Failed to parse python error\n"; 26 | } 27 | PyErr_Clear(); 28 | } 29 | 30 | void call_python(bp::dict &localDict, int id) { 31 | try { 32 | bp::object scriptFunction = bp::extract(localDict["hello_python"]); 33 | if(scriptFunction) 34 | scriptFunction(id); 35 | else 36 | std::cout << "Script did not have a hello function!\n"; 37 | } catch(const bp::error_already_set &e) { 38 | std::cout << "Exception in script: "; 39 | print_py_error(); 40 | } catch(const std::exception &e) { 41 | std::cout << "Exception in script: " << e.what() << "\n"; 42 | } catch(...) { 43 | std::cout << "Exception in script: UNKNOWN\n"; 44 | } 45 | } 46 | 47 | int MAIN(int argc, const unicode_char* argv[]) { 48 | Py_Initialize(); 49 | 50 | initTEST(); 51 | 52 | try { 53 | bp::object main_module = bp::import("__main__"); 54 | bp::dict globalDict = bp::extract(main_module.attr("__dict__")); 55 | bp::dict localDict = globalDict.copy(); 56 | 57 | bp::object ignored = bp::exec( 58 | "from TEST import hello_cpp\n" 59 | "\n" 60 | "def hello_python(id):\n" 61 | " hello_cpp(id)\n" 62 | "\n" 63 | , localDict, localDict); 64 | 65 | call_python(localDict, 1234); 66 | } catch(const bp::error_already_set &e) { 67 | std::cout << "Exception in script: "; 68 | print_py_error(); 69 | } catch(const std::exception &e) { 70 | std::cout << "Exception in script: " << e.what() << "\n"; 71 | } catch(...) { 72 | std::cout << "Exception in script: UNKNOWN\n"; 73 | } 74 | } 75 | 76 | -------------------------------------------------------------------------------- /03_python_callins/python_callins.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #ifdef WIN32 6 | #define MAIN wmain 7 | typedef wchar_t unicode_char; 8 | #else 9 | #define MAIN main 10 | typedef char unicode_char; 11 | #endif 12 | -------------------------------------------------------------------------------- /04_thread_safe/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | CMAKE_MINIMUM_REQUIRED(VERSION 2.6) 2 | 3 | PROJECT(04_thread_safe) 4 | 5 | SET(SOURCE_FILES 6 | thread_safe.cpp 7 | ) 8 | 9 | IF(WIN32) 10 | SET(SOURCE_FILES ${SOURCE_FILES} 11 | thread_safe.hpp 12 | ) 13 | ENDIF(WIN32) 14 | 15 | ADD_DEFINITIONS(-DBOOST_PYTHON_STATIC_LIB) 16 | 17 | ADD_EXECUTABLE(thread_safe ${SOURCE_FILES}) 18 | TARGET_LINK_LIBRARIES(thread_safe ${Boost_THREAD_LIBRARY} ${Boost_PYTHON_LIBRARY} ${PYTHON_LIBRARIES}) 19 | -------------------------------------------------------------------------------- /04_thread_safe/thread_safe.cpp: -------------------------------------------------------------------------------- 1 | #include "thread_safe.hpp" 2 | 3 | #include 4 | #include 5 | 6 | namespace bp = boost::python; 7 | 8 | class logger { 9 | boost::recursive_mutex cout_guard; 10 | public: 11 | template 12 | logger & operator << (const T & data){ 13 | boost::lock_guard lock(cout_guard); 14 | std::cout << data; 15 | return *this; 16 | } 17 | }; 18 | logger safe_cout; 19 | 20 | static int delay = 100; 21 | static int thread_count = 100; 22 | static int thread_loops = 10; 23 | 24 | struct aquire_py_GIL { 25 | PyGILState_STATE state; 26 | aquire_py_GIL() { 27 | state = PyGILState_Ensure(); 28 | } 29 | 30 | ~aquire_py_GIL() { 31 | PyGILState_Release(state); 32 | } 33 | }; 34 | struct release_py_GIL { 35 | PyThreadState *state; 36 | release_py_GIL() { 37 | state = PyEval_SaveThread(); 38 | } 39 | ~release_py_GIL() { 40 | PyEval_RestoreThread(state); 41 | } 42 | }; 43 | 44 | void hello(int id) { 45 | release_py_GIL unlocker; 46 | std::stringstream ss; 47 | ss << ">>> py: sleep: " << id << "\n"; 48 | safe_cout << ss.str(); 49 | boost::this_thread::sleep(boost::posix_time::millisec(rand()*delay/RAND_MAX)); 50 | } 51 | 52 | BOOST_PYTHON_MODULE(TEST) 53 | { 54 | bp::def("hello_cpp", hello); 55 | } 56 | 57 | void print_py_error() { 58 | try { 59 | PyErr_Print(); 60 | bp::object sys(bp::handle<>(PyImport_ImportModule("sys"))); 61 | bp::object err = sys.attr("stderr"); 62 | std::string err_text = bp::extract(err.attr("getvalue")()); 63 | safe_cout << err_text << "\n"; 64 | } catch (...) { 65 | safe_cout << "Failed to parse python error\n"; 66 | } 67 | PyErr_Clear(); 68 | } 69 | 70 | 71 | void call_python(bp::dict &localDict, int id) { 72 | try { 73 | aquire_py_GIL lock; 74 | try { 75 | bp::object scriptFunction = bp::extract(localDict["hello_python"]); 76 | if(scriptFunction) 77 | scriptFunction(id); 78 | else 79 | safe_cout << "Script did not have a hello function!\n"; 80 | } catch(const bp::error_already_set &e) { 81 | safe_cout << "Exception in script: "; 82 | print_py_error(); 83 | } 84 | } catch(const std::exception &e) { 85 | safe_cout << "Exception in script: " << e.what() << "\n"; 86 | } 87 | } 88 | 89 | void thread_proc(const int id, bp::dict localDict) { 90 | for (int i=0;i>> proc: " << id << "\n"; 94 | safe_cout << ss.str(); 95 | boost::this_thread::sleep(time_to_sleep); 96 | call_python(localDict, id); 97 | } 98 | } 99 | 100 | 101 | int MAIN(int argc, const unicode_char* argv[]) { 102 | Py_Initialize(); 103 | PyEval_InitThreads(); 104 | initTEST(); 105 | 106 | try { 107 | bp::object main_module = bp::import("__main__"); 108 | bp::dict globalDict = bp::extract(main_module.attr("__dict__")); 109 | bp::dict localDict = globalDict.copy(); 110 | 111 | try { 112 | bp::object ignored = bp::exec( 113 | "from TEST import hello_cpp\n" 114 | "\n" 115 | "def hello_python(id):\n" 116 | " hello_cpp(id)\n" 117 | "\n" 118 | , localDict, localDict); 119 | } catch(const bp::error_already_set &e) { 120 | safe_cout << "Exception in script: "; 121 | print_py_error(); 122 | } 123 | 124 | PyThreadState *state = PyEval_SaveThread(); 125 | 126 | boost::thread_group threads; 127 | for (int i=0;i 4 | 5 | #ifdef WIN32 6 | #define MAIN wmain 7 | typedef wchar_t unicode_char; 8 | #else 9 | #define MAIN main 10 | typedef char unicode_char; 11 | #endif 12 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | 3 | SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake;${CMAKE_MODULE_PATH}") 4 | SET_PROPERTY(GLOBAL PROPERTY USE_FOLDERS On) 5 | INCLUDE(${CMAKE_SOURCE_DIR}/cmake/SetMultiThread.cmake) 6 | 7 | 8 | PROJECT(embedd_python CXX C) 9 | 10 | IF(WIN32) 11 | set(Boost_USE_STATIC_LIBS ON) 12 | set(Boost_USE_STATIC_RUNTIME ON) 13 | set(BOOST_USE_MULTITHREADED ON) 14 | SET(BOOST_INCLUDEDIR "D:/source/include/boost-1_47" CACHE PATH "Path to boost includes") 15 | SET(BOOST_LIBRARYDIR "D:/source/lib/x64" CACHE PATH "Path to boost libraries") 16 | ENDIF(WIN32) 17 | 18 | IF(NOT SHARED_LIBS) 19 | IF(WIN32) 20 | OPTION(SHARED_LIBS "Compile shared libraries" OFF) 21 | ELSE(WIN32) 22 | OPTION(SHARED_LIBS "Compile shared libraries" ON) 23 | ENDIF(WIN32) 24 | ENDIF(NOT SHARED_LIBS) 25 | 26 | 27 | SET(BUILD_TARGET_EXE_PATH "${PROJECT_BINARY_DIR}") 28 | if(CMAKE_CL_64) 29 | MESSAGE(STATUS "Detected x64") 30 | SET(PYTHON_ROOT c:/python/27x64) 31 | ELSEIF(WIN32) 32 | MESSAGE(STATUS "Detected w32") 33 | SET(PYTHON_ROOT c:/python/27) 34 | ENDIF() 35 | 36 | FIND_PACKAGE(PythonLibsEx) 37 | IF (PYTHONLIBSEX_FOUND) 38 | MESSAGE(STATUS "Found python (lib) in: ${PYTHON_LIBRARY}") 39 | INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_DIRS}) 40 | ENDIF (PYTHONLIBSEX_FOUND) 41 | 42 | FIND_PACKAGE(Boost COMPONENTS system filesystem thread program_options python REQUIRED) 43 | if(Boost_FOUND) 44 | MESSAGE(STATUS "Found boost in: ${Boost_INCLUDE_DIRS} / ${Boost_LIBRARY_DIRS}") 45 | INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS}) 46 | else(Boost_FOUND) 47 | MESSAGE(FATAL_ERROR "boost NOT fround: ${Boost_ERROR_REASON}") 48 | endif(Boost_FOUND) 49 | 50 | IF(NOT WIN32) 51 | FIND_PACKAGE(Threads REQUIRED) 52 | IF (NOT CMAKE_USE_PTHREADS_INIT) 53 | message(FATAL_ERROR "Could not find POSIX threads") 54 | ENDIF (NOT CMAKE_USE_PTHREADS_INIT) 55 | FIND_PACKAGE(Threads REQUIRED) 56 | ENDIF(NOT WIN32) 57 | 58 | LINK_DIRECTORIES(${CMAKE_LIBRARY_PATH} ${BOOST_LIBRARYDIR}) 59 | 60 | SET_MULTITHREAD() 61 | ADD_SUBDIRECTORY(00_hello_world) 62 | ADD_SUBDIRECTORY(01_threads) 63 | ADD_SUBDIRECTORY(02_embed_python) 64 | ADD_SUBDIRECTORY(03_python_callins) 65 | ADD_SUBDIRECTORY(04_thread_safe) 66 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This is a sample multithreaded emedded python application. 2 | 3 | This is a tutorial for how to embed python correctly inside a multi 4 | threaded program. Python is a very neat language which is very easy to 5 | embed inside C++ thanks to the boost::python library. But there are some 6 | crucial parts which is missing from boost:python in regards to how to 7 | manage GIL and thread state which I introduce here. Since this is my 8 | first C++ tutorial I will include boost:thread as well as a quick hello 9 | world application as well. 10 | 11 | The text can be found at my blog: http://blog.medin.name 12 | 13 | http://blog.medin.name/2012/02/12/embedding-python-inside-a-multithreaded-c-program/ 14 | 15 | // Michael Medin -------------------------------------------------------------------------------- /cmake/FindPythonLibsEx.cmake: -------------------------------------------------------------------------------- 1 | # - Find python libraries 2 | # This module finds if Python is installed and determines where the 3 | # include files and libraries are. It also determines what the name of 4 | # the library is. This code sets the following variables: 5 | # 6 | # PYTHONLIBS_FOUND - have the Python libs been found 7 | # PYTHON_LIBRARIES - path to the python library 8 | # PYTHON_INCLUDE_PATH - path to where Python.h is found (deprecated) 9 | # PYTHON_INCLUDE_DIRS - path to where Python.h is found 10 | # PYTHON_DEBUG_LIBRARIES - path to the debug library 11 | # Python_ADDITIONAL_VERSIONS - list of additional Python versions to search for 12 | 13 | #============================================================================= 14 | # Copyright 2001-2009 Kitware, Inc. 15 | # 16 | # Distributed under the OSI-approved BSD License (the "License"); 17 | # see accompanying file Copyright.txt for details. 18 | # 19 | # This software is distributed WITHOUT ANY WARRANTY; without even the 20 | # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 21 | # See the License for more information. 22 | #============================================================================= 23 | # (To distribute this file outside of CMake, substitute the full 24 | # License text for the above reference.) 25 | 26 | INCLUDE(CMakeFindFrameworks) 27 | # Search for the python framework on Apple. 28 | CMAKE_FIND_FRAMEWORKS(Python) 29 | 30 | # Set up the versions we know about, in the order we will search. Always add 31 | # the user supplied additional versions to the front. 32 | set(_Python_VERSIONS 33 | ${Python_ADDITIONAL_VERSIONS} 34 | 2.7 2.6 2.5 2.4 2.3 2.2 2.1 2.0 1.6 1.5) 35 | 36 | FOREACH(_CURRENT_VERSION ${_Python_VERSIONS}) 37 | STRING(REPLACE "." "" _CURRENT_VERSION_NO_DOTS ${_CURRENT_VERSION}) 38 | IF(WIN32) 39 | FIND_LIBRARY(PYTHON_DEBUG_LIBRARY 40 | NAMES python${_CURRENT_VERSION_NO_DOTS}_d python 41 | PATHS 42 | ${PYTHON_ROOT}/libs/Debug 43 | ${PYTHON_ROOT}/libs 44 | [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]/libs/Debug 45 | [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]/libs ) 46 | ENDIF(WIN32) 47 | 48 | FIND_LIBRARY(PYTHON_LIBRARY 49 | NAMES python${_CURRENT_VERSION_NO_DOTS} python${_CURRENT_VERSION} 50 | PATHS 51 | ${PYTHON_ROOT}/libs 52 | [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]/libs 53 | # Avoid finding the .dll in the PATH. We want the .lib. 54 | NO_SYSTEM_ENVIRONMENT_PATH 55 | ) 56 | # Look for the static library in the Python config directory 57 | FIND_LIBRARY(PYTHON_LIBRARY 58 | NAMES python${_CURRENT_VERSION_NO_DOTS} python${_CURRENT_VERSION} 59 | # Avoid finding the .dll in the PATH. We want the .lib. 60 | NO_SYSTEM_ENVIRONMENT_PATH 61 | # This is where the static library is usually located 62 | PATH_SUFFIXES python${_CURRENT_VERSION}/config 63 | ) 64 | 65 | # For backward compatibility, honour value of PYTHON_INCLUDE_PATH, if 66 | # PYTHON_INCLUDE_DIR is not set. 67 | IF(DEFINED PYTHON_INCLUDE_PATH AND NOT DEFINED PYTHON_INCLUDE_DIR) 68 | SET(PYTHON_INCLUDE_DIR "${PYTHON_INCLUDE_PATH}" CACHE PATH 69 | "Path to where Python.h is found" FORCE) 70 | ENDIF(DEFINED PYTHON_INCLUDE_PATH AND NOT DEFINED PYTHON_INCLUDE_DIR) 71 | 72 | SET(PYTHON_FRAMEWORK_INCLUDES) 73 | IF(Python_FRAMEWORKS AND NOT PYTHON_INCLUDE_DIR) 74 | FOREACH(dir ${Python_FRAMEWORKS}) 75 | SET(PYTHON_FRAMEWORK_INCLUDES ${PYTHON_FRAMEWORK_INCLUDES} 76 | ${dir}/Versions/${_CURRENT_VERSION}/include/python${_CURRENT_VERSION}) 77 | ENDFOREACH(dir) 78 | ENDIF(Python_FRAMEWORKS AND NOT PYTHON_INCLUDE_DIR) 79 | 80 | FIND_PATH(PYTHON_INCLUDE_DIR 81 | NAMES Python.h 82 | PATHS 83 | ${PYTHON_ROOT}/include 84 | ${PYTHON_FRAMEWORK_INCLUDES} 85 | [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_CURRENT_VERSION}\\InstallPath]/include 86 | PATH_SUFFIXES 87 | python${_CURRENT_VERSION} 88 | ) 89 | 90 | # For backward compatibility, set PYTHON_INCLUDE_PATH, but make it internal. 91 | SET(PYTHON_INCLUDE_PATH "${PYTHON_INCLUDE_DIR}" CACHE INTERNAL 92 | "Path to where Python.h is found (deprecated)") 93 | 94 | ENDFOREACH(_CURRENT_VERSION) 95 | 96 | MARK_AS_ADVANCED( 97 | PYTHON_DEBUG_LIBRARY 98 | PYTHON_LIBRARY 99 | PYTHON_INCLUDE_DIR 100 | ) 101 | 102 | # We use PYTHON_INCLUDE_DIR, PYTHON_LIBRARY and PYTHON_DEBUG_LIBRARY for the 103 | # cache entries because they are meant to specify the location of a single 104 | # library. We now set the variables listed by the documentation for this 105 | # module. 106 | SET(PYTHON_INCLUDE_DIRS "${PYTHON_INCLUDE_DIR}") 107 | SET(PYTHON_LIBRARIES "${PYTHON_LIBRARY}") 108 | SET(PYTHON_DEBUG_LIBRARIES "${PYTHON_DEBUG_LIBRARY}") 109 | 110 | 111 | INCLUDE(FindPackageHandleStandardArgs) 112 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(PythonLibsEx DEFAULT_MSG PYTHON_LIBRARIES PYTHON_INCLUDE_DIRS) 113 | 114 | 115 | # PYTHON_ADD_MODULE( src1 src2 ... srcN) is used to build modules for python. 116 | # PYTHON_WRITE_MODULES_HEADER() writes a header file you can include 117 | # in your sources to initialize the static python modules 118 | FUNCTION(PYTHON_ADD_MODULE _NAME ) 119 | GET_PROPERTY(_TARGET_SUPPORTS_SHARED_LIBS 120 | GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS) 121 | OPTION(PYTHON_ENABLE_MODULE_${_NAME} "Add module ${_NAME}" TRUE) 122 | OPTION(PYTHON_MODULE_${_NAME}_BUILD_SHARED 123 | "Add module ${_NAME} shared" ${_TARGET_SUPPORTS_SHARED_LIBS}) 124 | 125 | # Mark these options as advanced 126 | MARK_AS_ADVANCED(PYTHON_ENABLE_MODULE_${_NAME} 127 | PYTHON_MODULE_${_NAME}_BUILD_SHARED) 128 | 129 | IF(PYTHON_ENABLE_MODULE_${_NAME}) 130 | IF(PYTHON_MODULE_${_NAME}_BUILD_SHARED) 131 | SET(PY_MODULE_TYPE MODULE) 132 | ELSE(PYTHON_MODULE_${_NAME}_BUILD_SHARED) 133 | SET(PY_MODULE_TYPE STATIC) 134 | SET_PROPERTY(GLOBAL APPEND PROPERTY PY_STATIC_MODULES_LIST ${_NAME}) 135 | ENDIF(PYTHON_MODULE_${_NAME}_BUILD_SHARED) 136 | 137 | SET_PROPERTY(GLOBAL APPEND PROPERTY PY_MODULES_LIST ${_NAME}) 138 | ADD_LIBRARY(${_NAME} ${PY_MODULE_TYPE} ${ARGN}) 139 | # TARGET_LINK_LIBRARIES(${_NAME} ${PYTHON_LIBRARIES}) 140 | 141 | IF(PYTHON_MODULE_${_NAME}_BUILD_SHARED) 142 | SET_TARGET_PROPERTIES(${_NAME} PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}") 143 | IF(WIN32 AND NOT CYGWIN) 144 | SET_TARGET_PROPERTIES(${_NAME} PROPERTIES SUFFIX ".pyd") 145 | ENDIF(WIN32 AND NOT CYGWIN) 146 | ENDIF(PYTHON_MODULE_${_NAME}_BUILD_SHARED) 147 | 148 | ENDIF(PYTHON_ENABLE_MODULE_${_NAME}) 149 | ENDFUNCTION(PYTHON_ADD_MODULE) 150 | 151 | FUNCTION(PYTHON_WRITE_MODULES_HEADER _filename) 152 | 153 | GET_PROPERTY(PY_STATIC_MODULES_LIST GLOBAL PROPERTY PY_STATIC_MODULES_LIST) 154 | 155 | GET_FILENAME_COMPONENT(_name "${_filename}" NAME) 156 | STRING(REPLACE "." "_" _name "${_name}") 157 | STRING(TOUPPER ${_name} _nameUpper) 158 | SET(_filename ${CMAKE_CURRENT_BINARY_DIR}/${_filename}) 159 | 160 | SET(_filenameTmp "${_filename}.in") 161 | FILE(WRITE ${_filenameTmp} "/*Created by cmake, do not edit, changes will be lost*/\n") 162 | FILE(APPEND ${_filenameTmp} 163 | "#ifndef ${_nameUpper} 164 | #define ${_nameUpper} 165 | 166 | #include 167 | 168 | #ifdef __cplusplus 169 | extern \"C\" { 170 | #endif /* __cplusplus */ 171 | 172 | ") 173 | 174 | FOREACH(_currentModule ${PY_STATIC_MODULES_LIST}) 175 | FILE(APPEND ${_filenameTmp} "extern void init${PYTHON_MODULE_PREFIX}${_currentModule}(void);\n\n") 176 | ENDFOREACH(_currentModule ${PY_STATIC_MODULES_LIST}) 177 | 178 | FILE(APPEND ${_filenameTmp} 179 | "#ifdef __cplusplus 180 | } 181 | #endif /* __cplusplus */ 182 | 183 | ") 184 | 185 | 186 | FOREACH(_currentModule ${PY_STATIC_MODULES_LIST}) 187 | FILE(APPEND ${_filenameTmp} "int ${_name}_${_currentModule}(void) \n{\n static char name[]=\"${PYTHON_MODULE_PREFIX}${_currentModule}\"; return PyImport_AppendInittab(name, init${PYTHON_MODULE_PREFIX}${_currentModule});\n}\n\n") 188 | ENDFOREACH(_currentModule ${PY_STATIC_MODULES_LIST}) 189 | 190 | FILE(APPEND ${_filenameTmp} "void ${_name}_LoadAllPythonModules(void)\n{\n") 191 | FOREACH(_currentModule ${PY_STATIC_MODULES_LIST}) 192 | FILE(APPEND ${_filenameTmp} " ${_name}_${_currentModule}();\n") 193 | ENDFOREACH(_currentModule ${PY_STATIC_MODULES_LIST}) 194 | FILE(APPEND ${_filenameTmp} "}\n\n") 195 | FILE(APPEND ${_filenameTmp} "#ifndef EXCLUDE_LOAD_ALL_FUNCTION\nvoid CMakeLoadAllPythonModules(void)\n{\n ${_name}_LoadAllPythonModules();\n}\n#endif\n\n#endif\n") 196 | 197 | # with CONFIGURE_FILE() cmake complains that you may not use a file created using FILE(WRITE) as input file for CONFIGURE_FILE() 198 | EXECUTE_PROCESS(COMMAND ${CMAKE_COMMAND} -E copy_if_different "${_filenameTmp}" "${_filename}" OUTPUT_QUIET ERROR_QUIET) 199 | 200 | ENDFUNCTION(PYTHON_WRITE_MODULES_HEADER) 201 | -------------------------------------------------------------------------------- /cmake/SetMultiThread.cmake: -------------------------------------------------------------------------------- 1 | # SET_MULTITHREAD Macro 2 | # Sets multithread switches for Visual Studio and GNU G++ compilers 3 | # Uses static runtime library on Windows 4 | # Can be used multiple times, but overrides any switches added before the first call 5 | # The /RuntimeLibrary:MT SET switch could be an option, if future CMake versions support it 6 | 7 | MACRO ( SET_MULTITHREAD ) 8 | 9 | IF ( NOT MT_SET ) 10 | 11 | SET ( MT_SET 1 ) 12 | 13 | # Threads compatibility 14 | IF ( MSVC ) 15 | MESSAGE ( STATUS "Setting MSVC MT switches") 16 | SET ( 17 | CMAKE_CXX_FLAGS_DEBUG 18 | "/D_DEBUG /MTd /Zi /Ob0 /Od /GZ" 19 | CACHE STRING "MSVC MT flags " FORCE 20 | ) 21 | SET(CMAKE_C_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG}) 22 | 23 | SET ( 24 | CMAKE_CXX_FLAGS_RELEASE 25 | "/MT /O2 /Ob2 /D NDEBUG" 26 | CACHE STRING "MSVC MT flags " FORCE 27 | ) 28 | SET(CMAKE_C_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE}) 29 | 30 | SET ( 31 | CMAKE_CXX_FLAGS_MINSIZEREL 32 | "/MT /O1 /Ob1 /D NDEBUG" 33 | CACHE STRING "MSVC MT flags " FORCE 34 | ) 35 | SET(CMAKE_C_FLAGS_MINSIZEREL ${CMAKE_CXX_FLAGS_MINSIZEREL}) 36 | 37 | SET ( 38 | CMAKE_CXX_FLAGS_RELWITHDEBINFO 39 | "/MT /Zi /O2 /Ob1 /D NDEBUG" 40 | CACHE STRING "MSVC MT flags " FORCE 41 | ) 42 | SET(CMAKE_C_FLAGS_RELWITHDEBINFO ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}) 43 | 44 | # Maybe future CMake versions will implement this 45 | #SET ( 46 | # CMAKE_CXX_FLAGS_RELEASE 47 | # "/RuntimeLibrary:MT ${CMAKE_CXX_FLAGS_RELEASE}" 48 | #) 49 | ENDIF ( MSVC ) 50 | 51 | IF ( CMAKE_COMPILER_IS_GNUCXX ) 52 | MESSAGE ( STATUS "Setting GCC MT switches" ) 53 | SET ( 54 | CMAKE_CXX_FLAGS 55 | "${CMAKE_CXX_FLAGS} -pthread" 56 | ) 57 | ENDIF ( CMAKE_COMPILER_IS_GNUCXX ) 58 | 59 | ENDIF ( NOT MT_SET ) 60 | 61 | ENDMACRO ( SET_MULTITHREAD ) 62 | --------------------------------------------------------------------------------