我想了解如何编译和链接 Windows 上的动态链接库。我通常会使用 CMake 来完成此类任务,但我想了解如何在没有 CMake(或任何其他构建系统)的情况下实现它。我正在寻找可以输入 powershell 的原始命令。
在 UNIX 上,这相当简单,但在 Windows 上我似乎遇到了困难,似乎没有任何好的资源,至少在过去几天里我找不到(无论是在 stackoverflow 还是在其他任何地方)。有一些解决方案接近我的问题,但他们无法澄清我的所有问题,因此我在这里问这个问题。
我编写了一个简单的玩具项目,应该有助于澄清我遇到的问题。
项目结构如下:
root
├── build
├── lib
│ ├── myMathLib.h
│ └── myMathLib.cpp
├── main.cpp
└── compileAndRun.bat
在
lib
文件夹中,我有以下文件及其内容:
// 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;
}
主文件只是调用这个函数:
// main.cpp
#include <iostream>
#include "lib/myMathLib.h"
int main() {
MyMathLib math;
std::cout << "2 + 3 = " << math.add(2, 3) << std::endl;
return 0;
}
我的
compileAndRun.bat
文件看起来如下
@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
在此脚本中,我可以编译源文件,甚至可以在
libMyMath.dll
文件夹中创建 build
文件。但是,当我尝试将我的 main.obj
文件链接到动态库(第 14 行)时,我收到 build\libMyMath.dll : fatal error LNK1107: invalid or corrupt file: cannot read at 0x2F8
编译器错误,并且我无法继续前进,所以我的问题是如何链接它现在针对我的 main.cpp
文件生成 DLL 文件。
还有一个问题:如果我只打算在 C++ 代码库中使用此代码,我是否需要
extern "C"
?我认为名称修改不是问题,所以我可能会放弃它,但我看到其他人都在这样做,但我认为这只是为了使其也可用于 C。
还有一个澄清:我知道
__declspec(dllexport)
和 __declspec(dllimport)
仅适用于 Windows 平台,但根据我所读到的内容,我可以摆脱它们并提供 *.def
文件。从我读到的内容来看,这似乎不是首选方法,但如果有人可以展示(再次,出于教育目的)我如何在没有 #pragma
的情况下使用 *.def
文件实现库代码,那就会了非常感谢。
链接 DLL 时,会创建导入库 libMyMath.lib。该库具有与静态库相同的 .lib 扩展名,但它不包含函数的代码。只有调用 DLL 中实现的函数存根。
当您构建 EXE 文件时,您必须链接 LIB 而不是 DLL:
cl /nologo /EHsc /Od /I. build\main.obj /Fe:build\dynamicLibExample.exe /link /DLL /LIBPATH:build build\libMyMath.lib