Search code examples
c++boostlinker-errorsemscriptenboost-filesystem

How can I properly link Boost when compiling with Emscripten?


How can I properly link Boost when compiling with Emscripten?

main.cpp:

#include <boost/filesystem.hpp>

int main() {
  boost::filesystem::exists("file.txt");
}

Compile and link:

> em++ main.cpp --use-ports=boost_headers -sUSE_BOOST_HEADERS=1 -lboost_headers
wasm-ld: error: /tmp/emscripten_temp_u68f6vxm/main_0.o: undefined symbol: boost::filesystem::detail::status(boost::filesystem::path const&, boost::system::error_code*)
em++: error: '/home/ubuntu/tmp/emscripten/emsdk/upstream/bin/wasm-ld -o a.out.wasm /tmp/emscripten_temp_u68f6vxm/main_0.o -L/home/ubuntu/tmp/emscripten/emsdk/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten /home/ubuntu/tmp/emscripten/emsdk/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten/libboost_headers.a -lGL-getprocaddr -lal -lhtml5 -lstubs-debug -lnoexit -lc-debug -ldlmalloc -lcompiler_rt -lc++-noexcept -lc++abi-debug-noexcept -lsockets -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr /tmp/tmpv1sq5rj0libemscripten_js_symbols.so --strip-debug --export=emscripten_stack_get_end --export=emscripten_stack_get_free --export=emscripten_stack_get_base --export=emscripten_stack_get_current --export=emscripten_stack_init --export=stackAlloc --export=stackSave --export=stackRestore --export=__get_temp_ret --export=__set_temp_ret --export=__wasm_call_ctors --export-if-defined=__start_em_asm --export-if-defined=__stop_em_asm --export-if-defined=__start_em_lib_deps --export-if-defined=__stop_em_lib_deps --export-if-defined=__start_em_js --export-if-defined=__stop_em_js --export-if-defined=main --export-if-defined=__main_argc_argv --export-if-defined=fflush --export-table -z stack-size=65536 --initial-memory=16777216 --max-memory=16777216 --no-entry --stack-first --table-base=1' failed (returned 1)

With -lboost_filesystem:

wasm-ld: error: unable to find library -lboost_filesystem

Building Boost from source

git clone --recursive --branch=boost-1.83.0 --depth=1 https://github.com/boostorg/boost.git
cd boost

# Without specifying a toolset, it shows the help
# When specifying --with-toolset=emscripten, it says toolset emscripten not recognized
# b2 is generated --with-toolset=gcc
./bootstrap.sh --with-toolset=gcc

# from https://stackoverflow.com/a/47751199/16847511
./b2 toolset=emscripten

The last command (./b2 toolset=emscripten) gives an error:

emcc: warning: .bc output file suffix used without -flto or -emit-llvm.  Consider using .o extension since emcc will output an object file, not a bitcode file [-Wemcc]
emscripten.archive bin.v2/libs/log/build/emscripten-3.1.55/release/link-static/threading-multi/visibility-hidden/libboost_log.bc
bin.v2/libs/log/build/emscripten-3.1.55/release/link-static/threading-multi/visibility-hidden/attribute_name.bc:1:2: error: expected top-level entity

Using emconfigure ./b2 toolset=gcc works, but builds a regular version, not one suitable for Emscripten. Using my first code snippet as an example:

> em++ main.cpp --use-ports=boost_headers -sUSE_BOOST_HEADERS=1 -lboost_headers -lboost_filesystem -L/tmp/boost/stage/lib
wasm-ld: warning: /tmp/boost/stage/lib/libboost_filesystem.a: archive member 'codecvt_error_category.o' is neither Wasm object file nor LLVM bitcode
wasm-ld: warning: /tmp/boost/stage/lib/libboost_filesystem.a: archive member 'exception.o' is neither Wasm object file nor LLVM bitcode
wasm-ld: warning: /tmp/boost/stage/lib/libboost_filesystem.a: archive member 'directory.o' is neither Wasm object file nor LLVM bitcode
wasm-ld: warning: /tmp/boost/stage/lib/libboost_filesystem.a: archive member 'operations.o' is neither Wasm object file nor LLVM bitcode
wasm-ld: warning: /tmp/boost/stage/lib/libboost_filesystem.a: archive member 'path.o' is neither Wasm object file nor LLVM bitcode
wasm-ld: warning: /tmp/boost/stage/lib/libboost_filesystem.a: archive member 'path_traits.o' is neither Wasm object file nor LLVM bitcode
wasm-ld: warning: /tmp/boost/stage/lib/libboost_filesystem.a: archive member 'portability.o' is neither Wasm object file nor LLVM bitcode
wasm-ld: warning: /tmp/boost/stage/lib/libboost_filesystem.a: archive member 'unique_path.o' is neither Wasm object file nor LLVM bitcode
wasm-ld: warning: /tmp/boost/stage/lib/libboost_filesystem.a: archive member 'utf8_codecvt_facet.o' is neither Wasm object file nor LLVM bitcode
wasm-ld: error: /tmp/emscripten_temp_k9_q4uwl/simple-boost_0.o: undefined symbol: boost::filesystem::detail::status(boost::filesystem::path const&, boost::system::error_code*)
em++: error: '/home/ubuntu/tmp/emscripten/emsdk/upstream/bin/wasm-ld -o a.out.wasm /tmp/emscripten_temp_k9_q4uwl/simple-boost_0.o /home/ubuntu/tmp/emscripten/emsdk/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten/libboost_headers.a /tmp/boost/stage/lib/libboost_filesystem.a -L/tmp/boost/stage/lib -L/home/ubuntu/tmp/emscripten/emsdk/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten /home/ubuntu/tmp/emscripten/emsdk/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten/libboost_headers.a -lGL-getprocaddr -lal -lhtml5 -lstubs-debug -lnoexit -lc-debug -ldlmalloc -lcompiler_rt -lc++-noexcept -lc++abi-debug-noexcept -lsockets -mllvm -combiner-global-alias-analysis=false -mllvm -enable-emscripten-sjlj -mllvm -disable-lsr /tmp/tmp2dceaguelibemscripten_js_symbols.so --strip-debug --export=emscripten_stack_get_end --export=emscripten_stack_get_free --export=emscripten_stack_get_base --export=emscripten_stack_get_current --export=emscripten_stack_init --export=stackAlloc --export=stackSave --export=stackRestore --export=__get_temp_ret --export=__set_temp_ret --export=__wasm_call_ctors --export-if-defined=__start_em_asm --export-if-defined=__stop_em_asm --export-if-defined=__start_em_lib_deps --export-if-defined=__stop_em_lib_deps --export-if-defined=__start_em_js --export-if-defined=__stop_em_js --export-if-defined=main --export-if-defined=__main_argc_argv --export-if-defined=fflush --export-table -z stack-size=65536 --initial-memory=16777216 --max-memory=16777216 --no-entry --stack-first --table-base=1' failed (returned 1)

Solution

  • After trying with the develop branch it worked nicely for me.

    Per your request I verified using the 1.83.0 branch checkout, and sure enough, I ran into the build errors.

    So I'd suggest you to build your own 1.84.0 (or develop) version which apparently has that fixed.

    Of course, don't use the headers from --use-ports. Instead, use the headers from your own checkout:

    em++ main.cpp -I ~/custom/boost/ -L ~/custom/boost/stage/lib/ -lboost_filesystem
    

    The -I flag tells the compiler where to find includes.

    The -L flag tells the linker where to find the shared libraries.

    And here's it working nicely using my develop build (which reports as 1.85.0):

    enter image description here