Opened 7 years ago

Closed 6 years ago

#11756 closed Patches (fixed)

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: Raffi Enficiaud
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 (3)

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

Download all attachments as: .zip

Change History (67)

comment:1 by viboes, 7 years ago

Component: Nonetest
Owner: set to Gennadiy Rozental

comment:2 by joerg.krause@…, 7 years ago

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 by Raffi Enficiaud, 7 years ago

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 by bartosz.krasinski@…, 7 years ago

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 by Raffi Enficiaud, 7 years ago

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 by bartosz.krasinski@…, 7 years ago

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 by Raffi Enficiaud, 7 years ago

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

comment:8 by Raffi Enficiaud, 7 years ago

Component: testconfig
Owner: changed from Gennadiy Rozental to John Maddock

comment:9 by joerg.krause@…, 7 years ago

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

by André Draszik <git@…>, 6 years ago

gcc: #define BOOST_NO_FENV_H on FPU-less arches

comment:10 by André Draszik <git@…>, 6 years ago

Summary: Unable to compile boost test library on openwrt - mipsboost.Config doesn't detect FPU-less arches (Unable to compile boost test library on FPU-less arches)

comment:11 by André Draszik <git@…>, 6 years ago

Type: Support RequestsPatches

comment:12 by John Maddock, 6 years ago

Component: configtest
Owner: changed from John Maddock to Gennadiy Rozental

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.

by André Draszik <git@…>, 6 years ago

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

comment:13 by André Draszik <git@…>, 6 years ago

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

comment:14 by John Maddock, 6 years ago

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 by André Draszik <git@…>, 6 years ago

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 by André Draszik <git@…>, 6 years ago

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 by John Maddock, 6 years ago

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.

by André Draszik <git@…>, 6 years ago

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

comment:18 by André Draszik <git@…>, 6 years ago

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 by Raffi Enficiaud, 6 years ago

Milestone: To Be DeterminedBoost 1.63.0
Owner: changed from Gennadiy Rozental to Raffi Enficiaud

comment:20 by Raffi Enficiaud, 6 years ago

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 by André Draszik <git@…>, 6 years ago

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 by Raffi Enficiaud, 6 years ago

In develop, merged at rev cbbacca13083eaacd9c2d197524540ff9e37bade

comment:23 by Raffi Enficiaud, 6 years ago

Status: newassigned

comment:24 by Raffi Enficiaud, 6 years ago

Merged to master (rev cd74a43a784bff0d9c4768fa26f5f1f2b1359014)

comment:25 by Raffi Enficiaud, 6 years ago

Resolution: fixed
Status: assignedclosed

comment:26 by smetz, 6 years ago

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 by Raffi Enficiaud, 6 years ago

Resolution: fixed
Status: closedreopened

comment:28 by Raffi Enficiaud, 6 years ago

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 by smetz, 6 years ago

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

in reply to:  28 comment:30 by anonymous, 6 years ago

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 by Raffi Enficiaud, 6 years ago

Hi there,

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

comment:32 by Raffi Enficiaud, 6 years ago

Milestone: Boost 1.63.0Boost 1.64.0

comment:33 by Raffi Enficiaud, 6 years ago

Ping?

comment:34 by André Draszik <git@…>, 6 years ago

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 by Raffi Enficiaud, 6 years ago

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 by André Draszik <git@…>, 6 years ago

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 :-)

comment:37 by Raffi Enficiaud, 6 years ago

Hi there again,

I moved the FPE logic in the macro BOOST_TEST_FPE_SUPPORT_WITHOUT_SEH__ . It would be cool if you can test the branch again.

The way I see this is that there is only 3 options in the code that should be handled:

  • no fpe
  • seh based fpe
  • implementation based on fenv (and in that case, not all platforms support all signals)

All in all, I think that moving this switch to 2 configuration macros make the code easier to understand and to maintain.

Let me know the result of your tests. 1.64 will be closing soon, it would be good to have your feedback asap :)

Thanks, Raffi

comment:38 by Raffi Enficiaud, 6 years ago

Kind ping :)

comment:39 by André Draszik <git@…>, 6 years ago

This still doesn't work (same as in comment 34):

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:1384:36: error: 'feenableexcept' was not declared in this scope
     int res = feenableexcept( mask );
                                    ^
./boost/test/impl/execution_monitor.ipp: In function 'unsigned int boost::fpe::disable(unsigned int)':
./boost/test/impl/execution_monitor.ipp:1419:37: error: 'fedisableexcept' was not declared in this scope
     int res = fedisableexcept( mask );

This still goes into the wrong branch when not using glibc - we use the musl C library and gcc, so GLIBC is *not* defined (and therefore the non-posix, non-standard GNU APIs feenableexcept() and fedisableexcept() are not available), but at the same BOOST_NO_FENV_H and BOOST_CLANG are not defined, either. Hence the test in execution_monitor.hpp doesn't work:

  #if !defined(BOOST_NO_FENV_H) && !defined(BOOST_CLANG) || \
      (defined(__GLIBC__) && defined(__USE_GNU))

in reply to:  37 comment:40 by André Draszik <git@…>, 6 years ago

Replying to comment 37:

The way I see this is that there is only 3 options in the code that should be handled:

  • no fpe
  • seh based fpe
  • implementation based on fenv (and in that case, not all platforms support all signals)

Basically, there should be 3 options for defining the interface in .hpp, but 4 options based on the compilation environment for the .ipp:

  1. no fpe
  2. seh based fpe
  3. implementation based on fenv (and in that case, not all platforms support all signals)
    1. using standard C/C++ APIs
    2. using non-standard glibc extensions (feenableexcept() etc.)

Which is what I meant in comment 34

comment:41 by Raffi Enficiaud, 6 years ago

Ok, now I think I understood the problem:

  • the feenableexcept/fedisableexcept are not standard, those are GLIBC extensions
  • having fenv does not ensure that those 2 functions are in there, for having those function, we should be ensured that we are indeed compiling with GLIBC
  • however, for anything outside this and SEH based extensions, there is no easy way to mask floating point exceptions

So, I suggest the following:

  • The macro indicating that the floating point exception settings is supported becomes BOOST_TEST_FPE_SUPPORT_WITH_GLIBC_EXTENSIONS__ and is defined like this:
#if defined(BOOST_SEH_BASED_SIGNAL_HANDLING) && !defined(UNDER_CE)
  //! Indicates tha the floating point exception handling is supported
  //! through SEH
  #define BOOST_TEST_FPE_SUPPORT_WITH_SEH__
#elif !defined(BOOST_SEH_BASED_SIGNAL_HANDLING) && !defined(UNDER_CE)
  #if !defined(BOOST_NO_FENV_H) && !defined(BOOST_CLANG) && \
      (defined(__GLIBC__) && defined(__USE_GNU))
  //! Indicates that floating point exception handling is supported for the
  //! non SEH version of it, for the GLIBC extensions only
  #define BOOST_TEST_FPE_SUPPORT_WITH_GLIBC_EXTENSIONS__
  #endif
#endif

  • the branch taking the feenableexcept/fedisableexcept is guarded by this macro
  • the branch taking the SEH extension is not affected
  • all the rest is falls back to the "unsupported" branch (returning BOOST_FPE_OFF/BOOST_FPE_INV). In particular, I do not see how to support 3.a from your comment.

Does this sound correct?

comment:42 by André Draszik <git@…>, 6 years ago

Yes, looks right.

As for 3.a from my comment, I don't think there's an easy way to support it either. Googling a little bit it probably is possible, but that's out of scope for this issue here.

comment:43 by Raffi Enficiaud, 6 years ago

Good, can you then please test again the branch topic/11756-non-standards-fpexception-intel?

Many thanks!

comment:44 by André Draszik <git@…>, 6 years ago

That seems to work, at least it compiles in all cases I care about :-)

Thanks!

comment:45 by Jörg Krause, 6 years ago

We recently bumped the boost version from 1.61.0 to 1.63.0 in Buildroot. Now, we get build errors for two architectures which were compiling successfully before: SH4 and OR1K. Both use a uclibc-toolchain.

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:1382:32: error: 'feclearexcept' was not declared in this scope
     feclearexcept(BOOST_FPE_ALL);
                                ^
./boost/test/impl/execution_monitor.ipp:1383:36: error: 'feenableexcept' was not declared in this scope
     int res = feenableexcept( mask );
                                    ^
./boost/test/impl/execution_monitor.ipp: In function 'unsigned int boost::fpe::disable(unsigned int)':
./boost/test/impl/execution_monitor.ipp:1422:32: error: 'feclearexcept' was not declared in this scope
     feclearexcept(BOOST_FPE_ALL);
                                ^
./boost/test/impl/execution_monitor.ipp:1423:37: error: 'fedisableexcept' was not declared in this scope
     int res = fedisableexcept( mask );

I've checked out the branch topic/11756-non-standards-fpexception-intel of the test module, it does not build either.

At least, the SH4 toolchain does not have fenv.h. I did not checked to OR1K toolchain, yet.

Here are some macros I've checked using the branch 11756:

  • BOOST_NO_FENV_H is defined
  • BOOST_SEH_BASED_SIGNAL_HANDLING is not defined
  • BOOST_TEST_FPE_SUPPORT_WITH_GLIBC_EXTENSIONS__ is defined

comment:46 by Raffi Enficiaud, 6 years ago

Hi Jörg,

Thanks for looking at this as well! The macro definitions you report are weird:

  #if !defined(BOOST_NO_FENV_H) && !defined(BOOST_CLANG) && \
      (defined(__GLIBC__) && defined(__USE_GNU))
  //! Indicates that floating point exception handling is supported for the
  //! non SEH version of it, for the GLIBC extensions only
  #define BOOST_TEST_FPE_SUPPORT_WITH_GLIBC_EXTENSIONS__
  #endif

this means that if BOOST_NO_FENV_H is defined, then BOOST_TEST_FPE_SUPPORT_WITH_GLIBC_EXTENSIONS__ cannot be defined. Are you on revision 6f0d88ca9db00b449a795afa3218b815fe8c01b0 ? (I forced pushed like 1 hour ago)

comment:47 by Jörg Krause <joerg.krause@…>, 6 years ago

No, I am on revision c0fb4b1c21865d2096fbee2f3c77026f5a743180.

Sorry, the macro definitions I posted are wrong. This is the correct ones:

  • BOOST_NO_FENV_H is not defined
  • BOOST_TEST_FPE_SUPPORT_WITH_GLIBC_EXTENSIONS__ is defined

Note, this is the content of output/host/opt/ext-toolchain/sh4-buildroot-linux-uclibc/include/c++/5.4.0/fenv.h:

#ifndef _GLIBCXX_FENV_H
#define _GLIBCXX_FENV_H 1

#pragma GCC system_header

#include <bits/c++config.h>
#if _GLIBCXX_HAVE_FENV_H
# include_next <fenv.h>
#endif

#if __cplusplus >= 201103L

#if _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
{
  // 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;
} // namespace

#endif // _GLIBCXX_USE_C99_FENV_TR1

#endif // C++11

#endif // _GLIBCXX_FENV_H

comment:48 by Raffi Enficiaud, 6 years ago

Hi,

Thanks for the update. You said in comment 45 that SH4 does not have fenv. Does that still hold true? If yes, then BOOST_NO_FENV_H should be defined.

I would kindly ask to test the following 2 revisions:

  • 02f9a561bc8003cb38fcc5b0863482459a38ea4f (18 October 2016)
  • eec86d1fbe68aea190ce05a080d20e1569fb82a9 (24 August 2016)

It looks to me that BOOST_NO_FENV_H is not properly set.

Also, what are the status of the following two defines, for those two architectures:

  • __GLIBC__
  • __USE_GNU

Thanks!

comment:49 by Jörg Krause <joerg.krause@…>, 6 years ago

Sorry about by confusion about fenv.h. The toolchain tarball include the C++ Library header file fenv.h in sh4-buildroot-linux-uclibc/include/c++/5.4.0/, but it does not have a fenv.h in sysroot. I guess the later is generated somehow, right? (I've compared with another arm musl-toolchain which does have fenv.h in sysroot).


I've compiled the following example with the SH4 C++ compiler:

#include <iostream>
#include <cfenv>
#include <cmath>
 
#pragma STDC FENV_ACCESS ON
 
volatile double zero = 0.0; // volatile not needed where FENV_ACCESS is supported
volatile double one = 1.0;  // volatile not needed where FENV_ACCESS is supported
 
int main()
{
    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout <<  "1.0/0.0 = " << 1.0 / zero << '\n';
    if(std::fetestexcept(FE_DIVBYZERO)) {
        std::cout << "division by zero reported\n";
    } else {
        std::cout << "divsion by zero not reported\n";
    }
 
    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "1.0/10 = " << one/10 << '\n';
    if(std::fetestexcept(FE_INEXACT)) {
        std::cout << "inexact result reported\n";
    } else {
        std::cout << "inexact result not reported\n";
    }
 
    std::feclearexcept(FE_ALL_EXCEPT);
    std::cout << "sqrt(-1) = " << std::sqrt(-1) << '\n';
    if(std::fetestexcept(FE_INVALID)) {
        std::cout << "invalid result reported\n";
    } else {
        std::cout << "invalid result not reported\n";
    }
}

Invoking the cross-compiler:

buildroot ) output/host/usr/bin/sh4-linux-g++ -std=c++11 main.cc
main.cc: In function ‘int main()’:
main.cc:12:5: error: ‘feclearexcept’ is not a member of ‘std’
     std::feclearexcept(FE_ALL_EXCEPT);
     ^
main.cc:12:24: error: ‘FE_ALL_EXCEPT’ was not declared in this scope
     std::feclearexcept(FE_ALL_EXCEPT);
                        ^
main.cc:14:8: error: ‘fetestexcept’ is not a member of ‘std’
     if(std::fetestexcept(FE_DIVBYZERO)) {
        ^
main.cc:14:26: error: ‘FE_DIVBYZERO’ was not declared in this scope
     if(std::fetestexcept(FE_DIVBYZERO)) {
                          ^
main.cc:20:5: error: ‘feclearexcept’ is not a member of ‘std’
     std::feclearexcept(FE_ALL_EXCEPT);
     ^
main.cc:22:8: error: ‘fetestexcept’ is not a member of ‘std’
     if(std::fetestexcept(FE_INEXACT)) {
        ^
main.cc:22:26: error: ‘FE_INEXACT’ was not declared in this scope
     if(std::fetestexcept(FE_INEXACT)) {
                          ^
main.cc:28:5: error: ‘feclearexcept’ is not a member of ‘std’
     std::feclearexcept(FE_ALL_EXCEPT);
     ^
main.cc:30:8: error: ‘fetestexcept’ is not a member of ‘std’
     if(std::fetestexcept(FE_INVALID)) {
        ^
main.cc:30:26: error: ‘FE_INVALID’ was not declared in this scope
     if(std::fetestexcept(FE_INVALID)) {


Commit 02f9a561bc8003cb38fcc5b0863482459a38ea4f (18 October 2016) produces the following error:

from libs/test/src/execution_monitor.cpp:16:
./boost/test/execution_monitor.hpp:503:27: error: ‘FE_DIVBYZERO’ was not declared in this scope
     BOOST_FPE_DIVBYZERO = FE_DIVBYZERO,
                           ^
./boost/test/execution_monitor.hpp:504:27: error: ‘FE_INEXACT’ was not declared in this scope
     BOOST_FPE_INEXACT   = FE_INEXACT,
                           ^
./boost/test/execution_monitor.hpp:505:27: error: ‘FE_INVALID’ was not declared in this scope
     BOOST_FPE_INVALID   = FE_INVALID,
                           ^
./boost/test/execution_monitor.hpp:506:27: error: ‘FE_OVERFLOW’ was not declared in this scope
     BOOST_FPE_OVERFLOW  = FE_OVERFLOW,
                           ^
./boost/test/execution_monitor.hpp:507:27: error: ‘FE_UNDERFLOW’ was not declared in this scope
     BOOST_FPE_UNDERFLOW = FE_UNDERFLOW,
                           ^
./boost/test/execution_monitor.hpp:509:27: error: ‘FE_ALL_EXCEPT’ was not declared in this scope
     BOOST_FPE_ALL       = FE_ALL_EXCEPT,


Whereas commit eec86d1fbe68aea190ce05a080d20e1569fb82a9 (24 August 2016) produces the same error as reported in comment 45.


For SH4:

  • __GLIBC__ is defined
  • __USE_GNU is defined

comment:50 by Raffi Enficiaud, 6 years ago

Thanks for the quick reply.

Something troubles me a bit: you said earlier that things were working fine with boost 1.61. Since then, all the changes to the FPE were the following:

  • the macros FE_DIVBYZERO ... are not something that are necessarily defined, this is why their use has been protected if ifdefs and you are having the compilation error on 02f9a561bc8003cb38fcc5b0863482459a38ea4f
  • feenableexcept/fedisableexcept are GNU extensions, this is why the latest status on this is to check for the macros __GLIBC__ and __USE_GNU and restrict the code to that case.

So I have 2 hypothesis in mind:

  • you are not compiling the code with the same options as you did before: the rationale behind is that C++11 is now defining <cfenv> which automatically would avoid the definition of BOOST_NO_FENV_H, while it was defined before
  • for the cross compilation, more restrictions should be applied on how to check for the existence of feenableexcept/fedisableexcept (which means additional/other macros than __GLIBC__ and __USE_GNU), but in that case I do not understand why it would have been working with boost 1.61

So ... would you check again with boost 1.61? Sorry to ask you that, but I am really lost there :-)

To nail down further the cause of those issues, it would be even better if you could (still based on the assumption that it was working with boost 1.61):

  • check with the entire boost 1.61
  • check with the latest boost develop but with boost.test 1.61

Thanks!

comment:51 by Raffi Enficiaud, 6 years ago

We can also iterate further:

  • you may tell me how to set up this environment from eg. Ubuntu or a docker image
  • you may also tell me the values of those macros: BOOST_LIB_C_GNU as well as BOOST_GCC

Thanks again, Raffi

comment:52 by Jörg Krause <joerg.krause@…>, 6 years ago

I figured something out!

It is working for version 1.61.0 (and 1.62.0) for this toolchain because Buildroot is patching config/platform/linux.hpp:

+// uClibc has no support for fenv.h, and also a few architectures
+// don't have fenv.h support at all (or incomplete support) even with
+// glibc.
+
+//
+#if defined(__UCLIBC__) || defined(__nios2__) || defined(__microblaze__)
+#  define BOOST_NO_FENV_H
+#endif

Now let me explain my confusion about BOOST_NO_FENV_H:

When I wrote BOOST_NO_FENV_H is defined it was because of I was building a patched "in-tree" boost. When I wrote BOOST_NO_FENV_H is not defined it was because of I was building an unpatched "out-of-tree" version of boost. Note, Buildroot applies patches to in-tree packages, but does not apply the patches to out-of-tree packages. In this case, I was using the git clone for an out-of-tree build. Therefore, the git clone does not had the patch applied, and BOOST_NO_FENV_H was not set by the patch. May bad, sorry!

In short, for an unpatched boost BOOST_NO_FENV_H is not defined for that toolchain.


Nevertheless, I did a git bisect (with the patch applied) for the test submodule: bisect says that eec86d1fbe68aea190ce05a080d20e1569fb82a9 (trac 11756: fix usage of floating point exception macros) is the bad commit. That means: when BOOST_NO_FENV_H is set because of the patch, boost compiles before this commit, but not after.

comment:53 by Raffi Enficiaud, 6 years ago

Thanks again for the quick feedback. So the problem does not seem to be totally related to boost.test :)

I believe that the last version of the branch topic/11756-non-standards-fpexception-intel should work fine with BOOST_NO_FENV_H. I kindly ask you to checkout this version (6f0d88ca9db00b449a795afa3218b815fe8c01b0) and test with BOOST_NO_FENV_H set.

For the definition of BOOST_NO_FENV_H, we can

  • ask to boost.build
  • and/or mimic the behaviour of the patching inside boost.test directly, not directly by setting the BOOST_NO_FENV_H but by indicating the lack of those GNU extensions via the non definition of the macro BOOST_TEST_FPE_SUPPORT_WITH_GLIBC_EXTENSIONS__

comment:54 by Jörg Krause <joerg.krause@…>, 6 years ago

Yes, with BOOST_NO_FENV_H set by the patch, version 1.63.0 of boost and the test module updated to commit 6f0d88ca9db00b449a795afa3218b815fe8c01b0 compiles for that toolchain.

I would say it is best to check for fenv.h, instead of depending on macro definition. But I do not know the boost build system...

comment:54 by Jörg Krause <joerg.krause@…>, 6 years ago

Yes, with BOOST_NO_FENV_H set by the patch, version 1.63.0 of boost and the test module updated to commit 6f0d88ca9db00b449a795afa3218b815fe8c01b0 compiles for that toolchain.

I would say it is best to check for fenv.h, instead of depending on macro definition. But I do not know the boost build system...

comment:55 by Raffi Enficiaud, 6 years ago

The thing is that fenv.h is there, and hence this is normal that BOOST_NO_FENV_H is not defined. What is not normal is that __GLIBC__ and __USE_GNU are also defined, which should not be the case (this is ulibC after all).

So my suggestion is not to define BOOST_NO_FENV_H, but to not define BOOST_TEST_FPE_SUPPORT_WITH_GLIBC_EXTENSIONS__ for the ulibC (this is the purpose of the macro).

I wanted to know if something outside of boost.test has changed, and this is indeed the case (boost.build or config).

But maybe I am missing sthg?

comment:56 by Jörg Krause <joerg.krause@…>, 6 years ago

For whatever reasons uclibc defines both __UCLIBC__ and __GLIBC__, whereas musl does not define any such macro, e.g. there is no __MUSL__ and will never be.

This is the commit log from the fenv.h patch used in Buildroot (I cannot add links here):

The boost build system does not properly test whether fenv.h is
available, and if it is, if it supports all the features used by
Boost. This causes build failures with uClibc (reported upstream at
https://svn.boost.org/trac/boost/ticket/11756) but also with glibc on
specific architectures that don't have a full fenv implementation,
such as NIOSII or Microblaze.

To address this, we forcefully disable the use of fenv support in the
affected configurations.

I am afraid I am not much of help here. From my point of view, it should be checked if fenv.h is available, and then check for the GLIBC extensions.

in reply to:  12 comment:57 by André Draszik <git@…>, 6 years ago

I think it all makes sense, just re-iterating comment 12:

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. [...]

comment 56:

From my point of view, it should be checked if fenv.h is available, and then check for the GLIBC extensions.

So this is what is being done now. The fact that uclibc defines __GLIBC__ and __USE_GNU without implementing the glibc extensions (on all arches it supports?) is the problem here.

Just adding a check for __UCLIBC__ into boost.test to guard usage of feenableexcept() etc. would be right if uclibc didn't implement them at all. I don't know if it does or not. I think it might for some arches?

comment:58 by Raffi Enficiaud, 6 years ago

I also agree that the problem seems to rather be on the side of uLibC right now. So what I suggest is to mimic the behavior of #comment:52 by adding this

// ...
  #if !defined(BOOST_NO_FENV_H) && !defined(BOOST_CLANG) && \
      defined(__GLIBC__) && defined(__USE_GNU) && \
      !(defined(__UCLIBC__) || defined(__nios2__) || defined(__microblaze__))
  #define BOOST_TEST_FPE_SUPPORT_WITH_GLIBC_EXTENSIONS__
  #endif
// ...

like it was done for boost 1.61. This has the advantage to not define BOOST_NO_FENV_H and focus the macro on the glibC extensions availability.

Can you quickly test the branch topic/11756-ulibc-disabling ?

Thanks

comment:59 by Jörg Krause, 6 years ago

Unfortunately, trac does not accept my posting because it thinks it is spam. Now, my comment is lost...

So, I rewrite...

uClibc does have a fenv.h in the system directory path. It installs fenv.h to the sysroot path if it was configured with UCLIBC_HAS_FENV. However, this feature is only implemented for i386.

So, uClibc does have fenv.h, but does not necessarily implements and installs it. Furthermore, the following macros are defined:

  • BOOST_NO_FENV_H is not defined
  • __UCLIBC__ is defined
  • __USE_GNU is defined
  • __GLIBC__ is defined

However, I think it is better to check with a test program if certain features are available, instead of relying on a bunch of macros:

1) check if feclearexcept() is available => HAS_FENV 2) check for the macros => HAS_FENV_FE_xxx 3) check for the GNU extension => HAS_FENV_GNU

However, I am not familiar with the Boost build system.

comment:60 by Raffi Enficiaud, 6 years ago

Would you please quickly try the branch topic/11756-ulibc-disabling and let me know if that works for you?

Again, uclibC should not define __USE_GNU and/or __GLIBC__ from my understanding. But it is more the level of the workaround what we are doing now.

comment:61 by Jörg Krause, 6 years ago

Sorry, that part got lost because I had to rewrite: I've checked the branch without any patches from Buildroot and it compiles successfully.

comment:62 by Raffi Enficiaud, 6 years ago

Merged to develop rev e4db0d6d2c900807f8aa68406469876b7ef78262

comment:63 by Raffi Enficiaud, 6 years ago

Resolution: fixed
Status: reopenedclosed

Merged to master, rev af78890325948bed598361966fa7f5fc9560c41d. Closing as fixed, until next time :)

Note: See TracTickets for help on using tickets.