使用gcc编译简单的C语言dll失败

3

我将尝试用gcc编译一个使用C语言编写的简单DLL。虽然我已经按照多个教程的指导进行了尝试,但即使我把文件精简到最基本也无法编译成功。

test_dll.c

#include <stdio.h>

__declspec(dllexport) int __stdcall hello() {
    printf ("Hello World!\n");
}

尝试使用以下命令进行编译:
gcc -c test_dll.c

失败时,会得到以下输出。
test_dll.c: In function '__declspec':
test_dll.c:3:37: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'hello'
 __declspec(dllexport) int __stdcall hello() {
                                     ^
test_dll.c:5:1: error: expected '{' at end of input
 }
 ^

gcc版本

gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04.3)

1
你是否在编译 Windows 平台?__declspec(dllexport) 与 Windows 特殊的链接器语义(导入库)有关,而在其他系统上不存在。 - user2371524
也许这可以帮助 https://dev59.com/m2w15IYBdhLWcg3wSJk3 - Support Ukraine
2
可能是在GCC或Cygwin中创建DLL?的重复问题。 - KevinDTimm
我认为你需要回答这个问题:你的目标输出是针对Windows还是Linux?Windows使用DLL,而Linux(通常)使用SO。你似乎正在使用Linux(Ubuntu),所以你真的在尝试针对不同的操作系统(Windows),还是在尝试创建一个可以在Linux上使用的SO? - Neil
是的,我确实是在为Windows编译。没有意识到我需要交叉编译。谢谢大家。 - Casperscacion
2个回答

6

这取决于您想要做什么:

1. 在Linux上构建Linux库

然后删除__declspec(dllexport)__stdcall。在Linux上,您不需要在源代码中添加任何特殊内容来构建库。请注意,库在Linux上不是DLL,它们被命名为*.so(共享对象)。您将需要使用-fPIC进行编译,并使用-shared进行链接以创建您的.so文件。请使用Google获取更多详细信息。

2. 在Linux上构建Windows DLL

安装mingw软件包(在软件包管理器中搜索它们)。然后,不要仅使用gcc,而是调用针对Windows/mingw的交叉编译器,例如i686-w64-mingw32-gcc

3. 允许跨平台构建库,包括Windows

如果您希望能够从相同的代码在Windows和Linux上构建库,则需要一些预处理器技巧,以便只有在针对Windows时才使用__declespec()。我通常使用类似于以下内容的东西:

#undef my___cdecl
#undef SOEXPORT
#undef SOLOCAL
#undef DECLEXPORT

#ifdef __cplusplus
#  define my___cdecl extern "C"
#else
#  define my___cdecl
#endif

#ifndef __GNUC__
#  define __attribute__(x)
#endif

#ifdef _WIN32
#  define SOEXPORT my___cdecl __declspec(dllexport)
#  define SOLOCAL
#else
#  define DECLEXPORT my___cdecl
#  if __GNUC__ >= 4
#    define SOEXPORT my___cdecl __attribute__((visibility("default")))
#    define SOLOCAL __attribute__((visibility("hidden")))
#  else
#    define SOEXPORT my___cdecl
#    define SOLOCAL
#  endif
#endif

#ifdef _WIN32
#  undef DECLEXPORT
#  ifdef BUILDING_MYLIB
#    define DECLEXPORT __declspec(dllexport)
#  else
#    ifdef MYLIB_STATIC
#      define DECLEXPORT my___cdecl
#    else
#      define DECLEXPORT my___cdecl __declspec(dllimport)
#    endif
#  endif
#endif

然后在需要由库导出的每个声明前加上DECLEXPORT,并在每个定义前加上SOEXPORT。这只是一个快速的示例。


1
你似乎忽略了他正在Windows上编写一个DLL,并使用例如Cygwin的gcc。顺便说一下,Cygwin的答案与您的第1部分相同,但不需要-fPic - JeremyP
@JeremyP 不,问题明确说明了 gcc 版本 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04.3) - user2371524
好的,我没看到那个。 - JeremyP
也许是新的Windows 10 Ubuntu子系统 ;) - user2371524
我听说微软正在为Windows 11试用一种新的内核,该内核使用Linux核心和NT系统调用的兼容层。 - JeremyP
显示剩余2条评论

4

由于你正在Linux上编译,所以gcc将Linux视为目标平台。

你想要做的是交叉编译Windows。这意味着你需要一个交叉编译器。在Ubuntu Linux上可用的一个是mingw。

你可以使用以下命令来安装:

apt-get install gcc-mingw32 

然后您可以使用以下命令进行编译:

gcc-mingw32 -c test_dll.c

进一步编译成dll需要。
gcc-mingw32 --shared test_dll.o -o test_dll.dll

这个dll可以在Windows上使用。


谢谢,这个方法可行,但是Felix先回答了,所以我标记了他的答案。 - Casperscacion
无论如何,它更加详细并探索了所有可能性。所以,是的,我不介意。 - Ajay Brahmakshatriya
这仍然是一个针对交叉编译情况的好答案,所以在这里点赞——我有点惊讶,Ubuntu真的将mingw变体的gcc称为gcc-mingw32吗?这不符合约定([target-triplet]-gcc):o - user2371524

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接