26 lipca 2015

[python] V8 JavaScript Engine

V8 to silnik JavaScript, natomiast pyv8 jest jego wrapperem do pythona.
Niestety nie udało mi się znaleźć informacji, w jaki sposób przekompilować wersję dla python-a 3. Z tego co wyczytałem projekt opiera się na boost::python-ie, może okazać się także konieczne zainstalowanie narzędzia scons. Wrapper bazuje na rewizji r19623 i skrypt budujący cofa repozytorium do tej wersji. Jest więc starsze o około 6000 commitów o tego co jest na trunku. Mam nadzieje, że nie oznacza to, że projekt obumiera.
svn checkout http://v8.googlecode.com/svn/trunk/ v8
svn checkout http://pyv8.googlecode.com/svn/trunk/ pyv8

export V8_HOME=~/v8
cp pyv8
python setup.py build

# biblioteka zostanie zapisana w ~/.local
python setup.py install --user 
Przykład:
#! /usr/bin/env python2

import PyV8

ctxt = PyV8.JSContext()
ctxt.enter()
result = ctxt.eval('var str = "Hello world!"; \
                    str.substring(1, 5);')
print(result)
Wynik:
ello

24 lipca 2015

[python] HTTP POST requests - PycURL

Kolejne podejście do wykonania HTTP POST requesta (poprzednie opisałem tutaj). Przydatne linki:
Biblioteka znacznie bardziej popularna i posiadająca wiele portów do różnych języków, co wiąże się z tym, że łatwiej jest odnaleźć przykłady i rozwiązać potencjalne problemy. W rozdziale Quick Start, znajduje się kilka interesujących, z omówieniem ich mechanizmów. Ciekawy wydał mi się pycrul.WRITEDATA. Z tego co udało mi się rozumieć, biblioteka nie posiada bufora na odpowiedź od serwera i to zadaniem aplikacji jest ustawienie go, dzięki tej opcji.
#! /usr/bin/env python3

import pycurl
import urllib.parse
from io import BytesIO

def post3():
    buffer = BytesIO()
    c = pycurl.Curl()

    c.setopt(pycurl.URL, 'http://requestb.in/kcco1337')
    c.setopt(pycurl.WRITEDATA, buffer)

    post_data = {'login': 'user1', 'password': 'hasło 1'}
    post_fields = urllib.parse.urlencode(post_data)
    c.setopt(pycurl.POST, 1)
    c.setopt(pycurl.POSTFIELDS, post_fields)

    c.perform()
    c.close()

    print(buffer.getvalue().decode('iso-8859-1'))
Raw body:
password=has%C5%82o+1&login=user1

23 lipca 2015

Budowanie aplikacji NaCl (NativeClient) w przeglądarce

Podjąłem próbę zbudowania przykładowej aplikacji NaCl w przeglądarce, ale muszę się przyznać, że odniosłem porażkę. Może w przyszłości jeszcze się tym zajmę. Do pracy zachęcił mnie filmik:


Ale w kilku miejscach jest on nieaktualny, dlatego warto równolegle śledzić odświeżoną wersję dokumentacji:
Kilka problemów, które mi się przytrafiły.
  • Przy pierwszym odpaleniu, konsola zawisała podczas ściągania pakietów. Pomogło zamknięci i ponowne odpalenie, za każdym razem kolejne pakiety się instalowały i konsola zawisała na jakimś następnym. Trzeba było kontynuować, dopóki nie pokazał się prompt bash-a.
  • Uruchomienie programu natychmiast zamykało konsolę. Rozwiązaniem okazało się wyłącznie "Native Client GDB-based debugging".
  • Po odpaleniu dema, aplikacja wyświetlała w przeglądarce status: "Status: ERROR [NaCl module load failed: Nexe crashed during startup]". Niestety tego nie udało mi się już pokonać.

22 lipca 2015

[gdb] - pomocne instrukcje

Współpraca z gdb zaczyna się rozwijać, więc mała notka z najbardziej przydatnymi komendami, ale najpierw przydatne linki:
Te klika komend warto wpisać na stałe do pliku konfiguracyjnego ~/.gdbinit.
# zastąpienie domyślnego assemblera att, na wersję intel-owsą
set disassembly-flavor intel

# zapisywanie historii poleceń do pliku
set history filename ~/.gdb_history
set history save on
set history size 100000

# TUI - text user interface (po wywołaniu layout)
set tui border-kind ascii
set tui border-mode half
set tui active-border-mode bold
Komendy TUI, które pozwalają zorientować się co tak naprawdę dzieje się z programem:
  • layout - wyświetla pseudo okno, w którym może być prezentowany kod assemblera, rejestry lub kod źródłowy. Przykładowe wywołania: layout asm, layout src, layout reg
  • info win - informacja o wyświetlanych oknach
  • focus - przełączanie focusu na różne okna, przydatne przy pracy z myszką, przykład: focus cmd
  • refresh - odświeża wszystkie okna, sam nie wiem czemu, ale ich wygląd często się psuje. Wygodniejszą metodą służącą odświeżaniu jest zastosowanie skrótu klawiaturowego, ale o tym poniżej
Przydatne skróty klawiaturowe w pracy z TUI.
  • Wyłączanie TUI, można zastosować jeden z poniższych skrótów:
    • Ctrl+x Ctrl+a
    • Ctrl+x a
  • Odświeżanie okien - odpowiednik komendy refresh:
    • Ctrl+x+l
  • Włączanie layoutu
    • Ctrl+x 1 - jedno okno
    • Ctrl+x 2 - dwa okno

  • Szybkie odwołanie się do komend z historii, bez potrzeby fokusownia okna cmd i używania strzałek
    • Ctrl+p/Ctrp+w - góra/dół

Operowanie z kodem, to przede wszystkim prezentacja wycinków pamięci w jakimś przyjaznym formacie:
  • display - wyświetla zmienną/rejestr, przy każdym zatrzymaniu programu, np. display $eax
  • x - wyświetlanie zwartości pamięci, format wywołania wygląda następująco
    x/[rozmiar][format][rozmiar pola] [adres]
    , gdzie:
    • Rozmiar - ilość bajtów jakie będą wyświetlone
    • Format:
      • d - dec
      • x - hex
      • z - jakeiś inne hex?
      • u - unsigned dec
      • f - float
      • c - char (ASCII)
      • a - adres
      • i - instrukcja
      • s - string
    • Rozmiar pola:
      • b - byte (8 bitów)
      • h - halfword (16 bitów)
      • w - word (32 bity)
      • g - giant (64 bity)
Przykład użycia x:
(gdb) x/12xb 0x8048af4
0x8048af4 <_ZN8MyClass1C2Ev>:    0x55  0x89  0xe5  0x83  0xec  0x08  0x8b  0x45
0x8048afc <_ZN8MyClass1C2Ev+8>:  0x08  0x83  0xec  0x0c
Debugowani kodu assemblera trochę różni się trochę od sytuacji, gdy działamy tylko z kodem źródłowym. W takim wypadku zamiast wyniku działania jednej linii kodu, interesuje nas bardziej jaki jest wynik działania jednej instrukcji kodu:
  • si - wykonuje pojedynczą instrukcję

21 lipca 2015

Budowanie wyrażeń regularnych z regex101.com

Super strona ułatwiająca budowanie i debugowanie wyrażeń regularnych. Nie znam nic co można by porównać do możliwości tej aplikacją, z tak przyjaznym interfejsem.

13 lipca 2015

Boost.Python - Pisanie rozszerzeń dla python-a w C++

Boost.Python pozwala na wykorzystanie klas i metod zaimplementowanych w C++ w Pythonie i odwrotnie. Skupiłem się na pierwszej części. Garść przydatnych linków:
Takie mieszanie technologi, niestety sprawia, że szukanie błędów staje się trochę denerwujące, ale już po dwóch godzinach udało mi się uzyskać działający przykład, który mniej więcej jest tym co chciałem uzyskać. Co ciekawe (jak mówi dokumentacji), kod napisany w C++, rzadko będzie wymagał zmian dostosowujących go do współpracy z Boost.Python-em, co uważam jest dużym plusem.
W pierwszej kolejności należy stworzyć plik źródłowy (tutaj SimplePrinter.cpp), z deklaracją wrappera - gdzie mówimy jakie interfejsy będą widoczny w Pythonie. Boost.Python posiada abstrakcję na std::vector, z której tutaj skorzystałem. Później korzystając z takiego modułu, należy stworzyć specjalny obiekt, dzięki któremu można skonwertować np. listę pythonową i skorzystać z danych w niej zawartych w kodzie C++ (przykład na końcu). Kilka ważnych uwag.
  • Należy pamiętać aby nazwa modułu (w BOOST_PYTHON_MODULE) była identyczna z nazwą pliku biblioteki dynamicznej, inaczej podczas importowanie takiego modułu można natknąć się niewiele mówiący błąd.
  • Nazywanie metody "print" sprawiła, że uzyskiwałem błąd, gdy próbowałem z takiej metody skorzystać. Najpewniej jest to związane z jakimś konfliktem, gdyż print (Python 2) jest słowem kluczowym.
#include <iostream>
#include <string>
#include <vector>

struct SimplePrinter
{
    void setWords(std::vector<std::string> words) {
        _words = words;
    }

    size_t count() const {
        return _words.size();
    }

    void show() {
        std::cout << "All: ";
        for (const auto& w : _words) {
            std::cout << w << " ";
        }
        std::cout << std::endl;
    }

private:
    std::vector<std::string> _words;
};

#include <boost/python.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
using namespace boost::python;

BOOST_PYTHON_MODULE(simple_printer)
{
    class_<std::vector<std::string>>("VectorOfStrings")
        .def(vector_indexing_suite<std::vector<std::string>>());

    class_<SimplePrinter>("SimplePrinter")
        .def("setWords", &SimplePrinter::setWords)
        .def("count", &SimplePrinter::count)
        .def("show", &SimplePrinter::show);
}
W celu skompilowania przykładu skorzystałem z Pythonowego distutils, które umożliwia budowanie modułów (nie miałem z tym narzędziem wcześniej do czynienia, ale wydaje się bardzo schludnym rozwiązaniem). W pierwszej kolejności należy stworzyć plik setup.py (w moim przypadku w tym samym katalogu, gdzie znajdowały się źródła). Tutaj ponownie, trzeba sprawdzić, czy nazwa modułu zgadza się z tą, która została zadeklarowana w wraperze C++. Co ważne, moja klasa korzysta z nowego standardu C++14, stąd dodatkowa flaga: extra_compile_args.
#!/usr/bin/env python

from distutils.core import setup
from distutils.extension import Extension

setup(name="PackageName",
    ext_modules=[
        Extension(name="simple_printer",
            sources=["SimplePrinter.cpp"],
            libraries=["boost_python"],
            extra_compile_args=["-std=c++14"])
    ])
Budowanie:
$ cd cpp_boost_python
$ ls
setup.py  SimplePrinter.cpp

$ python setup.py build

running build
running build_ext
building 'simple_printer' extension
creating build
creating build/temp.linux-x86_64-2.7
x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fno-strict-aliasing -D_FORTIFY_SOURCE=2 -g -fstack-protector-strong -Wformat -Werror=format-security -fPIC -I/usr/include/python2.7 -c SimplePrinter.cpp -o build/temp.linux-x86_64-2.7/SimplePrinter.o -std=c++14
cc1plus: warning: command line option ‘-Wstrict-prototypes’ is valid for C/ObjC but not for C++
creating build/lib.linux-x86_64-2.7
c++ -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions -Wl,-Bsymbolic-functions -Wl,-z,relro -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -D_FORTIFY_SOURCE=2 -g -fstack-protector-strong -Wformat -Werror=format-security -Wl,-Bsymbolic-functions -Wl,-z,relro -D_FORTIFY_SOURCE=2 -g -fstack-protector-strong -Wformat -Werror=format-security build/temp.linux-x86_64-2.7/SimplePrinter.o -lboost_python -o build/lib.linux-x86_64-2.7/simple_printer.so
Po zbudowaniu biblioteka będzie znajdować się w podkatalogu build (build/lib.linux-x86_64-2.7/simple_printer.so).
Na sam koniec test działania.
$ cd build/lib.linux-x86_64-2.7
$ ls 
simple_printer.so

$ python
>>> import simple_printer
>>> s = simple_printer.SimplePrinter()
>>> words = simple_printer.VectorOfStrings()
>>> words.extend(w for w in ["first", "second"])
>>> s.setWords(words)
>>> s.count()
2
>>> s.show()
All: first second