erincatto / box2d

Box2D is a 2D physics engine for games
https://box2d.org
MIT License
8.34k stars 1.54k forks source link

Emscripten compilation issues #780

Open eduardodoria opened 2 months ago

eduardodoria commented 2 months ago

I'm getting this error when compiling with Emscripten:

solver.c:32:2: error: call to undeclared function '_mm_pause'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]

Tried to add this to CMakeLists.txt:

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-implicit-function-declaration")

And I got this error:

wasm-ld: error: engine/libs/box2d/libbox2d.a(solver.c.o): undefined symbol: _mm_pause

So, I modified solver.c with code similar to miniaudio lib:

Instead of:

#if defined(B2_CPU_ARM)
static inline void b2Pause (void)
{
    __asm__ __volatile__("isb\n");
}
#else
#include <immintrin.h>
static inline void b2Pause(void)
{
    _mm_pause();
}
#endif

I changed to:


#if !defined(B2_CPU_ARM)
#include <immintrin.h>
#endif

static inline void b2Pause(void)
{
#if defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)
    /* x86/x64 */
    #if (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__DMC__)) && !defined(__clang__)
        #if _MSC_VER >= 1400
            _mm_pause();
        #else
            #if defined(__DMC__)
                /* Digital Mars does not recognize the PAUSE opcode. Fall back to NOP. */
                __asm nop;
            #else
                __asm pause;
            #endif
        #endif
    #else
        __asm__ __volatile__ ("pause");
    #endif
#elif (defined(__arm__) && defined(__ARM_ARCH) && __ARM_ARCH >= 7) || defined(_M_ARM64) || (defined(_M_ARM) && _M_ARM >= 7) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__)
    /* ARM */
    #if defined(_MSC_VER)
        /* Apparently there is a __yield() intrinsic that's compatible with ARM, but I cannot find documentation for it nor can I find where it's declared. */
        __yield();
    #else
        __asm__ __volatile__ ("yield"); /* ARMv6K/ARMv6T2 and above. */
    #endif
#else
    /* Unknown or unsupported architecture. No-op. */
#endif
}

And works now!

erincatto commented 2 months ago

This page suggests a way to handle _mm_pause in WASM. https://emscripten.org/docs/porting/simd.html

eduardodoria commented 2 months ago

This page suggests a way to handle _mm_pause in WASM. https://emscripten.org/docs/porting/simd.html

It says _mm_pause is "No-op.".

But anyway, the code from miniaudio that I am using is working.

erincatto commented 2 months ago

The miniaudio solution has a lot of stuff. I'll be trying to build on Emscripten soon and will investigate.

Peter0x44 commented 2 months ago

@eduardodoria Your approach to those errors wasn't really correct.

In file included from /tmp/box2d/src/contact_solver.c:482:
/home/peter/.emscripten_cache/sysroot/include/compat/emmintrin.h:11:2: error: "SSE2 instruction set not enabled"
   11 | #error "SSE2 instruction set not enabled"
      |  ^

The issue with the intrinsics is that -msse2 needs to be a compile option in order for that to compile. Emscripten also wants -msimd128.

emcc: error: passing any of -msse, -msse2, -msse3, -mssse3, -msse4.1, -msse4.2, -msse4, -mavx, -mfpu=neon flags also requires passing -msimd128 (or -mrelaxed-simd)!
 elseif (EMSCRIPTEN)
        message(STATUS "Box2D on Emscripten")
+       target_compile_options(box2d PRIVATE -msimd128 -msse2)
 elseif (UNIX)

This patch fixes that specific compiler error. -mavx2 seems to be unsupported.

The next error I see is:

/tmp/box2d/src/timer.c:192:8: error: use of undeclared identifier 'size_t'; did you mean 'sizeof'?
  192 |         for ( size_t i = 0; i < count; i++ )
      |               ^~~~~~
      |               sizeof
/tmp/box2d/src/timer.c:192:17: error: expression is not assignable
  192 |         for ( size_t i = 0; i < count; i++ )
      |               ~~~~~~~~ ^

But this is just a normal problem with depending on a transitive include, including stddef.h in timer.c solved it for me.

Peter0x44 commented 2 months ago

Also, for emscripten, building the samples doesn't currently work, because of FetchContent_MakeAvailable(glfw). This fails likeso:

-- Checking for modules 'wayland-client>=0.2.7;wayland-cursor>=0.2.7;wayland-egl>=0.2.7;xkbcommon>=0.5.0'
--   Package 'wayland-client', required by 'virtual:world', not found
--   Package 'wayland-cursor', required by 'virtual:world', not found
--   Package 'wayland-egl', required by 'virtual:world', not found
--   Package 'xkbcommon', required by 'virtual:world', not found
CMake Error at /usr/share/cmake/Modules/FindPkgConfig.cmake:645 (message):
  The following required packages were not found:

   - wayland-client>=0.2.7
   - wayland-cursor>=0.2.7
   - wayland-egl>=0.2.7
   - xkbcommon>=0.5.0

Call Stack (most recent call first):
  /usr/share/cmake/Modules/FindPkgConfig.cmake:873 (_pkg_check_modules_internal)
  build/_deps/glfw-src/src/CMakeLists.txt:164 (pkg_check_modules)

https://emscripten.org/docs/compiling/Contrib-Ports.html For raylib, we are using the javascript glfw implementation mentioned here, link with -sUSE_GLFW=3 instead of downloading and building glfw for that circumstance.

eduardodoria commented 2 months ago

@Peter0x44 you are correct. Just added target_compile_options(box2d PRIVATE -msimd128 -msse2) and include stddef.h fixed.

Peter0x44 commented 2 months ago

Also, for emscripten, building the samples doesn't currently work, because of FetchContent_MakeAvailable(glfw). This fails likeso:

This is just where the problems begin. The shaders need porting to gles2, along with some changes/removal of glad. But I think that's better discussed in a different issue.

erincatto commented 2 months ago

I think I addressed these issues in #787. However, I haven't tested Emscripten with this yet.