My experience, is to work with both approaches. I will say more like "parallel", "series" & "incrementally".
For example, I'm designing an app. with 10 modules, and want to migrate to 3 platforms.
So I, start with a single platform, and 3 modules, usually the most important, like "core" or "system".
Then, I try to migrate that same app. to the second platform. Sometimes, I add some stuff, refactor types name, and switch back to the original platform those changes.
Example (Using "C#" & "Plain C" as "platforms, altought, you may think in "Linux", "iOS", Windows Compact Edition):
I have a custom XML parser in C# (.NET), for practical sources, "a platform", I want to migrate it to "Plain C", as another "platform".
I have this enumeration type in C#:
But, in "Plain C", for some reason, I need to prefix, the equivalent enumeration:
So, I decide, than I go back to the "C#" code, and replace it with:
When, I have those 3 modules in equivalent code, in 2 platforms, I add the migration to the third platform. Again, sometimes, I add things or refactor things, and apply those changes back to the previous platforms.
When I have the 3 platforms working, I start to add an additional module, to each platform.
Repeat the process, until all modules are available in the 3 platforms.
I don't try to do or migrate the whole app., neither "serial", neither "parallel". Only parts of of it. Add the "incremental" concept.
Even, that a section of code is working in a platform, is possible, that when migrating to another you'll change types names, and apply back those changes to the first destination.