1

I'm trying to cross-compile a piece of code which uses float.h to set some FPU sizes.

The particular piece of code that requires it is:

#ifdef SINGLE
  _control87(_PC_24, _MCW_PC); /* Set FPU control word for single precision. */
#else /* not SINGLE */
  _control87(_PC_53, _MCW_PC); /* Set FPU control word for double precision. */
#endif /* not SINGLE */

When I compile, however, I get the error

/home/rcrozier/src/xfemm-hg/mfemm/../cfemm/fmesher/triangle.c:4922:14: error: '_PC_53' undeclared (first use in this function)
   _control87(_PC_53, _MCW_PC); /* Set FPU control word for double precision. */

Another person explains what seems to be the same problem in more detail here. There is also a very similar issue described in a (rather old) thread here. In case it's relevant, I'm using mingw-w64, but via the M Cross Environment

What exactly is the problem with float.h in this case, and is there a workaround?

EDIT: Verbose output from gcc

Using built-in specs.
COLLECT_GCC=/opt/mxe/usr/bin/x86_64-w64-mingw32.shared-gcc
Target: x86_64-w64-mingw32.shared
Configured with: /opt/mxe/tmp-gcc-x86_64-w64-mingw32.shared/gcc-4.9.4/configure --target=x86_64-w64-mingw32.shared --build=x86_64-unknown-linux-gnu --prefix=/opt/mxe/usr --libdir=/opt/mxe/usr/lib --enable-languages=c,c++,objc,fortran --enable-version-specific-runtime-libs --with-gcc --with-gnu-ld --with-gnu-as --disable-nls --disable-multilib --without-x --disable-win32-registry --enable-threads=win32 --enable-libgomp --with-gmp=/opt/mxe/usr/x86_64-unknown-linux-gnu --with-isl=/opt/mxe/usr/x86_64-unknown-linux-gnu --with-mpc=/opt/mxe/usr/x86_64-unknown-linux-gnu --with-mpfr=/opt/mxe/usr/x86_64-unknown-linux-gnu --with-cloog=/opt/mxe/usr/x86_64-unknown-linux-gnu --with-as=/opt/mxe/usr/bin/x86_64-w64-mingw32.shared-as --with-ld=/opt/mxe/usr/bin/x86_64-w64-mingw32.shared-ld --with-nm=/opt/mxe/usr/bin/x86_64-w64-mingw32.shared-nm
Thread model: win32
gcc version 4.9.4 (GCC) 
COLLECT_GCC_OPTIONS='-c' '-I' '../cfemm/fmesher' '-I' '../cfemm/libfemm' '-I' '../cfemm/libfemm/liblua' '-I' '/usr/local/MATLAB/R2015a/extern/include' '-I' '/usr/local/MATLAB/R2015a/simulink/include' '-D' 'MATLAB_MEX_FILE' '-std=c99' '-D' '_GNU_SOURCE' '-fexceptions' '-fPIC' '-fno-omit-frame-pointer' '-pthread' '-v' '-fpermissive' '-D' 'CPU86' '-D' 'MX_COMPAT_32' '-O' '-D' 'NDEBUG' '-o' '/home/rcrozier/src/xfemm-hg/mfemm/../cfemm/fmesher/triangle.o' '-mtune=generic' '-march=x86-64'
 /opt/mxe/usr/libexec/gcc/x86_64-w64-mingw32.shared/4.9.4/cc1 -quiet -v -I ../cfemm/fmesher -I ../cfemm/libfemm -I ../cfemm/libfemm/liblua -I /usr/local/MATLAB/R2015a/extern/include -I /usr/local/MATLAB/R2015a/simulink/include -D_REENTRANT -U_REENTRANT -D MATLAB_MEX_FILE -D _GNU_SOURCE -D CPU86 -D MX_COMPAT_32 -D NDEBUG /home/rcrozier/src/xfemm-hg/mfemm/../cfemm/fmesher/triangle.c -quiet -dumpbase triangle.c -mtune=generic -march=x86-64 -auxbase-strip /home/rcrozier/src/xfemm-hg/mfemm/../cfemm/fmesher/triangle.o -O -std=c99 -version -fexceptions -fPIC -fno-omit-frame-pointer -fpermissive -o /tmp/ccMkwwWD.s
cc1: warning: command line option '-fpermissive' is valid for C++/ObjC++ but not for C
GNU C (GCC) version 4.9.4 (x86_64-w64-mingw32.shared)
    compiled by GNU C version 4.8.4, GMP version 6.1.1, MPFR version 3.1.4, MPC version 1.0.2
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/opt/mxe/usr/lib/gcc/x86_64-w64-mingw32.shared/4.9.4/../../../../x86_64-w64-mingw32.shared/sys-include"
#include "..." search starts here:
#include <...> search starts here:
 ../cfemm/fmesher
 ../cfemm/libfemm
 ../cfemm/libfemm/liblua
 /usr/local/MATLAB/R2015a/extern/include
 /usr/local/MATLAB/R2015a/simulink/include
 /opt/mxe/usr/lib/gcc/x86_64-w64-mingw32.shared/4.9.4/include
 /opt/mxe/usr/lib/gcc/x86_64-w64-mingw32.shared/4.9.4/include-fixed
 /opt/mxe/usr/lib/gcc/x86_64-w64-mingw32.shared/4.9.4/../../../../x86_64-w64-mingw32.shared/include
End of search list.

EDIT: more info

I also get the same result if I use the full directory path to the mingw-w64 float.h like so:

//#include <float.h>
#include "/opt/mxe/usr/x86_64-w64-mingw32.static/include/float.h"

EDIT more info on code structure

To give some further information, I am actually compiling C library (header and C file) where declaration of the function I'm using is included using extern C. The actual declaration from the header file is shown below:

#ifdef __cplusplus
extern "C" {
#endif

#ifdef ANSI_DECLARATORS
int triangulate(char *, struct triangulateio *, struct triangulateio *,
                 struct triangulateio *, int (*TriMessage)(const char * format, ...));
void trifree(VOID *memptr);
#else /* not ANSI_DECLARATORS */
int triangulate();
void trifree();
#endif /* not ANSI_DECLARATORS */

#ifdef __cplusplus
}
#endif

The actual library I'm using is Triangle. The float.h include is in triangle.c, and looks like this:

#ifdef CPU86
//#include <float.h>
#include "/opt/mxe/usr/x86_64-w64-mingw32.static/include/float.h"
#endif /* CPU86 */
#ifdef LINUX
#include <fpu_control.h>
#endif /* LINUX */

Where you define CPU86 or LINUX at compile time. For the cross build, I'm defining CPU86.

crobar
  • 2,810
  • 4
  • 28
  • 46

1 Answers1

0

OK, after some searching around I found this in triangle.c:

/* On some machines, my exact arithmetic routines might be defeated by the   */
/*   use of internal extended precision floating-point registers.  The best  */
/*   way to solve this problem is to set the floating-point registers to use */
/*   single or double precision internally.  On 80x86 processors, this may   */
/*   be accomplished by setting the CPU86 symbol for the Microsoft C         */
/*   compiler, or the LINUX symbol for the gcc compiler running on Linux.    */
/*                                                                           */

Note that it says "On 80x86 processors". The host you're compiling for - windows 64 bit (x86_64) - does not match that.

This is further supported by the official documentation from Microsoft about the extension that's used by the library you're trying to compile:

Mask

_MCW_PC (Precision control)

(Not supported on ARM or x64 platforms.)

[..]

_PC_24 (24 bits)

_PC_53 (53 bits)

_PC_64 (64 bits)

[..]

Thus I guess you need to configure your build differently, probably not defining CPU86. Though I don't know whether this really solves your issue, or just leads to wrong results. After all ... is this library even ported to 64 bit?

Daniel Jour
  • 15,896
  • 2
  • 36
  • 63
  • You make a good point, but, I've now had a chance to double check, and I can confirm that the same code does compile and run natively on Windows, using the mingw-w64 compiler (specifically the version in TDM-GCC 4.9.2). So while this is something to worry about, I don't think this is the issue. I did actually email the original author about this some time ago but he never replied. I can definitely confirm that it compiles on 64 Bit Linux and has solved many many problems without issue. – crobar Sep 19 '16 at 09:39
  • I've now also had a chance to check triangle.c, and the help text at the beginning specifically mentions 64 bit architectures (he mentions the DEC Alpha in the context of recommending whether to use single of double precision), so I think in principle `triangle` should work on 64 Bit and practice indicates this is the case. – crobar Sep 19 '16 at 09:50
  • Hmm ... and in these working builds, is there `CPU86` defined? Reading the readme file, I'd just leave it (as well as `LINUX`) undefined. Can you try that? – Daniel Jour Sep 19 '16 at 13:54
  • Yes, `CPU86` is defined. I wonder if on windows x64, the setting is ignored but the default just happens to be the same as this setting (i.e. standard double, no extended floating point precision) and it works. I will try just not defining it and see what happens. This might cure the symptom which is useful (thanks!) but doesn't actually explain why cross build fails but native doesn't (both using mingw-w64). – crobar Sep 19 '16 at 16:02