Day 41 — Exploring pybind11 with a snek

Today I paired with Ilia to walk through the poppler codebase. This was of great help as I don't have a lot of experience navigating through large C/C++ codebases. I got to learn about how cmake and C++ preprocessor directives work!

We also walked through the pdftoppm code to see how it converts a PDF to an image, and which sections of the code were not needed to write a pdftoppm Python wrapper.

Ori had also mentioned that pybind11 is worth a closer look to glue C/C++ and Python together. Since the poppler codebase is BIG, I thought about writing a small C example that I could then wrap using pybind11.

I've been toying with the idea of writing a snake game in C, so I started reading about ncurses and got the hello world working:


  #include <ncurses.h>

  void main()
  {
      initscr();                // start ncurses mode
      printw("Hello, world!");  // print hello world
      refresh();                // print it on the real screen
      getch();                  // wait for user input
      endwin();                 // end ncurses mode
  }


  $ gcc snek.c -lncurses
  $ ./a.out

Surprisingly, the order of -lncurses matters. If you put it before snek.c, the linker throws a lot of "undefined reference" errors!

Wrapping the code with pybind11 turned out to be super simple! I just needed to include the pybind11 header, change the name of the main function, and add some pybind11 boilerplate to declare the name of the Python module that exports the game function:


  #include <ncurses.h>
  #include <pybind11/pybind11.h>

  void game()
  {
      initscr();                // start ncurses mode
      printw("Hello, world!");  // print hello world
      refresh();                // print it on the real screen
      getch();                  // wait for user input
      endwin();                 // end ncurses mode
  }

  PYBIND11_MODULE(snek, m) {
      m.doc() = "Actually a snek!";
      m.def("game", &game, "The game function");
  }

After compiling snek.c into a shared library:


  $ g++ -O3 -Wall -shared -std=c++11 -fPIC `python3 -m pybind11 --includes` snek.c -o example.`python3-config --extension-suffix` -lncurses

I was able to import snek in Python, and call the game function, which ran the ncurses "hello world" program from Python!


  >>> import snek
  >>> snek.game()
  >>>

I also worked on writing a résumé because I have to start looking for jobs soon. Tomorrow I'll try to wrap pdftoppm using pybind11, and then try to write an actual snek game (which can be shipped to PyPI) over the week!