module: Re-implement using library constructors/destructors (#2018)

By using constructors/destructors we unify the case of static linking with
that of dynamic linking, and we reuse the build flag FEATURE_INIT_FINI. Using
constructors/destructors also allows us to cover the case where library
constructor/destructor functionality is unavailable, because we can expose the
module registration/unregistration functions as global symbols, to be called
explicitly from within the application.

Fixes https://github.com/jerryscript-project/jerryscript/issues/1952

JerryScript-DCO-1.0-Signed-off-by: Gabriel Schulhof gabriel.schulhof@intel.com
This commit is contained in:
Gabriel "_|Nix|_" Schulhof
2017-09-22 13:35:38 +03:00
committed by Zoltan Herczeg
parent 8d916a44f1
commit 81952f3cd0
11 changed files with 172 additions and 124 deletions
+55 -20
View File
@@ -13,14 +13,10 @@ type of module is requested.
Additionally, this extension provides a means of easily defining so-called "native" JerryScript modules which can be
resolved using the JerryScript native module resolver `jerryx_module_native_resolver()`, which can be passed to
`jerryx_module_resolve()`. Note, however, that native JerryScript modules are only supported and
`jerryx_module_native_resolver()` is only compiled in if compiler support for `__attribute__` extensions is present. In
effect this means that native JerryScript modules are available only when this extension is built with GCC or
LLVM/clang. In the absence of such support, you may construct alternative module systems and provide your own resolver
to `jerryx_module_resolve()`.
`jerryscript-ext/module.h` defines the preprocessor directive `JERRYX_NATIVE_MODULES_SUPPORTED` only if support for
native JerryScript modules is available.
`jerryx_module_resolve()`. Native modules are registered during application startup and by calling `dlopen()` by means
of library constructors, support for which can be turned on using the `FEATURE_INIT_FINI` build flag. In the absence of
such a flag, the module registration and unregistration functions are exposed as global symbols which can be called
explicitly.
## jerryx_module_resolve
@@ -52,9 +48,8 @@ jerryx_module_resolve (const jerry_char_t *name,
**Summary**
The resolver for JerryScript modules. A pointer to this function can be passed in the second parameter to
`jerryx_module_resolve` to search for the module among the JerryScript modules built into the binary. This function is
available only if the preprocessor directive `JERRYX_NATIVE_MODULES_SUPPORTED` is defined.
The resolver for native JerryScript modules. A pointer to this function can be passed in the second parameter to
`jerryx_module_resolve` to search for the module among the native JerryScript modules loaded so far.
**Prototype**
@@ -74,8 +69,7 @@ jerryx_module_native_resolver (const jerry_char_t *name,
**Summary**
Function pointer type for a function that will create an instance of a native module. This type is only defined if the
preprocessor directive `JERRYX_NATIVE_MODULES_SUPPORTED` is defined.
Function pointer type for a function that will create an instance of a native module.
**Prototype**
@@ -136,12 +130,15 @@ We can now load JavaScript files:
```c
static const jerryx_module_resolver_t resolvers[] =
{
/* Consult the JerryScript module resolver first, in case the requested module is a compiled-in JerryScript module. */
/*
* Consult the JerryScript native module resolver first, in case the requested module is a native JerryScript
* module.
*/
jerryx_module_native_resolver,
/*
* If the requested module is not a JerryScript module, assume it is a JavaScript file on disk and use the above-
* defined JavaScript file loader to load it.
* If the requested module is not a native JerryScript module, assume it is a JavaScript file on disk and use the
* above-defined JavaScript file loader to load it.
*/
load_and_evaluate_js_file
};
@@ -154,9 +151,11 @@ jerry_value_t js_module = jerryx_module_resolve (requested_module, resolvers, 2)
**Summary**
Helper macro to define a JerryScript module. Currently stores the name of the module and its initializer in an
executable linker section. This macro is available only if the preprocessor directive `JERRYX_NATIVE_MODULES_SUPPORTED`
is defined.
Helper macro to define a native JerryScript module. Currently declares a global static structure of type
`jerryx_native_module_t` and a constructor/destructor pair that calls `jerryx_native_module_register()` resp.
`jerryx_native_module_unregister()`. If the extension is built without the FEATURE_INIT_FINI flag, indicating that
support for library constructors and destructors is absent, the constructor and destructor are declared as global
symbols so that they may be called explicitly from within the application.
**Note**: The helper macro must appear at the bottom of a source file, and no semicolon must follow it.
@@ -165,7 +164,8 @@ is defined.
#define JERRYX_NATIVE_MODULE(module_name, on_resolve_cb)
```
- `module_name` - the name of the module without quotes
- `module_name` - the name of the module without quotes. This value is used as the prefix for the registration and unregistration funtions. For example, when `module_name` is `example_module`, this results in the declaration of two functions `example_module_register()` and `example_module_unregister()`. These functions are declared global if support for library constructors/destructors is absent, allowing you to call them from other parts of the code by
first forward-declaring them.
- `on_resolve_cb` - the function of type `jerryx_native_module_on_resolve_t` that will be called when the module needs to be
loaded.
@@ -184,3 +184,38 @@ my_module_on_resolve (void)
/* Note that there is no semicolon at the end of the next line. This is how it must be. */
JERRYX_NATIVE_MODULE (my_module, my_module_on_resolve)
```
**Example Usage When Library Constructors Are Unavailable**
```c
#include "jerryscript.h"
#include "jerryscript-ext/module.h"
/**
* Forward-declare the module registration and unregistration function.
*/
extern void my_module_register (void);
extern void my_module_unregister (void);
int
main (int argc, char **argv)
{
jerryx_module_resolver_t resolvers[] =
{
jerryx_native_module_resolver
};
/* This plays the role of the library constructor. */
my_module_register ();
jerry_init (JERRY_INIT_EMPTY);
...
jerry_value_t my_module = jerryx_module_resolve ("my_module", resolvers, 1);
...
jerry_cleanup ();
/* This plays the role of the library destructor */
my_module_unregister();
return 0;
}
```