如何使用 Delphi 正确地静态 link C?
How to properly statically link C with Delphi?
我怎样才能正确静态 link C 和 Delphi? Delphi 吐出一条错误消息:
[dcc32 错误]Project1.dpr(15): E2065 不满足转发或外部声明:'Test'
C 编译器是带有 COFF 目标文件的 Visual C++。
Delphi:
program Project1;
{$L C:\Source.obj}
function Test(): Integer; cdecl; external;
begin
WriteLn(Test);
end.
C:
extern "C" int __cdecl Test()
{
return 12;
}
int main()
{
return 0;
}
这取决于您使用的 C 编译器使用的名称修饰。例如,32 位 bcc32 编译器会将 Test
修饰为 _Test
。所以 Delphi 到 link 的代码应该是:
function Test(): Integer; cdecl; external name '_Test';
但是编译器之间的装饰确实不同,你没有说你使用的是哪个编译器。如果上面的代码没有帮助,那么您应该使用 C 编译器的工具转储 obj 文件并检查其中的函数名称。
另一个问题是您实际上使用的是 C++ 编译器而不是 C 编译器。这可以从您对
的使用中看出
extern "C"
这不是有效的 C。您应该删除它并切换到 C 编译器。将扩展名从 .cpp 更改为 .c 通常足以说服编译器将代码视为 C。
如果您开始从 C 标准库调用函数,例如 malloc
和朋友,那么您需要将 System.Win.Crtl
单元添加到您的 Delphi 代码的 uses 子句中。
另请注意,您不需要,实际上可能也不应该在 C 代码中实现 main
函数。如果要将 C 函数编译成单独的 C 程序,则将函数放在单独的源文件中,与包含 main 函数的源文件分开。这样你就可以将源文件编译成对象。您可以 link 它们进入 C 程序或您的 Delphi 代码。但是您不需要在 Delphi 程序中携带您不调用的 main
函数。
在 C 中,无参数 main
的正确签名是
int main(void)
同样,您的其他 C 函数应具有此签名:
int __cdecl Test(void)
当然,__cdecl
是默认值,因此我们完全可以忽略它:
int Test(void)
让我们把它们放在一起:
C
int Test(void)
{
return 12;
}
重要的是您使用 C 编译器进行编译,而不是作为 C++ 进行编译。如果你的编译是,正如你现在在编辑中所说的那样,MSVC,命令行将是:
cl /c source.c
Delphi
{$APPTYPE CONSOLE}
{$L Source.obj}
function Test: Integer; cdecl; external name '_Test';
begin
WriteLn(Test);
end.
输出
12
我怎样才能正确静态 link C 和 Delphi? Delphi 吐出一条错误消息:
[dcc32 错误]Project1.dpr(15): E2065 不满足转发或外部声明:'Test'
C 编译器是带有 COFF 目标文件的 Visual C++。
Delphi:
program Project1;
{$L C:\Source.obj}
function Test(): Integer; cdecl; external;
begin
WriteLn(Test);
end.
C:
extern "C" int __cdecl Test()
{
return 12;
}
int main()
{
return 0;
}
这取决于您使用的 C 编译器使用的名称修饰。例如,32 位 bcc32 编译器会将 Test
修饰为 _Test
。所以 Delphi 到 link 的代码应该是:
function Test(): Integer; cdecl; external name '_Test';
但是编译器之间的装饰确实不同,你没有说你使用的是哪个编译器。如果上面的代码没有帮助,那么您应该使用 C 编译器的工具转储 obj 文件并检查其中的函数名称。
另一个问题是您实际上使用的是 C++ 编译器而不是 C 编译器。这可以从您对
的使用中看出extern "C"
这不是有效的 C。您应该删除它并切换到 C 编译器。将扩展名从 .cpp 更改为 .c 通常足以说服编译器将代码视为 C。
如果您开始从 C 标准库调用函数,例如 malloc
和朋友,那么您需要将 System.Win.Crtl
单元添加到您的 Delphi 代码的 uses 子句中。
另请注意,您不需要,实际上可能也不应该在 C 代码中实现 main
函数。如果要将 C 函数编译成单独的 C 程序,则将函数放在单独的源文件中,与包含 main 函数的源文件分开。这样你就可以将源文件编译成对象。您可以 link 它们进入 C 程序或您的 Delphi 代码。但是您不需要在 Delphi 程序中携带您不调用的 main
函数。
在 C 中,无参数 main
的正确签名是
int main(void)
同样,您的其他 C 函数应具有此签名:
int __cdecl Test(void)
当然,__cdecl
是默认值,因此我们完全可以忽略它:
int Test(void)
让我们把它们放在一起:
C
int Test(void)
{
return 12;
}
重要的是您使用 C 编译器进行编译,而不是作为 C++ 进行编译。如果你的编译是,正如你现在在编辑中所说的那样,MSVC,命令行将是:
cl /c source.c
Delphi
{$APPTYPE CONSOLE}
{$L Source.obj}
function Test: Integer; cdecl; external name '_Test';
begin
WriteLn(Test);
end.
输出
12