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.
- 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
- 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"
- 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.
- 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.