Вход | Регистрация

Интрегриране на Python код в C/C++

  • Thumbs_upThumbs_upThumbs_upThumbs_upThumbs_upThumbs_upThumbs_up

    Случайно се сетих, че ще ми е полезно да мога да интегрирам python код в едно свое проектче на С. След извесно ровене из нета видях начин как може да го направя. Ето го и него:

    Първо трябва да инклуднете Python.h във сорса си(това става с #include <python3.0/Python.h> за python3.0 например). Това разбира се ще иска малко настройки при компилация. След доста ровене из нета стигнах до извода, че:

    g++/gcc alabala.c -o alabala -I/usr/local/include/python3.0 -pthread -lm -ldl -lutil -lpython3.0

    при мен върши работа (имам някаква бегла идея защо). Вероятно на друг компютър пътят ще е различен, но това би следвало да се очаква. Eто малко примерен код на нещо:

    #include <python3.0/Python.h>
        int main()
        {
            Py_Initialize();
            PyRun_SimpleString( "print('Hello World :D')" );
            Py_Finalize();
            return 0;
        }
    #include <python3.0/Python.h>
        int main()
        {
            Py_Initialize();
            FILE *fp      = fopen ("test.py",   "r+");
            PyRun_SimpleFile (fp, "test.py");
            Py_Finalize();
            return 0;
        }

    Ето и едно полезно линкче

    И още едно линкче

    P.S: Посочения горе начин за компилиране работи дори и при условие, че няма динамична библиотека(<path>/lib/libpython3.0.so, където <path> е мястото, където е инсталирана библиотеката). Ако има динамична библиотека работи и посочения от Славомир Къслев начин:

    gcc test.c -o test -I/usr/local/include/python3.0  -lpython3.0

    който очевидно е по-хубав, но изисква да има динамична библиотека на компютъра. Ако библиотеката не е в някое от стандартните места (/usr/lib, /usr/local/lib) може да се наложи експлицитно да се посочи къде е тя. Това става с добавяне на -L<път> към опциите на компилатора (-l показва коя библиотека да търси като първо се търси динамична по подразбиране и ако не съществува такава се търси статична). Опцията -I показва къде да търси неща от include-а освен във стандартните места.

    Динамичните библиотеки отсъстват от някой компютри, защото при компилация на питон от сорс(както аз бях направил) по подразбиране те не се създават. Може да се каже по време на конфигурацията да се създаде shared library(динамична библиотека). Това става с добавяне на --enable-shared към опциите на ./configure извикването. Тя е такава(динамичната), че не е необходимо да се посочват още опции на компилатора за да работи той добре, докато тези неща са необходими на статичната библиотека, за да може тя да функционира правилно.

    Съществена разлика при едното и при другото компилиране - на код embed-ваш python - (възможно е и при наличие на динамична библиотека да се каже на компилатора да не я ползва), е размера на получения изпълним файл. При използване на статична библиотека ми се получи файл 3.7 МБ, а при използване на динамична - 7 КБ, което е доста съществено.

    Ако някой има още корекции към написаното да каже и ще ги добавя :)

    Успех с използването на питон в С код или обратното :)

    15.04.2009 (променeно 26.04.2009)
  • Мерси, аз доста се ровех за това. Палче за теб! :P

    15.04.2009
  • Не е ли малко прекалено? Би трябвало и само

    gcc -o spam spam.c -I/usr/include/python3.0/ -lpython3.0

    да работи.

    Също така, пичовете от второто линкче съветват да се използва по-скоро

    #include <Python.h>

    пред #include <python3.0/Python.h> (иначе не би имало нужда и от -I/usr/include/python3.0/).

    15.04.2009
  • Аз пробвах с първото ти предложение и не проработи поне при мен ;) Иначе ако за теб работи - радвам се :)

    Колкото до второто - сигурно си прав, че като посочваш директорията, в която да търси файловете не е необходимо да слагаш python3.0 отпред, но със сигурност не вреди, защото съм пробвал ;) Накратко, ако някой е пробвал и видял, че и други по-привлекателни за него начини работят - нека каже. Предполагам, че всички ще се радваме да научим още нещо :)

    Поздрави :)

    16.04.2009
  • Thumbs_up

    Аз пробвах с първото ти предложение и не проработи поне при мен...

    Можеш ли да пратиш каква грешка ти дава? Останалите неща, които му даваш са shared library dependencies на libpython3.0 и линкера си се оправя сам и без тях.

    slavi@slavi-desktop:~$ ldd /usr/lib/libpython3.0.so
    linux-vdso.so.1 =>  (0x00007fff367fe000)
    libpthread.so.0 => /lib/libpthread.so.0 (0x00007f2b2e104000)
    libdl.so.2 => /lib/libdl.so.2 (0x00007f2b2df00000)
    libutil.so.1 => /lib/libutil.so.1 (0x00007f2b2dcfc000)
    libm.so.6 => /lib/libm.so.6 (0x00007f2b2da77000)
    libc.so.6 => /lib/libc.so.6 (0x00007f2b2d705000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f2b2e6e5000)

    Rant mode: Отношението 'при мен работи' е вредно. При Пешо, който между другото ползва PeshOS, и там python3.x е компилиран срещу libanti_posix_threads.so вместо libpthread.so например, няма да работи.

    Колкото до второто - сигурно си прав, че като посочваш директорията, в която да търси файловете не е необходимо да слагаш python3.0 отпред...

    Основния мотив да не слагаш python3.0/foo.h в кода е, че ако някой се опита да ти компилира програмата, а на неговата система има python3.1 (да речем =-), ще трябва да промени всеки файл от кода, за да ти подкара приложението. С варианта, който хората съветват, в най-лошия случай (т.е. ако ползваш plain-old-makefiles), ще трябва да се промени само един ред от Makefile-а.

    С това настрана, най-правилните линкове, които можеш да прочетеш, са тези от сайта на Python:

    Extending and Embedding the Python Interpreter

    Python/C API Reference Manual

    16.04.2009 (променeно 16.04.2009)
  • Даваше ми линкинг ерор. Не знам за теб, но аз се прибрах вкъщи и там не съм на същия компютър ;) Тъй че не мога да ти копирам точно грешката - сори. А това, което исках да ти кажа с това, че не на всеки комп работи това, което предложи, беше, че метода явно не е напълно универсален(и аз очквах да работи, ама не).

    Все пак мисля, че идеята не е да спорим кое работи и кое не - нека всеки си пробва и установи за себе си, ако се интересува от това.

    Колкото до писането на директорията в инклуда - не е добра практика за python - да, но едва ли е фатално(аз не бих го инклуднал в повече от един-два файла все пак).

    Мерси за линкчетата - ще ги погледна ;)

    Поздрави :)

    16.04.2009
  • Като постнеш каква е грешката и инфо за системата, може би ще мога да ти помогна.

    Също виж: Cargo cult programming

    16.04.2009
  • О, +1 за Cargo Cult Programming-а. Ако не знаеш защо нещо става/не става, не програмираш, а хвърляш боб. Хвърлянето на боб е забавно (особено ако го хвърляш по интересни хора), но не е никак интересно от програмистска гледна точка.

    17.04.2009
  • Тъй... Първо, ако използваш -I<dir> май е ясно, че не е добър варянт, ако искаш да ползваш мейкефайл. Това го ползваш, ако искаш да си правиш нещо за теб и само за теб. Тъй че частта с това ще стане със заместване на един ред във мейкфайла - не изглежда много усместна. От друга страна би трябвало и при питон да може да стане както с gtk. Там включваш gtk/gtk.h, настройваш cflags и още няколко неща и си пиеш чая. Ако ми кажеш, че и там не е хубаво да слагам gtk/ - няма да ти повярвам ;) Освен това, ако версията на питон е друга, много е вероярно част от нещата да не вървят. Тъй че променянето на няколко реда в няколко файла няма да ти е най-големия проблем. Също така аз знам какво прави python3.0/ във кода ми. Не знам точно какво прави всичко при компилирането, но това е друго неща ;) Тъй че мерси за линкчето - позабавлявах се докато го четох ;)

    18.04.2009 (променeно 18.04.2009)
  • Еррр, на -I<dir> мястото му е в CFLAGS в Makefile-а (ако ползваш Makefiles).

    А това за #include <python3.0/spam.h> го пише също във второто "линкче", което постна (не съм го измислил аз, в случай че имаш предразсъдъци към мен). Доколкото имам наблюдения, Python е доста стабилен между версиите дори и в C API (като излючим 2.x vs 3.x). Виж например този блог пост.

    Както и да е.

    PS: BTW, как мислиш, че gtk се оправя без -I<dir>?

    Hint:

    $ pkg-config --cflags gtk+-2.0
    -I/usr/include/gtk-2.0 -I/usr/lib/gtk-2.0/include -I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/pango-1.0 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12  

    За съжаление Python, не инсталира pkg-config пакет и човек се оправя сам.

    18.04.2009 (променeно 18.04.2009)
  • Не видях как да си настроя makefile-а, а като цяла не съм много запознат с тях. За това, което ми е трябвало съм си настройвал makefile, но като цяло не ги разбирам много(абе доста малко ги разбирам). Тъй че ще трябва да почета малко за да видя как да го направя.

    Иначе нямам нищо против теб, но това което каза не ми показа точно защо "моето" да е толкова по-лошо от нормалния варянт. Явно частта с това как точно да се оправи мейкефайла е ключовото място. Иначе видях, че не е добре при python да се ползва pythonx.y/Python.h. Но и твойто с -I -l изглеждаше, че има почти същите проблеми. Но както и да е. Ще потърся за makefile-ове и ще видя дали ще успея да го измисля. Е може и да не е много скоро, тъй като тук съм на windows... Но като съм си пак на моя компютър ще го пробвам.

    П.С: за gtk го правя с

    cc `pkg-config --cflags --libs gtk+-2.0` test.c -o test
    18.04.2009 (променeно 18.04.2009)
  • ... за gtk го правя с

    cc pkg-config --cflags --libs gtk+-2.0 test.c -o test

    Именно. Ако Python имаше pkg-config би го правил по същия начин.

    Малко знания са по-опасни от никакви знания.

    Утре някой колега ще тръгне да прави нещата по глупавия начин, защото го е прочел от някой "експерт дето поства по форумите". Затова живеем в свят, в който Ninety percent of everything is crap.

    Python поне е уникален в това, че добрите 10% информация са на едно място.

    18.04.2009 (променeно 18.04.2009)
  • Малкото знания някак трябва да станат на повече знания - не може изведнъж да научиш всичко. А и на много места където съм чел са писали незапознати хора, тъй че от там идва част от объркването.

    Част от причината да почна темата, от друга страна, беше някой по-запознат да поправи неточностите ми, за да мога да разбера нещата, които и на мен не са ми ясни/изглеждат ми нелогични.

    Предполагам, че като видим защо на мен не ми е тръгнало това с -I и -l ще добавим към началото на темата изводите и хората от форума няма да се объркват.

    Весели празници :)

    19.04.2009
  • Добавих корекции в първия си пост под формата на послепис, за да може, ако някой погледне темата, още в началото й да получи максималко много информация :)

    26.04.2009