diff --git a/CMakeLists.txt b/CMakeLists.txt index d771b73..b78ff66 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake) set_property(GLOBAL PROPERTY USE_FOLDERS ON) set(fx_all_assemblies - fx + fx.runtime fx.collections) if (NOT DEFINED fx_assemblies) @@ -36,6 +36,19 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin) -foreach (assembly ${fx_assemblies}) - add_subdirectory(${assembly}) -endforeach (assembly) +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/Templates.cmake) + +if ("fx.runtime" IN_LIST fx_assemblies) + add_fx_assembly( + NAME fx.runtime + NAMESPACES fx fx.reflection) +endif () + +if ("fx.collections" IN_LIST fx_assemblies) + add_fx_assembly( + NAME fx.collections + NAMESPACES fx.collections + DEPENDENCIES fx.runtime) +endif () + +add_executable(dynamic-test test/dynamic-test.c) diff --git a/assemblies/fx.collections.c b/assemblies/fx.collections.c new file mode 100644 index 0000000..d94f636 --- /dev/null +++ b/assemblies/fx.collections.c @@ -0,0 +1,14 @@ +#include +#include + +FX_ASSEMBLY_BEGIN() + FX_ASSEMBLY_NAME("fx.collections"); + FX_ASSEMBLY_VERSION(1, 0, 0, 0); + FX_ASSEMBLY_EXPORT_TYPE("fx.collections", "array", fx_array); + FX_ASSEMBLY_EXPORT_TYPE("fx.collections", "bitbuffer", fx_bitbuffer); + FX_ASSEMBLY_EXPORT_TYPE("fx.collections", "bitmap", fx_bitmap); + FX_ASSEMBLY_EXPORT_TYPE("fx.collections", "dict", fx_dict); + FX_ASSEMBLY_EXPORT_TYPE("fx.collections", "hashmap", fx_hashmap); + FX_ASSEMBLY_EXPORT_TYPE("fx.collections", "list", fx_list); + FX_ASSEMBLY_EXPORT_TYPE("fx.collections", "tree", fx_tree); +FX_ASSEMBLY_END() diff --git a/assemblies/fx.runtime.c b/assemblies/fx.runtime.c new file mode 100644 index 0000000..664289c --- /dev/null +++ b/assemblies/fx.runtime.c @@ -0,0 +1,12 @@ +#include +#include + +FX_ASSEMBLY_BEGIN() + FX_ASSEMBLY_NAME("fx.runtime"); + FX_ASSEMBLY_VERSION(1, 0, 0, 0); + FX_ASSEMBLY_EXPORT_TYPE("fx", "stream", fx_stream); + FX_ASSEMBLY_EXPORT_TYPE("fx", "string", fx_string); + FX_ASSEMBLY_EXPORT_TYPE("fx", "stringstream", fx_stringstream); + FX_ASSEMBLY_EXPORT_TYPE("fx", "iterator", fx_iterator); + FX_ASSEMBLY_EXPORT_TYPE("fx.reflection", "assembly", fx_assembly); +FX_ASSEMBLY_END() diff --git a/cmake/Templates.cmake b/cmake/Templates.cmake index 49e2b76..199457b 100644 --- a/cmake/Templates.cmake +++ b/cmake/Templates.cmake @@ -2,12 +2,9 @@ function(add_fx_assembly) set(options) set(one_value_args NAME) set(multi_value_args + NAMESPACES DEPENDENCIES - SUBDIRS - EXTRA_SOURCES - LIBS - INCLUDE_DIRS - DEFINES) + LIBS) cmake_parse_arguments(PARSE_ARGV 0 arg "${options}" "${one_value_args}" @@ -19,28 +16,23 @@ function(add_fx_assembly) string(REPLACE "." "_" assembly_token ${assembly_name}) string(TOUPPER ${assembly_token} assembly_token) - file(GLOB sources *.c *.h) + set(assembly_include_paths "") + set(assembly_sources + ${CMAKE_CURRENT_SOURCE_DIR}/assemblies/${assembly_name}.c) - foreach (dir ${arg_SUBDIRS}) - file(GLOB dir_sources ${dir}/*.c ${dir}/*.h) - set(sources ${sources} ${dir_sources}) + foreach (dir ${arg_NAMESPACES}) + add_subdirectory(${dir}) + set(assembly_sources ${assembly_sources} ${namespace_sources}) + set(assembly_include_paths ${assembly_include_paths} ${namespace_include_paths}) endforeach (dir) - file(GLOB sys_sources sys/${fx_system_name}/*.c sys/${fx_system_name}/*.h) - file(GLOB headers include/${assembly_path}/*.h) - message(STATUS "Building assembly ${assembly_name}") add_library(${assembly_target_name} SHARED - ${sources} - ${sys_sources} - ${root_header} - ${headers} - ${arg_EXTRA_SOURCES}) + ${assembly_sources}) - target_include_directories(${assembly_target_name} PUBLIC include/) + target_include_directories(${assembly_target_name} PUBLIC ${assembly_include_paths}) target_compile_definitions(${assembly_target_name} PUBLIC - ${assembly_token} FX_EXPORT=1 FX_ENABLE_FLOATING_POINT=${fx_enable_floating_point}) @@ -48,8 +40,7 @@ function(add_fx_assembly) PROPERTIES POSITION_INDEPENDENT_CODE ON) foreach (dep ${arg_DEPENDENCIES}) - string(REPLACE "." "-" dep_target_name ${dep}) - target_link_libraries(${assembly_target_name} ${dep_target_name}) + target_link_libraries(${assembly_target_name} ${dep}) endforeach (dep) foreach (lib ${arg_LIBS}) @@ -79,3 +70,31 @@ function(add_fx_assembly) install(TARGETS ${assembly_target_name}) install(FILES ${headers} DESTINATION include/${assembly_path}) endfunction(add_fx_assembly) + +macro(export_fx_namespace_details) + set(options) + set(one_value_args NAME) + set(multi_value_args) + cmake_parse_arguments(PARSE_ARGV 0 arg + "${options}" + "${one_value_args}" + "${multi_value_args}") + + set(namespace_name ${arg_NAME}) + string(REPLACE "." "/" namespace_path ${namespace_name}) + set(namespace_target_name ${namespace_name}) + + set(namespace_include_paths ${CMAKE_CURRENT_SOURCE_DIR}/include PARENT_SCOPE) + + file(GLOB namespace_sources + *.c *.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/${namespace_path}/*.h) + file(GLOB sys_sources sys/${fx_system_name}/*.c sys/${fx_system_name}/*.h) + file(GLOB headers include/${namespace_path}/*.h) + set(namespace_sources + ${namespace_sources} + ${sys_sources} + ${headers} + PARENT_SCOPE) +endmacro(export_fx_namespace_details) + diff --git a/fx.collections/CMakeLists.txt b/fx.collections/CMakeLists.txt index 6afe017..e7d34d5 100644 --- a/fx.collections/CMakeLists.txt +++ b/fx.collections/CMakeLists.txt @@ -1,5 +1,2 @@ -include(../cmake/Templates.cmake) - -add_fx_assembly( - NAME fx.collections - DEPENDENCIES fx) +export_fx_namespace_details( + NAME fx.collections) diff --git a/fx.reflection/CMakeLists.txt b/fx.reflection/CMakeLists.txt new file mode 100644 index 0000000..361da43 --- /dev/null +++ b/fx.reflection/CMakeLists.txt @@ -0,0 +1,6 @@ +set(namespace_include_paths ${CMAKE_CURRENT_SOURCE_DIR}/include PARENT_SCOPE) + +file(GLOB namespace_sources + *.c *.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/fx/reflection/*.h) +set(namespace_sources ${namespace_sources} PARENT_SCOPE) diff --git a/fx.reflection/assembly.c b/fx.reflection/assembly.c new file mode 100644 index 0000000..034b313 --- /dev/null +++ b/fx.reflection/assembly.c @@ -0,0 +1,264 @@ +#include +#include +#include +#include +#include + +enum map_entry_type { + MAP_ENTRY_NONE = 0, + MAP_ENTRY_ITEM, + MAP_ENTRY_BUCKET, +}; + +struct map_entry { + enum map_entry_type e_type; + uint64_t e_hash; + union { + fx_queue_entry e_entry; + fx_bst_node e_node; + }; +}; + +struct map_bucket { + struct map_entry b_entry; + fx_queue b_items; +}; + +struct map_item { + struct map_entry i_entry; + const char *i_name; +}; + +struct map { + fx_bst m_entries; +}; + +struct type { + struct map_item e_map_item; + fx_type e_type; +}; + +struct fx_assembly_p { + const char *a_name; + struct map a_types; + + struct { + long v_major; + long v_minor; + long v_build; + long v_revision; + } a_version; +}; + +/*** PRIVATE FUNCTIONS ********************************************************/ + +FX_BST_DEFINE_SIMPLE_GET( + struct map_entry, + uint64_t, + e_node, + e_hash, + map_get_entry); +FX_BST_DEFINE_SIMPLE_INSERT(struct map_entry, e_node, e_hash, map_put_entry); + +static struct map_bucket *map_item_convert_to_bucket( + struct map *map, + struct map_item *item) +{ + struct map_bucket *bucket = malloc(sizeof *bucket); + + memset(bucket, 0x0, sizeof *bucket); + + bucket->b_entry.e_hash = item->i_entry.e_hash; + bucket->b_entry.e_type = MAP_ENTRY_BUCKET; + + fx_bst_delete(&map->m_entries, &item->i_entry.e_node); + fx_queue_push_back(&bucket->b_items, &item->i_entry.e_entry); + map_put_entry(&map->m_entries, &bucket->b_entry); + + return bucket; +} + +static void map_put(struct map *map, const char *name, struct map_item *item) +{ + uint64_t hash = fx_hash_cstr(name); + + item->i_entry.e_type = MAP_ENTRY_ITEM; + item->i_entry.e_hash = hash; + item->i_name = name; + + struct map_entry *entry = map_get_entry(&map->m_entries, hash); + if (!entry) { + map_put_entry(&map->m_entries, &item->i_entry); + return; + } + + struct map_item *existing_item = NULL; + struct map_bucket *bucket = NULL; + switch (entry->e_type) { + case MAP_ENTRY_ITEM: + existing_item = (struct map_item *)entry; + bucket = map_item_convert_to_bucket(map, existing_item); + fx_queue_push_back(&bucket->b_items, &item->i_entry.e_entry); + break; + case MAP_ENTRY_BUCKET: + bucket = (struct map_bucket *)entry; + fx_queue_push_back(&bucket->b_items, &item->i_entry.e_entry); + break; + default: + break; + } +} + +static void assembly_set_name(struct fx_assembly_p *asm, const char *name) +{ + asm->a_name = name; +} + +static void assembly_set_version( + struct fx_assembly_p *asm, + long major, + long minor, + long build, + long revision) +{ + asm->a_version.v_major = major; + asm->a_version.v_minor = minor; + asm->a_version.v_build = build; + asm->a_version.v_revision = revision; +} + +#include +static void assembly_add_type( + struct fx_assembly_p *asm, + const char *full_name, + fx_type type_id) +{ + struct type *type = malloc(sizeof *type); + memset(type, 0x0, sizeof *type); + + map_put(&asm->a_types, full_name, &type->e_map_item); +} + +static void map_item_dump(struct map_item *item) +{ + struct type *type = (struct type *)item; + printf(" Type: %s\n", type->e_map_item.i_name); +} + +static void assembly_dump(struct fx_assembly_p *asm) +{ + printf("Loaded assembly:\n"); + printf(" %s, Version=%ld.%ld.%ld.%ld\n", + asm->a_name, + asm->a_version.v_major, + asm->a_version.v_minor, + asm->a_version.v_build, + asm->a_version.v_revision); + + fx_bst_node *cur_node = fx_bst_first(&asm->a_types.m_entries); + while (cur_node) { + struct map_entry *entry + = fx_unbox(struct map_entry, cur_node, e_node); + switch (entry->e_type) { + case MAP_ENTRY_ITEM: { + struct map_item *item = (struct map_item *)entry; + map_item_dump(item); + break; + } + + case MAP_ENTRY_BUCKET: { + struct map_bucket *bucket = (struct map_bucket *)entry; + fx_queue_entry *cur_qentry + = fx_queue_first(&bucket->b_items); + while (cur_qentry) { + struct map_item *item = fx_unbox( + struct map_item, + cur_qentry, + i_entry.e_entry); + map_item_dump(item); + cur_qentry = fx_queue_next(cur_qentry); + } + } + default: + break; + } + + cur_node = fx_bst_next(cur_node); + } +} + +/*** PUBLIC FUNCTIONS *********************************************************/ + +void fx_assembly_set_name(fx_assembly *asm, const char *name) +{ + FX_CLASS_DISPATCH_STATIC_V( + FX_REFLECTION_TYPE_ASSEMBLY, + assembly_set_name, + asm, + name); +} + +void fx_assembly_set_version( + fx_assembly *asm, + long major, + long minor, + long build, + long revision) +{ + FX_CLASS_DISPATCH_STATIC_V( + FX_REFLECTION_TYPE_ASSEMBLY, + assembly_set_version, + asm, + major, + minor, + build, + revision); +} + +void fx_assembly_add_type( + fx_assembly *asm, + const char *full_name, + fx_type type_id) +{ + FX_CLASS_DISPATCH_STATIC_V( + FX_REFLECTION_TYPE_ASSEMBLY, + assembly_add_type, + asm, + full_name, + type_id); +} + +void fx_assembly_dump(const fx_assembly *asm) +{ + FX_CLASS_DISPATCH_STATIC_0( + FX_REFLECTION_TYPE_ASSEMBLY, + assembly_dump, + asm); +} + +/*** VIRTUAL FUNCTIONS ********************************************************/ + +static void assembly_init(fx_object *obj, void *priv) +{ +} + +static void assembly_fini(fx_object *obj, void *priv) +{ +} + +/*** CLASS DEFINITION *********************************************************/ + +// ---- fx_string DEFINITION +FX_TYPE_CLASS_DEFINITION_BEGIN(fx_assembly) + FX_TYPE_CLASS_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT) + FX_INTERFACE_ENTRY(to_string) = NULL; + FX_TYPE_CLASS_INTERFACE_END(fx_object, FX_TYPE_OBJECT) +FX_TYPE_CLASS_DEFINITION_END(fx_assembly) + +FX_TYPE_DEFINITION_BEGIN(fx_assembly) + FX_TYPE_ID(0xf6690c30, 0x6642, 0x42f0, 0xb79f, 0xe2baf3684b1b); + FX_TYPE_CLASS(fx_assembly_class); + FX_TYPE_INSTANCE_PRIVATE(struct fx_assembly_p); + FX_TYPE_INSTANCE_INIT(assembly_init); + FX_TYPE_INSTANCE_FINI(assembly_fini); +FX_TYPE_DEFINITION_END(fx_assembly) diff --git a/fx.reflection/include/fx/reflection/assembly.h b/fx.reflection/include/fx/reflection/assembly.h new file mode 100644 index 0000000..73f2777 --- /dev/null +++ b/fx.reflection/include/fx/reflection/assembly.h @@ -0,0 +1,37 @@ +#ifndef FX_REFLECTION_ASSEMBLY_H_ +#define FX_REFLECTION_ASSEMBLY_H_ + +#include + +FX_DECLS_BEGIN; + +#define FX_REFLECTION_TYPE_ASSEMBLY (fx_assembly_get_type()) + +FX_DECLARE_TYPE(fx_assembly); + +FX_TYPE_CLASS_DECLARATION_BEGIN(fx_assembly) +FX_TYPE_CLASS_DECLARATION_END(fx_assembly) + +FX_API fx_type fx_assembly_get_type(); + +FX_TYPE_DEFAULT_CONSTRUCTOR(fx_assembly, FX_REFLECTION_TYPE_ASSEMBLY); + +FX_API void fx_assembly_set_name(fx_assembly *asm, const char *name); +FX_API void fx_assembly_set_version( + fx_assembly *asm, + long major, + long minor, + long build, + long revision); + +FX_API void fx_assembly_add_type( + fx_assembly *asm, + const char *full_name, + fx_type type_id); + +FX_API void fx_assembly_dump(const fx_assembly *asm); + +FX_DECLS_END +; + +#endif diff --git a/fx/CMakeLists.txt b/fx/CMakeLists.txt index 859cede..f6bb034 100644 --- a/fx/CMakeLists.txt +++ b/fx/CMakeLists.txt @@ -1,5 +1,7 @@ -include(../cmake/Templates.cmake) +set(namespace_include_paths ${CMAKE_CURRENT_SOURCE_DIR}/include PARENT_SCOPE) -add_fx_assembly( - NAME fx - SUBDIRS hash) +file(GLOB namespace_sources + *.c *.h + hash/*.c hash/*.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/fx/*.h) +set(namespace_sources ${namespace_sources} PARENT_SCOPE) diff --git a/fx/include/fx/macros.h b/fx/include/fx/macros.h index 4a6a706..0d3466f 100644 --- a/fx/include/fx/macros.h +++ b/fx/include/fx/macros.h @@ -200,6 +200,28 @@ func_name(priv); \ } while (0) +#define FX_ASSEMBLY_BEGIN() \ + const fx_assembly *__fx_assembly_get(void) \ + { \ + static fx_assembly *self = NULL; \ + if (self) { \ + return self; \ + } \ + self = fx_assembly_create(); +#define FX_ASSEMBLY_END() \ + fx_assembly_dump(self); \ + return self; \ + } +#define FX_ASSEMBLY_NAME(name) fx_assembly_set_name(self, name) +#define FX_ASSEMBLY_VERSION(major, minor, build, revision) \ + fx_assembly_set_version(self, major, minor, build, revision) +#define FX_ASSEMBLY_EXPORT_TYPE(namespace_name, type_name, type_id) \ + extern fx_type type_id##_get_type(void); \ + fx_assembly_add_type( \ + self, \ + namespace_name "." type_name, \ + type_id##_get_type()) + #ifdef __cplusplus #define FX_DECLS_BEGIN extern "C" { #define FX_DECLS_END } diff --git a/fx/type.h b/fx/type.h index bfa51ea..fa8c3f5 100644 --- a/fx/type.h +++ b/fx/type.h @@ -24,6 +24,7 @@ struct fx_type_component { struct fx_type_registration { enum fx_type_category r_category; + const char *r_name; struct fx_bst_node r_node; const fx_type_info *r_info; struct _fx_class *r_class; @@ -35,6 +36,7 @@ struct fx_type_registration { extern struct fx_type_registration *fx_type_get_registration(fx_type id); extern struct fx_type_component *fx_type_get_component( - const fx_bst *tree, const union fx_type *key); + const fx_bst *tree, + const union fx_type *key); #endif diff --git a/test/dynamic-test.c b/test/dynamic-test.c new file mode 100644 index 0000000..e7f3d2c --- /dev/null +++ b/test/dynamic-test.c @@ -0,0 +1,22 @@ +#include +#include + +int main(int argc, const char **argv) +{ + printf("dynamic loader\n"); + void *assembly = dlopen(argv[1], RTLD_LAZY); + if (!assembly) { + printf("cannot load %s\n", argv[1]); + return -1; + } + + const void *(*asm_info)(void) = dlsym(assembly, "__fx_assembly_get"); + if (!asm_info) { + printf("cannot find assembly info for %s", argv[1]); + return -1; + } + + asm_info(); + printf("OK\n"); + return 0; +}