ti-enxame.com

Escrevendo código C ++ multiplataforma (Windows, Linux e Mac OSX)

Esta é minha primeira tentativa de escrever qualquer coisa um pouco complicada em C++. Estou tentando criar uma biblioteca compartilhada com a qual possa interagir com os aplicativos Objective-C e .NET (ok, essa parte vem depois ...)

O código que eu tenho é -

#ifdef TARGET_OS_MAC
  // Mac Includes Here
#endif

#ifdef __linux__
  // Linux Includes Here
  #error Can't be compiled on Linux yet
#endif

#ifdef _WIN32 || _WIN64
  // Windows Includes Here
  #error Can't be compiled on Windows yet
#endif

#include <iostream>

using namespace std;

bool probe(){
  #ifdef TARGET_OS_MAC
    return probe_macosx();
  #endif
  #ifdef __linux__
    return probe_linux();
  #endif
  #ifdef _WIN32 || _WIN64
    return probe_win();
  #endif
}

bool probe_win(){
  // Windows Probe Code Here
  return true;
}

int main(){

  return 1;
}

Eu tenho um aviso do compilador, simplesmente untitled: In function ‘bool probe()’:untitled:29: warning: control reaches end of non-void function - mas também gostaria muito de receber informações ou recursos que as pessoas possam sugerir sobre como escrever melhor esse tipo de código ....

35
Lee Hambley

Vou abordar esta função específica:

bool probe() {
#ifdef TARGET_OS_MAC
  return probe_macosx();
#Elif defined __linux__
  return probe_linux();
#Elif defined _WIN32 || defined _WIN64
  return probe_win();
#else
#error "unknown platform"
#endif
}

Escrever dessa maneira, como uma cadeia de if-Elif-else, elimina o erro porque é impossível compilar sem uma declaração de retorno válida ou sem o #error.

(Acredito que o WIN32 esteja definido para Windows de 32 e 64 bits, mas não poderia ser informado definitivamente sem procurá-lo. Isso simplificaria o código.)


Infelizmente, você não pode usar #ifdef _WIN32 || _WIN64: consulte http://codepad.org/3PArXCxo para obter uma amostra de mensagem de erro. Você pode usar o operador especial definido apenas por pré-processamento , como fiz acima.


Em relação à divisão de plataformas de acordo com funções ou arquivos inteiros (como sugerido ), você pode ou não querer fazer isso. Depende dos detalhes do seu código, como o quanto é compartilhado entre plataformas e o que você (ou sua equipe) acha melhor manter a funcionalidade sincronizada, entre outros problemas.

Além disso, você deve lidar com a seleção de plataforma em seu sistema de compilação, mas isso não significa que você não pode usar o pré-processador: use macros definidas condicionalmente (pelo makefile ou sistema de compilação) para cada plataforma. De fato, essa é frequentemente a solução mais prática com modelos e funções embutidas, o que a torna mais flexível do que tentar eliminar o pré-processador. Ele combina bem com a abordagem de arquivo inteiro, portanto você ainda a usa quando apropriado.

Você pode querer ter um único cabeçalho de configuração que converta todas as várias macros específicas do compilador e da plataforma em macros conhecidas e compreendidas que você controla. Ou você pode adicionar -DBEAKS_PLAT_LINUX à linha de comando do compilador - por meio do sistema de compilação - para definir essa macro (lembre-se de usar um prefixo para nomes de macro).

32
Roger Pate

em vez de se repetir e escrever as mesmas linhas #ifdef .... novamente, novamente e novamente, talvez você seja melhor declarando o método probe () em um cabeçalho e fornecendo três arquivos de origem diferentes, um para cada plataforma. Isso também tem o benefício de que, se você adicionar uma plataforma, não precisará modificar todas as fontes existentes, mas apenas adicionar novos arquivos. Use seu sistema de construção para selecionar o arquivo de origem apropriado.

Estrutura de exemplo:

include/probe.h
src/Arch/win32/probe.cpp
src/Arch/linux/probe.cpp
src/Arch/mac/probe.cpp

O aviso ocorre porque o probe () não retorna um valor. Em outras palavras, nenhum dos três #ifdefs corresponde.

46
stijn

Parece que nenhum dos TARGET_OS_MAC, __linux__, _WIN32 ou _WIN64 é definido no momento em que você compila seu código.

Então é como se seu código fosse:

bool probe(){
}

É por isso que o compilador reclama de atingir o final de uma função não nula. Não há cláusula return.


Além disso, para a pergunta mais geral, aqui estão minhas diretrizes ao desenvolver software/bibliotecas de várias plataformas/arquitetura:

Evite casos específicos. Tente escrever um código independente do SO.

Ao lidar com coisas específicas do sistema, tente agrupar as coisas em classes "opacas". Por exemplo, se você estiver lidando com arquivos (APIs diferentes no Linux e Windows), tente criar uma classe File que incorpore toda a lógica e forneça uma interface comum, independentemente do sistema operacional. Se algum recurso não estiver disponível em um sistema operacional, lide com ele: se o recurso não faz sentido para um sistema operacional específico, geralmente é bom não fazer nada.

Em resumo: quanto menos #ifdef o melhor. E não importa o quão portátil seja o seu código, teste-o em todas as plataformas antes de liberá-lo.

Boa sorte ;)

5
ereOn

Para adicionar algo mais a isso, além das opções pendentes acima, as diretivas __linux__ e _WIN32 são conhecidos pelo compilador, onde o TARGET_OS_MAC a diretiva não era, isso pode ser resolvido usando __Apple__. Fonte: http://www.winehq.org/pipermail/wine-patches/2003-July/006906.html

1
Lee Hambley

O aviso é que, se nenhuma das definições estiver realmente definida, você não terá return em sua função de análise. A correção para isso é colocada em um padrão return.

1
Tristan