Em termos muito simples, o que torna um programa multiplataforma é sua capacidade de pegar as fontes de um ambiente, compilá-las em outro e fazer com que o produto final funcione conforme o esperado.
Em termos menos simples, é haver sobreposição total entre o que o programa espera estar disponível e o que os ambientes de destino fornecem. Depois de fazer qualquer coisa que faça a sobreposição menor que 100%, como o uso de uma biblioteca específica do ambiente ou um recurso de linguagem com comportamento indefinido, você vincula seu programa aos ambientes que podem fornecer os recursos não sobrepostos.
("Plataforma" é um pouco de uma palavra mole. As pessoas podem falar sobre Windows e Unix como plataformas ou Linux, OS X, BSD e Solaris como plataformas, embora todas sejam nominalmente Unix. Execute qualquer uma das opções acima em diferentes as arquiteturas de hardware e as coisas ficam ainda mais nebulosas. Dito isso, vou começar a usar a palavra.)
Felizmente, existem padrões para facilitar esse problema:
Línguas. Você está escrevendo C ++, que foi padronizado pela ISO em 1998. Qualquer programa que você escreva em conformidade com esse padrão pode ser compilado e executado com os resultados esperados em qualquer plataforma com um compilador e tempo de execução em conformidade. Não há limite para o tamanho ou sofisticação do programa, desde que não se desvie do padrão. Se um programa que atenda ao padrão não for executado conforme o esperado em uma determinada plataforma, a implementação do idioma nessa plataforma se tornará suspeita. Muitos idiomas têm suítes de teste cuidadosamente projetadas que podem ser usadas para verificar a conformidade.
O Java recebe uma menção especial porque não apenas padroniza uma linguagem, como também padroniza o código do objeto, o que torna seus programas executáveis em qualquer lugar sem recompilação. Isso é feito empurrando o ponto de conformidade para baixo em uma camada adicional em uma máquina virtual personalizada da plataforma (ou mesmo hardware) capaz de executar o código do objeto.
APIs. As chamadas que você faz para que seu programa faça certas coisas também podem ser padronizadas. Assim como os idiomas, essas APIs e as bibliotecas que os implementam podem ser configuradas para se comportarem conforme os chamadores esperam, usando uma implementação subjacente adequada para uma plataforma específica. Uma dessas APIs são os padrões POSIX do IEEE , que surgiram como uma maneira de conter a fragmentação que estava acontecendo no Unix durante a década de 1980. (Eu estava na época; esse aspecto não era divertido.) Ao definir chamadas e comportamento padrão, os fornecedores de sistemas podiam dar a seus clientes a confiança de que a migração para o sistema operacional não implicaria uma quantidade enorme de trabalho, como ocorreu no passado. O POSIX foi amplamente adotado e ainda é amplamente utilizado quase 30 anos depois.
Eu fiz vários projetos que aderiram aos padrões de maneira servil porque eu sabia que eles teriam que ser executados em várias plataformas. O que obtive pelos meus problemas foi um código que funcionava em todos os lugares que eu planejava executá-lo e me surpreendeu agradavelmente em alguns que não tinha.