39

I have a c++ project I would like to convert to a web application. For this purpose, I would like to use Emscripten to build the project.

The project uses some external libraries. I managed to compile or find the JavaScript version of most libraries and now I am stuck with the Boost ones. Actually I do not even know how to start for Boost: they use a boostrap script to generate the files to build the libraries. It is possible to pass the toolset to this script but Emscripten is obviously not supported.

My project uses the following parts of Boost: Thread, Regex, FileSystem, Signals, System. How can I compile these libraries using Emscripten?

Edit

Following the answer of npclaudiu, I bootstrapped the library with the gcc toolkit, then I edited project-config.jam to configure the compiler, replacing:

# Compiler configuration. This definition will be used unless
# you already have defined some toolsets in your user-config.jam
# file.
if ! gcc in [ feature.values <toolset> ]
{
    using gcc ;
}

with

# Compiler configuration. This definition will be used unless
# you already have defined some toolsets in your user-config.jam
# file.
if ! gcc in [ feature.values <toolset> ]
{
    using gcc : : "/full/path/to/em++" ;
}

Now, typing ./b2 effectively builds the libraries. Boost.Signals and Boost.System compile well. The others have some errors.

Boost.Thread complains:

libs/thread/src/pthread/thread.cpp:503:27: error: use of undeclared identifier 'pthread_yield'
        BOOST_VERIFY(!pthread_yield());
                      ^

Boost.Regex complains a lot about CHAR_BIT to be undeclared but it seems to be a problem in emscripten:

In file included from libs/regex/build/../src/c_regex_traits.cpp:28:
In file included from ./boost/regex/v4/c_regex_traits.hpp:26:
In file included from ./boost/regex/v4/regex_workaround.hpp:35:
/path/to/emscripten/system/include/libcxx/vector:1989:92: error: use of undeclared identifier 'CHAR_BIT'
static const unsigned __bits_per_word = static_cast<unsigned>(sizeof(__storage_type) * CHAR_BIT);
                                                                                       ^

Boost.FileSystem seems to fail due to emscripten too:

In file included from libs/filesystem/src/windows_file_codecvt.cpp:21:
/path/to/emscripten/system/include/libcxx/cwchar:117:9: error: no member named 'FILE' in the global namespace
using ::FILE;
      ~~^
Julien
  • 2,139
  • 1
  • 19
  • 32

6 Answers6

32

I finally managed to compile the needed libraries with emscripten. Here are the steps I followed.

Changes in emscripten

Edit system/include/libcxx/climits to add the following definitions (see http://github.com/kripken/emscripten/issues/531):

#ifndef CHAR_BIT
# define CHAR_BIT __CHAR_BIT__
#endif

#ifndef CHAR_MIN
# define CHAR_MIN (-128)
#endif

#ifndef CHAR_MAX
# define CHAR_MAX 127
#endif

#ifndef SCHAR_MIN
# define SCHAR_MIN (-128)
#endif

#ifndef SCHAR_MAX
# define SCHAR_MAX 127
#endif

#ifndef UCHAR_MAX

# define UCHAR_MAX 255
#endif

#ifndef SHRT_MIN
# define SHRT_MIN (-32767-1)
#endif

#ifndef SHRT_MAX
# define SHRT_MAX 32767
#endif

#ifndef USHRT_MAX
# define USHRT_MAX 65535
#endif

#ifndef INT_MAX
# define INT_MAX __INT_MAX__
#endif

#ifndef INT_MIN
# define INT_MIN (-INT_MAX-1)
# define INT_MIN (-INT_MAX-1)
#endif

#ifndef UINT_MAX
# define UINT_MAX (INT_MAX * 2U + 1)
#endif

#ifndef LONG_MAX
# define LONG_MAX __LONG_MAX__
#endif

#ifndef LONG_MIN
# define LONG_MIN (-LONG_MAX-1)
#endif

#ifndef ULONG_MAX
# define ULONG_MAX (LONG_MAX * 2UL + 1)
#endif

Add the following line in system/include/libcxx/cwchar

#include <cstdio>

Compiling Boost as shared libraries

As suggested by npclaudiu, bootstrap the library using the gcc toolkit. Then edit project-config.jam to configure the compiler and replace:

# Compiler configuration. This definition will be used unless
# you already have defined some toolsets in your user-config.jam
# file.
if ! gcc in [ feature.values <toolset> ]
{
    using gcc ;
}

with

# Compiler configuration. This definition will be used unless
# you already have defined some toolsets in your user-config.jam
# file.
if ! gcc in [ feature.values <toolset> ]
{
    using gcc : : "/full/path/to/emscripten/em++" ;
}

Force BOOST_HAS_SCHER_YIELD in boost/config/posix_features.hpp, around the line 67.

Then compile the libraries: ./b2 thread regex filesystem signals system

Compiling Boost as static libraries

Do all the above steps, then edit tools/build/v2/tools/gcc.jam and replace:

toolset.flags gcc.archive .AR $(condition) : $(archiver[1]) ;

with

toolset.flags gcc.archive .AR $(condition) : "/full/path/to/emscripten/emar" ;

and

toolset.flags gcc.archive .RANLIB $(condition) : $(ranlib[1]) ;

with

toolset.flags gcc.archive .RANLIB $(condition) :
  "/full/path/to/emscripten/emranlib" ;

Compile the libraries: ./b2 link=static variant=release threading=single runtime-link=static thread signals system filesystem regex

Community
  • 1
  • 1
Julien
  • 2,139
  • 1
  • 19
  • 32
  • Great work @julien. Did you try to use `user-config.jam` instead of hardcoding the paths? – abergmeier Apr 26 '13 at 08:09
  • @LCIDFire I was not familiar enough with the configuration files of Boost, so I did not try `user-config.jam`. It was really a trial-and-error progression and I still have work to do before my game runs. – Julien Apr 26 '13 at 08:53
  • @Julien , thanks for the post, i'm working on a project in similar situation, i built boost following your advice. One question, how do you handle those classes/functoins that are in header files only? they're not built into static or shared library – jerry Nov 15 '16 at 09:30
12

For the record, Boost now includes an "emscripten" toolset, which (in my experience) makes the process described above unnecessary.

To use, boostrap boost as normal, then compile with b2 (or bjam) like so:

b2 toolset=emscripten 
Mike_L
  • 121
  • 1
  • 4
  • 5
    this indeed is promising, but i am running into problems such as `Error: ambiguity found when searching for best transformation Trying to produce type 'SEARCHED_LIB' from:` ... have you been successful in building Boost with Emscripten on OSX? – ofloveandhate Jul 20 '18 at 20:27
  • 2
    It appears that this error is caused by the way that b2 looks for external libraries (eg. zlib, icu, bzip2, etc). I was able to hack around the issue by modifying `boost_1_67_0/tools/build/src/build/generators.jam` to explicitly ignore generator `searched-lib-generator` – JoshS Dec 07 '18 at 17:22
  • 1
    how to remove the error: https://github.com/boostorg/regex/issues/59#issuecomment-828707747 – midzer Feb 02 '22 at 01:33
9

In newer versions of emscripten, you can simply add Boost libraries using ports. It's now as easy as adding this flag to the compiler and linker: -s USE_BOOST_HEADERS=1

If you're using CMake, you can add the flag like this:

set_target_properties(your_targets_name_here PROPERTIES COMPILE_FLAGS "-s USE_BOOST_HEADERS=1" LINK_FLAGS "-s USE_BOOST_HEADERS=1")

More details from issue

thadk
  • 1,002
  • 1
  • 9
  • 18
askuri
  • 345
  • 3
  • 10
  • Is there any solution when using emcc alone, not with emcc? I still get the link error when using -s USE_BOOST_HEADERS=1. Thanks! – Dani P. Feb 20 '21 at 13:07
3

You could try to configure Boost libraries specifying gcc as toolset, as Emscripten recommends itself as being a drop-in replacement for gcc. Also, I think it's better if you build Boost as static libraries for this case. Keep in mind that most of the Boost libraries are header-only, because they only define template classes/functions.

npclaudiu
  • 2,401
  • 1
  • 18
  • 19
  • 1
    The Boost libraries listed in my question are not header only, otherwise it would be too easy :) I am going to try your solution, I just need to find how to tell Boost to compile with `emcc` instead of `gcc`. – Julien Mar 31 '13 at 08:09
  • Same problem here, headers-only libraries from Boost work fine with -s USE_BOOST_HEADERS=1 but others require compiling and linking manually and I have trouble with it, either with emcc or emcmake, see related https://stackoverflow.com/questions/66292106/link-errors-with-boost-port-of-header-only-libraries-for-emscripten-in-c-was – Dani P. Feb 21 '21 at 21:56
2

UPDATE for emsdk:

After a lot of trial and error, I was able to get emscripten 1.39 to compile Boost 1.71 in the following way:

Install emsdk if you haven't already from https://emscripten.org/docs/getting_started/downloads.html

Navigate to the emsdk install folder and do

./emsdk install latest && ./emsdk activate latest && source ./emsdk_env.sh

Navigate to the directory where you want to clone the Boost repo and run

git clone --recursive https://github.com/boostorg/boost.git

You can add the argument '--jobs N' where N is the number of processes to clone submodules with (this will go a lot faster if you do this).

cd boost

Now use the bootstrap script to create the boost-build executable b2

./bootstrap.sh

Finally, as your emsdk is already activated from the step above, you can build Boost using emconfigure to configure everything as it needs to be for calls to gcc to use emscripten instead

emconfigure ./b2 toolset=gcc --prefix=<directory_to_install_to> --build-dir=<directory_for_intermediate_build_files>

Now to install the includes and libs to your chosen prefix directory, run

emconfigure ./b2 toolset=gcc --prefix=<directory_to_install_to> --build-dir=<directory_for_intermediate_build_files> install
1

I don't know if you've happened to see this particular question in the FAQ, but in case you haven't:

Q. How do I link against system libraries like SDL, boost, etc.?

A. System libraries that are included with emscripten - libc, libc++ (C++ STL) and SDL - are automatically included when you compile (and just the necessary parts of them). You don't even need -lSDL, unlike other compilers (but -lSDL won't hurt either).

Other libraries not included with emscripten, like boost, you would need to compile yourself and link with your program, just as if they were a module in your project. For example, see how BananaBread links in libz. (Note that in the specific case of boost, if you only need the boost headers, you don't need to compile anything.)

Another option for libraries not included is to implement them as a JS library, like emscripten does for libc (minus malloc) and SDL (but not libc++ or malloc). See --js-library in emcc.

Community
  • 1
  • 1
Jorge Israel Peña
  • 36,800
  • 16
  • 93
  • 123