teslamotors / fixed-containers

C++ Fixed Containers
MIT License
377 stars 33 forks source link

Compiling with emscripten #128

Open abeimler opened 3 months ago

abeimler commented 3 months ago

Hi,

I am experiencing a compiler error when using emscripten (compiling to wasm) since the latest update.

In file included from libs/fixed_containers/include/fixed_containers/fixed_circular_deque.hpp:4:
In file included from libs/fixed_containers/include/fixed_containers/fixed_deque.hpp:14:
libs/fixed_containers/include/fixed_containers/random_access_iterator.hpp:171:37: error: no member named 'iterator_' in 'RandomAccessIterator<ConstEntryProvider, MutableEntryProvider, CONSTNESS, DIRECTION>'
  171 |         return Self(std::next(other.iterator_, n));
      |                               ~~~~~ ^
1 error generated.

Looking into RandomAccessIterator<ConstEntryProvider, MutableEntryProvider, CONSTNESS, DIRECTION>, it appears that iterator_ is not a member. This raises the question of why it compiles successfully with gcc.

Notes:

/bin/ccache /usr/lib/emscripten/em++ -isystem vcpkg_installed/wasm32-emscripten/include ... -Os -DNDEBUG -std=c++20 -fcolor-diagnostics -fcolor-diagnostics -Wall ... -MD -MT ...

some warnings and include paths, but nothing special

I has not set up or cross-compiled the fixed-containers project itself with emcc; this issue arises in my other projects that build with emcc. The compilation works fine with gcc, but not for the web build.

This issue occurs with a personal fork of fixed-containers, which is up-to-date with the current main branch.

abeimler commented 3 months ago

I tried to compile my fixed-containers branch with emscripten and get this errors:

CMake Options:

-DENABLE_TESTING:BOOL=ON
-DENABLE_CROSS_COMPILING:BOOL=ON
-DDEFAULT_TRIPLET=wasm32-emscripten
-DEMSCRIPTEN_ROOT_PATH:STRING=/usr/lib/emscripten
-DCMAKE_C_COMPILER:STRING=/usr/lib/emscripten/emcc
-DCMAKE_CXX_COMPILER:STRING=/usr/lib/emscripten/em++
-DEMSCRIPTEN_VERSION:STRING=3.1.44
-DVCPKG_CHAINLOAD_TOOLCHAIN_FILE:STRING=/usr/lib/emscripten/cmake/Modules/Platform/Emscripten.cmake
cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=/usr/lib/emscripten/emcc -DCMAKE_CXX_COMPILER=/usr/lib/emscripten/em++ -DENABLE_TESTING:BOOL=ON -DENABLE_CROSS_COMPILING:BOOL=ON -DDEFAULT_TRIPLET=wasm32-emscripten -DEMSCRIPTEN_ROOT_PATH:STRING=/usr/lib/emscripten -DCMAKE_C_COMPILER:STRING=/usr/lib/emscripten/emcc -DCMAKE_CXX_COMPILER:STRING=/usr/lib/emscripten/em++ -DEMSCRIPTEN_VERSION:STRING=3.1.44 -DVCPKG_CHAINLOAD_TOOLCHAIN_FILE:STRING=/usr/lib/emscripten/cmake/Modules/Platform/Emscripten.cmake -G Ninja -S fixed-containers -B fixed-containers/cmake-build-debug-web
-- CPM: Adding package project_options@0.35.1 (v0.35.1)
-- Unknown architecture  - using x64
-- fetch emscripten repo main branch. ...
-- enable cross-compiling
-- use emscripten cross-compiling
-- use emscripten cross-compiler emulator: ;--experimental-wasm-threads
-- Target Architecture: wasm32-emscripten
-- Default Triplet: wasm32-emscripten
-- Host Triplet: x64-linux
-- Setup cross-compiler for wasm32-emscripten
-- Use cross-compiler toolchain for vcpkg: /usr/lib/emscripten/cmake/Modules/Platform/Emscripten.cmake
-- Running vcpkg install
Detecting compiler hash for triplet x64-linux...
Detecting compiler hash for triplet wasm32-emscripten...
All requested packages are currently installed.
FAILED: test/CMakeFiles/circular_integer_range_iterator_test.dir/circular_integer_range_iterator_test.cpp.o 
/bin/ccache /usr/lib/emscripten/em++ -DFIXED_CONTAINERS_IOSTREAM_SUPPORT -Ifixed-containers/include -isystem fixed-containers/cmake-build-debug-web/vcpkg_installed/wasm32-emscripten/include -g -std=c++20 -fcolor-diagnostics -fcolor-diagnostics -fno-sanitize-recover=all -fsanitize=address,undefined -fno-exceptions -ftemplate-backtrace-limit=0 -ftrivial-auto-var-init=pattern -Weverything -Wno-c++98-compat-pedantic -Wc++98-compat-extra-semi -Wno-weak-template-vtables -Wno-global-constructors -Wno-range-loop-bind-reference -Wno-covered-switch-default -Wno-switch-default -Wno-exit-time-destructors -Wno-used-but-marked-unused -Wno-c++20-compat -Wno-ctad-maybe-unsupported -Wno-padded -Wno-poison-system-directories -MD -MT test/CMakeFiles/circular_integer_range_iterator_test.dir/circular_integer_range_iterator_test.cpp.o -MF test/CMakeFiles/circular_integer_range_iterator_test.dir/circular_integer_range_iterator_test.cpp.o.d -o test/CMakeFiles/circular_integer_range_iterator_test.dir/circular_integer_range_iterator_test.cpp.o -c fixed-containers/test/circular_integer_range_iterator_test.cpp
In file included from fixed-containers/test/circular_integer_range_iterator_test.cpp:1:
In file included from fixed-containers/include/fixed_containers/circular_integer_range_iterator.hpp:8:
fixed-containers/include/fixed_containers/random_access_iterator.hpp:171:37: error: no member named 'iterator_' in 'RandomAccessIterator<ConstEntryProvider, MutableEntryProvider, CONSTNESS, DIRECTION>'
  171 |         return Self(std::next(other.iterator_, n));
      |                               ~~~~~ ^
fixed-containers/test/circular_integer_range_iterator_test.cpp:15:15: error: static assertion failed due to requirement 'sizeof(fixed_containers::RandomAccessIterator<fixed_containers::CircularIntegerRangeEntryProvider<fixed_containers::IntegerRange>, fixed_containers::CircularIntegerRangeEntryProvider<fixed_containers::IntegerRange>, fixed_containers::IteratorConstness::CONSTANT_ITERATOR, fixed_containers::IteratorDirection::FORWARD>) == 32'
   15 | static_assert(sizeof(CircularIntegerRangeIterator<IteratorDirection::FORWARD, IntegerRange>) == 32);
      |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
fixed-containers/test/circular_integer_range_iterator_test.cpp:15:94: note: expression evaluates to '24 == 32'
   15 | static_assert(sizeof(CircularIntegerRangeIterator<IteratorDirection::FORWARD, IntegerRange>) == 32);
      |               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~
fixed-containers/test/circular_integer_range_iterator_test.cpp:183:9: error: use of undeclared identifier 'EXPECT_DEATH'
  183 |         EXPECT_DEATH(void(it1 != it3), "");  // Hard error if attempting to compare unrelated ranges
      |         ^
3 errors generated.
[2/87] Building CXX object test/CMakeFiles/fixed_circular_queue_test.dir/fixed_circular_queue_test.cpp.o
FAILED: test/CMakeFiles/fixed_circular_queue_test.dir/fixed_circular_queue_test.cpp.o 
/bin/ccache /usr/lib/emscripten/em++ -DFIXED_CONTAINERS_IOSTREAM_SUPPORT -Ifixed-containers/include -isystem fixed-containers/cmake-build-debug-web/vcpkg_installed/wasm32-emscripten/include -g -std=c++20 -fcolor-diagnostics -fcolor-diagnostics -fno-sanitize-recover=all -fsanitize=address,undefined -fno-exceptions -ftemplate-backtrace-limit=0 -ftrivial-auto-var-init=pattern -Weverything -Wno-c++98-compat-pedantic -Wc++98-compat-extra-semi -Wno-weak-template-vtables -Wno-global-constructors -Wno-range-loop-bind-reference -Wno-covered-switch-default -Wno-switch-default -Wno-exit-time-destructors -Wno-used-but-marked-unused -Wno-c++20-compat -Wno-ctad-maybe-unsupported -Wno-padded -Wno-poison-system-directories -MD -MT test/CMakeFiles/fixed_circular_queue_test.dir/fixed_circular_queue_test.cpp.o -MF test/CMakeFiles/fixed_circular_queue_test.dir/fixed_circular_queue_test.cpp.o.d -o test/CMakeFiles/fixed_circular_queue_test.dir/fixed_circular_queue_test.cpp.o -c fixed-containers/test/fixed_circular_queue_test.cpp
In file included from fixed-containers/test/fixed_circular_queue_test.cpp:1:
In file included from fixed-containers/include/fixed_containers/fixed_circular_queue.hpp:4:
In file included from fixed-containers/include/fixed_containers/fixed_circular_deque.hpp:4:
In file included from fixed-containers/include/fixed_containers/fixed_deque.hpp:14:
fixed-containers/include/fixed_containers/random_access_iterator.hpp:171:37: error: no member named 'iterator_' in 'RandomAccessIterator<ConstEntryProvider, MutableEntryProvider, CONSTNESS, DIRECTION>'
  171 |         return Self(std::next(other.iterator_, n));
      |                               ~~~~~ ^
1 error generated.
[3/87] Building CXX object test/CMakeFiles/filtered_integer_range_iterator_test.dir/filtered_integer_range_iterator_test.cpp.o
FAILED: test/CMakeFiles/filtered_integer_range_iterator_test.dir/filtered_integer_range_iterator_test.cpp.o 
/bin/ccache /usr/lib/emscripten/em++ -DFIXED_CONTAINERS_IOSTREAM_SUPPORT -Ifixed-containers/include -isystem fixed-containers/cmake-build-debug-web/vcpkg_installed/wasm32-emscripten/include -g -std=c++20 -fcolor-diagnostics -fcolor-diagnostics -fno-sanitize-recover=all -fsanitize=address,undefined -fno-exceptions -ftemplate-backtrace-limit=0 -ftrivial-auto-var-init=pattern -Weverything -Wno-c++98-compat-pedantic -Wc++98-compat-extra-semi -Wno-weak-template-vtables -Wno-global-constructors -Wno-range-loop-bind-reference -Wno-covered-switch-default -Wno-switch-default -Wno-exit-time-destructors -Wno-used-but-marked-unused -Wno-c++20-compat -Wno-ctad-maybe-unsupported -Wno-padded -Wno-poison-system-directories -MD -MT test/CMakeFiles/filtered_integer_range_iterator_test.dir/filtered_integer_range_iterator_test.cpp.o -MF test/CMakeFiles/filtered_integer_range_iterator_test.dir/filtered_integer_range_iterator_test.cpp.o.d -o test/CMakeFiles/filtered_integer_range_iterator_test.dir/filtered_integer_range_iterator_test.cpp.o -c fixed-containers/test/filtered_integer_range_iterator_test.cpp
fixed-containers/test/filtered_integer_range_iterator_test.cpp:63:15: error: static assertion failed due to requirement 'sizeof(fixed_containers::BidirectionalIterator<fixed_containers::FilteredIntegerRangeEntryProvider<fixed_containers::(anonymous namespace)::AlwaysTruePredicate, fixed_containers::IntegerRange>, fixed_containers::FilteredIntegerRangeEntryProvider<fixed_containers::(anonymous namespace)::AlwaysTruePredicate, fixed_containers::IntegerRange>, fixed_containers::IteratorConstness::CONSTANT_ITERATOR, fixed_containers::IteratorDirection::FORWARD>) == 32'
   63 | static_assert(sizeof(FilteredIntegerRangeIterator<AlwaysTruePredicate,
      |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   64 |                                                   IteratorDirection::FORWARD,
      |                                                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~
   65 |                                                   IntegerRange>) == 32);
      |                                                   ~~~~~~~~~~~~~~~~~~~~
fixed-containers/test/filtered_integer_range_iterator_test.cpp:65:66: note: expression evaluates to '16 == 32'
   63 | static_assert(sizeof(FilteredIntegerRangeIterator<AlwaysTruePredicate,
      |               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   64 |                                                   IteratorDirection::FORWARD,
      |                                                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~
   65 |                                                   IntegerRange>) == 32);
      |                                                   ~~~~~~~~~~~~~~~^~~~~
fixed-containers/test/filtered_integer_range_iterator_test.cpp:66:15: error: static assertion failed due to requirement 'sizeof(fixed_containers::BidirectionalIterator<fixed_containers::FilteredIntegerRangeEntryProvider<fixed_containers::(anonymous namespace)::AlwaysTruePredicate, fixed_containers::CompileTimeIntegerRange<0, 3>>, fixed_containers::FilteredIntegerRangeEntryProvider<fixed_containers::(anonymous namespace)::AlwaysTruePredicate, fixed_containers::CompileTimeIntegerRange<0, 3>>, fixed_containers::IteratorConstness::CONSTANT_ITERATOR, fixed_containers::IteratorDirection::FORWARD>) == 16'
   66 | static_assert(sizeof(FilteredIntegerRangeIterator<AlwaysTruePredicate,
      |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   67 |                                                   IteratorDirection::FORWARD,
      |                                                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~
   68 |                                                   CompileTimeIntegerRange<0, 3>>) == 16);
      |                                                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
fixed-containers/test/filtered_integer_range_iterator_test.cpp:68:83: note: expression evaluates to '8 == 16'
   66 | static_assert(sizeof(FilteredIntegerRangeIterator<AlwaysTruePredicate,
      |               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   67 |                                                   IteratorDirection::FORWARD,
      |                                                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~
   68 |                                                   CompileTimeIntegerRange<0, 3>>) == 16);
      |                                                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~
fixed-containers/test/filtered_integer_range_iterator_test.cpp:69:15: error: static assertion failed due to requirement 'sizeof(fixed_containers::BidirectionalIterator<fixed_containers::FilteredIntegerRangeEntryProvider<fixed_containers::(anonymous namespace)::SpecificValuePredicate, fixed_containers::CompileTimeIntegerRange<0, 3>>, fixed_containers::FilteredIntegerRangeEntryProvider<fixed_containers::(anonymous namespace)::SpecificValuePredicate, fixed_containers::CompileTimeIntegerRange<0, 3>>, fixed_containers::IteratorConstness::CONSTANT_ITERATOR, fixed_containers::IteratorDirection::FORWARD>) == 24'
   69 | static_assert(sizeof(FilteredIntegerRangeIterator<SpecificValuePredicate,
      |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   70 |                                                   IteratorDirection::FORWARD,
      |                                                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~
   71 |                                                   CompileTimeIntegerRange<0, 3>>) == 24);
      |                                                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
fixed-containers/test/filtered_integer_range_iterator_test.cpp:71:83: note: expression evaluates to '12 == 24'
   69 | static_assert(sizeof(FilteredIntegerRangeIterator<SpecificValuePredicate,
      |               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   70 |                                                   IteratorDirection::FORWARD,
      |                                                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~
   71 |                                                   CompileTimeIntegerRange<0, 3>>) == 24);
      |                                                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~
In file included from fixed-containers/test/filtered_integer_range_iterator_test.cpp:1:
In file included from fixed-containers/include/fixed_containers/filtered_integer_range_iterator.hpp:4:
fixed-containers/include/fixed_containers/bidirectional_iterator.hpp:79:57: warning: implicit conversion loses integer precision: 'unsigned long long' to 'std::size_t' (aka 'unsigned long') [-Wshorten-64-to-32]
   79 |       : reference_provider_(std::forward<First>(first), std::forward<Args>(args)...)
      |         ~~~~~~~~~~~~~~~~~~~                             ^~~~~~~~~~~~~~~~~~~~~~~~
fixed-containers/test/filtered_integer_range_iterator_test.cpp:91:26: note: in instantiation of function template specialization 'fixed_containers::BidirectionalIterator<fixed_containers::FilteredIntegerRangeEntryProvider<fixed_containers::(anonymous namespace)::AlwaysTruePredicate>, fixed_containers::FilteredIntegerRangeEntryProvider<fixed_containers::(anonymous namespace)::AlwaysTruePredicate>, fixed_containers::IteratorConstness::CONSTANT_ITERATOR, fixed_containers::IteratorDirection::FORWARD>::BidirectionalIterator<fixed_containers::IntegerRange, unsigned long long, fixed_containers::(anonymous namespace)::AlwaysTruePredicate>' requested here
   91 |         constexpr ItType it{IntegerRange::closed_open(0, 3), 0ULL, AlwaysTruePredicate{}};
      |                          ^

I do not expect to run the tests fully in wasm, just a quick test for the build.

alexkaratarakis commented 3 months ago

This is caused by two phase-lookup and the function not being used/instantiated. This allows the build to succeed in msvc/gcc/clang because they never actually attempt to instantiate the function. Here is a simple example that compiles even though it references a variable that doesn't exist:

template <class T>
struct MockTemplate
{
    int foo(const MockTemplate<T>& input) const { return input.variable_that_does_not_exist; }
};

int main()
{
    MockTemplate<int> it{};
    (void)it;
    // it.foo(it);
}

I am guessing emscripten tries to instantiate everything instead, hitting the issue immediately. The above example should also fail to compile with emscripten.

I have a fix for the reported issue. The PR also adds unit tests that instantiate the function and highlight the non-existent variable.

abeimler commented 3 months ago

Thanks for the quick fix, I recompiled the fixed-container with emscripten and it seems to work, the only expected errors:

fixed-containers/test/circular_integer_range_iterator_test.cpp:18:15: error: static assertion failed due to requirement 'sizeof(fixed_containers::RandomAccessIterator<fixed_containers::CircularIntegerRangeEntryProvider<fixed_containers::IntegerRange>, fixed_containers::CircularIntegerRangeEntryProvider<fixed_containers::IntegerRange>, fixed_containers::IteratorConstness::CONSTANT_ITERATOR, fixed_containers::IteratorDirection::FORWARD>) == 32'
   18 | static_assert(sizeof(CircularIntegerRangeIterator<IteratorDirection::FORWARD, IntegerRange>) == 32);
      |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
fixed-containers/test/circular_integer_range_iterator_test.cpp:18:94: note: expression evaluates to '24 == 32'
   18 | static_assert(sizeof(CircularIntegerRangeIterator<IteratorDirection::FORWARD, IntegerRange>) == 32);
      |               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~
fixed-containers/test/circular_integer_range_iterator_test.cpp:186:9: error: use of undeclared identifier 'EXPECT_DEATH'
  186 |         EXPECT_DEATH(void(it1 != it3), "");  // Hard error if attempting to compare unrelated ranges
      |         ^

I also recompiled my other Project with emscripten, no build errors. :+1: