0

由于各种原因,我一直在尝试自己编译FANN库。我在使用 MinGW 的 Windows 10 上。为了简单起见,我打算这样开始:

g++ mushroom.c -o shroom.exe -lm -I src\ -I src\include\ src\doublefann.c

mushroom.c包括<stdio.h>"fann.h"。)

使用-I src\ -I src\include\ src\doublefann.c允许我摆脱由于找不到头文件而导致的各种未定义引用错误,但它现在不断抛出以下未定义引用:

doublefann.c:(.text+0x4ee9): undefined reference to GetTickCount()

仅供参考,这出现在 fann.h(第 54 行)中:

/* COMPAT_TIME REPLACEMENT */ 
#ifndef _WIN32
#include <sys/time.h>
#else   /* _WIN32 */
#if !defined(_MSC_EXTENSIONS) && !defined(_INC_WINDOWS)  
extern unsigned long __stdcall GetTickCount(void);

简而言之,这似乎是链接 Windows 库的错误,我真的不知道如何继续以找到要链接的相关库。

这是完整的fann.h和完整的doublefann.c

4

1 回答 1

4

免责声明和注意事项

编辑:自从昨晚睡觉以来,我改进了我的方法,所以你不必编辑实际的 FANN 源文件。(为了记录,我最初的方法是有效的,如果你真的在乎,你可以查看编辑历史来看看那是什么)。

首先,对于遇到这个问题的任何其他人,我应该指出,实际上没有必要以这种方式使用 FANN。该网站提供了 cmake 文件以及 Visual Studio 解决方案,它们都可以正常工作。

 

怎么了

回顾这个问题,问题很明显,我讨厌自己在第一个时间之前没有看到它。您会注意到该命令中的所有文件都具有*.c扩展名。请原谅我把你当作新手对待,但我不能假设你什么都知道,否则我可能会给出错误的答案。*.cC源文件的规范文件扩展名。gnu 工具链是一个相当灵活的软件,您可以在大多数情况下无错误地编译C代码。g++但你不应该,因为你会得到这个错误。由于您的源文件 ,mushroom.cC源文件,因此只需将代码编译为C即可(在本例中为gcc,而不是g++)。但是,如果您在程序中使用iostreamstring或类或任何其他C++代码之类的东西,则将其编译为C++是正确的(按照惯例,您会将扩展名更改为 以*.cpp进行澄清,但我不确定GNU 工具链关心)。在这种情况下,每当您想在C++程序中包含C代码时,请务必将其包装在 中,以便编译器知道调用约定和标签是C标准,这并不总是与C++标准相同。这意味着不仅从C++调用C代码extern "C"{}extern "C"以错误的方式将参数传递给函数的风险(导致段错误的好方法),但是在编译为程序集时变量和函数重命名的方式在两种语言之间是不同的,这就是为什么你进入Undefined Reference链接阶段,而不是编译阶段。在这种情况下,不仅是doublefann.c一个C源文件(它本身可以很好地链接),而且包含GetTickCount(). 具体来说,您链接到%SYSTEMROOT%\System32\kernel32.dll(通常,但我相信 MinGW 使用PATH_TO_MinGW\lib\lib32k.a),它定义了程序如何在机器代码级别与 Windows 操作系统交互。该实用程序在此处定义为在C__stdcall中从操作系统调用诸如GetTickCount()汇编函数之类的东西代码。因为这是在 a 中*.dll,所以编译器无法更改__stdcall以适应C++约定。这是因为“ dll”代表“动态链接库”。本质上,这意味着这些文件在安装 Windows(或 MinGW)时已经编译成机器代码。所以编辑它是无意义的,因为你需要对每个 x86_64 处理器的操作码有深入的工作知识。因此,在C__stdcall中调用将以预期的方式完成所有操作,但在C++中调用需要extern "C",否则它会破坏函数声明的名称并可能导致运行时错误。

tl;博士

FANN 是用C编写的,C =/= C++,所以不要期望C++编译器总是能完美地编译C代码。

 

解决方案

有两种方法可以解决这个问题。

1

如果您正在使用C++功能/库,请将源代码的名称更改为mushroom.cpp(如果需要)并更改行(无论它出现在程序中的哪个位置)

#include "doublefann.c"

像这样包裹:

extern "C"{
    #include "doublefann.c"
}

如果您通读 fann.h,您可能已经注意到以下几行:

#ifdef __cplusplus //line 65
extern "C"
{

#ifndef __cplusplus
} /* to fool automatic indention engines */ 
#endif
#endif  /* __cplusplus */

别担心,这些似乎没有冲突。坦率地说,我不确定这些线路的目的是什么,但我确信他们知道自己在做什么。

2

如果mushroom.c真的只是纯C,只需编译使用:

gcc -o shroom.exe mushroom.c -lm -I src\ -I src\ -I src\include\ src\doublefann.c -Wall

这应该有效。我补充说-Wall,因为我喜欢能够使我的代码绝对完美,请随意将其排除在外,它只会打印您可能遇到的所有警告。

于 2016-02-11T10:58:40.547 回答