8

I have fairly basic programming experience with Java and I've tried C++ and Python. While it makes sense for Java, the basic programs I've written in C++ have run just fine on Windows and OS X. I've been able to just send the source file to the other computer, compile, and run. The programs are fairly basic, mostly just basic object oriented stuff I've been doing to try to learn C++.

Obviously though, you can't just compile any C++ program on any machine and have it run fine. At what point does that happen? At what level of complexity does the platform start to matter and the program won't just run anywhere? Is it when you use platform specific libraries? Could a program be made cross platform in C++ just using cross platform libraries?

I've been trying to figure this out on my own but everything I've found either goes over my head or simply doesn't answer the question, much of what comes up are emulators or people asking what languages are cross platform.

  • 2
    Platform-specific libraries, nonstandard compiler extensions, any reliance on how bits are actually laid out in memory, and any other form of undefined/unspecified behavior are the typical reasons I know of for code becoming platform specific. If you avoid all of that, yes C++ is fairly portable by default. – Ixrec May 3 '15 at 23:24
  • "Could a program be made cross platform in C++ just using cross platform libraries?" This is mostly true. You also need to compile (make the binaries) for each platform because compiled machine code is specific to the architecture. – rwong May 3 '15 at 23:24
  • 1
    You could use Qt or POCO frameworks. – Basile Starynkevitch May 4 '15 at 11:12
6

There is a very clear line in the sand between cross-platform and mono-platform:

Does a program use only those APIs exposed by the Standard Library it is built on?

If you target a standard implementation, then any platform that implements that standard should, in theory, compile and run your program correctly. There are plenty of exceptions, but in general if you avoid clever tricks you should be able to avoid many of those exceptions.

The reason why this issue comes up specifically with C++ is that for the longest time the C++ Standard Library did not include many modules that are useful for non-trivial programs. Concurrency and GUI are the two big ones. This meant that a program built using only the C++ Standard Library could not have many of the features we expect from modern software.

How do we write cross-platform software that does stuff the Standard Library does not support?

You mention "cross platform libraries," which in practice are normally called "frameworks" or "toolkits" based on their scope. The way to write software in C++ that is cross-platform is to target not only the Standard Library, but a framework that builds on your target platforms.

Essentially, you end up externalizing the platform-specific bits to another library. For example, wxWidgets is a popular framework. You can use its classes to construct a GUI and related functionality (e.g. standard dialogs for selecting files). Under the covers, it uses conditional compiling to implement the GUI using the native GUI for each platform. But as the user of the library, none of that matters to you.


Historical note: here in 2015 C++ compilers and libraries are, for the most part, really good. Go back a few years, and that is not true. C++ did not have an official standard until 1998, many years after its inception. It took vendors a long time to update their compilers and libraries to implement the standard correctly. Vendor-specific extensions abounded (and are still around, actually). Some compilers had nonstandard headers and functionality. Code portability was virtually nonexistent. C++'s reputation in terms of portability still suffers.

5

At what level of complexity does the platform start to matter and the program won't just run anywhere?

Basically anything non-trivial. If you write a non-trivial program, you will end up accidentally depending on a compiler-specific way that it orders overloads, looks up names, and other complex things. Furthermore, practically all non-trivial programs depend on non-Standard platform-specific behaviour because the Standard doesn't really provide anything except a few containers.

However, non-trivial programs can vary widely in how easy they are to port to another platform. If you programmed it well and stuck to the rules, you can port fairly easily, and bonus if you can abstract the pieces into a library (which may have already been provided for you, e.g. Boost.Filesystem).

Programs mostly only become very difficult to port between platforms if they perform tasks that are inherently platform-specific, for example, writing data to disk with certain atomicity/consistency guarantees, or, if you were a moron and went around doing stupid things that were never what you should have done in the first place, like casting between ints and pointers.

  • 2
    Surely this overstates the case? I know that more esoteric C++ code may run into various compiler bugs in older or lower-quality compilers, but any reasonably standards-conforming compiler should going to handle things like overloading and name lookup the same. The Standard library provides I/O, and (starting with C++11) threading, and filesystem support is being standardized. – Josh Kelley May 4 '15 at 19:10
  • @JoshKelley: That is basically nothing compared to what most programs require. Also, some very common compilers like MSVC do implement overloading, SFINAE and name lookup differently with different observable results. – DeadMG May 6 '15 at 23:35
1

In very simple terms, what makes a program cross-platform is your ability to take the sources from one environment, compile them in another and have the finished product work as expected.

In less simple terms, it's having full overlap between what the program expects to be available and what your target environments provide. Once you do anything that makes the overlap less than 100%, such as using an environment-specific library or a language feature with undefined behavior, you've tied your program to the environments(s) that can supply the non-overlapping features.

("Platform" is a bit of a squishy word. People can talk about Windows and Unix as platforms or Linux, OS X, BSD and Solaris as platforms even though they're all nominally Unix. Stir in running any of the above on different hardware architectures and things become even more nebulous. Having said that, I'll start using the word.)

Fortunately, there are standards to ease this problem:

Languages. You're writing C++, which was first standardized by the ISO in 1998. Any program you write that conforms to that standard can be compiled and run with the expected results on any platform with a conforming compiler and runtime. There's no limit to the size or sophistication of the program as long as it doesn't deviate from the standard. If a program that provably meets the standard doesn't run as expected on a given platform, the implementation of the language on that platform becomes suspect. Many languages have carefully-designed test suites that can be used to verify conformance.

Java gets a special mention because not only does it standardize a language, it also standardizes object code, which makes its programs runnable anywhere without recompilation. This is accomplished by pushing the point of conformance down an additional layer into a platform-customized virtual machine (or even hardware) which is capable of running the object code.

APIs. The calls you make to have your program do certain things can be standardized as well. Like languages, these APIs and the libraries that implement them can be set up to behave as the callers expect using an underlying implementation suitable for a particular platform. One such API is the IEEE's POSIX standards, which arose as a way to stem the fragmentation that was happening in Unix during the 1980s. (I was around then; that aspect of it wasn't fun.) By defining standard calls and behavior, system vendors could give their customers confidence that migrating to their OS wasn't going to entail huge amounts of work as it had in the past. POSIX was widely adopted and is still in wide use almost 30 years later.

I've done numerous projects which slavishly adhered to the standards because I knew they were going to have to run on multiple platforms. What I got for my troubles was code that worked everywhere I'd planned to run it and pleasantly surprised me on a few where I hadn't.

0

Basically, when you 'touch' stuff outside your program. One particular case (I don't dare to say the only case) is when you use libraries related to the operating system. Things like using shared memory between process and printing fancy things on the console. In the first case you access a piece of memory being handled by the operating system, in the second case the screen is also controlled by the operating system.

Doing a GUI is OS dependent, but there are GUI libraries made to be cross-platform, so you don't have to worry about that. At least in theory.

Is difficult to make anything non-trivial to be cross-platform. The good new is that if you use the right libraries and do proper testing is not that difficult to make software portable, at least if the code is not too big. How big is too big depends on your team's size, programming expertise, and so on.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.