¿Enlazar con una combinación de archivos .dll+.lib de Windows con GCC en Cygwin?

8 minutos de lectura

avatar de usuario de einpoklum
einpoklum

Sé cómo vincular bibliotecas en contextos Unix-ish: si estoy trabajando con .a o .so archivos, especifico el directorio de búsqueda raíz con -L/my/path/to/lib/ y para libMylib agrego -lMyLib.

pero que pasa si tengo

  • a .dll (por ejemplo, en el Windows\System32 directorio)?
  • a .dll (en Windows\System32) y un .lib (Algún lugar más)?

Estas DLL son de otra parte; No tengo acceso a sus fuentes, pero tengo acceso a los archivos de inclusión correspondientes, contra los cuales logro compilar.

  • Utilice el nombre de ruta completo del .lib o .dll archivo, no -L o -lsolo el nombre del archivo, como en g++ -o foo.exe foo.o c:\something\somethingelse\some.lib. (También puede usar la convención habitual -L/-l, pero solo si el archivo del nombre de la biblioteca comienza con ‘lib’, que normalmente no es el caso en Windows).

    – nanómetro

    31 de julio de 2013 a las 15:08

  • @nm: Hizo eso, no funcionó… ¿estás seguro de que se supone que funciona?

    – einpoklum

    31 de julio de 2013 a las 15:39

  • Funciona para mi. ¿Qué errores estás recibiendo?

    – nanómetro

    31 de julio de 2013 a las 16:18

  • Lamento revivir esto, pero tengo el mismo problema, probé cosas diferentes, incluida tu sugerencia @n.’pronouns’m. para vincular directamente al archivo lib. Pero sigo recibiendo un error de “referencia indefinida”. Estoy usando make generado por qmake y g++ de mingw73_64

    – mquasar

    18 de febrero de 2021 a las 0:48


  • Solo para agregar que @ n.18e9 es correcto en el sentido de que debe usar el nombre de ruta completo para el archivo lib sin ninguna opción -L o -l. Esto usa x86_64-w64-mingw32/8.3.0 con un archivo lib generado por MSVC, después de muchas pruebas y errores. También, importante asegúrese de que está vinculando a un archivo lib (y dll asociado) generado para un plataforma de 64 bits (en el destino X64 de MSVC, no en Win32). Si intenta usar un archivo lib de 32 bits, g ++ simplemente parecerá ignorarlo y le dará referencias indefinidas mientras se tira de los pelos probando todas las combinaciones.

    – David I.

    15 de julio de 2021 a las 7:23

Si puede enlazar contra un .lib en Cygwin o MinGW, entonces puede vincular (indirectamente) con una DLL.

En el mundo de MSVC, no es raro crear un importar biblioteca junto con una DLL. Es una biblioteca estática (.lib) que carga la DLL y ajusta la interfaz de la DLL. Simplemente llame a las funciones de contenedor en la biblioteca de importación (estática) y deje que la biblioteca de importación haga todas las cosas relacionadas con DLL.

  • Para la API de Windows, hay bibliotecas de importación en WindowsSDK.
  • Para sus propias DLL de MSVC, MSVC puede generar automáticamente las bibliotecas de importación cuando crea la DLL.
  • Para una DLL de terceros, puede crear una biblioteca contenedora estática basada en los archivos de encabezado correspondientes.

Vinculación contra el .lib El archivo en Cygwin o MinGW es posible. Ejemplo:

g++ -o myprg myprg.o -lShlwapi

Esto enlaza contra Shlwapi.lib. (La biblioteca debe estar en el directorio local o en la ruta de la biblioteca del enlazador).

La vinculación con bibliotecas de importación de archivos DLL funciona de la misma manera.

Nota 1: tenga en cuenta las diferentes ABI y la gestión de nombres. Sin embargo, llamar a funciones C simples en archivos DLL o LIB funcionará en la mayoría de los casos.

Nota 2: tenga en cuenta que g++ requiere que las bibliotecas se especifiquen en el orden correcto.

  • Esto no funciona para mí; Llevo días con esto y no encuentro solución. Cada vez que vinculo la biblioteca, aparece un error de “referencia indefinida a…”

    – Dodgers de pato

    6 de marzo a las 17:43

  • @DuckDodgers, ¿puedes nombrar 1-3 símbolos indefinidos? ¿Con qué biblioteca estás enlazando?

    – ManuelEnElTrabajo

    7 de marzo a las 7:48

  • Gracias por la respuesta. Estoy vinculando a una biblioteca personalizada llamada: HTUSB. Tengo bibliotecas estáticas y dinámicas que intento vincular a mi programa C++. Aquí hay una foto de mi estructura de carpetas: ibb.co/jf0xXHd. Puse el archivo dll y .lib en dos lugares en caso de que la estructura de la carpeta fuera el problema. Por último, este es el comando que utilizo para vincular los archivos: g++ decibel_test.cpp -I\Users\13122\OneDrive\Desktop\decibel -L”\Users\13122\OneDrive\Desktop\decibel\HTUSB.dll”. Y aquí hay un error “referencia indefinida a `_imp__HTUSB_Close@0′” siendo HTUSB_CLOSE una de las funciones en la biblioteca

    – Dodgers de pato

    8 de marzo a las 21:43


  • Verifique si la biblioteca de importación (.lib) exporta el símbolo dado. (dumpbin comando, o nm bajo cygwin). También asegúrese de que la gestión de nombres (y las convenciones de llamadas) coincidan, lo que puede ser un problema porque la biblioteca se ha compilado con un compilador diferente (=ABI diferentes).

    – ManuelEnElTrabajo

    9 de marzo a las 8:25

  • En primer lugar, ¡gracias por la continua respuesta! En segundo lugar, ejecuto “nm F HTUSB.lib” y obtengo “no existe tal archivo o directorio”. Pero luego ejecuto “nm F HTUSB.dll) y obtengo “sin símbolos”. Extraño porque el archivo dll definitivamente no está vacío y el archivo .lib definitivamente existe. Lo siento si las preguntas parecen tontas; soy nuevo en esto

    – Dodgers de pato

    9 de marzo a las 20:25

Avatar de usuario de David I
david yo

@einpoklum Convirtiendo mi comentario en una respuesta: @ n.18e9 es correcto en el sentido de que debe usar el nombre de ruta completo para el archivo lib sin ninguna opción -L o -l.
g++ -o foo.exe foo.o c:\something\somethingelse\some.lib. También puede vincular directamente al archivo DLL de Windows g++ -o foo.exe foo.o c:\something\somethingelse\some.dll.

Importante – asegúrese de que está vinculando a un archivo lib (y dll asociado) generado para un plataforma de 64 bits (en el destino X64 de MSVC, no en Win32).

OK, querías un ejemplo, bueno, vamos.

Aquí hay dos ejemplos que usan gcc/g++ para vincular a una DLL nativa de Windows que exporta funciones simples de C (usando aquí x86_64-w64-mingw32/8.3.0 en Windows 10).

Estoy usando mi propia biblioteca xmlsq gratuita como ejemplo https://www.cryptosys.net/xmlsq. Puede descargar la DLL nativa principal y todo el código fuente que se cita a continuación. Asegúrese de utilizar la DLL de 64 bits.

La DLL nativa de Windows diXmlsq.dll está escrito completamente en código C simple y exporta funciones C simples (externo “C”). En particular, para este ejemplo, exporta un XMLSQ_Gen_Version función que devuelve un valor entero. La DLL se compiló utilizando MSVC 12.0 para la plataforma X64. El archivo de biblioteca asociado generado por MSVC es diXmlsq.lib.

Debo agregar que esta DLL funciona exactamente igual que una DLL “Win32 API” de Windows, por lo que las instrucciones aquí deberían funcionar para las bibliotecas estándar de Windows en Windows\System32 (Nuevamente, asegúrese de vincular contra la versión de 64 bits).

Ejemplo 1. Una interfaz C simple.

Ambos comandos se compilan sin previo aviso en mi sistema:

> gcc -o test-ver test-ver.c "C:\fullpath\to\x64\diXmlsq.lib"

> gcc -o test-ver test-ver.c "C:\fullpath\to\x64\diXmlsq.dll"

diXmlsq.dll se compila utilizando el siguiente archivo de definición. (Alternativamente, podría usar __declspec(dllexport))

Árbitro: https://learn.microsoft.com/en-us/cpp/build/exporting-from-a-dll?view=msvc-160

diXmlsq.def

LIBRARY      "diXmlsq"
EXPORTS
    XMLSQ_Gen_Version

diXmlsq.h – la interfaz C para diXmlsq.dll

#ifdef __cplusplus
extern "C" {
#endif

long __stdcall XMLSQ_Gen_Version(void);

#ifdef __cplusplus
}
#endif

Para llamar a la función central en un programa simple en C:

test-ver.c

#include <stdio.h>
#include "diXmlsq.h"
int main(void)
{
    long n;
    n = XMLSQ_Gen_Version();
    printf("Version = %ld\n", n);
    return 0;
}

Ejemplo 2. Una interfaz C++.

Ambos comandos se compilan sin previo aviso usando g++.

> g++ -o test-simple test-simple.cpp xmlsq.cpp "C:\fullpath\to\x64\diXmlsq.lib"

> g++ -o test-simple test-simple.cpp xmlsq.cpp "C:\fullpath\to\x64\diXmlsq.dll"

La idea de la interfaz C ++ es ser una interfaz para la biblioteca C simple utilizando los tipos STL más convenientes como std::string y std::vector. Para simplificar las cosas, solo demostraremos el Gen::Version método.

A continuación, extractos del código C++:

test-simple.cpp – un programa de prueba en C++.

#include <iostream>
#include "xmlsq.hpp"
int main()
{
    std::cout << "xmlsq::Gen::Version=" << xmlsq::Gen::Version() << std::endl;
}

xmlsq.hpp – la interfaz C++

namespace xmlsq
{
    class Gen {
    private:
        Gen() {} // Static methods only, so hide constructor.
    public:
        /** Get version number of core diXmlsq DLL. */
        static int Version();
    };
}

xmlsq.cpp – la implementación de C++.

#include "diXmlsq.h"
#include "xmlsq.hpp"

namespace xmlsq
{
    int Gen::Version() {
        int n = XMLSQ_Gen_Version();
        return n;
    }
}

Ejemplo 3. Intentando vincular a la biblioteca de 32 bits por error.

> gcc -o test-ver test-ver.c "C:\fullpath\to\Win32\diXmlsq.lib"
C:/Strawberry/c/bin/../lib/gcc/x86_64-w64-mingw32/8.3.0/../../../../x86_64-w64-mingw32/bin/ld.exe: 
C:\Users\user\AppData\Local\Temp\cce27Dhl.o:test-ver.c:(.text+0xe): 
undefined reference to `XMLSQ_Gen_Version'
collect2.exe: error: ld returned 1 exit status

  • Obtienes un +1 por esfuerzo incluso antes de que haya tenido tiempo de investigar esto 🙂

    – einpoklum

    19 de julio de 2021 a las 16:25

¿Ha sido útil esta solución?