the bumpy road to the linux build

January 27th, 2007 by Bramz

The description of LiAR says: “‘LiAR isn’t a raytracer’ is an open source, cross platform, object-oriented and extendable ray tracer written in C++ and Python by Bram de Greve”. However, that’s not entirely true since currently, LiAR only runs on the Windows platform. It’s time to live up to the promise. To be honnest, I’ve attempted it before but I ran into troubles and I gave up. Now I want to pursue it to the end, however. And while I encounter and overcome the obstacles, I’ll try to document them.

The goal is to use Python’s distutils and write a single setup.py to build and install LiAR. So no make or autotools are allowed. The idea is that eventually, the setup.py can be used to build LiAR on Windows as well. I’ve decided against using setuptools (eggs) and SCons because distutils is already included in the standard libraries of Python. But first, I’ll be trying to get it working on linux alone, what is already good for quite some challenges.

First, a recap of how LiAR is built. It consists of different (extension) modules organized in a star topology. The center module is called the kernel and provides general definitions (Spectrum, Intersection, …) and abstract classes (SceneObject, Shader, Texture, …) that are used as vessels and ports by which the concrete modules (scenery, shaders, textures) must communicate. Each concrete module only depends on kernel (and of course 3rd party libraries if appropriate), and since LiAR is implemented in C++ this means including its headers and linking to it dynamically.

Unfortunately, distutils is not designed for architecture like that. It can build multiple extension modules in a single package, but they’re supposed to be independent of each other. They cannot be linked in a binary way, communication should be done through Python. Modules don’t have the usual libfoo.so name anyway. However, distutils does support the build of C libraries that the extension modules can link against, but only for static libraries and what we need is dynamic linkage.

This calls for a bit of hacking. Luckily, distutils has a mechanism that allows to add extra custom commands. This can be used to hijack the build_clib command (for static libraries) and use it to build shared libraries. A new command liar_build_shared_lib is derived from build_clib and the relevant methods are overridden. It’s a bit too long to post here (you can see for yourself in the code repository), but basically it’s a blend between build_clib and build_ext. The cmdclass argument in setup() is used to inject liar_build_shared_lib as the new build_clib.

The concrete modules need to be linked to kernel, but a Python extension module does not have the regular libfoo.so name, but simply foo.so instead. What I’ve done to solve this, is to create libkernel.so which is kernel sans kernel_init.cpp, and a shallow module kernel.so that consists only of kernel_init.cpp. This way, all modules can link to a regular library, and kernel.so exposes its content to Python.

By now, things pretty much compile. I can even import liar in Python, though I must use the LD_LIBRARY_PATH environment variable hack to tell the modules where they can find libkernel.so. And once I start running some scripts I quickly get segmentation faults. So there are still some things to solve =)

Also, I need to clean up setup.py a bit, because things were simply thrown together until it worked. Options are still pretty much hardcoded. And also, I would like to be install the kernel headers so that custom LiAR extensions can be build using the installed LiAR.

Comments are closed.