Windows10 + Visual Studio 2017 (VC14.1)로 테스트를 했다.

Python 3.7 + tensorflow 2.2 버전이다.

boost는 1.73.0 버전에 python numpy 포함해서 직접 컴파일 하였다.

 

파이썬에서 C++ 코드를 실행하는 2가지 방법이다.

1. C++에서 Base 클래스를 만들고 이를 파이썬에서 상속받아 클래스를 구현할때 C++에서 코드가 실행되게 하는 방법.

2. C++ 클래스에서 함수들을 만들고 파이썬에서 이를 실행하는 방법.

 

본인은 Windows10에 아나콘다 가상환경을 설정하지 않았다.

그래서 아나콘다 파이썬 기본 경로가 "C:\\ProgramData\\Anaconda3" 이다.

혹시 아나콘다 가상환경을 구성한 경우 각자 상황에 맞게 아나콘다 경로를 변경한다.

 

// Copyright Stefan Seefeld 2005.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// Boost 기본 예제 boost_1_73_0\libs\python\example\quickstart의 코드.
// 컴파일해서 실행하는 경우 제대로 동작하지 않아 직접수정하여 나중에 쓸려고 올려놓음.

#include <boost/python.hpp>

#include <boost/detail/lightweight_test.hpp>
#include <iostream>

namespace python = boost::python;

// An abstract base class
class Base : public boost::noncopyable
{
public:
  virtual ~Base() {};
  virtual std::string hello() = 0;
};

// C++ derived class
class CppDerived : public Base
{
public:
  virtual ~CppDerived() {}
  virtual std::string hello()
  { 
	  return "Hello from C++!";
  }
};

// Familiar Boost.Python wrapper class for Base
struct BaseWrap : Base, python::wrapper<Base>
{
  virtual std::string hello() 
  {
#if BOOST_WORKAROUND(BOOST_MSVC, <= 1300)
    // workaround for VC++ 6.x or 7.0, see
    // http://boost.org/libs/python/doc/tutorial/doc/html/python/exposing.html#python.class_virtual_functions
    return python::call<std::string>(this->get_override("hello").ptr());
#else
    return this->get_override("hello")();
#endif
  }
};


// Boost 기본 예제 boost_1_73_0\libs\python\example\quickstart의 코드
namespace { // Avoid cluttering the global namespace.

  // A friendly class.
	class hello
	{
	public:
		hello(const std::string& country) { this->country = country; }
		std::string greet() const { return "Hello from " + country; }
	private:
		std::string country;
	};

	// A function taking a hello object as an argument.
	std::string invite(const hello& w) {
		return w.greet() + "! Please come soon!";
	}
}


// Pack the Base class wrapper into a module
BOOST_PYTHON_MODULE(embedded_hello)
{
  python::class_<BaseWrap, boost::noncopyable> base("Base");
}


BOOST_PYTHON_MODULE(extending)
{
	using namespace boost::python;
	class_<hello>("hello", init<std::string>())
		// Add a regular member function.
		.def("greet", &hello::greet)
		// Add invite() as a member of hello!
		.def("invite", invite)
		;

	// Also add invite() as a regular function to the module.
	def("invite", invite);
}



void exec_test1()
{
	// Retrieve the main module
	python::object main = python::import("__main__");

	// Retrieve the main module's namespace
	python::object global(main.attr("__dict__"));

	// Define the derived class in Python.
	python::object result = python::exec(
		"from embedded_hello import *        \n"
		"class PythonDerived(Base):          \n"
		"    def hello(self):                \n"
		"        return 'Hello from Python!' \n",
		global, global);

	python::object PythonDerived = global["PythonDerived"];

	// Creating and using instances of the C++ class is as easy as always.
	CppDerived cpp;
	BOOST_TEST(cpp.hello() == "Hello from C++!");

	std::cout << "testing derived class from C++..." << std::endl;

	// But now creating and using instances of the Python class is almost
	// as easy!
	python::object py_base = PythonDerived();
	Base& py = python::extract<Base&>(py_base) BOOST_EXTRACT_WORKAROUND;

	// Make sure the right 'hello' method is called.
	BOOST_TEST(py.hello() == "Hello from Python!");

	std::cout << "success!" << std::endl;
}


void exec_test2()
{
	// Retrieve the main module
	python::object main = python::import("__main__");

	// Retrieve the main module's namespace
	python::object global(main.attr("__dict__"));

	python::object result = python::exec(
		"from extending import *        \n"
		"hi = hello('California')         \n"
		"hi.greet() \n",
		global, global);

	python::object print = python::import("__main__").attr("__builtins__").attr("print");
	print(result);
}

void exec_test_error()
{
    std::cout << "intentionally causing a python exception..." << std::endl;
    
    // Execute a statement that raises a python exception.
    python::dict global;
    python::object result = python::exec("print unknown \n", global, global);

	python::object print = python::import("__main__").attr("__builtins__").attr("print");
	print(result);
}

int main(int argc, char **argv)
{
	BOOST_TEST(argc == 2);
	std::string script = argv[1];


	// Register the module with the interpreter
	if (PyImport_AppendInittab("embedded_hello", &PyInit_embedded_hello) == -1)
		throw std::runtime_error("Failed to add embedded_hello to the interpreter's "
			"builtin modules");

	if (PyImport_AppendInittab("extending", &PyInit_extending) == -1)
		throw std::runtime_error("Failed to add embedded_hello to the interpreter's "
			"builtin modules");


	// Initialize the interpreter
	Py_SetPythonHome(L"C:\\ProgramData\\Anaconda3");
	Py_Initialize();

	bool error_expected = false;

	if (
		python::handle_exception(exec_test1)
		|| python::handle_exception(exec_test2)
		)
	{
		if (PyErr_Occurred())
		{
			if (!error_expected)
				BOOST_ERROR("Python Error detected");
			PyErr_Print();
		}
		else
		{
			BOOST_ERROR("A C++ exception was thrown  for which "
				"there was no exception translator registered.");
		}
	}

	// Boost.Python doesn't support Py_Finalize yet, so don't call it!
	return boost::report_errors();
}

 

위의 코드를 실행하면 아래와 같은 결과가 나타난다.

+ Recent posts