emscripten icon indicating copy to clipboard operation
emscripten copied to clipboard

How do I get emcc to `make_js_executable` when using CMake?

Open david-fong opened this issue 1 month ago • 4 comments

I'm building an executable target with CMake. It produces a JS file, and I'd like there to be a NodeJS shebang line added, and execute permissions to be set.

I see that em++ wraps em++.py, which wraps emcc.py, which uses link.py, and in link.py, I see https://github.com/emscripten-core/emscripten/blob/main/tools/link.py#L478-L483, in make_js_executable(), which adds a shebang and tries to chmod. This is what I want, but it's not happening.

I see that make_js_executable is only called if options.executable. The only place I see that sets options.executable is https://github.com/emscripten-core/emscripten/blob/main/tools/link.py#L720-L721, which conditions upon os.environ.get('EMMAKEN_JUST_CONFIGURE') or 'conftest.c' in options.input_files or 'conftest.cpp' in options.input_files. I don't know what EMMAKEN_JUST_CONFIGURE is, but I only see it set in emconfigure.py, and that doesn't sound relevant to me as I'm using CMake (I run cmake and pass the Emscripten.cmake toolchain file instead of emcmake, but from skimming emcmake.py, that seems fine). I see EmccOptions::executable is initialized to False in https://github.com/emscripten-core/emscripten/blob/main/tools/cmdline.py#L55-L63. I tried adding --emscripten or LINKER:--emscripten in target_link_options, but that didn't seem to make a difference (I was just wild-guessing that that would get what I want).

How do I get what I'm looking for? Is it possible?

I feel like this should just be handled for me by the Emscripten.cmake toolchain file or something. I'm guessing it wouldn't be needed when the target is --no-entry or a side module. I don't know how a toolchain would condition upon those things though. add_link_options("$<$<IN_LIST:--no-entry,$<TARGET_PROPERTY:LINK_OPTIONS>>:--executable-or-whatever-flag-does-the-thing>") seems to be invalid due to self-reference. Maybe I'm overthinking it and emcc could handle it instead of Emscripten.cmake. That sounds easier.

This doesn't actually affect me that much, but it would be nice for quality of life. To elaborate, my project is mainly a library. In terms of executables, I just have a CLI wrapper for people to play with, but I don't really care about that when building for emscripten because the point of the emscripten build is so users can use the library via JS. So really it would just let me run tests directly from commandline without... typing a couple extra characters at the beginning of the command (i.e. node ). And the case of running through ctest is already covered because the Emscripten.cmake toolchain file very helpfully sets CROSS_COMPILING_EMULATOR.

david-fong avatar Oct 03 '25 22:10 david-fong

We don't currently have any way to enable make_js_executable explicitly. We have considered add one but it doesn't exist today. The only way that gets enabled today is for autoconf support, as you have discovered.

For cmake we have CROSS_COMPILING_EMULATOR as you have discovered.

The main blocker to creating a command line interface to enabled executable if figuring out the ergonomics of option. I supposed something like -sEXECUTABLE might be simplest thing? But this then would not work in windows of course.

Anther alternative would be create separate foo (shell script) and/or foo.bat (batch file on windows) and skip the #! line completely. The #! line has some limitations IIRC.

Another problem with -sEXECUTABLE is what what exactly to put on the #! line? Do we always put node there? What about bun, or other JS engines? Do you put the full path the version of node that emscripten itself uses or do we just expect node to exist in the user's PATH? We might need yet another settings .. or maybe something like -sLAUNCHER=/path/to/node (which could default to the emcc internal node?

sbc100 avatar Oct 03 '25 22:10 sbc100

Good points especially about multiple runtime options and shebang limitations.

I tried to think of something that could make use of the ENVIRONMENT setting or a hypothetical -sSHEBANG setting where the user can choose the shebang, but I don't feel like I came up with anything good.

Thanks for answering my question! Feel free to close this if you don't see a use for this ticket anymore.

david-fong avatar Oct 03 '25 23:10 david-fong

Actually I think we should leave it open since I would like to make this into an options somehow.

sbc100 avatar Oct 03 '25 23:10 sbc100

Another options I was considering is adding the #! line when the output file has no extension at all.

sbc100 avatar Oct 03 '25 23:10 sbc100