3 formas de organizar el código multiplataforma

1. Origen

En el artículo anterior, compartimos una plataforma multiplataforma de archivos de encabezado para convertirse en lo que era, este archivo de encabezado para Windows en la plataforma es más significativo, porque se ocupa de las funciones de biblioteca de declaraciones de importación y exportación ( dllexport, dllimport ).

De hecho, puede continuar expandiendo sobre la base de este archivo de encabezado para lograr un control más detallado . Por ejemplo: el juicio del compilador, el juicio de la versión del compilador , etc.

Del mismo modo, también encontraremos algunos problemas multiplataforma en el código fuente . Diferentes funciones en diferentes plataformas, la implementación no es la misma , ¿cómo organizar este código específico de la plataforma? Este artículo hablará sobre este tema.

PD: Al final del artículo se proporciona un ejemplo de código de compilación simple y multiplataforma.

2. Introducción al problema

Supongamos que escribimos una biblioteca y necesitamos implementar una función: obtener la marca de tiempo del sistema . Como autor de la biblioteca de implementación, decide proporcionar las siguientes funciones de API:

t_time.h: declarar la función de interfaz (t_get_timestamp);
t_time.c: implementar la función de interfaz;

La siguiente tarea es calcular la marca de tiempo actual del sistema a través de diferentes bibliotecas C o llamadas al sistema en la implementación de la función .

En la plataforma Linux , se puede lograr mediante el siguiente código:

struct timeval tv;
gettimeofday(&tv, null);
return tv.tv_sec * 1000 + tv.tv_usec / 1000;

En la plataforma Windows , esto se puede lograr mediante el siguiente código:

struct timeb tp;
ftime(&tp);
return tp.time *1000 + tp.millitm;

Entonces, la pregunta es: ¿cómo organizar estas dos piezas de código relacionado con la plataforma juntas ? Aquí hay tres métodos de organización diferentes. No hay diferencia entre lo bueno y lo malo. Todos tenemos hábitos diferentes. Simplemente elija el método que más le convenga a usted y a su equipo.

Además, solo hay una función en este ejemplo y es relativamente corta. Si estas funciones multiplataforma son muchas y muy largas, su elección puede ser diferente.

Tres, tres soluciones

plan 1

Directamente en la función de interfaz, distinga diferentes plataformas a través de definiciones de macros de plataforma .

Las definiciones de macro de plataforma ( T_LINUX, T_WINDOWS ) se introdujeron en el artículo anterior. El sistema operativo y el compilador se utilizan para determinar cuál es la plataforma actual, y luego se define una definición de macro de plataforma unificada para nuestro propio uso:

El código está organizado de la siguiente manera:

int64 t_get_timestamp()
{
    int64 ts = -1;
    
#if defined(T_LINUX)
    struct timeval tv;
    gettimeofday(&tv, null);
    ts = tv.tv_sec * 1000 + tv.tv_usec / 1000;
#elif defined(T_WINDOWS)
    struct timeb tp;
    ftime(&tp);
    ts = tp.time;
    ts = ts *1000 + tp.millitm;
#endif

    return ts;
}

De esta manera, todos los códigos de plataforma se colocan en funciones de API y la compilación condicional se realiza a través de definiciones de macro de plataforma , porque el código es relativamente corto y se ve bien.

Escenario 2

Coloque los códigos de implementación de diferentes plataformas en archivos separados y luego use #include símbolos de preprocesamiento para introducir códigos relacionados con la plataforma en las funciones de la API .

Eso es para agregar 2 archivos más:

t_time_linux.c: almacena la implementación del código en la plataforma Linux;
t_time_windows.c: almacena la implementación del código en la plataforma Windows;

(1) t_time_linux.c

#include "t_time.h"
#include <sys/time.h>

int64 t_get_timestamp()
{
    int64 ts = -1;
    
    struct timeval tv;
    gettimeofday(&tv, null);
    ts = tv.tv_sec * 1000 + tv.tv_usec / 1000;
    
    return ts;
}

(2) t_time_windows.c

#include "t_time.h"
#include <windows.h>
#include <sys/timeb.h>

int64 t_get_timestamp()
{
    int64 ts = -1;
    
    struct timeb tp;
    ftime(&tp);
    ts = tp.time;
    ts = ts *1000 + tp.millitm;

    return ts;
}

(3) t_time.c

Este archivo no hace nada, solo incluye otro código.

#include "t_time.h"

#if defined(T_LINUX)
#include <t_time_linux.c>
#elif defined(T_WINDOWS)
#include <t_time_windows.c>
#else
int64 t_get_timestamp()
{
    return -1;
}
#endif

Algunas personas están más disgustadas con este tipo de organización. Generalmente, es para incluir un archivo de encabezado .h , pero aquí hay una definición de macro de plataforma para incluir diferentes archivos de origen .c . ¿Se siente extraño? !

De hecho, hay algunas bibliotecas de código abierto que hacen esto, como las siguientes:

Esquema 3

En el esquema 2 anterior, el código fuente está lleno de códigos de implementación de diferentes plataformas.

De hecho, puede cambiar la forma de pensar. Ahora que se ha colocado en diferentes archivos según las diferentes plataformas, puede agregar diferentes archivos fuente al proceso de compilación .

El código de prueba se crea utilizando la herramienta cmake , por lo que puede editar el archivo CMakelists.txt para controlar los archivos fuente involucrados en la compilación.

Parte del archivo CMakelists.txt

# 设置平台变量
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
set(PLATFORM linux)
elseif (CMAKE_SYSTEM_NAME MATCHES "Windows")
set(PLATFORM windows)
endif()

# 根据平台变量,来编译不同的源文件
set(LIBSRC  t_time_${PLATFORM}.c)

Este tipo de organización hace que el código sea más "limpio" . Del mismo modo, también podemos ver que algunas bibliotecas de código abierto hacen lo mismo:

四 、 Una cosa más

Para la extensión del artículo, lo anterior es solo un fragmento del código publicado.

Escribí una de las demostraciones más simples , usando cmake para construir bibliotecas dinámicas multiplataforma, bibliotecas estáticas y programas ejecutables . El propósito de escribir esta demostración es principalmente como un shell para probar algún código al escribir el artículo.

En la plataforma Linux , compile manualmente a través de las instrucciones de cmake; en la plataforma Windows , puede compilar y ejecutar directamente a través del entorno de desarrollo integrado CLion , o puede generar directamente la solución VS2017 / 2019 a través de la herramienta cmake .

Esta demostración ya se ha puesto en el almacén de gitee en interés de un pequeño socio, deje un mensaje en un número público: dg36 , puede recibir la dirección de clonación.


Los buenos artículos deben enviarse ; cuanto más compartas, más afortunado eres.


Lectura recomendada

1. Puntero del lenguaje C: desde el principio de nivel inferior hasta habilidades sofisticadas, use gráficos y código para ayudarlo a explicarlo en profundidad
2. El principio de depuración de nivel inferior de gdb original es muy simple
3. Análisis paso a paso: cómo usar C para implementar la programación orientada a objetos
4. Todo lo dicho La arquitectura del software debe dividirse en capas y en módulos, y qué se debe hacer específicamente (1)
5. Se dice que la arquitectura del software debe dividirse en capas y en módulos, y qué debe hacerse específicamente (2)

Supongo que te gusta

Origin blog.csdn.net/u012296253/article/details/115366970
Recomendado
Clasificación