Please create an account to participate in the Slashdot moderation system

 



Forgot your password?
typodupeerror
×
Programming Books Media Book Reviews IT Technology

Write Portable Code 397

Simon P. Chappell writes "Much as a certain large software company located in the North-West of the United States of America might wish otherwise, there are many different operating systems and platforms in use in the world today. Software these days needs to able to operate in a disparate environment, either by communicating with these other platforms or by running on them or, increasingly, doing both. The Information Systems industry is making good progress with the communication half of the problem (even if a lot of it seems to involve large amounts of XML), but it is still struggling with the issues inherent with writing portable code. Brian Hook's contribution to all of this is Write Portable Code , which according to it's subtitle is an introduction to developing software for multiple platforms." Read on for the rest of Simon's review.
Write Portable Code
author Brian Hook
pages 248 (14 page index)
publisher No Starch Press
rating 8/10
reviewer Simon P. Chappell
ISBN 1593270569
summary I recommend this book to anyone working with portable code.


This is a book for computer programmers who write software designed to run on multiple platforms. It's also for programmers who suspect that their software may need to run on different platforms. This brings the book onto the radar for free and open source software authors, as they seek to create software that does not trap their end users into using specific operating systems. The Structure

There is a good progression shown in the eighteen chapters of the book. The first couple of chapters introduce the reader to portability concepts and then to some of the specific portability features of ANSI C and C++ that are used throughout the rest of the book.

The middle chapters of the book, cover individual portability topics. Some of these topics are the obvious ones, like Floating Point numbers, Networking, Operating System, File System and Dynamic Libraries. Other topics are less intuitively associated with portability, but when you read the chapter, it's inclusion is both obvious and necessary. These subjects include Source Code Management, Compilers, Scalability and Data. There is more to portability than many of us might suspect.

The last two chapters look at some alternative ways of getting portability. Scripting languages are discussed and the pros and cons of each ones portability is weighed. Lastly the use of cross-platform libraries and toolkits is addressed. Quite apropos given that the book's author is also the author of a cross platform library.

As an example of the thoughtful approach taken in this book, lets' take a look at the chapter on scripting languages. It's about the shortest chapter in the book, but representative of the approach that Mr. Hook brings to his work. This chapter takes a very honest look at the portability and cross-platform aspects of using scripting languages. There are advantages and disadvantages to the use of scripting languages. The advantages include everything that is a disadvantage of low-level languages like C/C++. Scripting languages do not require you to worry about about memory allocation, bindings, System API calls or any of the other bugbears of a low-level language programmer's life. The disadvantages of scripting languages naturally include performance, given their interpreted natures, a general lack of tools, such as development environments or IDEs and their tendency to sit high above the operating system with a corresponding detachment from low-level facilities and services of that same operating system. Mr. Hook's choice of scripting languages to consider was interesting. I expected Ruby and Python; both popular and capable in their own right. The inclusion of JavaScript/ECMAScript was also not too unexpected, now that standalone versions are bubbling up and becoming available. The real surprise, albeit a pleasant one, was the inclusion of Lua; a scripting language designed for platform portability and which seems to have managed to fully mature without making a blip on most geeks radar screens.

I like that Mr. Hook has experience writing portable software. This matched with his authorship of the Portable Open Source Harness (POSH) portability library and his contributions to the Simple Audio Library (SAL) gives a great deal of credence to his writing.

This is a solid "doing" book. Mr. Hook is under no illusion that he's writing an introduction to programming. This book has a consistent purpose to take experienced programmers and fully equip them to deal with portability and it does not deviate from this in the slightest.

The layout of the book is first rate, with clear typography, comfortable spacing, clear diagrams and tables and nicely highlighted callouts. I did not notice any obvious typos or glitches in the book. While the look of a book is not the author's fault if it is below par, a well presented book can enhance the reading and learning experience.

The examples are as realistic as possible. While some of the examples to teach principles might be simpler, they are typically backed up with examples from either the POSH or SAL projects, showing real world portability coding. The level of C/C++ required to understand the examples is higher than many books that I've read. That's not to say that the code seems obfuscated, but it's code that is taking into account aspects of the real world and is, by necessity, not simple. A further positive quality of the code examples is that they're very well explained; well enough that an inexperienced programmer with determination could follow them and come to an understanding.

Appendix B contains a summary of all of the portability rules presented through the book. There are twenty rules and each is reprised with a small explanation/reminder of it's application. An example: Rule 4 - "Never read or write structures monolithically from or to memory. Always read and write structures one element at a time, so that endian, alignment, and size differences are factored out."

If you're looking for more of a fluffy "about" book, then this is not it. This is not a complaint, rather I offer it as something to consider, before you buy what you might otherwise think is a beginner's book.

I must reiterate the non-trivial C/C++ example code the book contains. This book is for serious programmers and is not afraid to role up it's sleeves and cut real code.

This is a very well written and very readable book. There are many aspects to the subject matter of portability and Mr. Hook addresses more of them than many of us had previously suspected existed and addresses them with firm authority. I recommend this book to anyone working with portable code."


You can purchase Write Portable Code from bn.com. Slashdot welcomes readers' book reviews -- to see your own review here, read the book review guidelines, then visit the submission page.
This discussion has been archived. No new comments can be posted.

Write Portable Code

Comments Filter:
  • Scripting (Score:1, Informative)

    by Anonymous Coward on Wednesday November 09, 2005 @03:05PM (#13990894)
    When I made the decision to move to Linux, I started looking around for a cross-platform language. I was thinking about Java but there was an article on Slashdot about a Sun programmer who thought Java was not a good fit with their environment. One of the languages he suggested was Python. It has worked well for me.

    It may take a performance hit because it is interpreted but for the stuff I write that isn't usually a problem. It is relatively easy to distribute applications. I just burn a CD with python and the application. I write in a Linux environment and distribute to a Windows environment. I'm glad I chose Python because I get a lot more work done that if I were coding in Java.
  • by Rei ( 128717 ) on Wednesday November 09, 2005 @03:06PM (#13990900) Homepage
    C++ also has some very nicely organized ways you can write portable code. For example, data serialization - if I care about a piece of code being portable, all of my "structures" that may need to be shared are classes with the functions "serialize" and "deserialize", and all of the member variables/structures are classes with such functions (down to the most simple members, which are just wrappers around basic types; you can even wrap vectors and maps so that arrays of any kind are dealt with automatically). Each class's serialize function simply calls the serialize function on all of its members that need to be preserved; only the most basic types actually do any IO themselves.

    The net effect is that no matter how you change your code, or even if you template it over a range of types, everything always gets written out and read back in properly without having to resort to constantly changing special case read/write functions or having to know what is in every structure and how to write it. It keeps it very simple indeed. You could have a structure nested twenty levels deep containing arrays (vectors) and associative arrays (maps), and go in and change a dozen datatypes at different levels, and not have to modify a single piece of reading/writing code.
  • A few, simple rules (Score:2, Informative)

    by jandersen ( 462034 ) on Wednesday November 09, 2005 @03:07PM (#13990910)
    1. If writing for both UNIX and Windows - and/or possibly other systems, do the development on UNIX. The reason for this is simply that if you develop on Windows, you will all the time be pushed towards using non-portable features; the development toys, I mean tools, are made that way. Also, the portable parts of the C libs were made on UNIX with that system in mind.

    2. Stick to POSIX. The POSIX standard convers almost all the functionality needed for the internals of any application.

    3. Separate the GUI from the business end of the application. Use IPC to communicate between the parts.

    4. Avoid threads. Threads are the source of some of the hardest errors to debug; plus threads are NOT the same kind of fish on all platform, even when they are called 'POSIC threads'.
  • by WillAdams ( 45638 ) on Wednesday November 09, 2005 @03:08PM (#13990915) Homepage
    Try GNUstep, which is an opensource re-implementation of NeXT/Sun's OPENSTEP standard:

    http://www.gnustep.org/ [gnustep.org]

    It'll allow you to deploy on Linux, Windows, and possibly even the Sharp Zaurus depending on your project.

    They even have a web page up clarifying a mention of it in Aaron Hillegass' _Cocoa Programming on Mac OS X, Second Edition_

    http://www.gnustep.org/resources/BookClarification s.html [gnustep.org]

    It's licensed under the LGPL, so should be usable for most tasks.

    William
  • instructive (Score:2, Informative)

    by sammy baby ( 14909 ) on Wednesday November 09, 2005 @03:09PM (#13990927) Journal
    "Flipping the bird" is a colloquialism for making this gesture [wikipedia.org].
  • Re:Portable Code (Score:3, Informative)

    by moranar ( 632206 ) on Wednesday November 09, 2005 @03:12PM (#13990945) Homepage Journal
    See Figure 1 [dourish.com].
  • by ovit ( 246181 ) <dicroce@@@gmail...com> on Wednesday November 09, 2005 @03:13PM (#13990955) Homepage

    Apache Portable Runtime.

            td
  • Re:Unfortunate (Score:2, Informative)

    by keesh ( 202812 ) on Wednesday November 09, 2005 @03:31PM (#13991141) Homepage
    Eh? Java is 'cross platform' only in that it forces you to use the lowest common subset of all 'supported platforms'. Plus, far fewer platforms have a working JRE than a working C or C++ compiler or Perl or Ruby interpreter.
  • Re:but'cept (Score:1, Informative)

    by Anonymous Coward on Wednesday November 09, 2005 @03:51PM (#13991319)
    1) Performance is now basically the same as C/C++/Objective-C apps.

    No its not, peruse a few of the benchmarks here http://shootout.alioth.debian.org/ [debian.org]
  • Re:Unfortunate (Score:3, Informative)

    by dominator ( 61418 ) on Wednesday November 09, 2005 @04:00PM (#13991397) Homepage
    C and C++ are "portable assembly". All the languages that you mentioned are inherently portable and cross-platform.

    What Java has going over C and C++ is a useful large standard library framework. But heck, if you use say Qt, Mozilla's NSPR, Apache's APR, Glib, or something else as your C/C++ platform you'd have many of the same advantages that the Java library gives you.
  • by AKAImBatman ( 238306 ) <akaimbatman@gmaYEATSil.com minus poet> on Wednesday November 09, 2005 @04:48PM (#13991966) Homepage Journal
    I'm sorry, but if you can't manage to track down a JVM for your platform, you need your geek card revoked. I mean, hell, there are JVM instructions built into the damn ARM processors [arm.com]! What more do you want, an Angel to come down from the sky and say, "Hey you, over that way!"
  • First, split your code into four distinct modules. These modules need to be "black box" - ie: none of them can know the internals of the others. The first module should contain the internals of your code. The stuff that actually does the hard work, but doesn't try to do any I/O of any kind. It is also the only one you absolutely need to have.

    The second module deals with all the user interface stuff and nothing else. Any event handling is done in this module and nowhere else. That way, the rest of your code doesn't need to worry about what type of execution model is being used. It'll just work as you would expect. If there is no user interface, you don't need this module.

    To make the UI truly portable is hard. No specific capability is guaranteed. eg: GUIs don't guarantee a text console, and text consoles don't guarantee a GUI. My advice would be to split the module into two sub-modules. The first sub-module handles what you want to do, but contains nothing specific on how. For example, it might be filled with commands for selecting fonts, drawing lines, etc. However, it would not contain any calls to an underlying system. It should assume some abstract, theoretical, idealized user interface.

    The second sub-module (which may be a third-party library and not something you need to program at all) would then convert these commands into actual interface calls. If you're writing this yourself, I'd suggest starting with interfaces that are already fairly portable (eg: Qt, Gtk+, Ascii Art Library) where possible. If you can't, then you'll need to write alternative versions for different types of interface. But at least it's all in one place and squished down to the routine level, not entire screens.

    The third sub-module (again, third-party if available) would do the same as above but for file I/O. Again, the upper levels should make no assumptions at all. "Anything is possible in the next half hour", as Gerry Anderson would say. The lower levels then convert the "ideal" into what the system can actually do. Here, there are at least some standards. Use them. But then write special case code for platforms that can do better. Portable need not mean sub-optimal, it merely means sub-optimal (but guaranteed to work) until tuned.

    The fourth would do the same for networking. There is absolutely no reason why an application should know if you're using sockets, MPI message passing, IPv4, IPv6, DECNet or a guy waving two flags. At the application level, data comes in and goes out. The other end should be of no consequence, and the method of getting there should matter even less. High level networking should be abstract connections, using some sort of token to identify which connection is being referred to. There needs to be a middle layer here, to turn the abstract connection into a real networking protocol. The lowest level then handles the network calls required.

    You need the three layers, because you've two levels of abstraction (the network protocol and the network hardware) and therefore you need two levels of reification to turn the abstract into something usable. As network protocols can work over multiple mechanisms, the protocols are resolved first and the mechanisms second.

    Coding styles for ALL abstract components AND the first module should emphasize portability. There should be nothing system-specific there, so you should be able to use the absolutely vanilla ANSI specification of a language (where one exists). For C, if you want to cover ancient or obscure systems as well, you should duplicate all function declarations and external declarations, using a #ifdef to distinguish between ANSI C and K&R. There are probably other languages you need to support multiple variants of, just keep the areas where you need to have compile-time or interpret-time selection kept to a minimum.

    The low-level routines are only going to work on a limited range of systems, no matter what. Therefore, anything valid for that subset is fair

  • Re:What About UI? (Score:3, Informative)

    by miyako ( 632510 ) <miyako@g[ ]l.com ['mai' in gap]> on Wednesday November 09, 2005 @06:22PM (#13992940) Homepage Journal
    If you want a cross-platform GUI, then I think Java/Swing is the way to go a lot of the time.
    I program mainly in Java and C++, and if you are looking just at desktop machines (which is what I work with) then it's really not a big deal either way since you are mainly looking at *nix, Windows and maybe OS X. Swing is pretty much write-once for all three platforms- though you have to do some funkyness to get mac programs to look like mac programs under OS X. Qt is available for all three platforms as well. Athough I've never developed with it, AFAIK GTK+ is also available on OS X, as well as *nix and Windows.
    The thing is, it's no longer unreasonable to expect to write an application and have it run on a desktop system, a cell phone, and a PDA. Since most cellphones support at least a subset of Java, whereas I do not know of any that support Qt or GTK+, it seems that in these instances Java is the way to go.
  • by plumby ( 179557 ) on Wednesday November 09, 2005 @07:08PM (#13993356)
    I know you're kidding, but unfortunately there are a lot of responses here which indicate that Java is the end-all and be-all of portable programming.

    I'm sorry folks. Such people have never done real cross-platform programming. Java simply isn't an option on MANY platforms. If all you do is x86 platforms, and perhaps some Motorola workstation-class platforms, hey, you're fine.

    But that's not the real world.

    Might not be your real world, but in mine (enterprise-scale apps for a multinational financial company), we have no problem with portable Java (usually developed on Windows, mostly run in test/production on HP-UX, with the occasional Solaris and now Redhat Linux, and even a little running on our IBM mainframes).

    It's true that for some uses, such as certain embedded devices, Java is almost certainly not a sensible (or even possible) option, but in much of the industry it's a perfectly sensible choice for cross-platform development.

  • by Hal_Porter ( 817932 ) on Wednesday November 09, 2005 @08:29PM (#13993965)
    Jazelle runs something like 90% of the Java instructions, true. So a mobile phone for example does run most Java instructions.

    But you still need to support the rest in software. And then you need to get the java libraries, and write the native code that the java libraries end up talking to to touch the screen/filesystem/etc So you still need a JVM, even if most of the instructions run natively. And even if the API is the same, you are still running on a machine with either a tiny screen or none at all, not much CPU power, RAM or disk space and so on. And no hardware floating point, so any FP code will run like molasses. Oh, and the DRAM access is really slow.

    So you end up writing applications from scratch - its not as if something like Eclipse or Azureus or any desktop Java app will run on a mobile phone. And if you're going to do that, you might as well write them in C/C++ which is still quicker than Java, even with the Jazelle instructions.

    E.g. write some integer code. Look at what comes out of a decent ARM C compiler. It's tiny and it fits in the L1 cache. You can hoist all the CRT calls out of the loop to where they aren't time critical. The compiler can do a great job using the ARM instruction set to keep things quick. Now look at the Java equivalent. It's more instructions and because Java is stack based it needs to do much more loads from memory. And it needs to check all the array accesses, usually with calls into library code. So the footprint of the loop when it runs is too big to fit in the L1 cache.

    Plus you need to have flash memory space to store the java libs, native code and so on. If you JIT for performance, you need RAM for the native code and RAM or flash for the java, whereas for C you can run code out of flash. The C code will tend to use smaller libraries too.

    If you don't believe me, here's what John Carmack said

    http://www.armadilloaerospace.com/n.x/johnc/Recent %20Updates [armadilloaerospace.com]
          The biggest problem is that Java is really slow. On a pure cpu / memory /
          display / communications level, most modern cell phones should be
          considerably better gaming platforms than a Game Boy Advanced. With Java,
          on most phones you are left with about the CPU power of an original 4.77
          mhz IBM PC, and lousy control over everything.

With your bare hands?!?

Working...