I'm comparing Numerical Recipes four1.c to Nayuki's FFT. Both are the C versions, but I'm using a C++ driver. For the comparison, I'm compiling (or more appropriately, linking) both into an executable with CL.exe and g++. The two appear to be fighting over whether or not to use extern "C" for the four1 function, but neither seem to care about Nayuki's. I made a header file for four1 that checks for _WIN32 in order to switch appropriately, and it works, but seems to be a completely unacceptable hack. How would I fix this?
Here's the header file:
#pragma once
#ifdef _WIN32
extern "C" void four1(float data[], unsigned long nn, int isign);
#else
void four1(float data[], unsigned long nn, int isign);
#endif
This is what CL does without the extern "C":
drvr.obj : error LNK2019: unresolved external symbol "void __cdecl four1(float * const,unsigned long,int)" (?four1@@YAXQAMKH@Z) referenced in function _main
drvr.exe : fatal error LNK1120: 1 unresolved externals
And this is what g++ does if extern "C" is used:
/tmp/ccK1Hb2N.o: In function `main':
drvr.cpp:(.text+0x347): undefined reference to `four1'
collect2: error: ld returned 1 exit status
What works for CL doesn't work for g++, and what works for g++ doesn't work in CL. At least for this file. No such problem exists for the Nayuki code.
I tried revising the header file as advised, so now here's dfour1.h:
#pragma once
/* C++ needs to know that types and declarations are C, not C++. */
#ifdef __cplusplus
# define __BEGIN_DECLS extern "C" {
void dfour1(double data[], unsigned long nn, int isign);
# define __END_DECLS }
#else
# define __BEGIN_DECLS
# define __END_DECLS
#endif
g++ is fine with it. CL isn't.
>cl drvr.cpp dfour1.c fft.c carrier.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.00.24215.1 for x86
Copyright (C) Microsoft Corporation. All rights reserved.
drvr.cpp
Generating Code...
Compiling...
dfour1.c
fft.c
Generating Code...
Compiling...
carrier.cpp
Generating Code...
Microsoft (R) Incremental Linker Version 14.00.24215.1
Copyright (C) Microsoft Corporation. All rights reserved.
/out:drvr.exe
drvr.obj
dfour1.obj
fft.obj
carrier.obj
drvr.obj : error LNK2019: unresolved external symbol "void __cdecl dfour1(double * const,unsigned long,int)" (?dfour1@@YAXQANKH@Z) referenced in function _main
drvr.exe : fatal error LNK1120: 1 unresolved externals
Incidentally, the same happens if there is NO header file, and I simply add:
extern "C" void dfour1(double data[], unsigned long nn, int isign);
to the drvr.cpp file, and remove the header file. CL only works when extern "C"
is there, but then g++ doesn't. Whereas removing extern "C"
works with g++ but not with CL.
And yes I know the original header file was wrong, that was the point of the question. When I did it "correctly" it didn't work, thus the post. When I made an "incorrect" header file that checks for which compiler was being used, it worked, and that was the annoying part. Simply checking for c++ does not work.