2

I'm trying to use emscripten from cmake and generate a html file as the output, but it doesn't output an html file. Instead, it only outputs a js and wasm file.

I include/set the Emscripten toolchain file and set the CMAKE_EXECUTABLE_SUFFIX, But it doesn't work!

CMakeLists.txt

cmake_minimum_required(VERSION 3.2.1)

set(LINK_OPTIONS)

set(CMAKE_TOOLCHAIN_FILE $ENV{EMSDK_HOME}/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake)
set(CMAKE_EXECUTABLE_SUFFIX ".html")
set(LINK_OPTIONS ${LINK_OPTIONS} -sWASM=1 -sALLOW_MEMORY_GROWTH=1 -sNO_EXIT_RUNTIME=0 -sASSERTIONS=1)


project(emscripten_project)

add_executable(emscripten_project main.cpp)
target_link_options(emscripten_project PUBLIC ${LINK_OPTIONS})

main.cpp

#include <iostream>

int main()
{
    std::cout << "Emscripten Example\n";
    return 0;
}

The Configure and Build Commands cmake . -G Ninja && ninja

Running ninja -v, gives this:

[2/2] cmd.exe /C "cd . && C:\emsdk\upstream\emscripten\em++.bat  -o emscripten_project.html -sUSE_GLFW=3 -sWASM=1 -sALLOW_MEMORY_GROWTH=1 -sNO_EXIT_RUNTIME=0 -sASSERTIONS=1 CMakeFiles/emscripten_project.dir/src/main.cpp.o -o emscripten_project.js && cd ."

The important part is that something is passing -o emscripten_project.js after the first -o emscripten_project.html

My installed CMake version is 3.25.2, and emcc version output is "emcc (Emscripten gcc/clang-like replacement + linker emulating GNU ld) 3.1.25 (febd44b21ecaca86e2cb2a25ef3ed4a0a2076365)"

This issue also occurs when I use the emcmake wrapper isntead of specifying the toolchain file path manually.

starball
  • 20,030
  • 7
  • 43
  • 238
Techie-Guy
  • 131
  • 8

1 Answers1

2

The problem is order of operations. The Emscripten toolchain file does set(CMAKE_EXECUTABLE_SUFFIX ".js") (I hardcoded that url to Emscripten's 3.1.25 tag since that's what you're using). Toolchain files don't get sourced by CMake immediately- it sources them on an as-needed basis. If I recall correctly, the exact events where it sources toolchain files is not very well documented (see related: CMake: In which order are files parsed (cache, toolchain, etc.)?), but one of those events that triggers sourcing toolchain files is calls to the project() command.

You did:

set(CMAKE_EXECUTABLE_SUFFIX ".html")
...
project(emscripten_project) # <- toolchain gets read in here, and Emscripten's toolchain's set(CMAKE_EXECUTABLE_SUFFIX ".js") overrides/changes your .html to .js.

Your problem will go away when you instead do:

project(emscripten_project) # <- toolchain gets read in here, and Emscripten's toolchain does set(CMAKE_EXECUTABLE_SUFFIX ".js") 
...
set(CMAKE_EXECUTABLE_SUFFIX ".html") # <- you override/change .js to .html

Note that you can also set executable suffixes on a per-target basis using the SUFFIX target property.


More notes

Note also that instead of using set(LINK_OPTIONS ...), you can instead use the add_link_options command, which is more idiomatic in "modern CMake" (If I understand "modern CMake" correctly).

If you're working on a project that you expect other people to build and not just yourself, I'd suggest to not set CMAKE_TOOLCHAIN_FILE in your CMakeLists.txt- or at least only set it if it hasn't been specified by the person building the project (you can use if(DEFINED ...)). A courtesy of being a project maintainer is to not take away choice from your users from how they want to specify CMake options that were designed to be up to them to set such as the toolchain file (via configure command using -DCMAKE_TOOLCHAIN_FILE=... or --toolchain ...)

This problem could probably be prevented if the CMake toolchain file did a check for whether CMAKE_EXECUTABLE_SUFFIX has already been set and avoid clobbering it if so. I just saw that you raised an issue ticket on GitHub asking your question there as well and I commented to make this suggestion to the maintainers there.

starball
  • 20,030
  • 7
  • 43
  • 238