I just ran into exactly the same issue and even started one on the Emscripten github page (see here).
What worked for me was to put all the Emscripten specific flags into one long string which I then added with target_compile_options and target_link_options.
set(EMS
"SHELL:-s EXPORTED_FUNCTIONS=['_main','_malloc','_int_sqrt'] -s EXTRA_EXPORTED_RUNTIME_METHODS=['ccall','cwrap']"
)
target_compile_options(EmscriptenExample PRIVATE ${EMS})
target_link_options(EmscriptenExample PRIVATE ${EMS})
It's important to drop both, double quotes and whitespaces from the list of functions otherwise it won't work. At least with CMake 3.17.3 escaping the double quotes did not work for me.
/edit
For the sake of completeness: Emscripten now allows to remove the whitespace between the -s prefix and the actual flag. This makes it possible to actually use CMake's own target_*_options functions, e.g.:
target_link_options(target PRIVATE -sEXPORTED_FUNCTIONS=['_main','_foo','_bar'])
add_definitions
as it's affecting all targets, thetarget_compile_flags
as suggested above is preferable. Also, according to Emscripten QA:EMSCRIPTEN_KEEPALIVE also exports the function, as if it were on EXPORTED_FUNCTIONS.
– Cardon