16

I know how to link against libraries in Unix-ish contexts: If I'm working with .a or .so files, I specify the root search directory with -L/my/path/to/lib/ and for libMylib I add -lMyLib.

But what if I have

  • a .dll (e.g. in the Windows\System32 directory)?
  • a .dll (in Windows\System32) and a .lib (someplace else)?

These DLLs are by some other party; I don't have access to their sources - but do have access to the corresponding include files, against which I manage to compile.

einpoklum
  • 118,144
  • 57
  • 340
  • 684
  • Use the full path name of the `.lib` or `.dll` file, no `-L` or `-l`, just the filename, like in `g++ -o foo.exe foo.o c:\something\somethingelse\some.lib`. (You can also use the usual -L/-l convention but only if the library name file starts with 'lib', which is normally not the case under Windows). – n. m. could be an AI Jul 31 '13 at 15:08
  • @n.m.: Did that, it didn't work... are you sure that's supposed to work? – einpoklum Jul 31 '13 at 15:39
  • Works for me. What errors are you getting? – n. m. could be an AI Jul 31 '13 at 16:18
  • Sorry to revive this, but I'm having the same problem, I tried different things, including your suggestion @n.'pronouns'm. to link directly to the lib file. But I'm still getting an "undefined reference" error. I'm using make generated by qmake and mingw73_64's g++ – mquasar Feb 18 '21 at 00:48
  • 1
    Just to add that @n.18e9 is correct in that you must use the full path name for the lib file without any -L or -l options. This is using x86_64-w64-mingw32/8.3.0 with an MSVC-generated lib file, after a lot of trial and error. Also, **important** make sure you are linking to a lib file (and associated dll) generated for a **64-bit platform** (on MSVC target X64, not Win32). If you try and use a 32-bit lib file, g++ will just appear to ignore it and give you undefined references while you tear your hair out trying all the combinations. – David I Jul 15 '21 at 07:23
  • @DavidI: Please convert this into an answer, preferably with examples. – einpoklum Jul 15 '21 at 08:08

2 Answers2

14

If you can link against a .lib in Cygwin or MinGW, then you can (indirectly) link against a DLL.

In the MSVC world, it is not unusual to create an import library along with a DLL. It is a static library (.lib) that loads the DLL and wraps the interface of the DLL. You just call the wrapper functions in the (static) import library and let the import library do all the DLL-related things.

  • For the Windows API, there are import libraries in the WindowsSDK.
  • For your own MSVC DLLs, MSVC can automatically generate the import libraries when you build the DLL.
  • For a third party DLL, you can build a static wrapper library based on the corresponding header files.

Linking against the .lib file in Cygwin or MinGW is possible. Example:

g++ -o myprg myprg.o -lShlwapi

This links against Shlwapi.lib. (The library must be in the local directory or in the library path of the linker.)

Linking against import libraries of DLLs works the same way.

Note 1: Keep in mind the different ABIs and name mangeling. However, calling plain C functions in DLL or LIB files will work in most cases.

Note 2: Keep in mind that g++ requires the libraries to be specified in the correct order.

ManuelAtWork
  • 2,198
  • 29
  • 34
  • This doesn't work for me; I've been on this for days now and I can't get a solution. Whenever I link the library, I get an "undefined reference to ..." error – Duck Dodgers Mar 06 '22 at 17:43
  • 1
    @DuckDodgers, can you name 1-3 undefined symbols? What library are you linking against? – ManuelAtWork Mar 07 '22 at 07:48
  • Thank you for the response. I am linking to a custom library called: HTUSB. I have static and dynamic libraries that I am trying to link to my c++ program. Here's a pic of my folder structure: https://ibb.co/jf0xXHd. I put the dll and .lib file in two places just in case the folder structure was the issue. Lastly, here's the command I use to link the files: g++ decibel_test.cpp -I\Users\13122\OneDrive\Desktop\decibel -L"\Users\13122\OneDrive\Desktop\decibel\HTUSB.dll". And here's an error "undefined reference to `_imp__HTUSB_Close@0'" HTUSB_CLOSE being one of the funcs in the library – Duck Dodgers Mar 08 '22 at 21:43
  • 1
    Please check if the import library (.lib) exports the given symbol. (```dumpbin``` command, or ```nm``` under cygwin). Also make sure that name mangeling (and calling conventions) matches, which can be a problem the library has been compiled with a different compiler (=different ABIs). – ManuelAtWork Mar 09 '22 at 08:25
  • Firstly, thank you for the continuous response! Secondly, I run "nm F HTUSB.lib" and I get "no such file or directory". But then I run "nm F HTUSB.dll) and I get "no symbols". Strange because the dll file definitely isn't empty and the .lib file definitely exists. Sorry if the questions seem silly; I'm new to this – Duck Dodgers Mar 09 '22 at 20:25
  • Just call ```nm HTUSB.lib```. There must be symbols exported by the lib. If not, then your lib is either broken (or it has been built with competely incompatible toolchain). – ManuelAtWork Mar 10 '22 at 10:08
  • I run it and it says "HTUSB.lib: File format not recognized". Think it's broken? – Duck Dodgers Mar 10 '22 at 10:53
  • Broken or different toolchain. Are you mixing 32/64 bit builds maybe? What toolchain have you been using? What toolchain has generated the lib file? – ManuelAtWork Mar 10 '22 at 12:50
  • @DuckDodgers Are you by chance trying to write software that emulates the SE323 SPL software or uses its library? If so, is it by chance open source? – dronenb Mar 18 '23 at 17:32
  • @DuckDodgers I ask because I was looking into writing some software for the CM-170 from Galaxy audio... It looks like you are working with a REED R8080, which seems to be the same thing... – dronenb Mar 18 '23 at 17:40
6

@einpoklum Converting my comment to an answer: @n.18e9 is correct in that you must use the full path name for the lib file without any -L or -l options. g++ -o foo.exe foo.o c:\something\somethingelse\some.lib. You can also link directly to the Windows DLL file g++ -o foo.exe foo.o c:\something\somethingelse\some.dll.

Important - make sure you are linking to a lib file (and associated dll) generated for a 64-bit platform (on MSVC target X64, not Win32).

OK you wanted an example, well let's go.

Here are two examples using gcc/g++ to link to a Windows native DLL which exports plain C functions (using here x86_64-w64-mingw32/8.3.0 on Windows 10).

I'm using my own free xmlsq library as an example https://www.cryptosys.net/xmlsq. You can download the core native DLL and all the source code quoted below. Make sure you use the 64-bit DLL.

The native Windows DLL diXmlsq.dll is written entirely in plain C code and exports simple C functions (extern "C"). In particular, for this example, it exports a XMLSQ_Gen_Version function that returns an integer value. The DLL was compiled using MSVC 12.0 targetting the X64 platform. The associated library file generated by MSVC is diXmlsq.lib.

I should add that this DLL works exactly the same as a Windows "Win32 API" DLL, so the instructions here should work for the standard Windows libraries in Windows\System32 (again make sure you link against the 64-bit version).

Example 1. A plain C interface.

Both these commands compile without warning on my system:

> 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 is compiled using the following definition file. (You could alternatively use __declspec(dllexport))

Ref: 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 - the C interface to diXmlsq.dll

#ifdef __cplusplus
extern "C" {
#endif

long __stdcall XMLSQ_Gen_Version(void);

#ifdef __cplusplus
}
#endif

To call the core function in a plain C program:

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;
}

Example 2. A C++ interface.

Both these commands compile without warning using 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"

The idea of the C++ interface is to be an interface to the plain C library using the more convenient STL types like std::string and std::vector. To keep things simple we'll just demonstrate the Gen::Version method.

Extracts of the C++ code follow:

test-simple.cpp - a test C++ program.

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

xmlsq.hpp - the C++ interface

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 - the C++ implementation.

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

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

Example 3. Attempting to link to the 32-bit library by mistake.

> 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
David I
  • 881
  • 6
  • 10