fix build
This commit is contained in:
16
build.cm
16
build.cm
@@ -108,7 +108,8 @@ Build.compile_file = function(pkg, file, target, buildtype) {
|
|||||||
var core_dir = null
|
var core_dir = null
|
||||||
|
|
||||||
if (!fd.is_file(src_path)) {
|
if (!fd.is_file(src_path)) {
|
||||||
print('Source file not found: ' + src_path); disrupt
|
print('Source file not found: ' + src_path)
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get flags (with sigil replacement)
|
// Get flags (with sigil replacement)
|
||||||
@@ -177,9 +178,10 @@ Build.compile_file = function(pkg, file, target, buildtype) {
|
|||||||
log.console('Compiling ' + file)
|
log.console('Compiling ' + file)
|
||||||
var ret = os.system(full_cmd)
|
var ret = os.system(full_cmd)
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
print('Compilation failed: ' + file); disrupt
|
print('Compilation failed: ' + file)
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
return obj_path
|
return obj_path
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,6 +236,7 @@ Build.build_module_dylib = function(pkg, file, target, opts) {
|
|||||||
var _buildtype = _opts.buildtype || 'release'
|
var _buildtype = _opts.buildtype || 'release'
|
||||||
var _extra = _opts.extra_objects || []
|
var _extra = _opts.extra_objects || []
|
||||||
var obj = Build.compile_file(pkg, file, _target, _buildtype)
|
var obj = Build.compile_file(pkg, file, _target, _buildtype)
|
||||||
|
if (!obj) return null
|
||||||
|
|
||||||
var tc = toolchains[_target]
|
var tc = toolchains[_target]
|
||||||
var dylib_ext = tc.system == 'windows' ? '.dll' : (tc.system == 'darwin' ? '.dylib' : '.so')
|
var dylib_ext = tc.system == 'windows' ? '.dll' : (tc.system == 'darwin' ? '.dylib' : '.so')
|
||||||
@@ -299,7 +302,8 @@ Build.build_module_dylib = function(pkg, file, target, opts) {
|
|||||||
log.console('Linking module ' + file + ' -> ' + fd.basename(dylib_path))
|
log.console('Linking module ' + file + ' -> ' + fd.basename(dylib_path))
|
||||||
ret = os.system(cmd_str)
|
ret = os.system(cmd_str)
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
print('Linking failed: ' + file); disrupt
|
print('Linking failed: ' + file)
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -340,7 +344,9 @@ Build.build_dynamic = function(pkg, target, buildtype) {
|
|||||||
arrfor(c_files, function(file) {
|
arrfor(c_files, function(file) {
|
||||||
var sym_name = shop.c_symbol_for_file(pkg, file)
|
var sym_name = shop.c_symbol_for_file(pkg, file)
|
||||||
var dylib = Build.build_module_dylib(pkg, file, _target, {buildtype: _buildtype, extra_objects: support_objects})
|
var dylib = Build.build_module_dylib(pkg, file, _target, {buildtype: _buildtype, extra_objects: support_objects})
|
||||||
push(results, {file: file, symbol: sym_name, dylib: dylib})
|
if (dylib) {
|
||||||
|
push(results, {file: file, symbol: sym_name, dylib: dylib})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return results
|
return results
|
||||||
|
|||||||
@@ -187,9 +187,11 @@ JSC_CCALL(vector_normalize,
|
|||||||
double y = js2number(js, argv[1]);
|
double y = js2number(js, argv[1]);
|
||||||
double len = sqrt(x*x + y*y);
|
double len = sqrt(x*x + y*y);
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
JSValue result = JS_NewObject(js);
|
JS_FRAME(js);
|
||||||
|
JS_LOCAL(result, JS_NewObject(js));
|
||||||
JS_SetPropertyStr(js, result, "x", number2js(js, x/len));
|
JS_SetPropertyStr(js, result, "x", number2js(js, x/len));
|
||||||
JS_SetPropertyStr(js, result, "y", number2js(js, y/len));
|
JS_SetPropertyStr(js, result, "y", number2js(js, y/len));
|
||||||
|
JS_RestoreFrame(_js_ctx, _js_gc_frame, _js_local_frame);
|
||||||
ret = result;
|
ret = result;
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -258,6 +260,81 @@ mypackage/
|
|||||||
|
|
||||||
The module file (`rtree.c`) includes the library header and uses `cell.h` as usual. The support files are plain C — they don't need any cell macros.
|
The module file (`rtree.c`) includes the library header and uses `cell.h` as usual. The support files are plain C — they don't need any cell macros.
|
||||||
|
|
||||||
|
## GC Safety
|
||||||
|
|
||||||
|
ƿit uses a Cheney copying garbage collector. Any JS allocation — `JS_NewObject`, `JS_NewString`, `JS_SetPropertyStr`, etc. — can trigger GC, which **moves** heap objects to new addresses. C locals holding JSValue become stale after any allocating call.
|
||||||
|
|
||||||
|
### When you need rooting
|
||||||
|
|
||||||
|
If a function creates **one** heap object and returns it immediately, no rooting is needed:
|
||||||
|
|
||||||
|
```c
|
||||||
|
JSC_CCALL(mymod_name,
|
||||||
|
ret = JS_NewString(js, "hello");
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
If a function holds a heap object across further allocating calls, you must root it:
|
||||||
|
|
||||||
|
```c
|
||||||
|
JSC_CCALL(vector_normalize,
|
||||||
|
double x = js2number(js, argv[0]);
|
||||||
|
double y = js2number(js, argv[1]);
|
||||||
|
double len = sqrt(x*x + y*y);
|
||||||
|
if (len > 0) {
|
||||||
|
JS_FRAME(js);
|
||||||
|
JS_LOCAL(result, JS_NewObject(js));
|
||||||
|
// result is rooted — GC can update it through these calls:
|
||||||
|
JS_SetPropertyStr(js, result, "x", number2js(js, x/len));
|
||||||
|
JS_SetPropertyStr(js, result, "y", number2js(js, y/len));
|
||||||
|
JS_RestoreFrame(_js_ctx, _js_gc_frame, _js_local_frame);
|
||||||
|
ret = result;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Macros
|
||||||
|
|
||||||
|
| Macro | Purpose |
|
||||||
|
|-------|---------|
|
||||||
|
| `JS_FRAME(js)` | Save the GC and local frames. Required before any `JS_LOCAL`. |
|
||||||
|
| `JS_LOCAL(name, init)` | Declare and root a JSValue. GC updates it through its address. |
|
||||||
|
| `JS_RETURN(val)` | Restore the frame and return a value. |
|
||||||
|
| `JS_RETURN_NULL()` | Restore the frame and return `JS_NULL`. |
|
||||||
|
| `JS_RETURN_EX()` | Restore the frame and return `JS_EXCEPTION`. |
|
||||||
|
| `JS_RestoreFrame(...)` | Manual frame restore (for `JSC_CCALL` bodies that use `ret =`). |
|
||||||
|
|
||||||
|
### Rules of thumb
|
||||||
|
|
||||||
|
1. **One allocation, immediate return** — no rooting needed.
|
||||||
|
2. **Object + property sets** — root the object with `JS_LOCAL`.
|
||||||
|
3. **Array + loop** — root the array; if loop body creates objects, root the loop variable too with a manual `JSLocalRef`.
|
||||||
|
4. **`CELL_USE_INIT` bodies** — always use `JS_FRAME` / `JS_LOCAL` / `JS_RETURN`.
|
||||||
|
|
||||||
|
### Migrating from gc_mark
|
||||||
|
|
||||||
|
The old mark-and-sweep GC had a `gc_mark` callback in `JSClassDef` for C structs that held JSValue fields. This no longer exists. The copying GC needs to know the **address** of every pointer to update it when objects move.
|
||||||
|
|
||||||
|
If your C struct holds a JSValue that must survive across GC points, root it for the duration it's alive:
|
||||||
|
|
||||||
|
```c
|
||||||
|
typedef struct {
|
||||||
|
JSValue callback;
|
||||||
|
JSLocalRef callback_lr;
|
||||||
|
} MyWidget;
|
||||||
|
|
||||||
|
// When storing:
|
||||||
|
widget->callback = value;
|
||||||
|
widget->callback_lr.ptr = &widget->callback;
|
||||||
|
JS_PushLocalRef(js, &widget->callback_lr);
|
||||||
|
|
||||||
|
// When done (before freeing the struct):
|
||||||
|
// The local ref is cleaned up when the frame is restored,
|
||||||
|
// or manage it manually.
|
||||||
|
```
|
||||||
|
|
||||||
|
In practice, most C wrappers hold only opaque C pointers (like `SDL_Window*`) and never store JSValues in the struct — these need no migration.
|
||||||
|
|
||||||
## Static Declarations
|
## Static Declarations
|
||||||
|
|
||||||
Keep internal functions and variables `static`:
|
Keep internal functions and variables `static`:
|
||||||
|
|||||||
@@ -100,7 +100,6 @@ TYPE##_free(rt,n);}\
|
|||||||
static JSClassDef js_##TYPE##_class = {\
|
static JSClassDef js_##TYPE##_class = {\
|
||||||
.class_name = #TYPE,\
|
.class_name = #TYPE,\
|
||||||
.finalizer = js_##TYPE##_finalizer,\
|
.finalizer = js_##TYPE##_finalizer,\
|
||||||
.gc_mark = js_##TYPE##_mark,\
|
|
||||||
};\
|
};\
|
||||||
TYPE *js2##TYPE (JSContext *js, JSValue val) { \
|
TYPE *js2##TYPE (JSContext *js, JSValue val) { \
|
||||||
if (JS_GetClassID(val) != js_##TYPE##_id) return NULL; \
|
if (JS_GetClassID(val) != js_##TYPE##_id) return NULL; \
|
||||||
@@ -120,7 +119,6 @@ TYPE##_free(rt,n);}\
|
|||||||
static JSClassDef js_##TYPE##_class = {\
|
static JSClassDef js_##TYPE##_class = {\
|
||||||
.class_name = #TYPE,\
|
.class_name = #TYPE,\
|
||||||
.finalizer = js_##TYPE##_finalizer,\
|
.finalizer = js_##TYPE##_finalizer,\
|
||||||
.gc_mark = js_##TYPE##_mark,\
|
|
||||||
};\
|
};\
|
||||||
extern JSClassID js_##TYPE##_id;\
|
extern JSClassID js_##TYPE##_id;\
|
||||||
TYPE *js2##TYPE (JSContext *js, JSValue val) { \
|
TYPE *js2##TYPE (JSContext *js, JSValue val) { \
|
||||||
@@ -231,9 +229,10 @@ JSValue CELL_USE_NAME(JSContext *js) { do { c ; } while(0); }
|
|||||||
|
|
||||||
#define CELL_USE_FUNCS(FUNCS) \
|
#define CELL_USE_FUNCS(FUNCS) \
|
||||||
JSValue CELL_USE_NAME(JSContext *js) { \
|
JSValue CELL_USE_NAME(JSContext *js) { \
|
||||||
JSValue mod = JS_NewObject(js); \
|
JS_FRAME(js); \
|
||||||
|
JS_LOCAL(mod, JS_NewObject(js)); \
|
||||||
JS_SetPropertyFunctionList(js, mod, FUNCS, countof(FUNCS)); \
|
JS_SetPropertyFunctionList(js, mod, FUNCS, countof(FUNCS)); \
|
||||||
return mod; }
|
JS_RETURN(mod); }
|
||||||
|
|
||||||
#define CELL_PROGRAM_INIT(c) \
|
#define CELL_PROGRAM_INIT(c) \
|
||||||
JSValue CELL_USE_NAME(JSContext *js) { do { c ; } while(0); }
|
JSValue CELL_USE_NAME(JSContext *js) { do { c ; } while(0); }
|
||||||
|
|||||||
Reference in New Issue
Block a user