g++ - 为 link 寻找合适的 Windows 库以编译 FANN 库
g++ - Finding appopriate Windows libraries to link so as to compile FANN library
出于各种原因,我一直在尝试自己编译 FANN 库。我在 Windows 10 上使用 MinGW。为了简单起见,我打算以这样的方式开始:
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);
简而言之,这似乎是 linking windows 库的错误,我真的不知道如何继续才能找到与 [=36= 相关的库].
这是完整的fann.h and the full doublefann.c
免责声明和注意事项
编辑:自从昨晚睡觉后,我改进了我的方法,因此您不必编辑实际的 FANN 源文件。 (郑重声明,我最初的方法奏效了,如果你真的关心的话,你可以查看编辑历史,看看那是什么)。
首先,对于遇到这个问题的任何其他人,我应该指出,并不是真的有必要以这种方式使用 FANN。该网站提供了 cmake 文件以及 Visual Studio 都可以正常工作的解决方案。
怎么了
回过头来看这个问题,问题很明显,我恨自己在第一个小时之前没有看到它。您会注意到该命令中的所有文件都具有 *.c
扩展名。请原谅我把你当作新手对待,但我不能假设你知道任何事情,否则我可能会给出错误的答案。 *.c
是 C 源文件的规范文件扩展名。 gnu 工具链是一个相当灵活的软件,您 可以 编译 C 代码 g++
大多数时候没有错误。但你不应该,因为你会得到这个错误。由于您的源文件 mushroom.c
是 C 源文件,因此您只需将代码编译为 C 即可(在这种情况下使用 gcc
,而不是 g++
)。但是,如果您在程序中使用 iostream
或 string
或 类 或任何其他 C++ 代码,那么您是对的将其编译为 C++(按照惯例,您会将扩展名更改为 *.cpp
以进行澄清,但我不确定 GNU 工具链是否关心)。在那种情况下,每当你想在你的 C++ 程序中包含 C 代码时,一定要将它包装在 extern "C"{}
中,所以编译器知道调用约定和标签是 C 标准,这并不总是与 C++ 标准相同。这意味着不仅从 C++ 调用 C 代码而没有 extern "C"
风险以错误的方式将参数传递给函数(好方法导致段错误),但是两种语言在编译为汇编时重命名变量和函数的方式是不同的,这就是为什么你在链接阶段得到 Undefined Reference
而不是编译阶段的原因。在这种情况下,不仅 doublefann.c
是一个 C 源文件(它本身链接很好),而且包含 GetTickCount()
函数声明的库也是.具体来说,您正在链接到 %SYSTEMROOT%\System32\kernel32.dll
(通常,但我相信 MinGW 使用 PATH_TO_MinGW\lib\lib32k.a
),它定义了程序如何在机器代码级别与 Windows 操作系统交互。 __stdcall
实用程序在此处定义为在 C 代码中从 OS 调用诸如 GetTickCount()
之类的东西,它们是汇编函数。因为这是在 *.dll
中,编译器无法更改 __stdcall
以适应 C++ 约定。这是因为“dll
”代表“动态链接库”。本质上这意味着这些文件在安装 Windows(或 MinGW)时已经被编译成机器代码。所以编辑它是荒谬的,因为你需要对每个 x86_64 处理器的操作码有深入的工作知识。因此,调用 C 将以 __stdcall
期望的方式执行所有操作,但调用 C++ 需要 extern "C"
,否则它会破坏函数声明的名称并可能导致运行时错误。
tl;博士
FANN是用C、C=/=C++写的,所以不要'不要期望 C++ 编译器总是完美地编译 C 代码。
解决方案
有两种方法可以解决这个问题。
1
如果您使用的是 C++ features/libraries,请将源代码的名称更改为 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
因为我喜欢能够使我的代码绝对完美,请随意忽略它它只会打印您可能拥有的每个警告。
出于各种原因,我一直在尝试自己编译 FANN 库。我在 Windows 10 上使用 MinGW。为了简单起见,我打算以这样的方式开始:
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);
简而言之,这似乎是 linking windows 库的错误,我真的不知道如何继续才能找到与 [=36= 相关的库].
这是完整的fann.h and the full doublefann.c
免责声明和注意事项
编辑:自从昨晚睡觉后,我改进了我的方法,因此您不必编辑实际的 FANN 源文件。 (郑重声明,我最初的方法奏效了,如果你真的关心的话,你可以查看编辑历史,看看那是什么)。
首先,对于遇到这个问题的任何其他人,我应该指出,并不是真的有必要以这种方式使用 FANN。该网站提供了 cmake 文件以及 Visual Studio 都可以正常工作的解决方案。
怎么了
回过头来看这个问题,问题很明显,我恨自己在第一个小时之前没有看到它。您会注意到该命令中的所有文件都具有 *.c
扩展名。请原谅我把你当作新手对待,但我不能假设你知道任何事情,否则我可能会给出错误的答案。 *.c
是 C 源文件的规范文件扩展名。 gnu 工具链是一个相当灵活的软件,您 可以 编译 C 代码 g++
大多数时候没有错误。但你不应该,因为你会得到这个错误。由于您的源文件 mushroom.c
是 C 源文件,因此您只需将代码编译为 C 即可(在这种情况下使用 gcc
,而不是 g++
)。但是,如果您在程序中使用 iostream
或 string
或 类 或任何其他 C++ 代码,那么您是对的将其编译为 C++(按照惯例,您会将扩展名更改为 *.cpp
以进行澄清,但我不确定 GNU 工具链是否关心)。在那种情况下,每当你想在你的 C++ 程序中包含 C 代码时,一定要将它包装在 extern "C"{}
中,所以编译器知道调用约定和标签是 C 标准,这并不总是与 C++ 标准相同。这意味着不仅从 C++ 调用 C 代码而没有 extern "C"
风险以错误的方式将参数传递给函数(好方法导致段错误),但是两种语言在编译为汇编时重命名变量和函数的方式是不同的,这就是为什么你在链接阶段得到 Undefined Reference
而不是编译阶段的原因。在这种情况下,不仅 doublefann.c
是一个 C 源文件(它本身链接很好),而且包含 GetTickCount()
函数声明的库也是.具体来说,您正在链接到 %SYSTEMROOT%\System32\kernel32.dll
(通常,但我相信 MinGW 使用 PATH_TO_MinGW\lib\lib32k.a
),它定义了程序如何在机器代码级别与 Windows 操作系统交互。 __stdcall
实用程序在此处定义为在 C 代码中从 OS 调用诸如 GetTickCount()
之类的东西,它们是汇编函数。因为这是在 *.dll
中,编译器无法更改 __stdcall
以适应 C++ 约定。这是因为“dll
”代表“动态链接库”。本质上这意味着这些文件在安装 Windows(或 MinGW)时已经被编译成机器代码。所以编辑它是荒谬的,因为你需要对每个 x86_64 处理器的操作码有深入的工作知识。因此,调用 C 将以 __stdcall
期望的方式执行所有操作,但调用 C++ 需要 extern "C"
,否则它会破坏函数声明的名称并可能导致运行时错误。
tl;博士
FANN是用C、C=/=C++写的,所以不要'不要期望 C++ 编译器总是完美地编译 C 代码。
解决方案
有两种方法可以解决这个问题。
1
如果您使用的是 C++ features/libraries,请将源代码的名称更改为 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
因为我喜欢能够使我的代码绝对完美,请随意忽略它它只会打印您可能拥有的每个警告。