From: Marek VavruĊĦa Date: Mon, 23 Feb 2015 09:13:29 +0000 (+0100) Subject: lib: loadable versioned modules (api subject to change) X-Git-Tag: v1.0.0-beta1~301^2~21 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e7149d4ff2b3f1f01157fac59fab2100784c4bb2;p=thirdparty%2Fknot-resolver.git lib: loadable versioned modules (api subject to change) --- diff --git a/Makefile b/Makefile index ad004827a..961724b81 100644 --- a/Makefile +++ b/Makefile @@ -2,10 +2,10 @@ include config.mk include platform.mk # Targets -all: info libkresolve kresolved -install: libkresolve-install kresolved-install +all: info libkresolve modules kresolved +install: libkresolve-install modules-install kresolved-install check: all tests-check -clean: libkresolve-clean kresolved-clean tests-clean +clean: libkresolve-clean modules-clean kresolved-clean tests-clean .PHONY: all install check clean # Options @@ -25,4 +25,5 @@ CFLAGS += $(libknot_CFLAGS) $(libuv_CFLAGS) $(cmocka_CFLAGS) $(python_CFLAGS) include help.mk include lib/libkresolve.mk include daemon/kresolved.mk +include modules/modules.mk include tests/tests.mk diff --git a/config.mk b/config.mk index 6a302c22d..e2c7839ac 100644 --- a/config.mk +++ b/config.mk @@ -6,13 +6,15 @@ MINOR := 04 PREFIX := /usr/local BINDIR := /bin LIBDIR := /lib -INCLUDEDIR = /include +INCLUDEDIR := /include +MODULEDIR := $(LIBDIR)/kdns_modules # Tools ifndef CC CC := cc endif -CFLAGS += -std=c99 -D_GNU_SOURCE -Wall -fPIC -I$(abspath .) -DPACKAGE_VERSION="\"$(MAJOR).$(MINOR)\"" +CFLAGS += -std=c99 -D_GNU_SOURCE -Wall -fPIC -I$(abspath .) +CFLAGS += -DPACKAGE_VERSION="\"$(MAJOR).$(MINOR)\"" -DPREFIX="\"$(PREFIX)\"" -DMODULEDIR="\"$(MODULEDIR)\"" RM := rm -f LN := ln -s INSTALL := install diff --git a/daemon/worker.c b/daemon/worker.c index 4d0e351b8..9dce753e0 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -44,11 +44,16 @@ int worker_init(struct worker_ctx *worker, mm_ctx_t *mm) /* Open resolution context cache */ worker->resolve.cache = kr_cache_open("/tmp/kresolved", mm, CACHE_DEFAULT_SIZE); if (worker->resolve.cache == NULL) { - fprintf(stderr, "Cache directory '/tmp/kresolved' not exists, exitting.\n"); + fprintf(stderr, "Cache directory '/tmp/kresolved' not exists, exiting.\n"); kr_context_deinit(&worker->resolve); return KNOT_ERROR; } + /* Load basic modules */ + kr_context_register(&worker->resolve, "iterate"); + kr_context_register(&worker->resolve, "itercache"); + kr_context_register(&worker->resolve, "hints"); + return KNOT_EOK; } diff --git a/help.mk b/help.mk index 34c89aaaf..63d0408bc 100644 --- a/help.mk +++ b/help.mk @@ -7,6 +7,7 @@ info: $(info BINDIR: $(BINDIR)) $(info LIBDIR: $(LIBDIR)) $(info INCLUDEDIR: $(INCLUDEDIR)) + $(info MODULEDIR: $(MODULEDIR)) $(info ) $(info Features) $(info --------) diff --git a/lib/context.c b/lib/context.c index 9de4c3d65..16789a87f 100644 --- a/lib/context.c +++ b/lib/context.c @@ -15,10 +15,14 @@ */ #include +#include #include #include +#include + #include "lib/context.h" +#include "lib/defines.h" #include "lib/rplan.h" int kr_context_init(struct kr_context *ctx, mm_ctx_t *mm) @@ -43,5 +47,28 @@ int kr_context_deinit(struct kr_context *ctx) kr_cache_close(ctx->cache); } + for (size_t i = 0; i < ctx->mod_loaded; ++i) { + kr_module_unload(&ctx->modules[i]); + } + return KNOT_EOK; } + +int kr_context_register(struct kr_context *ctx, const char *module_name) +{ + size_t last = ctx->mod_loaded; + int ret = mreserve((char **) &ctx->modules, sizeof(struct kr_module), + last + 1, 0, &ctx->mod_reserved); + if (ret < 0) { + return kr_error(ENOMEM); + } + + struct kr_module *mod = &ctx->modules[last]; + ret = kr_module_load(mod, module_name, NULL); + if (ret != 0) { + return ret; + } + + ctx->mod_loaded += 1; + return kr_ok(); +} diff --git a/lib/context.h b/lib/context.h index 5d68f5ff4..08d9209b6 100644 --- a/lib/context.h +++ b/lib/context.h @@ -19,6 +19,7 @@ #include #include +#include "lib/module.h" #include "lib/cache.h" /*! @@ -31,10 +32,12 @@ */ struct kr_context { - struct kr_cache *cache; - list_t layers; - unsigned options; - mm_ctx_t *pool; + mm_ctx_t *pool; + struct kr_cache *cache; + struct kr_module *modules; + size_t mod_loaded; + size_t mod_reserved; + uint32_t options; }; /*! @@ -51,3 +54,11 @@ int kr_context_init(struct kr_context *ctx, mm_ctx_t *mm); * \return KNOT_E* */ int kr_context_deinit(struct kr_context *ctx); + +/*! + * \brief Register module to context. + * \param ctx context + * \param module_name + * \return KNOT_E* + */ +int kr_context_register(struct kr_context *ctx, const char *module_name); diff --git a/lib/defines.h b/lib/defines.h index e0cf92d80..f1db0202b 100644 --- a/lib/defines.h +++ b/lib/defines.h @@ -16,10 +16,18 @@ #pragma once +#include #include #include #include +/* + * Error codes. + */ +#define kr_ok() 0 +#define kr_error(x) -abs(x) +#define kr_strerror(x) strerror(abs(x)) + /* * Connection limits. */ @@ -36,4 +44,4 @@ #define KR_DNS_PORT 53 #define KR_DNAME_ROOT ((const knot_dname_t*)"") #define KR_EDNS_VERSION 0 -#define KR_EDNS_PAYLOAD 4096 +#define KR_EDNS_PAYLOAD 4096 \ No newline at end of file diff --git a/lib/layer/iterate.c b/lib/layer/iterate.c index a0ac5b851..c16c7b68c 100644 --- a/lib/layer/iterate.c +++ b/lib/layer/iterate.c @@ -26,6 +26,7 @@ #include "lib/rplan.h" #include "lib/defines.h" #include "lib/nsrep.h" +#include "lib/module.h" #define DEBUG_MSG(fmt...) QRDEBUG(kr_rplan_current(param->rplan), "iter", fmt) @@ -463,16 +464,14 @@ static int resolve(knot_layer_t *ctx, knot_pkt_t *pkt) } /*! \brief Module implementation. */ -static const knot_layer_api_t LAYER_ITERATE_MODULE = { - &begin, - &reset, - &finish, - &resolve, - &prepare_query, - NULL -}; - -const knot_layer_api_t *layer_iterate_module(void) +const knot_layer_api_t *iterate_layer(void) { - return &LAYER_ITERATE_MODULE; -} + static const knot_layer_api_t _layer = { + .begin = &begin, + .reset = &reset, + .finish = &finish, + .in = &resolve, + .out = &prepare_query + }; + return &_layer; +} \ No newline at end of file diff --git a/lib/layer/iterate.h b/lib/layer/iterate.h index a5821ac9b..758f7d39e 100644 --- a/lib/layer/iterate.h +++ b/lib/layer/iterate.h @@ -19,8 +19,7 @@ #include "lib/layer.h" /* Processing module implementation. */ -const knot_layer_api_t *layer_iterate_module(void); -#define LAYER_ITERATE layer_iterate_module() +extern const knot_layer_api_t *iterate_layer(void); /*! * \brief Result updates the query parent. diff --git a/lib/layer/itercache.c b/lib/layer/itercache.c index 0b0e501fe..bbc709e51 100644 --- a/lib/layer/itercache.c +++ b/lib/layer/itercache.c @@ -20,8 +20,8 @@ #include #include -#include "lib/layer/static.h" #include "lib/layer/iterate.h" +#include "lib/module.h" #define DEBUG_MSG(fmt...) QRDEBUG(kr_rplan_current(param->rplan), " cc ", fmt) @@ -267,16 +267,13 @@ static int write_cache(knot_layer_t *ctx, knot_pkt_t *pkt) } /*! \brief Module implementation. */ -static const knot_layer_api_t LAYER_ITERCACHE_MODULE = { - &begin, - NULL, - NULL, - &write_cache, - &read_cache, - NULL -}; - -const knot_layer_api_t *layer_itercache_module(void) +const knot_layer_api_t *itercache_layer(void) { - return &LAYER_ITERCACHE_MODULE; + static const knot_layer_api_t _layer = { + .begin = &begin, + .in = &write_cache, + .out = &read_cache + }; + + return &_layer; } diff --git a/lib/layer/itercache.h b/lib/layer/itercache.h index 5f3b7c2e1..532196b08 100644 --- a/lib/layer/itercache.h +++ b/lib/layer/itercache.h @@ -19,5 +19,4 @@ #include "lib/layer.h" /* Processing module implementation. */ -const knot_layer_api_t *layer_itercache_module(void); -#define LAYER_ITERCACHE layer_itercache_module() +extern const knot_layer_api_t *itercache_layer(void); diff --git a/lib/layer/stats.c b/lib/layer/stats.c deleted file mode 100644 index 610f84c15..000000000 --- a/lib/layer/stats.c +++ /dev/null @@ -1,77 +0,0 @@ -/* Copyright (C) 2014 CZ.NIC, z.s.p.o. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - -#include - -#include "lib/layer/stats.h" -#include "lib/rplan.h" - -#define DEBUG_MSG(fmt...) QRDEBUG(NULL, "stat", fmt) - -//static void update_stats(struct kr_ns *ns, double rtt) -//{ -// /* Knuth, TAOCP, p.232 (Welford running variance/mean). */ -// double d_mean = (rtt - ns->stat.M); -// ns->stat.n += 1; -// ns->stat.M += d_mean / ns->stat.n; -// ns->stat.S += d_mean * (rtt - ns->stat.M); -//} - -static int begin(knot_layer_t *ctx, void *param) -{ - ctx->data = param; - return ctx->state; -} - -static int finish(knot_layer_t *ctx) -{ -#ifndef NDEBUG - struct kr_layer_param *param = ctx->data; - struct kr_rplan *rplan = param->rplan; - const knot_pkt_t *answer = param->answer; - - /* Calculate total RTT and number of queries. */ - double total_rtt = 0.0; - size_t nr_queries = list_size(&rplan->resolved); - if (nr_queries > 0) { - struct kr_query *query_first = HEAD(rplan->resolved); - struct timeval t_end; - gettimeofday(&t_end, NULL); - total_rtt = time_diff(&query_first->timestamp, &t_end); - } - - lookup_table_t *rcode = lookup_by_id(knot_rcode_names, knot_wire_get_rcode(answer->wire)); - DEBUG_MSG("result => %s [%u records]\n", rcode ? rcode->name : "??", answer->rrset_count); - DEBUG_MSG("rtt => %.02lf [ms]\n", total_rtt); -#endif - - return ctx->state; -} - -/*! \brief Module implementation. */ -static const knot_layer_api_t LAYER_STATS_MODULE = { - &begin, - NULL, - &finish, - NULL, - NULL, - NULL -}; - -const knot_layer_api_t *layer_stats_module(void) -{ - return &LAYER_STATS_MODULE; -} diff --git a/lib/libkresolve.mk b/lib/libkresolve.mk index 9dddbb69b..4955b2589 100644 --- a/lib/libkresolve.mk +++ b/lib/libkresolve.mk @@ -1,9 +1,9 @@ libkresolve_SOURCES := \ lib/layer/iterate.c \ lib/layer/itercache.c \ - lib/layer/static.c \ - lib/layer/stats.c \ + lib/utils.c \ lib/nsrep.c \ + lib/module.c \ lib/context.c \ lib/resolve.c \ lib/zonecut.c \ @@ -11,12 +11,10 @@ libkresolve_SOURCES := \ lib/cache.c libkresolve_HEADERS := \ - lib/layer/iterate.h \ - lib/layer/itercache.h \ - lib/layer/static.h \ - lib/layer/stats.h \ lib/layer.h \ + lib/utils.h \ lib/nsrep.h \ + lib/module.h \ lib/context.h \ lib/resolve.h \ lib/zonecut.h \ diff --git a/lib/module.c b/lib/module.c new file mode 100644 index 000000000..d87ac0c9e --- /dev/null +++ b/lib/module.c @@ -0,0 +1,88 @@ +#include + +#include "lib/defines.h" +#include "lib/utils.h" +#include "lib/module.h" + +/*! \brief Library extension. */ +static inline const char *library_ext(void) +{ +#if defined(__APPLE__) + return ".dylib"; +#elif _WIN32 + return ".lib"; +#else + return ".so"; +#endif +} + +static void *load_symbol(void *lib, const char *prefix, const char *name) +{ + auto_free char *symbol = kr_strcatdup(3, prefix, "_", name); + return dlsym(lib, symbol); +} + +static int load_library(struct kr_module *module, const char *name, const char *path) +{ + if (path == NULL) { + return kr_error(EINVAL); + } + + auto_free char *lib_path = kr_strcatdup(4, path, "/", name, library_ext()); + if (lib_path == NULL) { + return kr_error(ENOMEM); + } + + module->lib = dlopen(lib_path, RTLD_LAZY); + if (module->lib) { + return kr_ok(); + } + + return kr_error(ENOENT); +} + +int kr_module_load(struct kr_module *module, const char *name, const char *path) +{ + if (load_library(module, name, path) != 0) { + if (load_library(module, name, "~/.local/" MODULEDIR) != 0) { + if (load_library(module, name, PREFIX MODULEDIR) != 0) { + } + } + } + + /* It's okay if it fails, then current exec space is searched. */ + if (module->lib == NULL) { + module->lib = RTLD_DEFAULT; + } + + /* Load all symbols. */ + module_api_cb *module_api = NULL; + *(void **) (&module_api) = load_symbol(module->lib, name, "api"); + *(void **) (&module->init) = load_symbol(module->lib, name, "init"); + *(void **) (&module->deinit) = load_symbol(module->lib, name, "deinit"); + *(void **) (&module->config) = load_symbol(module->lib, name, "config"); + *(void **) (&module->layer) = load_symbol(module->lib, name, "layer"); + + /* Check module API version (if declared). */ + if (module_api && module_api() > KR_MODULE_API) { + return kr_error(ENOTSUP); + } + + /* Initialize module */ + if (module->init) { + return module->init(module); + } + + return kr_ok(); +} + +void kr_module_unload(struct kr_module *module) +{ + if (module->deinit) { + module->deinit(module); + } + + if (module->lib && module->lib != RTLD_DEFAULT) { + dlclose(module->lib); + } +} \ No newline at end of file diff --git a/lib/module.h b/lib/module.h new file mode 100644 index 000000000..6a65d8f7c --- /dev/null +++ b/lib/module.h @@ -0,0 +1,63 @@ +/* Copyright (C) 2015 CZ.NIC, z.s.p.o. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +#pragma once + +#include + +/* + * Forward decls + */ +struct kr_module; + +/* + * API definition. + */ +#define KR_MODULE_API 0x20150401 /*!< API version */ +typedef uint32_t (module_api_cb)(void); +typedef int (module_init_cb)(struct kr_module *); +typedef int (module_deinit_cb)(struct kr_module *); +typedef int (module_config_cb)(struct kr_module *, void *); +typedef const knot_layer_api_t* (module_layer_cb)(void); + +/*! Loaded module representation. */ +struct kr_module { + module_init_cb *init; /*!< Constructor */ + module_deinit_cb *deinit; /*!< Destructor */ + module_config_cb *config; /*!< Configuration */ + module_layer_cb *layer; /*!< Layer getter */ + void *lib; /*!< Shared library handle or RTLD_DEFAULT */ + void *data; /*!< Custom data context. */ +}; + +/*! Load module instance into memory. + * @param module module structure + * @param name module name + * @param path module search path + * @return 0 or an error + */ +int kr_module_load(struct kr_module *module, const char *name, const char *path); + +/*! Unload module instance. + * @param module module structure + */ +void kr_module_unload(struct kr_module *module); + +/*! Export module API version (place this at the end of your module). + * @param module module name (f.e. hints) + */ +#define KR_MODULE_EXPORT(module) \ + uint32_t module ## _api() { return KR_MODULE_API; } \ No newline at end of file diff --git a/lib/resolve.c b/lib/resolve.c index 495ead185..fdbab518e 100755 --- a/lib/resolve.c +++ b/lib/resolve.c @@ -26,8 +26,6 @@ #include "lib/defines.h" #include "lib/layer/itercache.h" #include "lib/layer/iterate.h" -#include "lib/layer/static.h" -#include "lib/layer/stats.h" #define DEBUG_MSG(fmt...) QRDEBUG(kr_rplan_current(param->rplan), "resl", fmt) @@ -147,15 +145,23 @@ static int iterate(struct knot_requestor *requestor, struct kr_layer_param *para return ret; } +static void prepare_layers(struct knot_requestor *req, struct kr_layer_param *param) +{ + struct kr_context *ctx = param->ctx; + for (size_t i = 0; i < ctx->mod_loaded; ++i) { + struct kr_module *mod = &ctx->modules[i]; + if (mod->layer) { + knot_requestor_overlay(req, mod->layer(), param); + } + } +} + static int resolve_iterative(struct kr_layer_param *param, mm_ctx_t *pool) { - /* Initialize requestor and overlay. */ + /* Initialize requestor. */ struct knot_requestor requestor; knot_requestor_init(&requestor, pool); - knot_requestor_overlay(&requestor, LAYER_STATIC, param); - knot_requestor_overlay(&requestor, LAYER_ITERCACHE, param); - knot_requestor_overlay(&requestor, LAYER_ITERATE, param); - knot_requestor_overlay(&requestor, LAYER_STATS, param); + prepare_layers(&requestor, param); /* Iteratively solve the query. */ int ret = KNOT_EOK; diff --git a/lib/utils.c b/lib/utils.c new file mode 100644 index 000000000..2d0390e71 --- /dev/null +++ b/lib/utils.c @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include "lib/defines.h" +#include "lib/utils.h" + +/* + * Macros. + */ +#define strlen_safe(x) ((x) ? strlen(x) : 0) + +/* + * Cleanup callbacks. + */ +void _cleanup_free(char **p) +{ + free(*p); +} + +void _cleanup_close(int *p) +{ + if (*p > 0) close(*p); +} + +char* kr_strcatdup(unsigned n, ...) +{ + /* Calculate total length */ + size_t total_len = 0; + va_list vl; + va_start(vl, n); + for (unsigned i = 0; i < n; ++i) { + char *item = va_arg(vl, char *); + total_len += strlen_safe(item); + } + va_end(vl); + + /* Allocate result and fill */ + char *result = NULL; + if (total_len > 0) { + result = malloc(total_len + 1); + } + if (result) { + char *stream = result; + va_start(vl, n); + for (unsigned i = 0; i < n; ++i) { + char *item = va_arg(vl, char *); + if (item) { + size_t len = strlen(item); + memcpy(stream, item, len + 1); + stream += len; + } + } + va_end(vl); + } + + return result; +} \ No newline at end of file diff --git a/lib/layer/static.h b/lib/utils.h similarity index 66% rename from lib/layer/static.h rename to lib/utils.h index 8733952ed..3d6a57cc5 100644 --- a/lib/layer/static.h +++ b/lib/utils.h @@ -16,8 +16,18 @@ #pragma once -#include "lib/layer.h" +/* + * General-purpose attributes. + */ +#define auto_free __attribute__((cleanup(_cleanup_free))) +extern void _cleanup_free(char **p); +#define auto_close __attribute__((cleanup(_cleanup_close))) +extern void _cleanup_close(int *p); + +/* + * Defines. + */ +#define ARRAY_SIZE(x) (sizeof(x)/sizeof(*(x))) -/* Processing module implementation. */ -const knot_layer_api_t *layer_static_module(void); -#define LAYER_STATIC layer_static_module() +/*! \brief Concatenate N strings. */ +char* kr_strcatdup(unsigned n, ...); diff --git a/modules/gostats/gostats.go b/modules/gostats/gostats.go new file mode 100644 index 000000000..a64b7c0ac --- /dev/null +++ b/modules/gostats/gostats.go @@ -0,0 +1,36 @@ +package gostats + +/* +#include "lib/layer.h" +#include "lib/module.h" +extern int gostats_begin(knot_layer_t *, void *); +extern int gostats_finish(knot_layer_t *); +static inline const knot_layer_api_t *_layer(void) +{ + static const knot_layer_api_t _module = { + .begin = &gostats_begin, + .finish = &gostats_finish + }; + return &_module; +} +*/ +import "C" +import "unsafe" +import "fmt" + +//export gostats_begin +func gostats_begin(ctx *C.knot_layer_t, param unsafe.Pointer) C.int { + fmt.Println("go_begin()") + return 0 +} + +//export gostats_finish +func gostats_finish(ctx *C.knot_layer_t) C.int { + fmt.Println("go_finish()") + return 0 +} + +//export gostats_layer +func gostats_layer() *C.knot_layer_api_t { + return C._layer() +} \ No newline at end of file diff --git a/modules/gostats/gostats.mk b/modules/gostats/gostats.mk new file mode 100644 index 000000000..49a4fb803 --- /dev/null +++ b/modules/gostats/gostats.mk @@ -0,0 +1,4 @@ +hints_SOURCES := modules/gostats/gostats.g +gostats_DEPEND := libkresolve +gostats_LIBS := $(libkresolve_TARGET) $(libkresolve_LIBS) +$(call make_go_module,gostats) \ No newline at end of file diff --git a/lib/layer/static.c b/modules/hints/hints.c similarity index 62% rename from lib/layer/static.c rename to modules/hints/hints.c index d8fa56db8..d439015bd 100644 --- a/lib/layer/static.c +++ b/modules/hints/hints.c @@ -14,36 +14,43 @@ along with this program. If not, see . */ -#include "lib/layer/static.h" +#include "lib/module.h" +#include "lib/layer.h" #define DEBUG_MSG(fmt...) QRDEBUG(NULL, "hint", fmt) -static int reset(knot_layer_t *ctx) +static int begin(knot_layer_t *ctx, void *module_param) { - /* TODO: sync, cleanup after resolution */ + ctx->data = module_param; return ctx->state; } -static int begin(knot_layer_t *ctx, void *param) +static int query(knot_layer_t *ctx, knot_pkt_t *pkt) { - ctx->data = param; + return ctx->state; +} - /* TODO: read static hosts file */ +/* + * Module implementation. + */ - return ctx->state; +const knot_layer_api_t *hints_layer(void) +{ + static const knot_layer_api_t _layer = { + .begin = &begin, + .out = &query + }; + return &_layer; } -/*! \brief Module implementation. */ -static const knot_layer_api_t LAYER_STATIC_MODULE = { - &begin, - &reset, - NULL, - NULL, - NULL, - NULL -}; - -const knot_layer_api_t *layer_static_module(void) +int hints_init(struct kr_module *module) { - return &LAYER_STATIC_MODULE; + return 0; } + +int hints_deinit(struct kr_module *module) +{ + return 0; +} + +KR_MODULE_EXPORT(hints); diff --git a/modules/hints/hints.mk b/modules/hints/hints.mk new file mode 100644 index 000000000..2784d04ee --- /dev/null +++ b/modules/hints/hints.mk @@ -0,0 +1,4 @@ +hints_SOURCES := modules/hints/hints.c +hints_DEPEND := libkresolve +hints_LIBS := $(libkresolve_TARGET) $(libkresolve_LIBS) +$(call make_c_module,hints) \ No newline at end of file diff --git a/modules/modules.mk b/modules/modules.mk new file mode 100644 index 000000000..fca344e64 --- /dev/null +++ b/modules/modules.mk @@ -0,0 +1,19 @@ +# List of built-in modules +modules_TARGETS := hints + +# Make C module +define make_c_module +$(eval $(call make_module,$(1),modules/$(1))) +endef + +# Make Go module +define make_go_module +# TODO: compilable only with gccgo -shared +# go tool cgo -- $(CFLAGS) $$($(1)_SOURCES) +endef + +# Build rules +modules: $(modules_TARGETS) +modules-clean: $(addsuffix -clean,$(modules_TARGETS)) +modules-install: $(addsuffix -install,$(modules_TARGETS)) +$(foreach module,$(modules_TARGETS),$(eval include modules/$(module)/$(module).mk)) \ No newline at end of file diff --git a/platform.mk b/platform.mk index baa535cc8..97b97f027 100644 --- a/platform.mk +++ b/platform.mk @@ -50,7 +50,8 @@ $(2)/$(1)$(3): $$($(1)_OBJ) $$($(1)_DEPEND) $(1)-clean: $(RM) $$($(1)_OBJ) $$($(1)_DEP) $(2)/$(1)$(3) $(1)-install: $(2)/$(1)$(3) - $(INSTALL) $$^ $(PREFIX)/$(5) + $(INSTALL) -d $(PREFIX)/$(5) + $(INSTALL) $$^ $(PREFIX)/$(5) ifneq ($$(strip $$($(1)_HEADERS)),) $(INSTALL) -d $(PREFIX)/$(INCLUDEDIR)/$(1) $(INSTALL) $$($(1)_HEADERS) $(PREFIX)/$(INCLUDEDIR)/$(1) @@ -61,7 +62,8 @@ endef # Make targets (name,path) make_bin = $(call make_target,$(1),$(2),$(BINEXT),,$(BINDIR)) make_lib = $(call make_target,$(1),$(2),$(LIBEXT),-$(LIBTYPE),$(LIBDIR)) -make_module = $(call make_target,$(1),$(2),$(MODEXT),-$(MODTYPE),$(LIBDIR)) +make_module = $(call make_target,$(1),$(2),$(LIBEXT),-$(LIBTYPE),$(MODULEDIR)) +make_shared = $(call make_target,$(1),$(2),$(MODEXT),-$(MODTYPE),$(LIBDIR)) # Evaluate library define have_lib diff --git a/tests/test_integration.c b/tests/test_integration.c index a0317f48b..0bd103f25 100644 --- a/tests/test_integration.c +++ b/tests/test_integration.c @@ -52,6 +52,8 @@ static PyObject* init(PyObject* self, PyObject* args) #define CACHE_SIZE 100*1024 test_mm_ctx_init(&global_mm); kr_context_init(&global_context, &global_mm); + kr_context_register(&global_context, "iterate"); + kr_context_register(&global_context, "itercache"); global_tmpdir = test_tmpdir_create(); assert(global_tmpdir); global_context.cache = kr_cache_open(global_tmpdir, &global_mm, CACHE_SIZE); diff --git a/lib/layer/stats.h b/tests/test_utils.c similarity index 50% rename from lib/layer/stats.h rename to tests/test_utils.c index d66d1dc58..f123a9aac 100644 --- a/lib/layer/stats.h +++ b/tests/test_utils.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2014 CZ.NIC, z.s.p.o. +/* Copyright (C) 2015 CZ.NIC, z.s.p.o. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -14,10 +14,31 @@ along with this program. If not, see . */ -#pragma once +#include "tests/test.h" +#include -#include "lib/layer.h" +#include "lib/utils.h" -/* Processing module implementation. */ -const knot_layer_api_t *layer_stats_module(void); -#define LAYER_STATS layer_stats_module() +static void test_strcatdup(void **state) +{ + auto_free char *empty_res = kr_strcatdup(0); + assert_null(empty_res); + + auto_free char *null_res = kr_strcatdup(1, NULL); + assert_null(null_res); + + auto_free char *nullcat_res = kr_strcatdup(2, NULL, "beef"); + assert_string_equal(nullcat_res, "beef"); + + auto_free char *multi_res = kr_strcatdup(3, "need", "beef", "dead"); + assert_string_equal(multi_res, "needbeefdead"); +} + +int main(void) +{ + const UnitTest tests[] = { + unit_test(test_strcatdup), + }; + + return run_tests(tests); +} diff --git a/tests/tests.mk b/tests/tests.mk index a42c9eb4c..43c35e6ce 100644 --- a/tests/tests.mk +++ b/tests/tests.mk @@ -3,6 +3,7 @@ # tests_BIN := \ + test_utils \ test_context \ test_rplan \ test_cache \ @@ -36,7 +37,7 @@ $(eval $(call make_lib,libmock_calls,tests)) _test_integration_SOURCES := tests/test_integration.c _test_integration_LIBS := -Wl,-rpath,tests -Ltests -lmock_calls $(libmock_calls_LIBS) _test_integration_DEPEND := libmock_calls -$(eval $(call make_module,_test_integration,tests)) +$(eval $(call make_shared,_test_integration,tests)) # Preload mock library ifeq ($(PLATFORM),Darwin)