2012-08-15 15 views
6

Tengo una biblioteca de C estática que puedo compilar con diferentes opciones de tiempo de compilación (por ejemplo, _BUILD_SMALL, _BUILD_FAST). Tiene una funciónCómo alias las funciones de la biblioteca C?

void Foo(void); 

me gustaría utilizar una sola instancia de un instrumento de referencia para comparar el las versiones "rápidas" de la biblioteca "pequeño" y. No quiero usar .dlls.

¿Cómo puedo vincular a las bibliotecas "pequeñas" y "rápidas" y alias los nombres de las funciones para que pueda llamar a la versión pequeña y rápida. Lo ideal sería algo como:

void benchmark(void) 
{ 
    FAST_Foo(); 

    SMALL_Foo(); 
} 

Más información:

La biblioteca se puede construir con opciones diferentes optimizaciones -os frente -O3. Además, los algoritmos varían ligeramente (es decir, valores almacenados en caché versus valores de búsqueda siempre). Quiero comparar las compensaciones de tamaño y velocidad de las diferentes versiones. Me gustaría que las pruebas unitarias y el benchmarking se ejecuten en ambas versiones de la biblioteca de la manera más fácil posible.

+2

Esta pregunta es muy poco clara. – Falmarri

+0

¿Por qué no simplemente crear múltiples versiones con varias opciones activadas/desactivadas y comparar cada una? –

+0

No puede combinar ambas funciones en un solo enlace si tienen el mismo nombre (y no son estáticas). – mah

Respuesta

3

Esta es sólo una variación del método dado por @ Michał Górny (me acaba el espacio de comentario allí) ...

Se puede crear un archivo de la siguiente forma incluyen:

/* Automatically created file - do not edit or ugly dinosaur will eat you */ 
#ifndef PREFIX 
# define RENAME(f) 
#else 
# define RENAME(f) PREFIX ## f 
#endif 

/* list all the function and variables you want to rename here in one place */ 
#define func_foo RENAME(func_foo) 
#define func_bar RENAME(func_bar) 
/* ... many more ... */ 

#undef RENAME 

Al menos gcc le permite especificar la inclusión de un archivo de encabezado desde la línea de comandos con la opción -include rename.h (suponiendo que este archivo se llame rename.h). Debido a que usa gcc opciones parecidas (-O3 y Os), asumo que usa gcc en el resto de esta respuesta. De lo contrario, si su compilador de C es razonable, debería poder hacerlo de alguna manera similar.

Usted puede crear fácilmente dos o incluso tres versiones de la biblioteca que se pueden vincular al mismo tiempo si se desea, al ofrecer diferentes opciones para su compilador de C (en este caso a través CFLAGS ajuste):

CFLAGS += -include rename.h -DPREFIX=fast_ -D_BUILD_FAST -O3 -DBENCHMARKING 
CFLAGS += -include rename.h -DPREFIX=small_ -D_BUILD_SMALL -Os -DBENCHMARKING 
CFLAGS += -D_BUILD_FAST -O2 

Si los archivos de encabezado de su biblioteca se ven muy regulares y declara las funciones privadas de la biblioteca static, es fácil extraer las funciones de esos archivos de encabezado mediante un script ficticio utilizando expresiones regulares muy simples para generar automáticamente el archivo rename.h. Este es un objetivo de compilación natural si está usando make o algo similar. Todas las variables globales también necesitan ser renombradas usando el mismo método para permitir el uso simultáneo.

Hay tres puntos principales con esta solución:

  1. El negocio de cambio de nombre feo puede estar oculto en un archivo, que no es necesario para editar los archivos de origen reales - sobre todo que no es necesario que el desorden los archivos fuente, pero pueden mantenerlos limpios y fáciles de leer.
  2. El cambio de nombre puede ser fácilmente automatizado, si sigue algunos principios simples (las convenciones de codificación seguidas para los archivos de encabezado y los archivos de encabezado declararán todas las variables y funciones globales).
  3. No hay ninguna razón para hacer que la evaluación comparativa sea más engorrosa al necesitar ejecutar su programa de prueba varias veces (esto es relevante si usted es tan vago como yo y no me gustan las tareas repetitivas tan violentamente como yo; sé que a muchas personas no les importa , es de alguna manera una cuestión de preferencia).
+0

muy agradable y se ajusta a la pregunta, ¡gracias! –

2

Una forma sería: mantener el mismo nombre para ambos y llamar adecuadamente según la opción de tiempo de compilación configurada.

ifdef SMALL_FOO 
void foo() { 

/* Small foo code */ 
} 
#endif 

ifdef BIG_FOO 
void foo() { 

/* Big foo code */ 
} 
#endif 

Establecer la SMALL_FOO/BIG_FOO durante la compilación con -d.

+0

Lo había considerado. La implementación actual requeriría alguna duplicación para hacer esto, pero creo que podría hacerse. –

0

Usted dice que puede construir la biblioteca, cambiando las opciones de tiempo de compilación, entonces ¿por qué no edita el código para cambiar los nombres de las funciones en cada una? (Usted sería hacer dos versiones diferentes de su biblioteca.)

+0

las opciones de tiempo de compilación se pasan al preprocesador, el código no cambia (ese es el objetivo de todos modos). –

2

Como solución rápida, puede utilizar macro para destrozar el nombre de la función como:

#ifdef FAST 
# define FUNC(x) FAST_##x 
#else 
# define FUNC(x) SLOW_##x 
#endif 

void FUNC(Foo)(); 

Y ahora con -DFAST la biblioteca con FAST_Foo se ser construido; y sin él, uno con SLOW_Foo. Solo tenga en cuenta que necesita usar la macro FUNC() en la parte de implementación también (y siempre que se refiera a esa función desde el interior de la biblioteca), y #ifdef FAST para cambiar entre código rápido/lento.

Solo por favor no lo use en un código de producción.

+0

También agregaría un '#ifdef ALIAS' que cuando sea falso omitiría lo de arriba y en la cláusula' # else' tendría '#define FUNC (x) x'. Entonces no necesitaría usar la macro en la parte de implementación. –

+0

Estaba pensando en esto. Estaba buscando una solución de aliasing, pero había considerado crear funciones de biblioteca "mutiladas" específicas, y luego hacer un #ifdef FAST #define Foo FAST_Foo() #endif –

+0

Estoy de acuerdo con el cambio de nombre, pero personalmente no me gusta el camino sugerido aquí. No me gusta cambiar cómo aparecen los prototipos de funciones. Ya no puede buscarlos usando expresiones regulares, algunas herramientas para tratar con archivos C se confundirán y desordenará la vista. Preferiría hacerlo antes de la definición/declaración de la función. Por ejemplo, en el ejemplo anterior, di '#define Foo FUNC (Foo)' (usando las funciones 'FUNC()' macro y 'Foo()' donde la macro 'FUNC()' debería nombrarse mejor de otra manera si se usa de esta manera) . Entonces puedes tener un prototipo de función de aspecto normal. – FooF

2

Si intenta vincular en ambas bibliotecas estáticas al mismo archivo ejecutable, la segunda biblioteca enumerada en su línea de enlace no tendrá ningún efecto, porque todos los símbolos que proporcionó ya fueron satisfechos por la primera biblioteca. Si proporcionó funciones de envoltura únicas y simples para llamar al Foo, aún fallaría, ahora debido a múltiples definiciones. Aquí está un ejemplo:

/* x.c */ 
extern void Y_Bar(); 
extern void Z_Bar(); 
int main() 
{ 
    Y_Bar(); 
    Z_Bar(); 
} 

Este principales llamadas únicas funciones de contenedor, que se proporcionan en liby.a y libz.a.

/* y.c in liby.a */ 
#include <stdio.h> 
void Y_Bar() { 
    extern void Foo(); 
    Foo(); 
} 
void Foo() { 
    printf("%s\n", "that Foo"); 
} 

/* z.c in libz.a */ 
#include <stdio.h> 
void Z_Bar() { 
    extern void Foo(); 
    Foo(); 
} 
void Foo() { 
    puts("this foo"); 
} 

El intento de vincular el ejecutable con -ly -lz fallará.

Lo más fácil para usted es construir dos ejecutables por separado. Su controlador de referencia podría ejecutar ambos ejecutables para comparar su rendimiento relativo.

+0

He seleccionado esto como la solución más fácil para el código de producción. –

0

Tal vez se puede utilizar -D option when call gcc, like -D_FAST_, -D_SMALL_, o su lata recibido un parámetro de entrada cuando se utiliza hacer, como hacer uso CFG=FAST, make CFG=SMALL, en su makefile, se puede definir, cuando el parámetro get FAST, link to FAST library.

Cuestiones relacionadas