fix building C
This commit is contained in:
2
build.ce
2
build.ce
@@ -106,7 +106,7 @@ if (target_package) {
|
||||
_build = function() {
|
||||
lib = build.build_dynamic(target_package, target, buildtype)
|
||||
if (lib) {
|
||||
log.console('Built: ' + lib)
|
||||
log.console(`Built ${text(length(lib))} module(s)`)
|
||||
}
|
||||
} disruption {
|
||||
log.error('Build failed')
|
||||
|
||||
47
build.cm
47
build.cm
@@ -105,22 +105,23 @@ Build.compile_file = function(pkg, file, target, buildtype) {
|
||||
var _buildtype = buildtype || 'release'
|
||||
var pkg_dir = shop.get_package_dir(pkg)
|
||||
var src_path = pkg_dir + '/' + file
|
||||
var core_dir = null
|
||||
|
||||
if (!fd.is_file(src_path)) {
|
||||
print('Source file not found: ' + src_path); disrupt
|
||||
}
|
||||
|
||||
|
||||
// Get flags (with sigil replacement)
|
||||
var cflags = replace_sigils_array(pkg_tools.get_flags(pkg, 'CFLAGS', target))
|
||||
var target_cflags = toolchains[target].c_args || []
|
||||
var cc = toolchains[target].c
|
||||
|
||||
|
||||
// Symbol name for this file
|
||||
var sym_name = shop.c_symbol_for_file(pkg, file)
|
||||
|
||||
|
||||
// Build command
|
||||
var cmd_parts = [cc, '-c', '-fPIC']
|
||||
|
||||
|
||||
// Add buildtype-specific flags
|
||||
if (_buildtype == 'release') {
|
||||
cmd_parts = array(cmd_parts, ['-O3', '-DNDEBUG'])
|
||||
@@ -129,10 +130,16 @@ Build.compile_file = function(pkg, file, target, buildtype) {
|
||||
} else if (_buildtype == 'minsize') {
|
||||
cmd_parts = array(cmd_parts, ['-Os', '-DNDEBUG'])
|
||||
}
|
||||
|
||||
|
||||
push(cmd_parts, '-DCELL_USE_NAME=' + sym_name)
|
||||
push(cmd_parts, '-I"' + pkg_dir + '"')
|
||||
|
||||
|
||||
// External packages need core's source dir for cell.h, quickjs.h, blob.h
|
||||
if (pkg != 'core') {
|
||||
core_dir = shop.get_package_dir('core')
|
||||
push(cmd_parts, '-I"' + core_dir + '/source"')
|
||||
}
|
||||
|
||||
// Add package CFLAGS (resolve relative -I paths)
|
||||
arrfor(cflags, function(flag) {
|
||||
var f = flag
|
||||
@@ -221,9 +228,11 @@ function compute_link_key(objects, ldflags, target_ldflags, opts) {
|
||||
|
||||
// Build a per-module dynamic library for a single C file
|
||||
// Returns the content-addressed dylib path in .cell/build/<hash>.<target>.dylib
|
||||
Build.build_module_dylib = function(pkg, file, target, buildtype) {
|
||||
Build.build_module_dylib = function(pkg, file, target, opts) {
|
||||
var _opts = opts || {}
|
||||
var _target = target || Build.detect_host_target()
|
||||
var _buildtype = buildtype || 'release'
|
||||
var _buildtype = _opts.buildtype || 'release'
|
||||
var _extra = _opts.extra_objects || []
|
||||
var obj = Build.compile_file(pkg, file, _target, _buildtype)
|
||||
|
||||
var tc = toolchains[_target]
|
||||
@@ -244,8 +253,10 @@ Build.build_module_dylib = function(pkg, file, target, buildtype) {
|
||||
push(resolved_ldflags, f)
|
||||
})
|
||||
|
||||
// Content-addressed output: hash of (object + link flags + target)
|
||||
var link_key = compute_link_key([obj], resolved_ldflags, target_ldflags, {target: _target, cc: cc})
|
||||
// Content-addressed output: hash of (all objects + link flags + target)
|
||||
var all_objects = [obj]
|
||||
all_objects = array(all_objects, _extra)
|
||||
var link_key = compute_link_key(all_objects, resolved_ldflags, target_ldflags, {target: _target, cc: cc})
|
||||
var build_dir = get_build_dir()
|
||||
ensure_dir(build_dir)
|
||||
var dylib_path = build_dir + '/' + link_key + '.' + _target + dylib_ext
|
||||
@@ -275,6 +286,9 @@ Build.build_module_dylib = function(pkg, file, target, buildtype) {
|
||||
|
||||
push(cmd_parts, '-L"' + local_dir + '"')
|
||||
push(cmd_parts, '"' + obj + '"')
|
||||
arrfor(_extra, function(extra_obj) {
|
||||
push(cmd_parts, '"' + extra_obj + '"')
|
||||
})
|
||||
cmd_parts = array(cmd_parts, resolved_ldflags)
|
||||
cmd_parts = array(cmd_parts, target_ldflags)
|
||||
push(cmd_parts, '-o')
|
||||
@@ -288,7 +302,10 @@ Build.build_module_dylib = function(pkg, file, target, buildtype) {
|
||||
}
|
||||
|
||||
// Install to deterministic lib/<pkg>/<stem>.dylib
|
||||
// Strip .c/.cpp extension so the loader can find it by module name
|
||||
var file_stem = file
|
||||
if (ends_with(file_stem, '.cpp')) file_stem = text(file_stem, 0, -4)
|
||||
else if (ends_with(file_stem, '.c')) file_stem = text(file_stem, 0, -2)
|
||||
var install_dir = shop.get_lib_dir() + '/' + shop.lib_name_for_package(pkg)
|
||||
var stem_dir = fd.dirname(file_stem)
|
||||
if (stem_dir && stem_dir != '.') {
|
||||
@@ -310,9 +327,17 @@ Build.build_dynamic = function(pkg, target, buildtype) {
|
||||
var c_files = pkg_tools.get_c_files(pkg, _target, true)
|
||||
var results = []
|
||||
|
||||
// Compile support sources to cached objects
|
||||
var sources = pkg_tools.get_sources(pkg)
|
||||
var support_objects = []
|
||||
arrfor(sources, function(src_file) {
|
||||
var obj = Build.compile_file(pkg, src_file, _target, _buildtype)
|
||||
push(support_objects, obj)
|
||||
})
|
||||
|
||||
arrfor(c_files, function(file) {
|
||||
var sym_name = shop.c_symbol_for_file(pkg, file)
|
||||
var dylib = Build.build_module_dylib(pkg, file, _target, _buildtype)
|
||||
var dylib = Build.build_module_dylib(pkg, file, _target, {buildtype: _buildtype, extra_objects: support_objects})
|
||||
push(results, {file: file, symbol: sym_name, dylib: dylib})
|
||||
})
|
||||
|
||||
|
||||
@@ -244,6 +244,20 @@ audio_emscripten.c # Web/Emscripten
|
||||
|
||||
ƿit selects the appropriate file based on the target platform.
|
||||
|
||||
## Multi-File C Modules
|
||||
|
||||
If your module wraps a C library, place the library's source files in a `src/` directory. Files in `src/` are compiled as support objects and linked into your module's dylib — they are not treated as standalone modules.
|
||||
|
||||
```
|
||||
mypackage/
|
||||
rtree.c # module (exports js_mypackage_rtree_use)
|
||||
src/
|
||||
rtree.c # support file (linked into rtree.dylib)
|
||||
rtree.h # header
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
## Static Declarations
|
||||
|
||||
Keep internal functions and variables `static`:
|
||||
|
||||
@@ -713,14 +713,14 @@ function make_c_symbol(pkg, file) {
|
||||
return 'js_' + pkg_id + '_' + file_safe + '_use'
|
||||
}
|
||||
|
||||
// Get the deterministic dylib path for a module in lib/<pkg>/<stem>.dylib
|
||||
// Get the deterministic dylib path for a module in lib/<pkg_id>/<stem>.dylib
|
||||
function get_dylib_path(pkg, stem) {
|
||||
return global_shop_path + '/lib/' + safe_package_path(pkg) + '/' + stem + dylib_ext
|
||||
return global_shop_path + '/lib/' + get_package_id(pkg) + '/' + stem + dylib_ext
|
||||
}
|
||||
|
||||
// Get the deterministic mach path for a module in lib/<pkg>/<stem>.mach
|
||||
// Get the deterministic mach path for a module in lib/<pkg_id>/<stem>.mach
|
||||
function get_mach_path(pkg, stem) {
|
||||
return global_shop_path + '/lib/' + safe_package_path(pkg) + '/' + stem + '.mach'
|
||||
return global_shop_path + '/lib/' + get_package_id(pkg) + '/' + stem + '.mach'
|
||||
}
|
||||
|
||||
// Open a per-module dylib and return the dlopen handle
|
||||
|
||||
18
package.cm
18
package.cm
@@ -379,10 +379,26 @@ package.get_c_files = function(name, target, exclude_main) {
|
||||
push(result, selected)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
// Exclude src/ files (support files, not modules)
|
||||
var sources = package.get_sources(name)
|
||||
if (length(sources) > 0) {
|
||||
result = filter(result, function(f) {
|
||||
return find(sources, function(s) { return s == f }) == null
|
||||
})
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Get support source files: C files in src/ directories (not modules)
|
||||
package.get_sources = function(name) {
|
||||
var files = package.list_files(name)
|
||||
return filter(files, function(f) {
|
||||
return (ends_with(f, '.c') || ends_with(f, '.cpp')) && starts_with(f, 'src/')
|
||||
})
|
||||
}
|
||||
|
||||
// Get the absolute path for a package
|
||||
package.get_dir = function(name) {
|
||||
return get_path(name)
|
||||
|
||||
Reference in New Issue
Block a user