问题
I'm using Eigen3 on a cross compiled program using the arm-linux-gnueabihf-g++ (gcc version 4.8 from Linaro). The target platform is a duovero from gumstix using the Poky distribution - ARMv7. When I run the program with the Eigen code I get really strange values on the Eigen objects (see the output example at the end of this post).
I've tried to turn off vectorization, I've played with all these flags
-marm
-mcpu=cortex-a7
-mfpu=neon
-mfloat-abi=hard
but always get the same behavior. If I compile the same code on the duovero it works ok (vectors are properly initialized) but not when I cross-compile. I've even cross-compiled from different hosts (windows7 and ubuntu 14.04).
Any idea why this is happening?
This is my simple program (updated from comments)
#include <iostream>
using namespace std;
#include <stdio.h>
#include <Eigen/Eigen>
#include <Eigen/Dense>
using namespace Eigen;
int main()
{
cout << "Hello World!" << endl;
int j =3;
cout << j << endl << endl; // ok
float k =4.2;
cout << k << endl << endl; // not ok
printf("%f\n\n", k ); // ok
Vector3d test1;
test1 << 1.2, 2.3, 3.4;
cout << test1 << endl << endl; // not ok
printf("%f\n\n", test1(0) ); // ok
Vector3d test2(1,2,3);
cout << test2 << endl; // not ok
cout << test2(1) << endl << endl; // not ok
printf("%f\n\n", test2(0) ); // ok
cout << 0.5f << endl; // not ok
printf("%f\n\n", 0.5f ); // ok
return 0;
}
This is the output I get (updated)
Hello World!
3
0
4.200000
-1.24694e-06
-1.24695e-06
-1.24695e-06
1.200000
-1.24692e-06
-1.24692e-06
-1.24693e-06
3.8852e+68
1.000000
0
0.500000
Edit When I add the flag: -mfloat-abi=soft I get this error
arm-linux-gnueabihf-g++ -c -mfloat-abi=soft -g -Wall -W -fPIE -IC:\tmp\testingEigen -I. -IC:\COSMOS\source\thirdparty\arm\eigen3 -IC:\Qt\5.4\mingw491_32\mkspecs\linux-arm-gnueabihf-g++ -o main.obj C:\tmp\testingEigen\main.cpp
arm-linux-gnueabihf-g++ -o testingEigen main.obj
c:/program files (x86)/linaro/gcc-linaro-arm-linux-gnueabihf-4.8-2014.01/bin/../lib/gcc/arm-linux-gnueabihf/4.8.3/../../../../arm-linux-gnueabihf/bin/ld.exe: error: testingEigen uses VFP register arguments, main.obj does not
makefile:79: recipe for target 'testingEigen' failed
c:/program files (x86)/linaro/gcc-linaro-arm-linux-gnueabihf-4.8-2014.01/bin/../lib/gcc/arm-linux-gnueabihf/4.8.3/../../../../arm-linux-gnueabihf/bin/ld.exe: failed to merge target specific data of file main.obj
update: I tried what Notlikethat suggested. Tested the libraries (ex. readelf -h /usr/lib/libstdc++.so.6.0.18) and found that the current built is definitively soft-float ABI.
When I link statically my the code works well (even if cross compiler is for hard float, this works because the hardware actually has an FPU even if the image is configured for soft fp). The next thing I did was to find a cross compiler that is able to do do softfp, and it also worked when I added the flag. I downloaded it from https://launchpad.net/linaro-toolchain-binaries/+milestone/2012.04.
I guess my next step is to compile a poky image for the duovero that can do hard float. Has anyone done this?
final update: I've actually just compiled the latest poky image from yocto (poky 1.7) for the duovero using these instructions https://github.com/gumstix/yocto-manifest
and realised that this build uses hard fp. Now my cross compiler (arm-linux-gnueabihf-g++) and the target have the same floating point configuration and my code with Eigen and everything else is working perfectly! Happy! :)
回答1:
The problem would seem to be that you have a soft-float libstdc++ (and friends) on the device.
Consider an innocuous-looking function like std::ostream::operator<<(float)
- when you cross-compile with the hard-float toolchain, you generate code which will pass the float to the function in an FPU register. The static linker knows enough to double-check that this matches the libraries it's linking against (the hard-float ones bundled with the cross-toolchain itself). Then you take that binary and run it on the device...
The dynamic linker, being less clever, is just going to make sure that whatever libstdc++ it finds provides the symbols the program is asking for. It finds one of a similar-enough version which fits that bill, so all seems good. Except now you've got the situation where your code is passing float arguments to library functions in FPU registers, but the library functions (being soft-float) are expecting their float arguments in general-purpose registers, so they find uninitialised junk.
The best thing to do is to avoid the "link against one library, run against another" mismatch entirely, for which there are 3 reasonable options, in roughly decreasing order of severity:
- Link statically when you cross-compile.
- Put the cross-toolchain's hard-float libraries somewhere on the device's filesystem where you cross-compiled programs can find them (possibly resorting to LD_LIBRARY_PATH) - obviously you can't simply replace the existing libraries or you'd get the inverse ABI mismatch for the rest of your installed programs.
- Copy the system libraries off the device onto your host machine, so you can point the cross-linker at them instead of its bundled libraries, and cross-compile with
--mfloat-abi=soft
.
I'd normally suggest option 3 as the general case, however hard-float does have somewhat of a performance benefit so for floating-point-intensive code, so it may well be worth the bit of effort to get it to work.
Note that whilst some hard-float (i.e. "arm-linux-gnueabihf-") cross-toolchains also include soft-float libraries via multilib, others (like the Linaro ones I use) either don't, or only enable them for specific combinations of options representing ancient targets, which you probably don't want. If you did have a suitable multilib toolchain, that's what @TurboJ's suggestion in the comments is about - using arm-linux-gnueabihf-gcc
as the link command (not arm-linux-gnueabihf-ld
) with --mfloat-abi=soft
specified would tell it to link against the soft-float versions of its libraries if it supports that.
来源:https://stackoverflow.com/questions/30133534/eigen-vectors-not-initialized-when-cross-compiled-for-arm