如何使用cl命令?
大家好,我找到了一些关于如何在Python中调用C文件的信息。在这些例子中,有一个C文件,它包含了很多其他的头文件,这个C文件的开头是#include Python.h
。然后我发现#include Python.h
实际上还会引入很多其他的头文件,比如pystate.h
、object.h
等等,所以我把所有需要的头文件都包含进来了。在一个C++的开发环境中,它没有显示错误。我想做的是在Python中调用这个C代码,所以我用了from ctypes import *
,然后似乎需要通过像cl -LD test.c -test.dll
这样的代码生成一个dll
文件,但在这种情况下我该如何使用cl
呢?我用了Cygwin中的gcc
,它运行得很好。有没有人能帮我解决这个也就是说:在Python中调用C代码的问题?我说清楚了吗?谢谢大家!
好吧,现在我觉得有必要告诉大家我做了什么:我想达到的最终目标是:我很懒,不想把那些C代码重新写成Python代码(在某些情况下对我来说非常复杂),所以我只想生成Python可以调用的dll
文件。我按照谷歌上搜索“python call c”找到的一个例子,里面有两个版本:Linux和Windows:
这个例子是test.c
:
#include <windows.h>
BOOL APIENTRY
DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved) {
return TRUE;
}
__declspec(dllexport) int
multiply(int num1, int num2) {
return num1 * num2;
}
两个版本:
1. 在Linux下编译
gcc -c -fPIC test.c
gcc -shared test.o -o test.so
我在我的Vista系统的Cygwin中做了这个,运行得很好; :)
2. 在Windows下编译:
cl -LD test.c -test.dll
我在Windows命令行提示符中使用了cl
,但它不工作!
这些是Python代码:
from ctypes import *
import os
libtest = cdll.LoadLibrary(os.getcwd() + '/test.so')
print test.multiply(2, 2)
有没有人能试试这个,告诉我你得到了什么?谢谢!
1 个回答
你可以在这里找到微软C++编译器的命令行选项:这里。
看看下面这些cl的选项:
/nologo /GS /fp:precise /Zc:forScope /Gd
...然后用下面的命令链接你的文件:
/NOLOGO /OUT:"your.dll" /DLL <your lib files> /SUBSYSTEM:WINDOWS /MACHINE:X86 /DYNAMICBASE
请仔细查看这些选项的具体含义,我这里只列出了一些常用的。你应该了解它们的作用,所以尽量避免直接复制粘贴,确保你真的需要这些选项——上面链接的文档会对你有帮助。这只是我偶尔使用的设置。
请注意,你可以随时打开Visual Studio,配置构建选项,并从项目配置对话框中复制命令行调用。
编辑: 好的,这里有一些额外的建议,基于你在原问题中编辑的新信息。我把你简单DLL的示例代码粘贴到一个源文件中,并做了两个修改:
#include <windows.h>
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
{
return TRUE;
}
extern "C" __declspec(dllexport) int __stdcall multiply(int num1, int num2)
{
return num1 * num2;
}
首先,我通常希望从DLL导出的函数使用stdcall调用约定,因为这是Windows中常见的做法,并且有些语言根本无法处理cdecl,因为它们只知道stdcall。所以这是我做的一个修改。
其次,为了让导出更友好,我指定了extern "C",以避免名称修饰。然后我在命令行中编译代码,像这样:
cl /nologo /GS /Zc:forScope /Gd c.cpp /link /OUT:"foobar.dll" /DL kernel32.lib /SUBSYSTEM:WINDOWS /MACHINE:X86
如果你使用Visual Studio工具集中的DUMPBIN工具,你可以检查你的DLL导出:
dumpbin /EXPORTS foobar.dll
看到这样的输出...
ordinal hint RVA name
1 0 00001010 ?multiply@@YGHHH@Z
...你会注意到导出的名称被修饰了。通常你会希望导出有清晰的名称,所以要么使用DEF文件更详细地指定导出,要么使用上面的快捷方式。
最后,我得到了一个可以像这样加载到Python中的DLL:
In [1]: import ctypes
In [2]: dll = ctypes.windll.LoadLibrary("foobar.dll")
In [3]: dll.multiply
Out[3]: <_FuncPtr object at 0x0928BEF3>
In [4]: dll.multiply(5, 5)
Out[4]: 25
注意,我在这里使用的是ctypes.windll,这意味着使用的是stdcall。