Skip to content

Add C preprocessor support to JS libraries. - #1969

Closed
juj wants to merge 1 commit into
emscripten-core:incomingfrom
juj:preprocess_js_library
Closed

juj wants to merge 1 commit into
emscripten-core:incomingfrom
juj:preprocess_js_library

Conversation

@juj

@juj juj commented Jan 3, 2014

Copy link
Copy Markdown
Collaborator

Implement better support for C preprocessing directives. Enables the use of #if <expression with (), &&, ||, <, >, <=, >=, ==, !=, defined()>. Adds support for #define, #undef, #ifdef, #ifndef, #elif, #warning and #error. Does not (yet?) implement support for preprocessor macros, or text substitution outside preprocessor directives with #define. Add unit test.

…use of #if <expression with (), &&, ||, <, >, <=, >=, ==, !=, defined()>. Adds support for #define, #undef, #ifdef, #ifndef, #elif, #warning and #error. Does not (yet?) implement support for preprocessor macros, or text substitution outside preprocessor directives with #define. Add unit test.
@juj

juj commented Jan 3, 2014

Copy link
Copy Markdown
Collaborator Author

There is a bug that previously committed optimizations silently failed due to C preprocessor not working as expected. Lines like https://github.com/kripken/emscripten/blob/master/src/library_gl.js#L4195 were not properly evaluated, which caused the optimizations to fail.

@kripken

kripken commented Jan 4, 2014

Copy link
Copy Markdown
Member

Curious about the motivation here? Just for future use, or something concrete?

@juj

juj commented Jan 4, 2014

Copy link
Copy Markdown
Collaborator Author

In addition to fixing the abovementioned case where things silently failed with #if A && !B, there's a few places in library_gl.js where I want to do #if A || B, but couldn't, and had to do

#if A
code
#endif
#if B
code
#endif

and duplicate the same section of code. I figured you wouldn't let such a PR pass, so decided to first implement better preprocessor support to be able to do that.

Comment thread src/parseTools.js

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not use a regex?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regexes aren't that readable or self-descriptive. I think this is more documentative, plus probably faster as well.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am 99% sure this would be much slower, regexes are JITed extremely efficiently in modern JS engines.

@kripken

kripken commented Jan 5, 2014

Copy link
Copy Markdown
Member

My main concern is that this is a big new chunk of code that makes the core compiler more complex, and we would need to maintain in the future.

So I am strongly inclined to specifically fix the issues you mention of #if A && !B and #if A || B. For example, how about if ran eval on what comes after the #if? (perhaps only if it is not a simple identifier, as an optimization)

@juj

juj commented Jan 7, 2014

Copy link
Copy Markdown
Collaborator Author

I thought about eval(), but then rejected it as a deadend since I don't think it will be easily possible to make it support preprocessor expansion, macros, ..., VA_ARGS or # or ## operators in the future if needed. I also searched if there would be an existing C preprocessing library out there implemented in JS, but could not find anything suitable.

People expect a lot of things from their existing knowledge when they see C preprocessing directives. The current code hardcodes the few cases it supports, and silently fails on the ones it doesn't. I don't think it's mature for the project to take the stance that only those preprocessor directives that our src/library_xx.js happen to use are supported, and incrementally keep hardcoding new cases whenever people report bugs against them (those recent #if 1 and #include x.js for example). I wanted to find the proper abstractions here that would have at least some chance of being future-proof, while trying to keep the code in a manageable size. Another route could be to reuse Clang preprocessor with Clang -E option, which would be a full black box process.

@coolwanglu

Copy link
Copy Markdown
Contributor

I wonder if this could be useful: https://github.com/mozilla/pdf.js/blob/master/external/builder/builder.js#L23
In their case, it's actual JS directives in the C style, you can put anything after #if and the expression will be evaluated using vm.runInNewContext.

I don't believe it could support ## though, but maybe the flexibility makes more sense for JS

@kripken

kripken commented Jan 7, 2014

Copy link
Copy Markdown
Member

That looks like nice code. But with a little refactoring I think ours could do everything they do.

@juj, my concern with your code is the size and complexity, in a part of the compiler I really want to keep as simple as possible. I agree we should not fail silently on things we don't support, once we do that, I think we would be in pretty good shape, and if people ask for more features, we could add them like #include was added.

@juj juj closed this Jan 9, 2014
@juj juj mentioned this pull request Aug 22, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

3 participants