compiling a dynamic link library (DLL) on windows with cl.exe and powershell but without CMake, MSBuild or Visual Studio

I want to understand how to compile and link dynamic link-libraries work on Windows. I’d typically use CMake for this type of task, but I want to understand how I could achieve it without CMake (or any other build system). I am looking for raw commands to type into powershell.

On UNIX, this is rather straightforward, but on Windows I seem to be hitting a wall and there doesn’t seem to be any good resources, at least non that I could find in the last coupel of days (neither here on stackoverflow nor anywhere else). There are a few solution that come close to my problem, but they were not able to clarify all questions I had so hence me asking this question here.

I have coded up a simple toy project that should help to clarify where I am having issues.

The project structure is as follows:

root
├── build
├── lib
│   ├── myMathLib.h
│   └── myMathLib.cpp
├── main.cpp
└── compileAndRun.bat

Within the lib folder, I have the following files and their content:

// myMathLib.h
#pragma once

#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
  #ifdef COMPILED
    #define API __declspec(dllexport)
  #else
    #define API __declspec(dllimport)
  #endif
#endif

extern "C" {

class MyMathLib {
public:
  API int add(int a, int b);
};

}
// myMathLib.cpp
#include "lib/myMathLib.h"

int MyMathLib::add(int a, int b) {
  return a + b;
}

The main file is simply calling this function:

// main.cpp
#include <iostream>
#include "lib/myMathLib.h"

int main() {
  MyMathLib math;
  std::cout << "2 + 3 = " << math.add(2, 3) << std::endl;
  return 0;
}

my compileAndRun.bat file looks liek the following

@echo off

del /q build
mkdir build

REM compile source files into object code
cl /nologo /c /EHsc /Od /I. /DCOMPILED lib/myMathLib.cpp /Fobuild\myMathLib.obj
cl /nologo /c /EHsc /Od /I. main.cpp /Fobuild\main.obj

REM link object files into dynamic library
link /nologo /DLL /OUT:build\libMyMath.dll build\myMathLib.obj

REM compile main function and link library into executable
cl /nologo /EHsc /Od /I. build\main.obj /Fe:build\dynamicLibExample.exe /link /DLL /LIBPATH:build build\libMyMath.dll 

REM remove object files
del build\*.obj

REM run
echo Running dynamic library example
build\dynamicLibExample.exe

In this script, I am able to compile the source files and even create the libMyMath.dll file within the build folder. However, when I try to link my main.obj file against the dynamic library (line 14), I am getting a compiler error of build\libMyMath.dll : fatal error LNK1107: invalid or corrupt file: cannot read at 0x2F8 and I am unable to progress past this point, so my question is how I can link this DLL file now against my main.cpp file.

One additional question: Do I need extern "C" here if I am only planning to use this code in C++ codebases? I’d argue name mangling is not an issue so I could probably drop it but I see everyone else doing it, but I suppose it is just to make it available for C as well.

And one clarification: I understand that the __declspec(dllexport) and __declspec(dllimport) are only required for windows platforms, but from what I have read I could get rid of them and provide a *.def file. It seems this is not the preferred method from what I have read, but if someone could show (again, for educational purposes) how I could achieve a library code without the #pragmas and with a *.def file instead, that would be much appreciated.

  • I know where you are coming from. Microsoft doesn’t do a good job of publishing a complete set of compiler options. Compiler options that existed in the early 1990’s are still available but no longer documented. See following for compiler options : learn.microsoft.com/en-us/cpp/build/…

    – 

  • Great, it’s not just me then! Thanks for the link, couldn’t find this on learn.microsoft.com, and I have checked a few of their sites.

    – 

When you link the DLL, the import library libMyMath.lib is created. This library has the same .lib extension as a static library, but it doesn’t contain the code of the functions. There are only function stubs that call the implementation in the DLL.

You must link with the LIB instead of the DLL, when you build the EXE file:

cl /nologo /EHsc /Od /I. build\main.obj /Fe:build\dynamicLibExample.exe /link /DLL /LIBPATH:build build\libMyMath.lib 

Leave a Comment