Bruno Rijsman
Bruno Rijsman

Reputation: 3797

Code generated by "thrift -gen cpp" does not compile on macOS: 'boost/tr1/functional.hpp' file not found

I am on macOS High Sierra 10.13.6

I installed thrift as follows:

$ brew install thrift

It is the following version:

$ thrift --version
Thrift version 0.11.0

I installed boost as follows:

$ brew install boost

I have the following model.thrift file:

struct Person {
    1: required i32 age;
}

I run the Thrift compiler to generate the cpp code as follows:

$ thrift -gen cpp model.thrift

I have to following cpp_encode.cpp file that includes the generate code:

#include "gen-cpp/model_types.h"

int main(int argc, char const *argv[])
{
    return 0;
}

I attempt to compile the file as follows:

$ g++ -Wall -I /usr/local/include -L /usr/local/lib -o cpp_encode cpp_encode.cpp

The compiler version is as follows:

 $ g++ --version
 Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
 Apple LLVM version 9.1.0 (clang-902.0.39.2)
 Target: x86_64-apple-darwin17.7.0
 Thread model: posix
 InstalledDir: /Library/Developer/CommandLineTools/usr/bin

I get the following compile error:

 $ g++ -Wall -I /usr/local/include -L /usr/local/lib -o cpp_encode cpp_encode.cpp
 In file included from cpp_encode.cpp:1:
 In file included from ./gen-cpp/model_types.h:14:
 In file included from /usr/local/include/thrift/TBase.h:24:
 In file included from /usr/local/include/thrift/protocol/TProtocol.h:28:
 In file included from /usr/local/include/thrift/transport/TTransport.h:24:
 /usr/local/include/thrift/stdcxx.h:32:10: fatal error: 'boost/tr1/functional.hpp' file not found
 #include <boost/tr1/functional.hpp>

The directory /usr/local/boost directory exists:

$ ls -1 /usr/local/include/boost
accumulators
algorithm
align
align.hpp
aligned_storage.hpp
any.hpp
archive
[...]

But the directory /usr/local/include/boost/tr1 does not exist:

$ ls -1 /usr/local/include/boost/tr1
ls: /usr/local/include/boost/tr1: No such file or directory

Should I install /usr/local/include/boost/tr1? If so, how?

Should I use Thrift differently?

Upvotes: 1

Views: 1628

Answers (3)

Bruno Rijsman
Bruno Rijsman

Reputation: 3797

There are a couple of issues here:

  • On macOS you must use clang++ instead of g++. Also, you must use the libc++ library instead of the default libstdc++; the included version of libstdc++ is quite old and therefore does not include C++11 library features. See How to compile C++ with C++11 support in Mac Terminal

  • You don't need -I /usr/local/include or -L /usr/local/lib (but adding them doesn't cause harm)

If you want the program to not just compile but also link, there are some additional issues:

  • You also need to compile and link with the generated code gen-cpp/model_types.cpp

  • You need add the implementation of Coordinate::operator to the program. Thrift does generate the declaration for the Coordinate::operator< but does not generate the implementation of Coordinate::operator<. The reason for this is that Thrift does not understand the semantics of the struct and hence cannot guess the correct implementation of the comparison operator. This is discussed at http://mail-archives.apache.org/mod_mbox/thrift-user/201007.mbox/%[email protected]%3E

.

bool Coordinate::operator<(const Coordinate& other) const
{
    if (x < other.x) {
        return true;
    } else if (x > other.x) {
        return false;
    } else if (y < other.y) {
        return true;
    } else {
        return false;
    }
}

Given all of the above, the following works:

clang++ -std=c++11 -stdlib=libc++ -Wall -o cpp_encode cpp_encode.cpp gen-cpp/model_types.cpp

Note 1: This simple program does not require it, but once you write more complete Thrift code, you will need to link with the thrift library (-lthrift) and with the boost library (-lboost).

Note 2: I am granting the bounty to Corristo; even though his reply did not quite give the answer, his suggested test program got me started on the path that eventually led to the solution.

Upvotes: 3

Corristo
Corristo

Reputation: 5510

You can look at the code that causes the inclusion of boost/tr1/functional in thrift/stdcxx.h

#if defined(BOOST_NO_CXX11_HDR_FUNCTIONAL) || (defined(_MSC_VER) \
    && _MSC_VER < 1800) || defined(FORCE_BOOST_FUNCTIONAL)
#include <boost/tr1/functional.hpp>
#define _THRIFT_FUNCTIONAL_TR1_ 1
#endif

Since we can safely assume that your MacOS g++ doesn't define _MSC_VER there is only one of two options remaining: Either you yourself defined the FORCE_BOOST_FUNCTIONAL macro (unlikely), or BOOST_NO_CXX11_HDR_FUNCTIONAL is not defined.

By looking at the boost config documentation we find that BOOST_NO_CXX11_HDR_FUNCTIONAL is defined when

The standard library does not provide a C++11 compatible version of < functional >.

Since I don't know how Apples LLVM version maps to the real LLVM version I can't tell whether your version of clang has C++11 enabled by default, but my best guess is that you need to enable it manually. The only other alternative is that there is a boost config bug which causes clang to be identified as not having C++11 <functional>.

To test whether your version of clang has C++11 enabled by default you can try to compile a file with the following content

int main() 
{
  return []() -> int { return 0; }
}

without setting any compiler flags.

So to summarize:

  • Check whether you (or a thirdparty library you're using in addition to thrift) is defining the FORCE_BOOST_FUNCTIONAL macro
  • Check whether your compiler supports C++11 by default, if not add -std=c++11 to the list of compiler flags
  • If neither is the case, try upgrading your version of Boost, maybe a newer version will correctly identify your compiler supporting C++11 functional
  • Otherwise, file a bug with boost.config.

Upvotes: 3

sehe
sehe

Reputation: 393134

It appears that thrift is generating deprecated code.

Maybe you can upgrade to a newer version if it exists.

Otherwise, you could try to downgrade the boost version (beware of support limitations).

The TR1 bits have long (loooong) been adopted into the standard.

So in general the same things exist, but no longer using the tr1 namespace. E.g.

#include <boost/function.hpp>

could work, or

#include <functional>

for the standard library version.

Upvotes: 0

Related Questions