Aspectos Essenciais para Portar Aplicações C++ do Windows para Linux

Introdução

Recentemente obtive um código-fonte desenvolvido originalmente para Windows. Após depuração, funcionou perfeitamente no ambiente Windows, porém o cenário de produção exigia execução em servidores Linux. Assim, tornou-se necessário realizar a portabilidade do código C++.

Um colega sugeriu a utilização da biblioteca Boost, pois a mesma já abstrai diversas diferenças entre os sistemas operacionais, permitindo que um mesmo código seja executado em ambas as plataformas. Porém, algumas diferenças não são abstraídas pela biblioteca e precisam ser tratadas manualmente.

  1. Carregamento de Bibliotecas

No Windows, pode-se utilizar diretivas de pré-processador para especificar bibliotecas:

#ifdef _WIN32
#pragma comment(lib, "osip2.lib")
#pragma comment(lib, "osipparser2.lib")
#pragma comment(lib, "eXosip.lib")
#pragma comment(lib, "ProtocoloRede.lib")
#pragma comment(lib, "xmlparser.lib")
#else
// Configurações para Linux
#endif

No entanto, esta abordagem não funciona no Linux. Nesse sistema operacional, as bibliotecas devem ser linkingadas diretamente durante a compilação:

g++ -o aplicacao main.cpp -leXosip2 -ljrtp -ljthread -losip2 -losipparser2 -ltinyxml
  1. Caminhos de Arquivos de Cabeçalho

O Windows aceita ambas as notações de caminho:

#include "eXosip2/eXosip.h"
#include "eXosip2\eXosip.h"

O Linux, por outro lado, reconhece apenas a notação com barras normais:

#include "eXosip2/eXosip.h"
  1. Compilação no Linux

No Linux, geralmente não é necessário especificar o tipo de biblioteca. O compilador procura automaticamente por bibliotecas compartilhadas (libnome.so) antes de buscar bibliotecas estáticas (libnome.a). É importante especificar os caminhos de biblioteca com a opção -L:

g++ -std=gnu++11 -ggdb3 Modulo.cpp Cliente.cpp Sessao.cpp Protocolo.cpp \
    -fPIC -shared -o libclientsdk.so -L /usr/local/lib \
    -I /home/projeto/sdk -I /usr/include \
    -leXosip2 -ljrtp -ljthread -losip2 -losipparser2 -ltinyxml \
    -lboost_system -lboost_filesystem -lpthread -lboost_thread

O compilador primeiro procura em /usr/local/lib (especificado por -L), depois nos diretórios do sistema.

  1. flags de Compilação

Ao compilar bibliotecas compartilhadas, é fundamental incluir a flag -fPIC para gerar código indepenednte de posição:

relocation R_X86_64_32 against symbol can not be used when making shared object; recompile with -fPIC

Erros Comuns e Soluções

Erro: bits/c++config.h não encontrado

In file included from algo_mgr.cpp:1:
/usr/include/c++/4.8/string:28: fatal error: bits/c++config.h: No such file or directory

Solução: Adicionra o caminho correto do cabeçalho:

-I /usr/include/c++/4.8

Para arquiteturas 64 bits, utilize CFLAGS=-m64; para 32 bits, utilize CFLAGS=-m32.

Erro: nullptr não declarado

error: nullptr was not declared in this scope

Solução: Adicionar suporte ao padrão C++11:

CFLAGS=-m64 -fpic -std=gnu++0x

Erro: std::string não encontrado

error: string in namespace std does not name a type

Solução: Encluir o cabeçalho necessário:

#include <string>

Erro: strcpy_s não disponível

error: strcpy_s was not declared in this scope

Solução: Substituir por strncpy:

strncpy(destino, origem, tamanho_maximo);

Erro: jump to label

error: jump to label [-fpermissive]
_LABEL_:

Solução: Definir como macro ou rearranjar o código para evitar saltos sobre inicializações.

Erro: AVCodecParameters não declarado

error: AVCodecParameters was not declared in this scope

Solução: Verificar e corrigir os caminhos dos cabeçalhos do FFmpeg.

Erro: incomplete type boost::interprocess::interprocess_semaphore

error: invalid use of incomplete type class boost::interprocess::interprocess_semaphore

Solução: Incluir o cabeçalho correto do Boost e adicionar -lrt ao linking. Em alguns casos, pode ser necessário implementar manualmente o semáforo.

Erro: linkagem FFmpeg

fatal error: libavutil/buffer.h: No such file or directory

Solução: Especificar o diretório correto dos cabeçalhos:

-I /usr/local/include_ffmpeg57

Erro: referência indefinida a pthread

undefined reference to symbol pthread_rwlock_wrlock
DSO missing from command line

Solução: Adicionar -lpthread às flags de linking:

-lpthread -lboost_thread

Erro: main não definido

undefined reference to main

Solução: Garantir que o arquivo contendo a função main() seja incluído na compilação.

Erro: linkagem do Boost.Log

undefined reference to boost::log::core::get()
undefined reference to boost::log::add_global_attribute()

Solução: Adicionar as bibliotecas corretas e definir a macro:

-lboost_thread -DBOOST_LOG_DYN_LINK -lboost_log_setup -lboost_log

Erro: ordem de linkagem

Quando existem dependências entre bibliotecas, a ordem em que são especificadas é crucial:

g++ -o programa main.o -lliveMedia -lBasicUsageEnvironment -lgroupsock -lUsageEnvironment

Conclusão

A portabilidade de código C++ entre Windows e Linux requer atenção a detalhes específicos de cada plataforma. O uso de bibliotecas bem mantidas como Boost pode simplificar significativamente este processo, mas conhecimento das diferenças entre os sistemas operacionais permanece essencial para resolver problemas de compilação e linkagem.

Tags: C++ Linux Windows portabilidade boost

Publicado em 6-21 16:48