Structuring cross-platform C code
Working on a current project that has to be written in C (no C++ or Java) and work cross-platform (Windows and Unix). I've grown so accustomed to C++ and Java that I'm not really sure how best to structure my code to make it portable across multiple platforms. Obviously, I'm trying to adhere to ANSI C as closely as possible, but I have various modules (serial input/output, network sockets, threads) that vary from platform to platform.
Currently, I've split things up so that I have a base project that defines various header files: mem.h, serial.h, socket.h, etc. These define platform-independent "interfaces" (function prototypes) to all of the functionality I need. They pass data around using opaque pointers, similar to the way the FILE pointer is used with fopen() and friends.
Under the base project I have subdirectories for "mem", "serial", "socket", etc. Under each of these, I have separate directories for "windows", "unix", etc. So in base/serial/windows/serial.c, I have the Windows-specific implentation of the serial interface, whereas the Unix-specific version is in base/serial/unix/serial.c.
This structure, while usable, seems so very...verbose. I'm wondering if there's a better way to structure things. I'd like to stay away from littering my code with #ifdefs. Does anyone have any suggestions....?
Mr. Nobody
Thursday, May 13, 2004
You're on the right track. In general, you'll find that having a well-defined interface between system-specific and generic code works a lot better than #ifdef blocks in the code.
I think it might be a little neater to have a directory structure where each "platform" has its own sub-tree.
Something like this:
base/
subsystem1/
subsystem2/
...
platform/
win32/
unix/
Then, you just need to be real aggressive about factoring out all the platform-agnostic code, and minimizing the amount that ends up in the "windows" and "unix" directories.
-Mark
Mark Bessey
Thursday, May 13, 2004
From what I can tell our system (a former employer) was like yours. In our source code management system we had all of the 'base' code in as one project then different projects for different OS which linked to the common code in the base. Then the build process would simply get all of the code in the project and build binaries. Worked pretty well.
MR
Thursday, May 13, 2004
Mark beat me to it. Separate platform trees is the way to do it instead of #ifdefs all over creation. It gets too messy in a very short time because it isn't just PC vs Unix but PC vs Solaris vs AIX vs HPUX vs Linux and soon you can't read your code.
Separate trees duplicate the same files with slightly different code in several places. You might think that would cause big maintenance headaches, but it actually helps by forcing you to sequester the truely platform-specific from the commonalities that you end up with only a few files that are really different. Soon you figure out how to parameterize the majority of them.
old_timer
Thursday, May 13, 2004
If you've got Unix experience, you might want to take a look at the autoconf toolchain. It's kinda painful to get it working for a windows build, unfortunately.
Chris Tavares
Thursday, May 13, 2004
Definitely sounds like the "platform tree" method is much more prefarable than the #ifdef route. Does anyone know of a good open-source project to look at that separates its code by platform? I'd just like to browse through something to get a better feel for it.
Mr. Nobody
Thursday, May 13, 2004
To break it down even farther we have one project with two platform trees PC and Unix. There used to be other platforms like OpenVMS and other systems but they're long gone. Under Unix there are sub-trees for Common, AIX, HP, Linux & Sun so that those things which are common to all Unix are in only one place. And the folders for each different company each hold extremely few files. Sometimes only one. With about 1 million lines of code, that which is specific to Sun and only Sun turns out to be maybe a dozen lines of code.
old_timer
Thursday, May 13, 2004
Mr Nobdy asks: "Does anyone know of a good open-source project to look at that separates its code by platform?"
Take a look at the Tcl scripting language source. It's very clean, readable C code, organised as suggested above in generic plus platform-specific directories. Also includes some of the functionality you mention eg. cross-platform sockets, serial comms. See http://tcl.tk/software/tcltk/downloadnow84.tml
Colin Macleod
Thursday, May 13, 2004
Mr Nobody
I'd second the Tcl recommendation. You might also want to look at Plan 9, a highly portable operating system written in not quite ANSI C:
http://plan9.bell-labs.com/plan9dist/
A paper on adding support for new architectures gives a good overview of the structure of the source code:
http://plan9.bell-labs.com/sys/doc/libmach.html
You might also look at the chapter on "Portability" in "The Practice of Programming" by Kernighan & Pike.
as
Thursday, May 13, 2004
Check out
http://apr.apache.org/
"The mission of the Apache Portable Runtime (APR) project is to create and maintain software libraries that provide a predictable and consistent interface to underlying platform-specific implementations. The primary goal is to provide an API to which software developers may code and be assured of predictable if not identical behaviour regardless of the platform on which their software is built, relieving them of the need to code special-case conditions to work around or take advantage of platform-specific deficiencies or features."
It's used in Subversion (source control system).
Joel Spolsky
Fog Creek Software Thursday, May 13, 2004
Thanks for the pointers everyone, this is exactly the kind of information I was looking for...
Mr. Nobody
Thursday, May 13, 2004
Look at wxWidgets (formerly wxWindows). Heck, if you drop the "can't use C++" limitation, *use* wxWidgets -- it probably does most of what you want already. :-)
Radius guy
Saturday, May 15, 2004
Recent Topics
Fog Creek Home
|