Modify

Ticket #11756 (reopened Patches)

Opened 16 months ago

Last modified 2 weeks ago

boost.Test: non standards compliant use of FE_* macros (unable to compile boost test library on FPU-less arches)

Reported by: bartosz.krasinski@… Owned by: renficiaud
Milestone: Boost 1.64.0 Component: test
Version: Boost 1.59.0 Severity: Problem
Keywords: Cc:

Description

In file included from ./boost/test/unit_test_monitor.hpp:18:0,

from ./boost/test/impl/unit_test_monitor.ipp:20, from libs/test/src/unit_test_monitor.cpp:16:

./boost/test/execution_monitor.hpp:492:27: error: 'FE_DIVBYZERO' was not declared in this scope ./boost/test/execution_monitor.hpp:493:27: error: 'FE_INEXACT' was not declared in this scope ./boost/test/execution_monitor.hpp:494:27: error: 'FE_INVALID' was not declared in this scope ./boost/test/execution_monitor.hpp:495:27: error: 'FE_OVERFLOW' was not declared in this scope ./boost/test/execution_monitor.hpp:496:27: error: 'FE_UNDERFLOW' was not declared in this scope ./boost/test/execution_monitor.hpp:498:27: error: 'FE_ALL_EXCEPT' was not declared in this scope

these constants are not defined in fenv.h version 1.58 was compiled successfully

bartek@homesrv:~/builds/boost_1_59_0$ mips-openwrt-linux-g++ -v Reading specs from /work/openwrt-sdk/staging_dir/toolchain-mips_r2_gcc-4.6-linaro_uClibc-0.9.33.2/bin/../lib/gcc/mips-openwrt-linux-uclibc/4.6.3/specs COLLECT_GCC=mips-openwrt-linux-g++ COLLECT_LTO_WRAPPER=/work/openwrt-sdk/staging_dir/toolchain-mips_r2_gcc-4.6-linaro_uClibc-0.9.33.2/bin/../libexec/gcc/mips-openwrt-linux-uclibc/4.6.3/lto-wrapper Target: mips-openwrt-linux-uclibc Configured with: /work/openwrt/build_dir/toolchain-mips_r2_gcc-4.6-linaro_uClibc-0.9.33.2/gcc-linaro-4.6-2012.02/configure --prefix=/work/openwrt/staging_dir/toolchain-mips_r2_gcc-4.6-linaro_uClibc-0.9.33.2 --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=mips-openwrt-linux-uclibc --with-gnu-ld --enable-target-optspace --disable-libgomp --disable-libmudflap --disable-multilib --disable-nls --with-host-libstdcxx=-lstdc++ --with-float=soft --with-gmp=/work/openwrt/staging_dir/host --with-mpfr=/work/openwrt/staging_dir/host --disable-decimal-float --with-mips-plt --with-mpc=/work/openwrt/staging_dir/host --disable-libssp --disable-cxa_atexit --with-headers=/work/openwrt/staging_dir/toolchain-mips_r2_gcc-4.6-linaro_uClibc-0.9.33.2/include --enable-languages=c,c++ --enable-shared --enable-threads --with-slibdir=/work/openwrt/staging_dir/toolchain-mips_r2_gcc-4.6-linaro_uClibc-0.9.33.2/lib --enable-lto --with-libelf=/work/openwrt/staging_dir/host --disable-tls Thread model: posix gcc version 4.6.3 20120201 (prerelease) (Linaro GCC 4.6-2012.02)

Attachments

0001-config-BOOST_NO_FENV_H.patch Download (3.6 KB) - added by André Draszik <git@…> 6 months ago.
gcc: #define BOOST_NO_FENV_H on FPU-less arches
0001-execution_monitor-fix-soft-float-issues.patch Download (4.3 KB) - added by André Draszik <git@…> 6 months ago.
fix FE_* usage in test (based on previous comment)
0001-execution_monitor-fix-soft-float-issues.2.patch Download (6.1 KB) - added by André Draszik <git@…> 6 months ago.
fix FE_* usage in test (updated again based on johnmaddock's tips)

Change History

comment:1 Changed 16 months ago by viboes

  • Owner set to rogeeff
  • Component changed from None to test

comment:2 Changed 15 months ago by joerg.krause@…

Same with Buildroot, e.g.  http://autobuild.buildroot.net/results/28d/28db2fc2d6bffeb7c842fbcce2eeaf89ae5f8b01/build-end.log.

The problem is, that some architectures, currently do not implement FE_DIVBYZERO, even though they have <fenv.h> and feenableexcept().

comment:3 Changed 14 months ago by renficiaud

I do not have access to those platforms. Do you know by chance if those "deficiencies" are described in the boost.config project?

http://www.boost.org/doc/libs/1_60_0/libs/config/doc/html/boost_config/boost_macro_reference.html#boost_config.boost_macro_reference.macros_that_describe_c__03_defects

especially the macro

BOOST_NO_FENV_H

comment:4 Changed 14 months ago by bartosz.krasinski@…

Hi

here is search result:

bartek@homesrv:~/builds/boost_1_59_0$ grep -rnw . -e "BOOST_NO_FENV_H" ./libs/config/test/all/Jamfile.v2:394:test-suite "BOOST_NO_FENV_H" : ./libs/config/test/config_info.cpp:1073: PRINT_MACRO(BOOST_NO_FENV_H); ./libs/config/test/boost_no_fenv_h.ipp:9:// MACRO: BOOST_NO_FENV_H ./libs/config/test/no_fenv_h_pass.cpp:9:// Test file for macro BOOST_NO_FENV_H ./libs/config/test/no_fenv_h_pass.cpp:11:// BOOST_NO_FENV_H should be defined. ./libs/config/test/no_fenv_h_pass.cpp:23:#ifndef BOOST_NO_FENV_H ./libs/config/test/config_test.cpp:380:#ifndef BOOST_NO_FENV_H ./libs/config/test/config_test.cpp:1611: std::cerr << "Failed test for BOOST_NO_FENV_H at: " << FILE << ":" << LINE << std::endl; ./libs/config/test/no_fenv_h_fail.cpp:9:// Test file for macro BOOST_NO_FENV_H ./libs/config/test/no_fenv_h_fail.cpp:11:// BOOST_NO_FENV_H should not be defined. ./libs/config/test/no_fenv_h_fail.cpp:23:#ifdef BOOST_NO_FENV_H ./libs/config/doc/html/boost_config/boost_macro_reference.html:293: <code class="computeroutput"><span class="identifier">BOOST_NO_FENV_H</span></code> ./libs/config/doc/macro_reference.qbk:74:[[`BOOST_NO_FENV_H`][Platform, Standard library][

./boost/math/tools/config.hpp:339:#if ((defined(linux) && !defined(UCLIBC) && !defined(BOOST_MATH_HAVE_FIXED_GLIBC))
defined(QNX) defined(IBMCPP)) && !defined(BOOST_NO_FENV_H)

./boost/test/execution_monitor.hpp:63:#if !defined(BOOST_NO_FENV_H)

./boost/test/execution_monitor.hpp:489:#elif defined(BOOST_NO_FENV_H)
defined(BOOST_CLANG)

./boost/test/impl/execution_monitor.ipp:1382:#elif defined(GLIBC) && defined(USE_GNU) && !defined(BOOST_CLANG) && !defined(BOOST_NO_FENV_H) ./boost/test/impl/execution_monitor.ipp:1419:#elif defined(GLIBC) && defined(USE_GNU) && !defined(BOOST_CLANG) && !defined(BOOST_NO_FENV_H) ./boost/detail/fenv.hpp:10:#if defined(BOOST_NO_FENV_H) ./boost/config/platform/cygwin.hpp:43:#define BOOST_NO_FENV_H ./boost/config/compiler/intel.hpp:497:# define BOOST_NO_FENV_H ./boost/config/compiler/visualc.hpp:47:# define BOOST_NO_FENV_H

when i added mentioned macro: BOOST_NO_FENV_H to the boost/config/user.hpp header then i successfully built following libraries (in comparision to the previous build - without this macro):

libbost_unit_test_framework.a libbost_test_exec_monitor.a libbost_prge_xec_monitor.a

of course for openwrt-linux-mips platform

thanks for clue

comment:5 Changed 14 months ago by renficiaud

Thank you for your feedback,

Boost.Test relies on Boost.Config for the proper configuration of the BOOST_NO_FENV_H macro. From your message, it looks like this macro is not properly defined for your platform openwrt-linux-mips, and if you define it manually, Boost.Test properly compiles.

Have I understood properly?

comment:6 Changed 14 months ago by bartosz.krasinski@…

Yes, exactly

It is because, i guess, first of all i build bootstrap in x86_64.

./bootstrap.sh

next i build boost for x86_64 and x86 platforms (debian)

./b2 link=static variant=release --prefix=/work/libextern/boost-x86 address-model=32 cxxflags=-fPIC install

once again, thanks bartek

./b2 link=static variant=release --prefix=/work/libextern/boost-x64 address-model=64 cxxflags=-fPIC install

finally i create boost.config.jam file, in which i place:

using gcc : mips : "mips-openwrt-linux-g++" ;

and i build boost for mips:

./b2 toolset=gcc-mips link=static variant=release --prefix=/work/libextern/boost-mips cxxflags=-fPIC --user-config=user.config.jam install

maybe I missed something that boost build system did not recognized correctly mips platform but now i will add manually mentioned macro and it is enough for me.

comment:7 Changed 14 months ago by renficiaud

I will transfer the issue to Boost.Config then. Thanks

comment:8 Changed 14 months ago by renficiaud

  • Owner changed from rogeeff to johnmaddock
  • Component changed from test to config

comment:9 Changed 14 months ago by joerg.krause@…

Boost detects a fenv.h system header and assumes it defines FE_DIVBYZERO and friends. The involved toolchains does have this system header, but they do not define these macros, e.g. the mipsel toolchain from Buildroot (fenv.h includes tr1/cfenv):

/** @file tr1/cfenv
 *  This is a TR1 C++ Library header. 
 */

#ifndef _GLIBCXX_TR1_CFENV
#define _GLIBCXX_TR1_CFENV 1

#pragma GCC system_header

#include <bits/c++config.h>

#if _GLIBCXX_HAVE_FENV_H
# include <fenv.h>
#endif

#ifdef _GLIBCXX_USE_C99_FENV_TR1

#undef feclearexcept
#undef fegetexceptflag
#undef feraiseexcept
#undef fesetexceptflag
#undef fetestexcept
#undef fegetround
#undef fesetround
#undef fegetenv
#undef feholdexcept
#undef fesetenv
#undef feupdateenv

namespace std _GLIBCXX_VISIBILITY(default)
{
namespace tr1
{
  // types
  using ::fenv_t;
  using ::fexcept_t;

  // functions
  using ::feclearexcept;
  using ::fegetexceptflag;
  using ::feraiseexcept;
  using ::fesetexceptflag;
  using ::fetestexcept;

  using ::fegetround;
  using ::fesetround;

  using ::fegetenv;
  using ::feholdexcept;
  using ::fesetenv;
  using ::feupdateenv;
}
}

#endif // _GLIBCXX_USE_C99_FENV_TR1

#endif // _GLIBCXX_TR1_CFENV

Changed 6 months ago by André Draszik <git@…>

gcc: #define BOOST_NO_FENV_H on FPU-less arches

comment:10 Changed 6 months ago by André Draszik <git@…>

  • Summary changed from Unable to compile boost test library on openwrt - mips to boost.Config doesn't detect FPU-less arches (Unable to compile boost test library on FPU-less arches)

comment:11 Changed 6 months ago by André Draszik <git@…>

  • Type changed from Support Requests to Patches

comment:12 Changed 6 months ago by johnmaddock

  • Owner changed from johnmaddock to rogeeff
  • Component changed from config to test

Sorry to ping this back to Boost.Test, but I believe this is a misunderstanding of how fenv.h works. The key point is:

A fully standards conforming fenv.h does not have to define any FE_* macros, and if it does define them, then it defines macros only for the FP exceptions it actually supports.

So correct usage requires a triple check:

1) Check BOOST_NO_FENV_H to see if the header is supported.

2) Include the header and then check FE_ALL_EXCEPT to see if any FP exceptions are supported.

3) Before using the individual FE_* macros, you need to check for their existence too as not all may be supported.

And finally.... the standard also permits other FE_* macros if there are exceptions supported other than the standard set. There's no standard way to tell what these might be, but their presence can be inferred by checking FE_ALL_EXCEPT against the bitwise or of the other FE_* macros.

Changed 6 months ago by André Draszik <git@…>

fix FE_* usage in test (based on previous comment)

comment:13 Changed 6 months ago by André Draszik <git@…>

  • Summary changed from boost.Config doesn't detect FPU-less arches (Unable to compile boost test library on FPU-less arches) to boost.Test: non standards compliant use of FE_* macros (unable to compile boost test library on FPU-less arches)

comment:14 Changed 6 months ago by johnmaddock

That doesn't quite get it: if fenv.h is available, but FE_DIVBYZERO is unset then BOOST_FPE_DIVBYZERO is also left unset (for example), where as it should be set to a stub value I guess (1 or 0).... except a quick grep of the source suggests these are unused anyway? Which just leaves BOOST_FPE_ALL which definitely needs to be in #if...#else block, so I suggest something more like:

#ifdef FE_DIVBYZERO
    BOOST_FPE_DIVBYZERO = FE_DIVBYZERO,
#else
    BOOST_FPE_DIVBYZERO = 0,
#endif
#ifdef FE_INEXACT
    BOOST_FPE_INEXACT   = FE_INEXACT,
#else
    BOOST_FPE_INEXACT   = 0,
#endif
#ifdef FE_INVALID
    BOOST_FPE_INVALID   = FE_INVALID,
#else
    BOOST_FPE_INVALID   = 0,
#endif
#ifdef FE_OVERFLOW
    BOOST_FPE_OVERFLOW  = FE_OVERFLOW,
#else
    BOOST_FPE_OVERFLOW  = 0,
#endif
#ifdef FE_UNDERFLOW
    BOOST_FPE_UNDERFLOW = FE_UNDERFLOW,
#else
    BOOST_FPE_UNDERFLOW = 0,
#endif
#ifdef FE_ALL_EXCEPT
    BOOST_FPE_ALL       = FE_ALL_EXCEPT,
#else
    BOOST_FPE_ALL       = 1,
#endif

comment:15 Changed 6 months ago by André Draszik <git@…>

Based on your previous comment:

Include the header and then check FE_ALL_EXCEPT to see if any FP exceptions are supported

I understood that if fenv.h is available, then FE_ALL_EXCEPT can have *any* value. In my case, it is defined, but it's defined to 0, since no exceptions are supported. Hence I had a check for this. This is now gone, and with this version BOOST_FPE_ALL would be == 0, too.

Hence I think it should be checking

#ifdef FE_ALL_EXCEPT && (FE_ALL_EXCEPT != 0)

BOOST_FPE_ALL = FE_ALL_EXCEPT,

#else

BOOST_FPE_ALL = 1,

#endif

instead ?

comment:16 Changed 6 months ago by André Draszik <git@…>

On the other hand, does it really make sense to set BOOST_FPE_ALL to 1 if exceptions are not supported in the implementation? Wouldn't this be better?

#ifdef FE_ALL_EXCEPT
    BOOST_FPE_ALL       = FE_ALL_EXCEPT,
#else
    BOOST_FPE_ALL       = 0,
#endif

comment:17 Changed 6 months ago by johnmaddock

Yes it does make more sense for BOOST_FPE_ALL to be 0 in that case - I just followed existing practice for the case where there is no fenv.h as I wasn't sure what effect a zero value might have in the code's assumptions. I think the library authors will have to figure that one out.

Changed 6 months ago by André Draszik <git@…>

fix FE_* usage in test (updated again based on johnmaddock's tips)

comment:18 Changed 6 months ago by André Draszik <git@…>

Thanks!

I've had another look and I think this is a good version now. This works well for me on my target device as well as on my host machine.

comment:19 Changed 5 months ago by renficiaud

  • Owner changed from rogeeff to renficiaud
  • Milestone changed from To Be Determined to Boost 1.63.0

comment:20 Changed 4 months ago by renficiaud

I am looking at this right now, and it is running fine on branch origin/topic/11756-floatingpoint-exception-macros. However, I am just thinking:

  • In case fenv.h is not found, does it mean that floating point exception is just not supported?
  • Does this mean the same as FE_ALL_EXCEPT not defined?

I am just thinking of making this distinction together with the use of BOOST_FPE_OFF.

I also would like to have a better coverage of this. On your platform, what happens when you divide by 0 with and without your patch applied?

Thanks,

comment:21 Changed 4 months ago by André Draszik <git@…>

Thanks. I can't really answer your questions regarding missing fenv.h / FE_ALL_EXCEPT and BOOST_FPE_OFF. A standards compliant env should provide both, but of course FE_ALL_EXCEPT may be 0.

 http://pubs.opengroup.org/onlinepubs/009695399/basedefs/fenv.h.html  http://en.cppreference.com/w/cpp/numeric/fenv/FE_exceptions

I am not an expert on boost so I need some more information on what you want me to test please. Without my patch it doesn't compile on my platform.

comment:22 Changed 4 months ago by renficiaud

In develop, merged at rev cbbacca13083eaacd9c2d197524540ff9e37bade

comment:23 Changed 4 months ago by renficiaud

  • Status changed from new to assigned

comment:24 Changed 4 months ago by renficiaud

Merged to master (rev cd74a43a784bff0d9c4768fa26f5f1f2b1359014)

comment:25 Changed 2 months ago by renficiaud

  • Status changed from assigned to closed
  • Resolution set to fixed

comment:26 Changed 7 weeks ago by smetz

Hi, this modification generates a buid error for Intel compilers (version 11.0 in my case).

Indeed, for Intel compilers BOOST_NO_FENV_H is set as true, and compiler will not find fe* functions in execution_monitor.ipp lines 1382 and 1422.

comment:27 Changed 7 weeks ago by renficiaud

  • Status changed from closed to reopened
  • Resolution fixed deleted

comment:28 follow-up: ↓ 30 Changed 7 weeks ago by renficiaud

Hi smetz,

Is this visible now on the regression board? I have no access to neither the Intel nor the "FPU-less" machines.

comment:29 Changed 7 weeks ago by smetz

It doesn't appear in the regression board for the moment. This regression appeared in the boost 1.63 version.

comment:30 in reply to: ↑ 28 Changed 7 weeks ago by anonymous

Maybe you just have to come back on some modifications:

in boost/test/impl/execution_monitor.ipp lines 1378 and 1418, change:

#elif defined(__GLIBC__) && defined(__USE_GNU)

by

#elif defined(__GLIBC__) && defined(__USE_GNU) && !defined(BOOST_CLANG) && !defined(BOOST_NO_FENV_H)

This works on my side with the Intel compiler. But I'm not sure that this will not introduce a new regression for the CLang compiler, I don't know if CLang support floatingpoint exceptions.

comment:31 Changed 3 weeks ago by renficiaud

Hi there,

It would be handy if you can give a try to branch topic/11756-non-standards-fpexception-intel. Thanks!

comment:32 Changed 3 weeks ago by renficiaud

  • Milestone changed from Boost 1.63.0 to Boost 1.64.0

comment:33 Changed 3 weeks ago by renficiaud

Ping?

comment:34 Changed 2 weeks ago by André Draszik <git@…>

The suggested fix in topic/11756-non-standards-fpexception-intel breaks non-glibc builds (musl-libc in my case):

gcc.compile.c++ [...]/mipsel-poky-linux-musl/boost/bin.v2/libs/test/build/gcc-4.3.1/release/threading-multi/execution_monitor.o
    "mipsel-poky-linux-musl-g++" "-mel" "-mabi=32" "-msoft-float" "-march=mips32r2" "-mips16" "-minterlink-compressed" "-mtune=24kec" "-mdsp" "-Wl,-O1" "-Wl,--as-needed" "-fstack-protector-strong" "-Wl,-z,relro,-z,now" "--sysroot=[...sysroot...]"  -ftemplate-depth-128 -O2 -pipe -g -feliminate-unused-debug-types -fstack-protector-strong -pie -fpie -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -Werror=format-security -fvisibility-inlines-hidden -O3 -finline-functions -Wno-inline -Wall -pedantic -pthread -fPIC -Wno-variadic-macros -DBOOST_ALL_NO_LIB=1 -DBOOST_CHRONO_DYN_LINK=1 -DBOOST_SYSTEM_DYN_LINK=1 -DBOOST_SYSTEM_NO_DEPRECATED -DBOOST_TEST_DYN_LINK=1 -DBOOST_TIMER_DYN_LINK=1 -DNDEBUG  -I"." -c -o "[...]/mipsel-poky-linux-musl/boost/bin.v2/libs/test/build/gcc-4.3.1/release/threading-multi/execution_monitor.o" "libs/test/src/execution_monitor.cpp"
In file included from libs/test/src/execution_monitor.cpp:16:0:
./boost/test/impl/execution_monitor.ipp: In function 'unsigned int boost::fpe::enable(unsigned int)':
./boost/test/impl/execution_monitor.ipp:1387:36: error: 'feenableexcept' was not declared in this scope
./boost/test/impl/execution_monitor.ipp: In function 'unsigned int boost::fpe::disable(unsigned int)':
./boost/test/impl/execution_monitor.ipp:1428:37: error: 'fedisableexcept' was not declared in this scope

Those two #ifdefs can not be made the same as as in execution_monitor.hpp, as the header file only does standard posix stuff, wheres the implementation uses the non-POSIX, non-standard-C APIs feenableexcept() and fedisableexcept(), which are only available when using glibc.

IOW, the test for __GLIBC__ and __USE_GNU must remain, and I think the two tests should go back to the original version:

-#elif defined(__GLIBC__) && defined(__USE_GNU)
+#elif defined(__GLIBC__) && defined(__USE_GNU) && !(defined(BOOST_NO_FENV_H) || defined(BOOST_CLANG))

sorry for that.

comment:35 Changed 2 weeks ago by renficiaud

Thanks for the quick feedback. Ok for the report, but to me the good solution is to be coherent with whatever is done to define the enum:

namespace fpe {

enum masks {
    BOOST_FPE_OFF       = 0,

#ifdef BOOST_SEH_BASED_SIGNAL_HANDLING /* *** */
    BOOST_FPE_DIVBYZERO = EM_ZERODIVIDE,
    BOOST_FPE_INEXACT   = EM_INEXACT,
    BOOST_FPE_INVALID   = EM_INVALID,
    BOOST_FPE_OVERFLOW  = EM_OVERFLOW,
    BOOST_FPE_UNDERFLOW = EM_UNDERFLOW|EM_DENORMAL,

    BOOST_FPE_ALL       = MCW_EM,

#elif defined(BOOST_NO_FENV_H) || defined(BOOST_CLANG) /* *** */
    BOOST_FPE_ALL       = BOOST_FPE_OFF,

#else /* *** */

// ...

So maybe a proper macro that says if there is nothing available and gathering the scenario where any of the BOOST_NO_FENV_H, BOOST_CLANG, __USE_GNU etc is defined (or not).

What do you think?

comment:36 Changed 2 weeks ago by André Draszik <git@…>

Hm, not sure. On one hand I agree being coherent would be nice, but on the other hand it already isn't (and probably can't be) when you also take Windows & Visual Studio into account in the implementation. It would seem that there are always going to be different implementations based on the compilation environment (Windows CE / MSVC / Posix / Non-Posix Unices / gcc / clang / fenv / no-fenv).

Maybe I'm wrong. It does appear that the whole floating point support is a bit of a mess and hard to get right in a portable way, though.

Happy to test a patch :-)

View

Add a comment

Modify Ticket

Change Properties
<Author field>
Action
as reopened
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.