What are the exact steps for creating and then linking against a Win32 DLL on the command line?

10,356

See this related question on how to build the DLL.

Your library code as it stands does not export any symbols and your executable does not import the symbols from your library. Two typical patterns for doing that are shown below but you might want to read up on that first.

The first method uses __declspec() to declare in the code what functions (or other items) are exported from your DLL and imported by other executables. You use a header file to declare the exported items and have a preprocessor flag used to control whether the symbols are exports or imports:

mylib.h:

#ifndef MYLIB_H
#define MYLIB_H

#if defined(BUILDING_MYLIB)
#define MYLIB_API __declspec(dllexport) __stdcall
#else
#define MYLIB_API __declspec(dllimport) __stdcall
#endif

#ifdef __cplusplus
extern "C" {
#endif

int MYLIB_API helloworld(void);

#ifdef __cplusplus
}
#endif

#endif

I have also specifically set the calling convention to __stdcall as are most DLL functions (I could have used WINAPI instead of __stdcall if I had included windows.h) and have declared the functions as extern "C" so their names do not get mangled when compiled as C++. Not such a problem here as it's all C, but if you were to build the DLL from C source and then try to use it from a C++ executable then the imported names would be incorrect.

The code could then look like this:

mylib.c

#include "mylib.h"
#include <stdio.h>

int MYLIB_API helloworld(void)
{
    printf("Hello World DLL");
    return 42;
}

You'd build your DLL using the following command line. As well as creating the DLL it will create the import library (.lib) required to use your DLL from another executable (as well as the export file, but that is only required in certain circumstances):

cl /DBUILDING_MYLIB mylib.c /LD

The /DBUILDING_MYLIB argument defines the preprocessor symbol used to control whether the functions in the DLL are exports (if it is defined) or imports (not defined). So you'd define it when building the DLL but not when building your application.

The /LD parameter tells cl to produce a DLL.

The second method is to use module definition files as mentioned in the comments. You can use the code you already have but you also need to create the module definition file. At it's simplest it looks like this:

LIBRARY   mylib
EXPORTS
   helloworld

In this case to build the DLL you require the following command line:

cl /LD mylib.c /link /DEF:mylib.def

You could then code your application so that it used your library header with the imported version of your DLL function:

main.c

/* No need to include this if you went the module definition
 * route, but you will need to add the function prototype.
 */
#include "mylib.h"

int main(void)
{
    helloworld();
    return (0);
}

Which you could then compile with the following command line (assuming the import library from the DLL creation is in the same directory as your main.c). This step is the same whether you used declspec or module definition files:

cl main.c /link mylib.lib

Arguments passed after the /link argument are passed onto the linker command line as they appear, so as just a filename it is used as extra input to link into the executable. In this case we specify the import library generated when we built the DLL.

The command lines I've shown here are pretty much the absolute minimum you'd need but it'll allow you to create a DLL and link an application to it.

I have assumed the calling convention is correct in all of the above and I have not experimented much to see whether I got it wrong at any point.

Share:
10,356
merlin2011
Author by

merlin2011

I am a student. A perpetual student. For the convenience of those who Google and copy &amp; paste resulting URL, feel free to try my plugins for Firefox and Chrome. I have recently released my primary project Arachne, a lightning-fast cooperative threading library. Please give it a whirl and create an issue if you see any problems. I have also written a few simple tools, such as one for tmux automation, an improved version of the venerable Unix column, and a tool for adding color to text in the terminal based on user-specified patterns.

Updated on June 05, 2022

Comments

  • merlin2011
    merlin2011 almost 2 years

    Here's my library Lib.c file:

    #include <stdio.h>
    
    int helloworld(){
        printf("Hello World DLL");
    }
    

    Here's my exe Main.c file:

    int helloworld();
    
    
    int main(int argc, char** argv){
        helloworld();
    }
    

    I would like to create Lib.dll, and Main.exe, where Lib.dll comes from Lib.c and Main.exe links against Lib.dll.

    What are the specific steps to achieve this?

  • Mark Ransom
    Mark Ransom over 12 years
    You should be more explicit about the fact that creating the .dll also creates a .lib at the same time.
  • Adrian McCarthy
    Adrian McCarthy over 12 years
    This answer is good. If you don't like using the __declspec extension, you can create a [module definition file][msdn.microsoft.com/en-us/library/28d6s79h(v=vs.100).as‌​px] that specifies the exported interface. It can give more control over what (and how) you expose externally.
  • Ben Voigt
    Ben Voigt over 12 years
    You probably want to use extern "C" for exported symbols, and maybe also __stdcall (or the WINAPI macro).
  • tomlogic
    tomlogic over 12 years
    I assume the definition of MYLIB_API should be different when BUILDING_MYLIB isn't defined. Do you just remove the __declspec(dllexport) and keep the __stdcall for C++ code linking against the DLL?
  • tinman
    tinman over 12 years
    @tomlogic: it was different but I broke it in an edit, thanks. I'll edit to change but linking with C++ works without changes (once I've fixed it :)
  • merlin2011
    merlin2011 over 12 years
    I had already seen the related question cited here, but the answers were nowhere near as complete as this one, most likely because the asker already had more knowledge so didn't require as much completeness.