21 Commits

Author SHA1 Message Date
anth64 55fcc019e4 chore(CHANGELOG.md): add v1.0.0-pre.2 entry 2026-03-06 22:44:04 +01:00
anth64 5d758c2998 fix(module.c): validate dependencies before calling init in stk_module_load 2026-03-06 22:41:31 +01:00
anth64 2e2c3d5e9e feat: phase 1 complete - dependency system, cascade unload, pending queue (v1.0.0-pre.1) 2026-03-06 22:13:35 +01:00
anth64 6477cde367 feat(module.c, stk.c): implement pending queue and cascade dependency resolution 2026-03-06 07:52:34 +01:00
anth64 4f4ae80a14 test: add test_mod_dep build targets and update test_mod with metadata 2026-03-05 00:10:06 +01:00
anth64 8e9007fdfe refactor(module.c, stk.c): reorder stk_mod_t fields largest to smallest 2026-03-04 23:37:15 +01:00
anth64 6e8df4e0e1 feat(stk.c): add module metadata logging on init, load, reload, and unload 2026-03-04 07:46:29 +01:00
anth64 f4c76f7b5a feat(module.c): log all dependency validation failures before returning error 2026-03-03 23:10:46 +01:00
anth64 5e7b41ab68 feat(module.c): log offending modules on circular dependency detection 2026-03-03 23:03:46 +01:00
anth64 9a4b5ee9ef refactor(stk.h, module.c, stk.c): switch deps to exported array and clean up types
- Move stk_dep_t to public header
- Rename stk_set_module_dependencies_fn to stk_set_module_deps_sym
- Change default deps symbol name from stk_mod_dependencies to stk_mod_deps
- Read deps as direct exported stk_dep_t array instead of function call
- Update sentinel check to .id[0] != '\0'
- Default module version to 0.0.0 if not provided or invalid
- Remove deps_func from union in stk_module_load
2026-03-03 22:53:37 +01:00
anth64 ceb389de0d feat(module.c, stk.c): expose dependency functions and integrate into init and poll
- Make stk_validate_dependencies and stk_topo_sort non static
- Add extern declarations in stk.c
- Run stk_validate_dependencies after module loads in stk_init
- Validation failure is fatal; unload all modules and return error code
- Run stk_topo_sort after validation, sort failure is logged but not fatal
- Add validate_deps label in stk_poll so all load/unload paths run validation
- Add dep error codes to stk_error_string
2026-03-03 22:29:59 +01:00
anth64 6faf33d944 feat(module.c): add topological sort with cycle detection 2026-03-03 22:21:04 +01:00
anth64 46f0f31ed7 feat(module.c): add dependency validation pass 2026-03-03 22:09:24 +01:00
anth64 e48d5f0d5b feat(module.c): add internal version parsing and constraint validation 2026-03-03 21:59:45 +01:00
anth64 dc014292cb refactor(module.c, stk.c): replace parallel arrays with stk_mod_t struct
- Consolidate handles, function pointers, metadata, and deps into single stk_mod_t
- Remove all separate metadata arrays and index mappings
- Simplify init, free, realloc, load, and unload significantly
- stk.c externs reduced to stk_modules and module_count
2026-03-03 21:42:43 +01:00
anth64 cb7c43f8af feat(module.c): add stk_dep_t struct and dependency arrays 2026-03-03 21:23:57 +01:00
anth64 6bddc6a888 refactor(module.c): extract common setter logic into stk_set_fn_name helper 2026-03-03 21:06:37 +01:00
anth64 7d23ddbc11 feat(module.c): add stk_mod_dependencies setter and default symbol name 2026-03-03 20:50:52 +01:00
anth64 9aba1a9ad8 docs(readme): add missing module metadata function documentation 2026-03-02 22:02:39 +01:00
anth64 d344e9bbd3 feat(stk.h): add dependency management defines and callbacks
Add error codes for dependency failures, constraint operators,
and setter for custom dependencies symbol name.
2026-03-02 21:53:58 +01:00
anth64 33de5e981e docs(README): update project status to 0.1.3 2026-02-26 07:37:54 +01:00
10 changed files with 857 additions and 463 deletions
+34 -1
View File
@@ -7,6 +7,36 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## [1.0.0-pre.2] - 2026-03-06
### Fixed
- Module `init` is no longer called if dependencies are not satisfied. The library handle is unloaded and a dep error is returned.
## [1.0.0-pre.1] - 2026-03-06
### Added
- **Dependency System**: Full module dependency declaration and resolution
- Modules declare dependencies via an exported `stk_mod_deps` symbol, no stk headers required in modules, only the memory layout contract must be respected (`{ char[64], char[32] }` sentinel-terminated array)
- Version constraint operators: `=` (exact), `>=` (minimum, default), `^` (compatible — same major, greater or equal minor/patch)
- Version defaults to `0.0.0` if not provided or unparseable
- Dependency validation on `stk_init` and every `stk_poll` cycle
- Topological sort with cycle detection, load and unload ordering enforced
- All dependency failures logged before returning
- **Cascade Unload**: When a module is removed, all dependents cascade unload automatically and are added to the pending queue. Cascades repeat until the loaded set is stable
- **Pending Queue**: Modules that fail dependency validation are deferred. When their dependencies become available they are retried and loaded automatically. Entries are removed if their file is deleted
### Changed
- `stk_set_module_dependencies_fn` renamed to `stk_set_module_deps_sym`. Deps are now an exported array symbol, not a function
- Default deps symbol name changed from `stk_mod_dependencies` to `stk_mod_deps`
- `stk_dep_t` added to public header `stk.h`
- `stk_mod_t` field order changed to largest-to-smallest for correct memory alignment with zero padding waste
- Dependency validation failure during `stk_init` no longer fatal, affected modules are deferred to the pending queue
- Poll cycle now logs the full loaded module list as a single summary after any event that changes the loaded set, instead of logging each module individually
### Notes
- This release marks Phase 1 complete: hot-reloading foundation with dependency management
- Memory layout contract for `stk_mod_deps`: sentinel-terminated array of `{ char[64], char[32] }`. Modules do not need to include `stk.h`, define the struct inline or via your engine's own header as long as the layout matches
## [0.1.3] - 2026-02-25
### Added
@@ -115,7 +145,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Dependency management and versioning not yet implemented
- API is unstable and subject to change in future releases
[Unreleased]: https://github.com/anth64/stk/compare/v0.1.2...HEAD
[Unreleased]: https://github.com/anth64/stk/compare/v1.0.0-pre.2...HEAD
[1.0.0-pre.2]: https://github.com/anth64/stk/compare/v1.0.0-pre.1...v1.0.0-pre.2
[1.0.0-pre.1]: https://github.com/anth64/stk/compare/v0.1.3...v1.0.0-pre.1
[0.1.3]: https://github.com/anth64/stk/releases/tag/v0.1.3
[0.1.2]: https://github.com/anth64/stk/releases/tag/v0.1.2
[0.1.1]: https://github.com/anth64/stk/releases/tag/v0.1.1
[0.1.1]: https://github.com/anth64/stk/releases/tag/v0.1.1
+54 -9
View File
@@ -131,6 +131,42 @@ cc -shared -o my_module.dll my_module.c
Place the compiled module in the `mods/` directory (default), and `stk` will automatically load it and watch for changes.
### Module Metadata
Modules can optionally export metadata functions:
```c
const char *stk_mod_name(void) { return "My Module"; }
const char *stk_mod_version(void) { return "1.2.0"; }
const char *stk_mod_description(void) { return "Does something useful"; }
```
All three are optional. Version defaults to `0.0.0` if not exported or unparseable.
### Declaring Dependencies
Modules declare dependencies via an exported sentinel-terminated array. No stk headers are required in the module. The only requirement is that the memory layout matches: `{ char[64], char[32] }`.
```c
typedef struct {
char id[64];
char version[32];
} dep_t;
dep_t stk_mod_deps[] = {
{ "physics", ">=2.0.0" },
{ "renderer", "^1.0.0" },
{ "", "" } /* sentinel */
};
```
Version constraint operators:
- `=1.0.0` exact match
- `>=2.0.0` minimum version, also the default if no operator is specified
- `^1.0.0` same major, greater or equal minor/patch
If a dependency is removed at runtime, all affected modules are unloaded and queued. When the dependency comes back, they load automatically.
### Configuration
```c
@@ -146,15 +182,18 @@ stk_set_module_init_fn("my_init");
/* Set custom shutdown function name (default: "stk_mod_shutdown") */
stk_set_module_shutdown_fn("my_shutdown");
/* Set function name to get module name */
/* Set function name to get module name (default: "stk_mod_name") */
stk_set_module_name_fn("my_mod_name");
/* Set function name to get module version */
/* Set function name to get module version (default: "stk_mod_version") */
stk_set_module_version_fn("my_mod_version");
/* Set functio name to get module description */
/* Set function name to get module description (default: "stk_mod_description") */
stk_set_module_description_fn("my_mod_description");
/* Set deps array symbol name (default: "stk_mod_deps") */
stk_set_module_deps_sym("my_mod_deps");
/*
* All the above functions must be called before stk_init()
* if the defaults need to be changed.
@@ -177,6 +216,10 @@ stk_init();
- `void stk_set_tmp_dir_name(const char *name)` - Set temp directory name
- `void stk_set_module_init_fn(const char *name)` - Set module init function name
- `void stk_set_module_shutdown_fn(const char *name)` - Set module shutdown function name
- `void stk_set_module_name_fn(const char *name);` - Set module name function name
- `void stk_set_module_version_fn(const char *name);` - Set module version function name
- `void stk_set_module_description_fn(const char *name);` - Set module description function name
- `void stk_set_module_deps_sym(const char *name)` - Set module deps array symbol name (default: `stk_mod_deps`)
#### Logging
- `void stk_set_logging_enabled(unsigned char enabled)` - Enable/disable all logging
@@ -191,9 +234,7 @@ stk_init();
## Project Status
**Current Version:** 0.1.2 (Pre-release)
Fixed Windows compatibility issues.
**Current Version:** 1.0.0-pre.1
### What Works
- Cross-platform module loading and hot-reloading
@@ -201,10 +242,14 @@ Fixed Windows compatibility issues.
- Robust hot-reload even during extremely rapid file changes
- Enhanced logging with levels, timestamps, and filtering
- Runtime-configurable logging behavior
- Optional module metadata (name, version, description)
- Dependency declaration, validation, and versioning
- Cascade unload when dependencies are removed
- Pending queue with automatic retry when deps become available
- Topological sort with cycle detection
### In Progress (Phase 1)
- Module metadata (name, version, description)
- Dependency management and versioning
### Phase 2
- WASM module support
See [CHANGELOG.md](CHANGELOG.md) for detailed release notes.
+15
View File
@@ -6,6 +6,7 @@
/* Buffers */
#define STK_LOG_PREFIX_BUFFER 64
#define STK_MOD_DEP_OPERATOR_BUFFER 3
#define STK_MOD_DESC_BUFFER 256
#define STK_MOD_DIR_BUFFER 256
#define STK_MOD_ID_BUFFER 64
@@ -26,6 +27,9 @@
#define STK_MOD_LIBRARY_LOAD_ERROR 2
#define STK_MOD_SYMBOL_NOT_FOUND_ERROR 3
#define STK_MOD_REALLOC_FAILURE 4
#define STK_MOD_DEP_NOT_FOUND_ERROR 5
#define STK_MOD_DEP_VERSION_MISMATCH_ERROR 6
#define STK_MOD_DEP_CIRCULAR_ERROR 7
/* Platform return codes */
#define STK_PLATFORM_OPERATION_SUCCESS 0
@@ -38,6 +42,11 @@
#define STK_FLAG_INITIALIZED 0x01
#define STK_FLAG_LOGGING_ENABLED 0x02
/* Dependency constraint operators */
#define STK_DEP_MIN 0
#define STK_DEP_EXACT 1
#define STK_DEP_COMPAT 2
#if defined(__linux__) || defined(_WIN32)
#define STK_EVENT_BUFFER 4096
#endif
@@ -62,6 +71,11 @@ typedef enum {
STK_MOD_RELOAD
} stk_module_event_t;
typedef struct {
char id[STK_MOD_ID_BUFFER];
char version[STK_MOD_VERSION_BUFFER];
} stk_dep_t;
unsigned char stk_init(void);
void stk_shutdown(void);
size_t stk_module_count(void);
@@ -74,6 +88,7 @@ void stk_set_logging_enabled(unsigned char enabled);
void stk_set_module_name_fn(const char *name);
void stk_set_module_version_fn(const char *name);
void stk_set_module_description_fn(const char *name);
void stk_set_module_deps_sym(const char *name);
unsigned char stk_is_logging_enabled(void);
#ifdef __cplusplus
+3 -3
View File
@@ -1,9 +1,9 @@
#ifndef STK_VERSION_H
#define STK_VERSION_H
#define STK_VERSION_MAJOR 0
#define STK_VERSION_MINOR 1
#define STK_VERSION_PATCH 3
#define STK_VERSION_MAJOR 1
#define STK_VERSION_MINOR 0
#define STK_VERSION_PATCH 0
#define STK_STRINGIFY_HELPER(x) #x
#define STK_STRINGIFY(x) STK_STRINGIFY_HELPER(x)
+510 -411
View File
File diff suppressed because it is too large Load Diff
+200 -29
View File
@@ -8,11 +8,19 @@
typedef int (*stk_init_mod_func)(void);
typedef void (*stk_shutdown_mod_func)(void);
extern void **stk_handles;
extern stk_init_mod_func *stk_inits;
extern stk_shutdown_mod_func *stk_shutdowns;
extern char (*stk_module_ids)[STK_MOD_ID_BUFFER];
typedef struct {
char desc[STK_MOD_DESC_BUFFER];
char name[STK_MOD_NAME_BUFFER];
char id[STK_MOD_ID_BUFFER];
char version[STK_MOD_VERSION_BUFFER];
void *handle;
stk_init_mod_func init;
stk_shutdown_mod_func shutdown;
stk_dep_t *deps;
size_t dep_count;
} stk_mod_t;
extern stk_mod_t *stk_modules;
extern size_t module_count;
unsigned char stk_flags = STK_FLAG_LOGGING_ENABLED;
@@ -43,6 +51,11 @@ unsigned char stk_module_init_memory(size_t capacity);
unsigned char stk_module_realloc_memory(size_t new_capacity);
void stk_module_unload(size_t index);
void stk_module_unload_all(void);
unsigned char stk_validate_dependencies(size_t count);
unsigned char stk_topo_sort(size_t count, size_t *order);
void stk_pending_add(const char *path);
void stk_pending_remove(const char *id);
size_t stk_pending_retry(void);
static void build_path(char *dest, size_t dest_size, const char *dir,
const char *file)
@@ -64,11 +77,47 @@ static const char *stk_error_string(int error_code)
return "init failure";
case STK_MOD_REALLOC_FAILURE:
return "memory reallocation failed";
case STK_MOD_DEP_NOT_FOUND_ERROR:
return "dependency not found";
case STK_MOD_DEP_VERSION_MISMATCH_ERROR:
return "dependency version mismatch";
case STK_MOD_DEP_CIRCULAR_ERROR:
return "circular dependency detected";
default:
return "unknown error";
}
}
static void stk_log_module(size_t index)
{
const char *name =
stk_modules[index].name[0] ? stk_modules[index].name : NULL;
const char *desc =
stk_modules[index].desc[0] ? stk_modules[index].desc : NULL;
if (name && desc)
stk_log(STK_LOG_INFO, " %s v%s - %s (%s)",
stk_modules[index].id, stk_modules[index].version, desc,
name);
else if (name)
stk_log(STK_LOG_INFO, " %s v%s (%s)", stk_modules[index].id,
stk_modules[index].version, name);
else if (desc)
stk_log(STK_LOG_INFO, " %s v%s - %s", stk_modules[index].id,
stk_modules[index].version, desc);
else
stk_log(STK_LOG_INFO, " %s v%s", stk_modules[index].id,
stk_modules[index].version);
}
static void stk_log_modules(void)
{
size_t i;
stk_log(STK_LOG_INFO, "Loaded modules (%lu):", module_count);
for (i = 0; i < module_count; i++)
stk_log_module(i);
}
unsigned char stk_init(void)
{
char (*files)[STK_PATH_MAX] = NULL;
@@ -76,6 +125,8 @@ unsigned char stk_init(void)
char full_path[STK_PATH_MAX_OS];
char tmp_path[STK_PATH_MAX_OS];
int load_result;
unsigned char dep_result;
size_t *order = NULL;
platform_mkdir(stk_mod_dir);
build_path(stk_tmp_dir, sizeof(stk_tmp_dir), stk_mod_dir, stk_tmp_name);
@@ -127,12 +178,42 @@ unsigned char stk_init(void)
}
}
if (successful_loads < file_count) {
if (successful_loads < file_count)
stk_module_realloc_memory(successful_loads);
}
free(files);
if (module_count == 0)
goto scanned;
dep_result = stk_validate_dependencies(module_count);
if (dep_result != STK_MOD_INIT_SUCCESS) {
size_t j;
char mod_tmp_path[STK_PATH_MAX_OS];
stk_log(STK_LOG_WARN,
"Some modules have unmet dependencies, deferring");
for (j = 0; j < module_count; j++) {
if (stk_modules[j].dep_count > 0) {
build_path(mod_tmp_path, sizeof(mod_tmp_path),
stk_tmp_dir, stk_modules[j].id);
strncat(mod_tmp_path, STK_MODULE_EXT,
sizeof(mod_tmp_path) -
strlen(mod_tmp_path) - 1);
stk_pending_add(mod_tmp_path);
stk_module_unload(j);
}
}
}
order = malloc(module_count * sizeof(size_t));
if (order) {
dep_result = stk_topo_sort(module_count, order);
if (dep_result != STK_MOD_INIT_SUCCESS)
stk_log(STK_LOG_ERROR, "Dependency sort failed: %s",
stk_error_string(dep_result));
free(order);
}
scanned:
watch_handle = platform_directory_watch_start(stk_mod_dir);
if (!watch_handle) {
@@ -143,9 +224,10 @@ scanned:
return STK_INIT_WATCH_ERROR;
}
stk_log(STK_LOG_INFO, "stk v%s initialized! Loaded %lu mod%s from %s/",
STK_VERSION_STRING, module_count, module_count != 1 ? "s" : "",
stk_mod_dir);
stk_log(STK_LOG_INFO, "stk v%s initialized, watching %s/",
STK_VERSION_STRING, stk_mod_dir);
if (module_count > 0)
stk_log_modules();
stk_flags |= STK_FLAG_INITIALIZED;
return STK_INIT_SUCCESS;
@@ -185,10 +267,27 @@ size_t stk_poll(void)
char mod_id[STK_MOD_ID_BUFFER];
int load_result;
size_t successful_appends = 0;
char (*module_ids)[STK_MOD_ID_BUFFER] = NULL;
unsigned char dep_result;
size_t *order = NULL;
if (module_count > 0) {
module_ids = malloc(module_count * sizeof(*module_ids));
if (module_ids) {
for (i = 0; i < module_count; i++) {
strncpy(module_ids[i], stk_modules[i].id,
STK_MOD_ID_BUFFER - 1);
module_ids[i][STK_MOD_ID_BUFFER - 1] = '\0';
}
}
}
events = platform_directory_watch_check(
watch_handle, &file_list, &file_count, module_ids, module_count);
if (module_ids)
free(module_ids);
events = platform_directory_watch_check(watch_handle, &file_list,
&file_count, stk_module_ids,
module_count);
if (!events)
goto finish_poll;
@@ -248,13 +347,16 @@ size_t stk_poll(void)
handle_grow:
remaining_loads = load_count - unload_count;
new_capacity = module_count + remaining_loads;
if (stk_module_realloc_memory(new_capacity) != STK_MOD_INIT_SUCCESS) {
if (stk_module_realloc_memory(new_capacity) != STK_MOD_INIT_SUCCESS)
goto free_poll;
}
begin_operations:
for (i = 0; i < unload_count; ++i)
for (i = 0; i < unload_count; ++i) {
stk_log(STK_LOG_INFO, "Unloaded module: %s",
stk_modules[unloaded_mod_indices[i]].id);
stk_pending_remove(stk_modules[unloaded_mod_indices[i]].id);
stk_module_unload(unloaded_mod_indices[i]);
}
for (i = 0; i < reload_count; ++i) {
int file_index = reloaded_mod_file_indices[i];
@@ -275,11 +377,10 @@ begin_operations:
}
load_result = stk_module_load(tmp_path, mod_index);
if (load_result != STK_MOD_INIT_SUCCESS) {
if (load_result != STK_MOD_INIT_SUCCESS)
stk_log(STK_LOG_ERROR, "Failed to reload module %s: %s",
file_list[file_index],
stk_error_string(load_result));
}
}
holes_to_fill = (load_count < unload_count) ? load_count : unload_count;
@@ -300,11 +401,10 @@ begin_operations:
}
load_result = stk_module_load(tmp_path, target_index);
if (load_result != STK_MOD_INIT_SUCCESS) {
if (load_result != STK_MOD_INIT_SUCCESS)
stk_log(STK_LOG_ERROR, "Failed to load module %s: %s",
file_list[file_index],
stk_error_string(load_result));
}
}
if (load_count > unload_count)
@@ -313,7 +413,7 @@ begin_operations:
if (unload_count > load_count)
goto trim_arrays;
goto free_poll;
goto validate_deps;
append_modules:
for (; i < load_count; ++i) {
@@ -344,11 +444,10 @@ append_modules:
module_count += successful_appends;
if (successful_appends < (load_count - holes_to_fill)) {
if (successful_appends < (load_count - holes_to_fill))
stk_module_realloc_memory(module_count);
}
goto free_poll;
goto validate_deps;
trim_arrays:
write_pos = unloaded_mod_indices[holes_to_fill];
@@ -358,12 +457,8 @@ trim_arrays:
}
for (read_pos = write_pos + 1; read_pos < module_count; ++read_pos) {
if (stk_handles[read_pos] != NULL) {
stk_handles[write_pos] = stk_handles[read_pos];
stk_inits[write_pos] = stk_inits[read_pos];
stk_shutdowns[write_pos] = stk_shutdowns[read_pos];
memcpy(stk_module_ids[write_pos],
stk_module_ids[read_pos], STK_MOD_ID_BUFFER);
if (stk_modules[read_pos].handle != NULL) {
stk_modules[write_pos] = stk_modules[read_pos];
++write_pos;
}
}
@@ -371,6 +466,82 @@ trim_arrays:
module_count = write_pos;
stk_module_realloc_memory(module_count);
validate_deps:
if (module_count == 0)
goto free_poll;
{
size_t cascade_indices[STK_PATH_MAX];
size_t cascade_count;
char cascade_tmp_path[STK_PATH_MAX_OS];
size_t j, k, cascade_write;
do {
cascade_count = 0;
for (j = 0; j < module_count; j++) {
if (stk_modules[j].dep_count == 0)
continue;
for (k = 0; k < stk_modules[j].dep_count; k++) {
if (is_mod_loaded(
stk_modules[j].deps[k].id) <
0) {
cascade_indices
[cascade_count++] = j;
break;
}
}
}
if (cascade_count == 0)
break;
for (j = 0; j < cascade_count; j++) {
size_t index = cascade_indices[j];
stk_log(STK_LOG_WARN,
"Unloading '%s': unmet dependencies",
stk_modules[index].id);
build_path(cascade_tmp_path,
sizeof(cascade_tmp_path),
stk_tmp_dir, stk_modules[index].id);
strncat(cascade_tmp_path, STK_MODULE_EXT,
sizeof(cascade_tmp_path) -
strlen(cascade_tmp_path) - 1);
stk_pending_add(cascade_tmp_path);
stk_module_unload(index);
}
cascade_write = 0;
for (j = 0; j < module_count; j++) {
if (stk_modules[j].handle != NULL) {
if (cascade_write != j)
stk_modules[cascade_write] =
stk_modules[j];
cascade_write++;
}
}
module_count = cascade_write;
} while (cascade_count > 0);
}
if (module_count > 0)
stk_module_realloc_memory(module_count);
order = malloc(module_count * sizeof(size_t));
if (order) {
dep_result = stk_topo_sort(module_count, order);
if (dep_result != STK_MOD_INIT_SUCCESS)
stk_log(STK_LOG_ERROR, "Dependency sort failed: %s",
stk_error_string(dep_result));
free(order);
}
stk_pending_retry();
if (module_count > 0)
stk_log_modules();
free_poll:
free(reloaded_mod_indices);
free(reloaded_mod_file_indices);
+9 -5
View File
@@ -22,23 +22,27 @@ test_program: test.c
test_mod$(MODULE_EXT): test_mod.c
$(CC) $(CFLAGS) -fPIC -shared -o $@ test_mod.c
test_mod_dep$(MODULE_EXT): test_mod_dep.c
$(CC) $(CFLAGS) -fPIC -shared -o $@ test_mod_dep.c
setup:
@mkdir -p mods
@cp -f test_mod$(MODULE_EXT) mods/ 2>/dev/null || true
@echo "Test environment ready: mods/ directory with test_mod$(MODULE_EXT)"
@cp -f test_mod_dep$(MODULE_EXT) mods/ 2>/dev/null || true
@echo "Test environment ready: mods/ directory with test modules"
run: test_program test_mod$(MODULE_EXT) setup
run: test_program test_mod$(MODULE_EXT) test_mod_dep$(MODULE_EXT) setup
@echo "Running integration test (CTRL+C to exit)..."
@./test_program
test: test_program test_mod$(MODULE_EXT) setup
test: test_program test_mod$(MODULE_EXT) test_mod_dep$(MODULE_EXT) setup
@echo "=== stk Integration Test ==="
@echo "1. Starting test program"
@echo "2. Will load test_mod$(MODULE_EXT) from mods/"
@echo "2. Will load test_mod and test_mod_dep from mods/"
@echo "3. Press CTRL+C to exit"
@echo "============================="
@./test_program || echo "Test completed."
clean:
rm -f test_program test_mod$(MODULE_EXT)
rm -f test_program test_mod$(MODULE_EXT) test_mod_dep$(MODULE_EXT)
rm -rf mods/
+8 -3
View File
@@ -23,16 +23,21 @@ test_program$(EXE_EXT): test.c
test_mod$(MODULE_EXT): test_mod.c
$(CC) $(CFLAGS) -fPIC -shared -o $@ test_mod.c
test_mod_dep$(MODULE_EXT): test_mod_dep.c
$(CC) $(CFLAGS) -fPIC -shared -o $@ test_mod_dep.c
setup:
ifeq ($(OS),Windows_NT)
@if not exist mods mkdir mods
@if exist test_mod.dll copy /Y test_mod.dll mods\ >nul 2>&1
@if exist test_mod_dep.dll copy /Y test_mod_dep.dll mods\ >nul 2>&1
else
@mkdir -p mods
@cp -f test_mod.so mods/ 2>/dev/null || true
@cp -f test_mod_dep.so mods/ 2>/dev/null || true
endif
test: test_program$(EXE_EXT) test_mod$(MODULE_EXT) setup
test: test_program$(EXE_EXT) test_mod$(MODULE_EXT) test_mod_dep$(MODULE_EXT) setup
ifeq ($(OS),Windows_NT)
@set PATH=../bin/debug;%PATH% && cmd /C "test_program.exe"
else
@@ -41,9 +46,9 @@ endif
clean:
ifeq ($(OS),Windows_NT)
@del /Q test_program.exe test_mod.dll 2>nul || true
@del /Q test_program.exe test_mod.dll test_mod_dep.dll 2>nul || true
@rmdir /S /Q mods 2>nul || true
else
@rm -f test_program test_mod.so
@rm -f test_program test_mod.so test_mod_dep.so
@rm -rf mods
endif
+5 -2
View File
@@ -2,8 +2,11 @@
int stk_mod_init(void)
{
printf("test mod initialized!\n");
printf("test_mod initialized!\n");
return 0;
}
void stk_mod_shutdown(void) { printf("test mod shut down.\n"); }
void stk_mod_shutdown(void) { printf("test_mod shut down.\n"); }
const char *stk_mod_name(void) { return "Test Module"; }
const char *stk_mod_version(void) { return "1.0.0"; }
+19
View File
@@ -0,0 +1,19 @@
#include <stdio.h>
typedef struct {
char id[64];
char version[32];
} dep_t;
int stk_mod_init(void)
{
printf("test_mod_dep initialized!\n");
return 0;
}
void stk_mod_shutdown(void) { printf("test_mod_dep shut down.\n"); }
const char *stk_mod_name(void) { return "Dependent Test Module"; }
const char *stk_mod_version(void) { return "1.0.0"; }
dep_t stk_mod_deps[] = {{"test_mod", ">=1.0.0"}, {"", ""}};