nlohmann / json

JSON for Modern C++

Home Page:https://json.nlohmann.me

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Error compile Android NDK error: 'strtof' is not a member of 'std'

fh127 opened this issue · comments

hi, can you help me, this error occurs when it compile with Android NDK

          error: 'strtof' is not a member of 'std'
         return std::strtof(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);

         error: 'ERANGE' was not declared in this scope
         if (reinterpret_cast<lexer_char_t*>(endptr) != m_cursor || errno == ERANGE)

For ERANGE see the PR. However, the std::strtof in the latest NDK STL looks fine to me and seems to be correctly used in this project. So I would say that there is a problem in your project setup (outdated NDK, weird defines, wrong STL?) and you rather find a solution in an Android developer forum :).

Also try to only run the preprocessor on the problematic source code and check if the included headers are actually defining strtof and are using them in the std namespace (e.g. by running GCC -E ...).

I merged PR #222. @fh127, is your issue solved by this?

commented

I came across the same problem (in my project, changing or tweaking NDK settings was not an option because of other dependancies) and ended up fixing using a workaround. I hope there would be a cleaner solution though.. What I did:

For GCC 4.9 (for example ndk r10d):

Add to_string in the beginning of json.hpp

#include <vector>

#ifdef JSON_ANDROID_WORKAROUNDS
namespace std
{
    template < typename T > std::string to_string(const T& n)
    {
        std::ostringstream stm;
        stm << n;
        return stm.str();
    }
}
#endif

// disable float-equal warnings on GCC/clang

Use strtod in two places (warning! this will of course lose precision and maybe other errors):

        long double str_to_float_t(long double* /* type */, char** endptr) const
        {
#ifdef JSON_ANDROID_WORKAROUNDS
            return std::strtod(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
#else
            return std::strtold(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
#endif
        }
        float str_to_float_t(float* /* type */, char** endptr) const
        {
#ifdef JSON_ANDROID_WORKAROUNDS
            return std::strtod(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
#else
            return std::strtof(reinterpret_cast<typename string_t::const_pointer>(m_start), endptr);
#endif
        }

For GCC 4.8 this was also needed (ndk r9c):

#ifdef JSON_ANDROID_WORKAROUNDS
    basic_json() {};
#else
    basic_json() = default;
#endif

Hi, @nlohmann , I tested the commit PR #222, when I am compiling in Android NDK, this error was solved:
error: 'ERANGE' was not declared in this scope'''
But I have more errores:
error: 'strtof' is not a member of 'std'
error: 'strtoll' is not a member of 'std'

I am using the Android NDK configuration, and doesn't support those function c. Application.MK:

                APP_STL := gnustl_static
                APP_CPPFLAGS :=  -std=c++11 -frtti -fexceptions
                APP_ABI :=  armeabi armeabi-v7a x86 arm64-v8a
                 NDK_TOOLCHAIN_VERSION := 4.9

this commit of the repository #c0bb5a5 work fine for my Android project

I use CrystaX NDK and it compiles all fine for android.

@fh127 @Dimon4eg As the code works in your cases, could you please give me a detailed version number of your NDK/GCC so that I can mention it in the README file?

@vjjjv I don't want to add these adjustments to my code, because GCC 4.8 is not supported anyway.

Instead of Google NDK I use CrystaX NDK (latest 10.3.1 from https://www.crystax.net).

commented

How about the GCC 4.9, I posted two workarounds for that too?

Its just a bit uncomfortable that a great lib is not compatible with some common dev envs because of such a small changes.. Or am I missing some bigger issues here? Is it so that it's not recommended to use the lib with changes that I made? (I am not super familiar with c++11 "specialities")

@vjjjv Can you not use the c++-shared standard library to get the missing to_string function?

commented

I am not sure, because I experience this problem using Unity and Qt frameworks for example - there the NDK settings come predefined and its not very clear if I can change them easily.

Can someone please provide an example project so I can try to execute the build myself? (I have no experience with Android NDK - I just want to install it in an Ubuntu VM and try it myself.)

Ok, I tried the following: I got Android NDK, Revision 11c and compiled the unit tests with the following files in a subdirectory Android:

Android.mk:

LOCAL_PATH := .
include $(CLEAR_VARS)
LOCAL_MODULE := jsonunit.out
LOCAL_SRC_FILES := ../test/unit.cpp
LOCAL_C_INCLUDES += ../src ../test
LOCAL_CPP_FEATURES += exceptions rtti
LOCAL_CPPFLAGS += -fexceptions -frtti -std=c++11
include $(BUILD_EXECUTABLE)

Application.mk:

APP_ABI := x86
APP_PLATFORM := android-21
APP_STL := c++_shared
APP_BUILD_SCRIPT := Android.mk

Executing ndk-build NDK_APPLICATION_MK=./Application.mk takes a long time, but completes without error.

I have no experience with Android NDK. Can someone please tell me:

  • Would the approach above be feasible for continuous integration?
  • Are the used flags sensible?

I really want to experience the reported problems on my machine to assess whether it makes sense to adjust the code. This may also be applicable to #136.

I had another try with the configuration above and only adjusted the NDK_TOOLCHAIN_VERSION parameter:

  • android-ndk-r11c
    • no NDK_TOOLCHAIN_VERSION given: GCC 4.9 20150123 (prerelease) is used; compiles
    • NDK_TOOLCHAIN_VERSION := clang: Clang 3.8.243773 is used; compiles
  • android-ndk-r10e
    • no NDK_TOOLCHAIN_VERSION given: GCC 4.8 is used; does not compile
    • NDK_TOOLCHAIN_VERSION := 4.9: GCC 4.9 20140827 (prerelease) is used; compiles
    • NDK_TOOLCHAIN_VERSION := clang: clang version 3.6 is used; compiles
  • android-ndk-r9d
    • no NDK_TOOLCHAIN_VERSION given: GCC 4.6 20120106 (prerelease) is used; does not compile
    • NDK_TOOLCHAIN_VERSION := clang: Clang 3.4 is used; compiles

I forgot to mention: So far, I was not able to reproduce the 'to_string' is not a member of 'std' error.

I checked another NDK:

  • crystax-ndk-10.3.1
    • no NDK_TOOLCHAIN_VERSION given: GCC 5.3 20151204 is used; compiles
    • NDK_TOOLCHAIN_VERSION := clang: Clang 3.7 is used; compiles
commented

Thank you for investigating this! Can you try with this Application.mk:

APP_ABI := x86
APP_PLATFORM := android-21
APP_STL := gnustl_static
APP_BUILD_SCRIPT := Android.mk

For me, this is how the issue re-produces. With "APP_STL := c++_shared" there is no issues, but as I mentioned before, in our project we cannot change the STL version.

Ok, I'll check this weekend. Which NDK version and compiler shall I try?

commented

For us, r10d GCC 4.9 is relevant

I can reproduce the error.

Combinations that do not work:

  • NDK10c with APP_STL := gnustl_static (using NDK_TOOLCHAIN_VERSION := clang)
  • NDK11e with APP_STL := gnustl_static (using NDK_TOOLCHAIN_VERSION := clang)

Combinations that do work:

  • NDK10c with APP_STL := c++_static (using NDK_TOOLCHAIN_VERSION := clang)
  • NDK11e with APP_STL := c++_static (using NDK_TOOLCHAIN_VERSION := clang)
  • crystax-ndk-10.3.1 with APP_STL := gnustl_static (using NDK_TOOLCHAIN_VERSION := clang)
  • crystax-ndk-10.3.1 with APP_STL := c++_static (using NDK_TOOLCHAIN_VERSION := clang)

A longer explanation can be found here.

Is changing to one of the working combinations an option for you @vjjjv?

(I removed the bug label, because the error is out of scope of the library, but is a known issue for the combination of used options in Android NDK)

commented

Interesting results on this one after all. We are using this json-lib in component that has to work with Unity and Qt frameworks - so it might be quite challenging to change the NDK options. But I could think Unity and Qt are also moving towards these better working setups in the long run.

For now we are quite happy with the workarounds I have posted here earlier. It seems that this should not be fixed in the json lib now when we know where the problem originates from.

I added a note to the README file and linked this discussion.

Does anyone have this working for the most recent NDK while using gradle? I use

    ndk {
        stl "c++_static"
    }

    externalNativeBuild {
        cmake {
            cppFlags "-fexceptions -frtti -std=c++11"
        }
    }

and I still get the 'to_string' is not a member of 'std'

I could compile the code, see #451 (comment).

I have no idea why but I needed this instead (this took me a few hours to figure out so hopefully it helps someone on Android using Gradle...):

    externalNativeBuild {
        cmake {
            cppFlags "-fexceptions -frtti -std=c++11"
            arguments "-DANDROID_STL=c++_shared"
        }
    }

@haydenkaizeta Thanks for sharing. Could you please give the exact version numbers so I can add a hint to the README?

android-ndk-r13b, buildToolsVersion "24.0.3", ANDROID_STL=c++_shared, built with clang

For me compiles ok with CrystaX NDK (but I'm not using this lib as separate cmake module, just include as header)

When using gnustl, add -D_GLIBCXX_USE_C99=1 -D_GLIBCXX_HAVE_WCSTOF=1 would fix it.
Tested with NDK r16b clang

More detail:
to_string is not available in gnu-libstdc++ "out of the box". I searched the sources and found that std::to_string is indeed in the lib (${NDK_HOME}/sources/cxx-stl/gnu-libstdc++/4.9/include/bits/basic_string.h) but opted out by

#if ((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \
     && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF))

see: https://stackoverflow.com/a/34352742/2395134

for armeabi-v7a , need -D_GLIBCXX_HAVE_WCSTOF=1 for std::wcstof