Yesterday I discussed getting ready to do some C work on the Raspberry Pi. Today I'll go into a bit more of how it went.
First I pulled the project source from my git repository using git clone, changed into the project directory and typed make. I had no real expectations what might happen. This is a project which has been mostly developed and tested on x86-64 Linux boxes, with the occasional foray onto a Macbook. I was genuinely surprised how far it got before failing. In this case because of some missing symbols.
This first problem was pretty easy to resolve, in principle. The missing symbols were all to do with curl. The project uses libcurl to make HTTP and HTTPS requests, and the linker could not find the library. It was apparent that I needed to install the libcurl library. A bit of playing with apt-get of various names turned up no obvious candidates so I headed for google. It turns out that there are several flavours of curl libraries, and the interactive curl tool itself. In this case what I needed was sudo apt-get libcurl4-openssl-dev. Good; install it and try the build again.
This time the build completed but there were a slew of unit test failures and segmentation faults, which took a bit of time to winkle out. At least Check could point me at the area of code being tested, even if I had to take it from there.
In order to find and fix these problems, I needed to run the build/test process many times. As things progressed I got fed up with the odd escape character sequences which kept appearing in the output. I'd imagine that on a real console or local terminal screen there would be some sort of emphasis (bold, italic, colour and so on), but on my ssh terminal session they just appeared as odd characters getting in the way of the error messages. I'm sure there are various ways to address this, but the one that I plumped for was to add export LC_ALL=C to the shell start-up script (.bashrc). This stops a lot of output from generating these sequences, and (according to some web sources, at least) can even make things run faster.
Some representative problems I fixed include:
- A bit of code which was using memcpy with overlapping start and end addresses. This blew up on the Raspberry Pi, but that's OK, as the spec for this library function explicitly states that it should only be used for non-overlapping moves. There is a safer version memmove specially for use in these kinds of cases.
- A function was returning a value of -1 to indicate an error in a type of char. This is a bit of a grey area - the existence of "unsigned char" can be taken to imply that "char" is signed. It's interesting that system level calls all return a type of int for this usage pattern, however.
- The gmtime function which converts a numeric "seconds since the epoch" timestamp to a pointer to a ztruct tm seems to use the same internal structure for each call, so it's important to take a copy before the next call to gmtime. In this case the code was attempting to use gmtime twice in the parameters to one printf call, with confused results.
- In one place a string was copied using memcpy but then not correctly zero-terminated. It seems that the intel Linux version conveniently happens to have some zeroes in the right place, but it's not something that the code should rely on!
Again I was largely surprised. The faults I found were all quite subtle, and all arguably problems with the original code rather than anything which needed "porting" or otherwise changing for this specific target architecture. To me this is impressive, given that this machine has a different CPU with a totally different instruction set, different memory and hardware architecture, different peripherals and storage, and only a small fraction of the memory space of the original platform. It looks like Linux and C are much more portable than I thought.
The outcome of this exercise which surprised me the most, though, was that once I had the code running, writing C under Linux on the Raspberry Pi no longer seemed the interesting challenge it had at the beginning. Essentially it has become too much like my day job. What has begun to interest me now, though, is the idea of programming the "bare metal" of the machine with no operating system, no library code, and no device drivers. Everything from scratch!
More on that idea next time.