जवाबों:
आपको Boost.Python पर एक नजर डालनी चाहिए । यहाँ उनकी वेबसाइट से लिया गया संक्षिप्त परिचय दिया गया है:
बूस्ट पायथन लाइब्रेरी पाइथन और C ++ के बीच तालमेल बिठाने की एक रूपरेखा है। यह आपको बिना किसी विशेष टूल का उपयोग किए, केवल आपके C ++ कंपाइलर का उपयोग करके C ++ वर्ग फ़ंक्शंस और ऑब्जेक्ट्स को तेज़ी से और मूल रूप से उजागर करने देता है। इसे C ++ इंटरफेस को गैर-आंतरिक रूप से लपेटने के लिए डिज़ाइन किया गया है, ताकि आपको इसे लपेटने के लिए C ++ कोड को बिल्कुल भी बदलना न पड़े, जिससे Boost.Python 3-पार्टी लाइब्रेरीज़ को Python में एक्सपोज़ करने के लिए आदर्श हो। लाइब्रेरी के उन्नत मेटाप्रोग्रामिंग तकनीकों का उपयोग उपयोगकर्ताओं के लिए इसके सिंटैक्स को सरल करता है, ताकि रैपिंग कोड एक तरह की घोषणात्मक इंटरफ़ेस परिभाषा भाषा (आईडीएल) का रूप ले ले।
ctypes मॉड्यूल मानक पुस्तकालय का हिस्सा है, और इसलिए यह स्वाइप की तुलना में अधिक स्थिर और व्यापक रूप से उपलब्ध है , जो हमेशा मुझे समस्याएं देने के लिए प्रेरित करता था ।
Ctypes के साथ, आपको अजगर पर किसी भी संकलन समय निर्भरता को संतुष्ट करने की आवश्यकता है, और आपका बंधन किसी भी अजगर पर काम करेगा जिसमें ctypes है, न कि केवल उसी के खिलाफ संकलित किया गया था।
मान लें कि आपके पास एक सरल C ++ उदाहरण वर्ग है जिसे आप foo.cpp नामक फ़ाइल में बात करना चाहते हैं:
#include <iostream>
class Foo{
public:
void bar(){
std::cout << "Hello" << std::endl;
}
};
चूंकि ctypes केवल C फ़ंक्शन से बात कर सकते हैं, इसलिए आपको उन्हें "C" बाहरी घोषित करने की आवश्यकता होगी।
extern "C" {
Foo* Foo_new(){ return new Foo(); }
void Foo_bar(Foo* foo){ foo->bar(); }
}
आगे आपको इसे साझा लाइब्रेरी में संकलित करना होगा
g++ -c -fPIC foo.cpp -o foo.o
g++ -shared -Wl,-soname,libfoo.so -o libfoo.so foo.o
और अंत में आपको अपना अजगर आवरण लिखना होगा (उदाहरण के लिए fooWrapper.py)
from ctypes import cdll
lib = cdll.LoadLibrary('./libfoo.so')
class Foo(object):
def __init__(self):
self.obj = lib.Foo_new()
def bar(self):
lib.Foo_bar(self.obj)
एक बार जब आपके पास ऐसा हो तो आप इसे कॉल कर सकते हैं
f = Foo()
f.bar() #and you will see "Hello" on the screen
extern "C" { __declspec(dllexport) Foo* Foo_new(){ return new Foo(); } __declspec(dllexport) void Foo_bar(Foo* foo){ foo->bar(); } }
ऐसा करने का सबसे तेज़ तरीका SWIG का उपयोग कर रहा है ।
SWIG ट्यूटोरियल से उदाहरण :
/* File : example.c */
int fact(int n) {
if (n <= 1) return 1;
else return n*fact(n-1);
}
इंटरफ़ेस फ़ाइल:
/* example.i */
%module example
%{
/* Put header files here or function declarations like below */
extern int fact(int n);
%}
extern int fact(int n);
यूनिक्स पर एक पायथन मॉड्यूल का निर्माण:
swig -python example.i
gcc -fPIC -c example.c example_wrap.c -I/usr/local/include/python2.7
gcc -shared example.o example_wrap.o -o _example.so
उपयोग:
>>> import example
>>> example.fact(5)
120
ध्यान दें कि आपके पास अजगर-देव होना चाहिए। इसके अलावा कुछ सिस्टमों में अजगर हेडर फाइलें /usr/include/python2.7 में आपके द्वारा इंस्टॉल किए गए तरीके के आधार पर होंगी।
ट्यूटोरियल से:
SWIG लगभग हर भाषा सुविधा के समर्थन के साथ एक काफी पूर्ण C ++ कंपाइलर है। इसमें प्रीप्रोसेसिंग, पॉइंटर्स, क्लासेस, इनहेरिटेंस और यहां तक कि C ++ टेम्प्लेट शामिल हैं। SWIG का उपयोग लक्ष्य भाषा में प्रॉक्सी कक्षाओं में संरचनाओं और कक्षाओं को पैकेज करने के लिए भी किया जा सकता है - बहुत स्वाभाविक तरीके से अंतर्निहित कार्यक्षमता को उजागर करना।
मैंने इस पृष्ठ से पायथन <-> C ++ में अपनी यात्रा शुरू की, जिसका उद्देश्य उच्च स्तर के डेटा प्रकारों को जोड़ना है (पायथन सूचियों के साथ बहुआयामी एसटीएल वैक्टर) :-)
दोनों ctypes और बूस्टहोमथॉन (और एक सॉफ्टवेयर इंजीनियर नहीं होने) के आधार पर समाधानों की कोशिश करने के बाद, मैंने उन्हें उच्च स्तरीय डेटाटाइप्स बाइंडिंग की आवश्यकता होने पर जटिल पाया है, जबकि मैंने SWIG पाया है ऐसे मामलों के लिए अधिक सरल ।
यह उदाहरण इसलिए SWIG का उपयोग करता है, और इसे लिनक्स में परीक्षण किया गया है (लेकिन SWIG उपलब्ध है और व्यापक रूप से विंडोज में भी उपयोग किया जाता है)।
इसका उद्देश्य पायथन को सी ++ फ़ंक्शन उपलब्ध कराना है जो 2 डी एसटीएल वेक्टर के रूप में एक मैट्रिक्स लेता है और प्रत्येक पंक्ति के औसत (1 डी एसटीएल वेक्टर के रूप में) देता है।
C ++ में कोड ("code.cpp") निम्नानुसार है:
#include <vector>
#include "code.h"
using namespace std;
vector<double> average (vector< vector<double> > i_matrix) {
// Compute average of each row..
vector <double> averages;
for (int r = 0; r < i_matrix.size(); r++){
double rsum = 0.0;
double ncols= i_matrix[r].size();
for (int c = 0; c< i_matrix[r].size(); c++){
rsum += i_matrix[r][c];
}
averages.push_back(rsum/ncols);
}
return averages;
}
समतुल्य शीर्ष लेखिका ("code.h") है:
#ifndef _code
#define _code
#include <vector>
std::vector<double> average (std::vector< std::vector<double> > i_matrix);
#endif
ऑब्जेक्ट फ़ाइल बनाने के लिए हम पहले C ++ कोड संकलित करते हैं:
g++ -c -fPIC code.cpp
फिर हम अपने C ++ फ़ंक्शंस के लिए एक SWIG इंटरफ़ेस परिभाषा फ़ाइल ("code.i") को परिभाषित करते हैं।
%module code
%{
#include "code.h"
%}
%include "std_vector.i"
namespace std {
/* On a side note, the names VecDouble and VecVecdouble can be changed, but the order of first the inner vector matters! */
%template(VecDouble) vector<double>;
%template(VecVecdouble) vector< vector<double> >;
}
%include "code.h"
SWIG का उपयोग करके, हम SWIG इंटरफ़ेस परिभाषा फ़ाइल से C ++ इंटरफ़ेस स्रोत कोड उत्पन्न करते हैं।
swig -c++ -python code.i
हम अंततः उत्पन्न C ++ इंटरफ़ेस स्रोत फ़ाइल संकलित करते हैं और एक साझा लाइब्रेरी को उत्पन्न करने के लिए सब कुछ एक साथ जोड़ते हैं जो सीधे पायथन ("_" मामलों) द्वारा आयात करने योग्य है:
g++ -c -fPIC code_wrap.cxx -I/usr/include/python2.7 -I/usr/lib/python2.7
g++ -shared -Wl,-soname,_code.so -o _code.so code.o code_wrap.o
अब हम पायथन लिपियों में फ़ंक्शन का उपयोग कर सकते हैं:
#!/usr/bin/env python
import code
a= [[3,5,7],[8,10,12]]
print a
b = code.average(a)
print "Assignment done"
print a
print b
वहाँ भी है pybind11
, जो Boost.Python के हल्के संस्करण की तरह है और सभी आधुनिक C ++ कंपाइलर के साथ संगत है:
Pytorch
pytorch.org/tutorials/advanced/cpp_extension.html यह भी पूरी तरह से VS Community
विंडोज पर काम करता है
पाइरेक्स या साइथन की जाँच करें । वे C / C ++ और Python के बीच अंतर करने के लिए पायथन जैसी भाषाएं हैं।
आधुनिक C ++ के लिए, cppyy का उपयोग करें: http://cppyy.readthedocs.io/en/latest/
यह Cling, Cl ++ / LLVM के लिए C ++ दुभाषिया पर आधारित है। बाइंडिंग रन-टाइम पर है और कोई अतिरिक्त मध्यवर्ती भाषा आवश्यक नहीं है। क्लैंग के लिए धन्यवाद, यह C ++ 17 का समर्थन करता है।
पाइप का उपयोग करके इसे स्थापित करें:
$ pip install cppyy
छोटी परियोजनाओं के लिए, संबंधित लाइब्रेरी और उन हेडर को लोड करें, जिनमें आप रुचि रखते हैं। जैसे ctypes उदाहरण से कोड लेते हैं यह थ्रेड है, लेकिन हेडर और कोड सेक्शन में विभाजित है:
$ cat foo.h
class Foo {
public:
void bar();
};
$ cat foo.cpp
#include "foo.h"
#include <iostream>
void Foo::bar() { std::cout << "Hello" << std::endl; }
इसे संकलित करें:
$ g++ -c -fPIC foo.cpp -o foo.o
$ g++ -shared -Wl,-soname,libfoo.so -o libfoo.so foo.o
और इसका उपयोग करें:
$ python
>>> import cppyy
>>> cppyy.include("foo.h")
>>> cppyy.load_library("foo")
>>> from cppyy.gbl import Foo
>>> f = Foo()
>>> f.bar()
Hello
>>>
बड़ी परियोजनाओं को तैयार प्रतिबिंब जानकारी के ऑटो-लोडिंग और उन्हें बनाने के लिए सीमेक टुकड़ों के साथ समर्थन किया जाता है, ताकि स्थापित पैकेजों के उपयोगकर्ता बस उपयोग कर सकें:
$ python
>>> import cppyy
>>> f = cppyy.gbl.Foo()
>>> f.bar()
Hello
>>>
एलएलवीएम के लिए धन्यवाद, उन्नत सुविधाएँ संभव हैं, जैसे कि स्वचालित टेम्पलेट तात्कालिकता। उदाहरण जारी रखने के लिए:
>>> v = cppyy.gbl.std.vector[cppyy.gbl.Foo]()
>>> v.push_back(f)
>>> len(v)
1
>>> v[0].bar()
Hello
>>>
नोट: मैं दुखी का लेखक हूं।
swig
, ctypes
या boost.python
। आपके बजाय अपने c ++ कोड के साथ काम करने के लिए अजगर पाने के लिए कोड लिखना होगा ... python c ++ का पता लगाने के लिए कड़ी मेहनत करता है। यह मानते हुए कि यह वास्तव में काम करता है।
यह पेपर, सभी वैज्ञानिक जरूरतों के लिए पायथन का दावा करता है , मूल रूप से कहता है: पायथन में सब कुछ पहले प्रोटोटाइप। फिर जब आपको किसी भाग को गति देने की आवश्यकता हो, तो SWIG का उपयोग करें और इस भाग को C में अनुवाद करें।
मैंने इसका कभी उपयोग नहीं किया है लेकिन मैंने ctypes के बारे में अच्छी बातें सुनी हैं । यदि आप इसे C ++ के साथ उपयोग करने का प्रयास कर रहे हैं, तो नाम के माध्यम से नामकरण से बचना सुनिश्चित करें extern "C"
। टिप्पणी के लिए धन्यवाद, फ्लोरियन बोश।
मुझे लगता है कि अजगर के लिए cffi एक विकल्प हो सकता है।
लक्ष्य पायथन से सी कोड को कॉल करना है। आपको तीसरी भाषा सीखे बिना ऐसा करने में सक्षम होना चाहिए: हर विकल्प के लिए आपको उनकी खुद की भाषा (साइथन, स्विग) या एपीआई (ctypes) सीखने की आवश्यकता होती है। इसलिए हमने यह मानने की कोशिश की कि आप पायथन और सी को जानते हैं और एपीआई के अतिरिक्त बिट्स को कम से कम करते हैं जो आपको सीखने की जरूरत है।
सवाल यह है कि पायथन से सी फ़ंक्शन को कैसे कॉल किया जाए, अगर मैं सही ढंग से समझ गया। फिर सबसे अच्छा दांव सीटीप्स (पाइथन के सभी वेरिएंट्स में बीटीडब्ल्यू पोर्टेबल) हैं।
>>> from ctypes import *
>>> libc = cdll.msvcrt
>>> print libc.time(None)
1438069008
>>> printf = libc.printf
>>> printf("Hello, %s\n", "World!")
Hello, World!
14
>>> printf("%d bottles of beer\n", 42)
42 bottles of beer
19
एक विस्तृत गाइड के लिए आप मेरे ब्लॉग लेख का संदर्भ लेना चाह सकते हैं ।
आधिकारिक पायथन दस्तावेजों में से एक में C / C ++ का उपयोग करके अजगर को विस्तारित करने के बारे में विवरण है । SWIG के उपयोग के बिना भी , यह काफी सीधा है और विंडोज पर पूरी तरह से काम करता है।
साइथन निश्चित रूप से जाने का रास्ता है, जब तक आप जावा रैपर लिखने का अनुमान नहीं लगाते हैं, जिस स्थिति में SWIG बेहतर हो सकता है।
मैं runcython
कमांड लाइन उपयोगिता का उपयोग करने की सलाह देता हूं , यह साइथन का उपयोग करने की प्रक्रिया को बहुत आसान बनाता है। यदि आपको संरचित डेटा को C ++ में पास करने की आवश्यकता है, तो Google के प्रोटोबॉफ़ पुस्तकालय पर एक नज़र डालें, यह बहुत सुविधाजनक है।
यहाँ एक न्यूनतम उदाहरण है जो मैंने बनाया है जो दोनों उपकरणों का उपयोग करता है:
https://github.com/nicodjimenez/python2cpp
आशा है कि यह एक उपयोगी प्रारंभिक बिंदु हो सकता है।
पहले आपको यह तय करना चाहिए कि आपका विशेष उद्देश्य क्या है। पायथन इंटरप्रेटर के विस्तार और एम्बेडिंग पर आधिकारिक पायथन प्रलेखन ऊपर उल्लेख किया गया था, मैं बाइनरी एक्सटेंशन का एक अच्छा अवलोकन जोड़ सकता हूं । उपयोग के मामलों को 3 श्रेणियों में विभाजित किया जा सकता है:
अन्य इच्छुक लोगों के लिए कुछ व्यापक परिप्रेक्ष्य देने के लिए और चूंकि आपका प्रारंभिक प्रश्न थोड़ा अस्पष्ट है ("एक सी या सी ++ लाइब्रेरी के लिए") मुझे लगता है कि यह जानकारी आपके लिए दिलचस्प हो सकती है। ऊपर दिए गए लिंक पर आप बाइनरी एक्सटेंशन और इसके विकल्प का उपयोग करने के नुकसान पर पढ़ सकते हैं।
सुझाए गए अन्य उत्तरों के अलावा, यदि आप एक त्वरक मॉड्यूल चाहते हैं, तो आप नंबा की कोशिश कर सकते हैं । यह "आयात समय, रनटाइम, या स्टेटिकली (शामिल पाइक टूल का उपयोग करके) में एलएलवीएम कंपाइलर इंफ्रास्ट्रक्चर का उपयोग करके अनुकूलित मशीन कोड उत्पन्न करके काम करता है"।
मुझे दुःख बहुत पसंद है, यह पायथन को सी ++ कोड के साथ विस्तारित करना बहुत आसान बनाता है, जब जरूरत होती है तो नाटकीय रूप से प्रदर्शन बढ़ाता है।
यह शक्तिशाली और स्पष्ट रूप से उपयोग करने के लिए बहुत सरल है,
यहाँ यह एक उदाहरण है कि आप कैसे एक संख्यात्मक सारणी बना सकते हैं और इसे C ++ में एक क्लास मेंबर फंक्शन में पास कर सकते हैं।
import cppyy
cppyy.add_include_path("include")
cppyy.include('mylib/Buffer.h')
s = cppyy.gbl.buffer.Buffer()
numpy_array = np.empty(32000, np.float64)
s.get_numpy_array(numpy_array.data, numpy_array.size)
C ++ में:
struct Buffer {
void get_numpy_array(int beam, double *ad, int size) {
// fill the array
}
}
आप बहुत आसानी से (CMake के साथ) एक Python मॉड्यूल भी बना सकते हैं, इस तरह आप हर समय C ++ कोड को फिर से जमा करने से बचेंगे।
pybind11 न्यूनतम रननीय उदाहरण
pybind11 को पहले https://stackoverflow.com/a/38542539/895245 पर उल्लेख किया गया था, लेकिन मैं यहां एक ठोस उपयोग उदाहरण देना चाहता हूं और कार्यान्वयन के बारे में कुछ और चर्चा करना चाहता हूं।
सभी और सभी, मैं अत्यधिक pybind11 की सलाह देता हूं क्योंकि इसका उपयोग करना वास्तव में आसान है: आप बस एक हेडर शामिल करते हैं और फिर pybind11 टेम्पलेट जादू का उपयोग करता है ताकि आप C ++ वर्ग का निरीक्षण कर सकें जिसे आप पायथन को उजागर करना चाहते हैं और जो पारदर्शी तरीके से करता है।
इस टेम्प्लेट मैजिक का नकारात्मक पक्ष यह है कि यह संकलन को धीमा कर देता है, जो कि pybind11 का उपयोग करने वाली किसी भी फ़ाइल में कुछ सेकंड जोड़ देता है, उदाहरण के लिए इस मुद्दे पर की गई जांच देखें । PyTorch सहमत हैं ।
यहाँ एक न्यूनतम चल उदाहरण है जो आपको यह महसूस करने के लिए देता है कि pybind11 कितना भयानक है:
class_test.cpp
#include <string>
#include <pybind11/pybind11.h>
struct ClassTest {
ClassTest(const std::string &name) : name(name) { }
void setName(const std::string &name_) { name = name_; }
const std::string &getName() const { return name; }
std::string name;
};
namespace py = pybind11;
PYBIND11_PLUGIN(class_test) {
py::module m("my_module", "pybind11 example plugin");
py::class_<ClassTest>(m, "ClassTest")
.def(py::init<const std::string &>())
.def("setName", &ClassTest::setName)
.def("getName", &ClassTest::getName)
.def_readwrite("name", &ClassTest::name);
return m.ptr();
}
class_test_main.py
#!/usr/bin/env python3
import class_test
my_class_test = class_test.ClassTest("abc");
print(my_class_test.getName())
my_class_test.setName("012")
print(my_class_test.getName())
assert(my_class_test.getName() == my_class_test.name)
संकलित करें और चलाएं:
#!/usr/bin/env bash
set -eux
g++ `python3-config --cflags` -shared -std=c++11 -fPIC class_test.cpp \
-o class_test`python3-config --extension-suffix` `python3-config --libs`
./class_test_main.py
यह उदाहरण दिखाता है कि कैसे pybind11 आपको आसानी ClassTest
से पायथन को C ++ वर्ग को उजागर करने की अनुमति देता है ! संकलन एक फ़ाइल का नाम देता है class_test.cpython-36m-x86_64-linux-gnu.so
जो class_test_main.py
स्वचालित रूप से के लिए परिभाषा बिंदु के रूप में चुनता हैclass_test
मूल रूप से परिभाषित मॉड्यूल के ।
शायद यह कितना भयानक है कि यह केवल डूब जाता है यदि आप मूल पायथन एपीआई के साथ हाथ से एक ही काम करने की कोशिश करते हैं, तो उदाहरण के लिए देखें कि ऐसा करने का उदाहरण, जिसमें लगभग 10x अधिक कोड है: https://github.com /cirosantilli/python-cheat/blob/4f676f62e87810582ad53b2fb426b74eae52aad5/py_from_c/pure.c इस उदाहरण से आप देख सकते हैं कि कैसे C कोड को दर्दनाक और स्पष्ट रूप से सभी जानकारी के साथ बिट जानकारी के साथ पाइथन वर्ग बिट को परिभाषित करना है। मेटाडाटा ...)। यह सभी देखें:
pybind11 उसी तरह होने का दावा करता है, Boost.Python
जिसका उल्लेख https://stackoverflow.com/a/145436/895245 पर किया गया था, लेकिन अधिक न्यूनतम होने के कारण यह बूस्ट परियोजना के अंदर होने के प्रकोप से मुक्त होता है:
pybind11 एक लाइटवेट हेडर-ओनली लाइब्रेरी है जो पायथन में C ++ प्रकारों को उजागर करता है और इसके विपरीत, मुख्य रूप से मौजूदा C ++ कोड के पायथन बाइंडिंग बनाने के लिए। इसके लक्ष्य और वाक्यविन्यास डेविड अब्राहम द्वारा उत्कृष्ट Boost.Python पुस्तकालय के समान हैं: संकलन-समय आत्मनिरीक्षण का उपयोग करके प्रकार की जानकारी को संदर्भित करके पारंपरिक विस्तार मॉड्यूल में बॉयलरप्लेट कोड को कम करना।
Boost.Python के साथ मुख्य मुद्दा- और इस तरह की परियोजना को बनाने का कारण Boost है। बूस्ट यूटिलिटी लाइब्रेरी का एक बहुत बड़ा और जटिल सूट है जो अस्तित्व में लगभग हर C ++ कंपाइलर के साथ काम करता है। इस संगतता की अपनी लागत है: संकलक नमूनों के सबसे पुराने और बुग्गीस्ट का समर्थन करने के लिए आर्कैन टेम्पलेट ट्रिक्स और वर्कआर्ड्स आवश्यक हैं। अब जब C ++ 11-संगत कंपाइलर्स व्यापक रूप से उपलब्ध हैं, तो यह भारी मशीनरी अत्यधिक बड़े और अनावश्यक निर्भरता बन गई है।
इस लाइब्रेरी को Boost.Python के एक छोटे से स्व-निहित संस्करण के रूप में सोचें, जो हर उस चीज को छीन लेता है जो बाध्यकारी पीढ़ी के लिए प्रासंगिक नहीं है। टिप्पणियों के बिना, कोर हेडर फ़ाइलों को केवल कोड की ~ 4K लाइनों की आवश्यकता होती है और पायथन (2.7 या 3.x, या PyPy2.7> = 5.7) और C ++ मानक लाइब्रेरी पर निर्भर करती है। यह कॉम्पैक्ट कार्यान्वयन कुछ नई सी ++ 11 भाषा सुविधाओं (विशेष रूप से: ट्यूपल्स, लैम्ब्डा फ़ंक्शन और वेरिएड टेम्प्लेट) के लिए संभव था। अपने निर्माण के बाद से, यह पुस्तकालय कई मायनों में Boost.Python से आगे बढ़ गया है, जिससे कई सामान्य स्थितियों में नाटकीय रूप से सरल बाध्यकारी कोड हो गया है।
pybind11 वर्तमान Microsoft Python C बाइंडिंग दस्तावेज़ द्वारा केवल गैर-देशी वैकल्पिक hightlighted है: https://docs.microsoft.com/en-us/visualstudio/python/working-with-c-cpp-python-in दृश्य-स्टूडियो; दृश्य = बनाम 2019 ( संग्रह )।
उबंटू 18.04, pybind11 2.0.1, पायथन 3.6.8, जीसीसी 7.4.0 पर परीक्षण किया गया।