这是我的库Lib.c
文件:
#include <stdio.h>
int helloworld(){
printf("Hello World DLL");
}
这是我的exe Main.c
文件:
int helloworld();
int main(int argc, char** argv){
helloworld();
}
我想创建Lib.dll
和Main.exe
,Lib.dll
来自Lib.c
,Main.exe
链接Lib.dll
。
实现这一目标的具体步骤是什么?
答案 0 :(得分:18)
请参阅this有关如何构建DLL的相关问题。
您的库代码不会导出任何符号,并且您的可执行文件不会从库中导入符号。这样做的两种典型模式如下所示,但您可能希望首先阅读。
第一种方法使用__declspec()
在代码中声明从DLL导出并由其他可执行文件导入的函数(或其他项)。您使用头文件来声明导出的项目,并使用预处理器标志来控制符号是导出还是导入:
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
我还专门将调用约定设置为__stdcall
和大多数DLL函数一样(如果我包含了windows.h,我可以使用WINAPI
而不是__stdcall
并且已声明函数为extern "C"
,因此在编译为C ++时,它们的名称不会受到损坏。这里没有这样的问题,因为它都是C,但如果你是从C源构建DLL然后尝试从C ++可执行文件中使用它,那么导入的名称将是不正确的。
代码可能如下所示:
mylib.c
#include "mylib.h"
#include <stdio.h>
int MYLIB_API helloworld(void)
{
printf("Hello World DLL");
return 42;
}
您可以使用以下命令行构建DLL。除了创建DLL之外,它还将创建从另一个可执行文件(以及导出文件中使用DLL)所需的导入库(.lib),但这仅在certain circumstances中需要):
cl /DBUILDING_MYLIB mylib.c /LD
/DBUILDING_MYLIB
参数定义用于控制DLL中的函数是导出(如果已定义)还是导入(未定义)的预处理程序符号。因此,您在构建DLL时定义它,而不是在构建应用程序时定义它。
/LD
参数告诉cl生成DLL。
第二种方法是使用评论中提到的module definition files。您可以使用已有的代码,但还需要创建模块定义文件。它最简单,看起来像这样:
LIBRARY mylib
EXPORTS
helloworld
在这种情况下,要构建DLL,您需要以下命令行:
cl /LD mylib.c /link /DEF:mylib.def
然后,您可以对应用程序进行编码,以便它将您的库标头与DLL函数的导入版本一起使用:
的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);
}
然后可以使用以下命令行进行编译(假设DLL创建中的导入库与main.c位于同一目录中)。无论您使用的是declspec还是模块定义文件,此步骤都是相同的:
cl main.c /link mylib.lib
/link
参数传递到链接器命令行后传递的参数,因为它只是一个文件名,它被用作链接到可执行文件的额外输入。在这种情况下,我们指定在构建DLL时生成的导入库。
我在这里显示的命令行几乎是您需要的绝对最小值,但它允许您创建DLL并将应用程序链接到它。
我认为调用约定在上述所有方面都是正确的,而且我没有多少尝试来看看我是否在任何时候都弄错了。