Reputation: 293
For various reasons I have been trying to compile the FANN library myself. I'm on Windows 10 with MinGW. To keep things simple I was going for something like this to start with:
g++ mushroom.c -o shroom.exe -lm -I src\ -I src\include\ src\doublefann.c
(mushroom.c
includes <stdio.h>
and "fann.h"
.)
Using the -I src\ -I src\include\ src\doublefann.c
allowed me to get rid of various undefined reference errors resulting from header files not being found, but it now keeps throwing the following undefined reference:
doublefann.c:(.text+0x4ee9): undefined reference to GetTickCount()
FYI, this appears in fann.h (line 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);
In short, this seems to be an error with linking windows libraries, and I don't really know how to proceed so as to find the relevant ones to link.
Here is the full fann.h and the full doublefann.c
Upvotes: 0
Views: 422
Reputation: 1140
EDIT: Since going to bed last night, I refined my approach so you don't have to edit the actual FANN source files. (For the record, my original approach worked and you can look at the edit history to see what that was if you really care).
Firstly, for anyone else stumbling across this question, I should note that it's not really necessary to use FANN this way. The website provides cmake files as well as Visual Studio Solutions that both work fine.
Looking back at the question, the problem is obvious and I hate myself for not seeing it before the first of way too many hours. You'll notice that all of the files in that command have the *.c
extension. Forgive me for treating you like a novice, but I can't assume you know anything or I risk giving a bad answer. *.c
is the canonical file extension for C source files. The gnu toolchain is a fairly flexible piece of software, and you can compile C code with g++
without errors most of the time. But you shouldn't, because you'll get this error. Since your source file, mushroom.c
, is a C source file, it'll work for you to just compile the code as C (in this case with gcc
, not g++
). If, however, you're using things in your program like iostream
or string
or classes or any other C++ code, you're right to compile it as C++ (by convention you would change the extension then to *.cpp
for clarification, but I'm not sure the GNU toolchain cares). In that case, whenever you want to include C code in your C++ program, be sure to wrap it in an extern "C"{}
, so that the compiler knows the calling conventions and labels are C standard, which isn't always the same as C++ standard. This means that not only does calling C code from C++ without extern "C"
risk passing arguments to functions in the wrong way (good way to cause a segfault), but the way variables and functions are renamed when compiled to assembly is different between the two languages, which is why you get Undefined Reference
in the linking stage, but not the compiling stage. In this case, not only is doublefann.c
a C source file (which by itself links fine), but so is the library that contains the function declaration of GetTickCount()
. Specifically, you're linking to %SYSTEMROOT%\System32\kernel32.dll
(normally, but I believe MinGW uses PATH_TO_MinGW\lib\lib32k.a
), which defines how programs can interact with the Windows Operating System at the machine-code level. The __stdcall
utility is defined here to call things like GetTickCount()
from the OS, which are assembly functions, within C code. Because this is in a *.dll
, the compiler cannot change __stdcall
to suit C++ coventions. This is due to the fact that "dll
" stands for "Dynamically Linked Library". Essentially this means that these files were already compiled into machine code when Windows (or MinGW) was installed. So editing it is nonsensical, because you'd need to have intimate working knowledge of the opcodes for every x86_64 processor ever made. Thus, calling in C will do everything in a way that __stdcall
expects, but calling in C++ requires the extern "C"
, or it'll mangle the names of your function declaration and possibly cause runtime errors.
FANN is written in C, C=/=C++, so don't expect a C++ compiler to always compile C code perfectly.
There are two ways to go about solving this problem.
If you're using C++ features/libraries, change the name of your source code to mushroom.cpp
(if you want) and change the line (wherever it occurs in your program)
#include "doublefann.c"
to be wrapped like so:
extern "C"{
#include "doublefann.c"
}
If you read through fann.h, you might have noticed the lines:
#ifdef __cplusplus //line 65
extern "C"
{
#ifndef __cplusplus
} /* to fool automatic indention engines */
#endif
#endif /* __cplusplus */
Don't worry, these don't appear to conflict. Frankly, I'm not sure what these lines are meant to accomplish, but I'm sure they know what they're doing.
If mushroom.c
really is just pure C, just compile using:
gcc -o shroom.exe mushroom.c -lm -I src\ -I src\ -I src\include\ src\doublefann.c -Wall
and that should work. I added -Wall
because I love being able to make my code absolutely perfect, feel free to leave that out it just prints every warning you could have.
Upvotes: 4