extern for my function that is called from elsewhere

54 views
Skip to first unread message

Rick Block

unread,
Sep 24, 2022, 12:47:45 PM9/24/22
to Closure Compiler Discuss
I'm trying to compile a p5.js program in advanced mode.

I understand I need to include externs for the p5.js functions I'm calling so the compiler does not rename them, and I'm doing this and it works fine.

I also understand I need to let the compiler know that the setup() and draw() functions (and anything else p5 calls) I'm defining are called from elsewhere, so must not be renamed and must not be deleted. I have read everything that I can find about this (including threads in this group) but I am apparently missing something.

Here's a trivial example (I know the p5 externs are not exactly complete, but they're sufficient for this example)

myp5.js:
function setup() {
  createCanvas(400, 400);
}

function draw() {
  background(220);
  square(5,5,100);
}

p5js.externs:
/**
  * @param {number} x
  * @param {number} y
  * @return {undefined}
  */
function createCanvas(x,y) {}

/**
  * @param {number|string} c
  * @return {undefined}
  */
function background(c) {}

/**
  * @param {number} x
  * @param {number} y
  * @param {number} size
  * @return {undefined}
  */
function square(x,y,size) {}

My question is what is the syntax for the externs for the functions I'm defining (setup and draw in this case) that I do not want renamed, and do not want deleted? As far as I can tell it's something like

/**
  * @return {undefined}
  */
function setup() {}

/**
  * @return {undefined}
  */
function draw() {}

but this says only not to rename these functions (and, with these externs I can see the functions are indeed not renamed if I include calls to them). How to I tell the compiler I also want them not to be deleted even though it looks like they're not called?

Nick Cullen

unread,
Sep 26, 2022, 10:32:06 AM9/26/22
to Closure Compiler Discuss
I have pretty much exactly the same question... except in my case it is working for some examples, but recently stopped working for others.

In my case I have a compilation script to compress several PAC files using ADVANCED_OPTIMIZATIONS using the REST API. The compilation script uses a standard "@externs" file which it sends via the js_externs parameter, while the js_code parameter holds the code to be compressed.

This has been working nicely for a set of related PAC files - reducing them to minimal functional code (and it still works for those source files), but for a new (and simple) example, the Closure compiler removes all the code, leaving one of the declared externs (a Global string variable) while deleting the other (the global function FindProxyForURL) which needs to be available to be called from outside the compiled code.

Stanimir Mladenov

unread,
Sep 26, 2022, 2:39:01 PM9/26/22
to Closure Compiler Discuss
If you are creating a library, then you should @export every function that should exist with the same name.

Rick Block

unread,
Sep 26, 2022, 8:47:44 PM9/26/22
to Closure Compiler Discuss
Thanks!

I've added @export in myp5.js for the functions I'm defining, copied base.js from https://github.com/google/closure-library/blob/master/closure/goog/base.js and compile with a command like

java -jar closure-compiler.jar --externs p5js.externs --compilation_level ADVANCED_OPTIMIZATIONS --js base.js --js myp5.js --js_output_file myp5-compiled.js

and all seems good.

Nick Cullen

unread,
Sep 27, 2022, 4:27:15 AM9/27/22
to Closure Compiler Discuss
Where is this documented ? In the documentation I found it specified that the use of @externs would achieve the required persistence and exposure of the names, including examples for function names to be called from uncompiled code.

This guidance offers the use of @externs as both better and preferred, with export suffering from several disadvantages / issues.

Stanimir Mladenov

unread,
Sep 27, 2022, 7:22:28 AM9/27/22
to closure-comp...@googlegroups.com
In the comment @export is a link to
https://github.com/google/closure-compiler/wiki/Annotating-JavaScript-for-the-Closure-Compiler#export-export-sometype.

I am a long time user of the closure ecosystem and the @export was
back then the best way to keep the names stable. Where the externs
would do the same now in a better way is new to me, that I learned
from you.

На вт, 27.09.2022 г. в 11:27 ч. 'Nick Cullen' via Closure Compiler
Discuss <closure-comp...@googlegroups.com> написа:
> --
>
> ---
> You received this message because you are subscribed to the Google Groups "Closure Compiler Discuss" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to closure-compiler-d...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/closure-compiler-discuss/999b80d3-94d3-4f5a-8e90-802e52ede05cn%40googlegroups.com.

Nick Cullen

unread,
Sep 27, 2022, 8:05:55 AM9/27/22
to Closure Compiler Discuss
Thanks for explaining.

I have been working to hone down my example to the minimal point at which it breaks. I THINK it is a bug, that occurs when the Function to be exported becomes simple enough to be 'in-lined' - and the Compiler decides to in-line it ... (and then it is no longer there to be retained as an @externs).

I suspect that 'the bug' is  that we are missing part of a test to say "Must the inlining candidate to be kept for some reason ?" - and the fact that it has to remain so it can be referenced as a a name from other code is not (or no longer) being checked. I wonder if an explicit prohibition on inlining the code would protect it (and as long as it still exists, it is kept as an @externs).

I'm slowly gathering a minimal example (and as simple as I can mange to make it), so that with minimal change - two functionally identical Javascript files fall one either side of the complexity threshold. I guess I have to figure out how to raise it as a Bug once I can gather a solid set of evidence to show it.
Reply all
Reply to author
Forward
0 new messages