From 20b6b593eb0e736d70cca80231e2b806c6a6eaf3 Mon Sep 17 00:00:00 2001 From: Chewing_Bever Date: Tue, 21 Nov 2023 09:36:58 +0100 Subject: [PATCH] refactor: started lnm library --- lnm/Makefile | 127 +++++++++++++++++++++++++++ lnm/config.mk | 15 ++++ lnm/include/lnm/common.h | 25 ++++++ lnm/include/lnm/loop.h | 42 +++++++++ lnm/src/_include/lnm/loop_internal.h | 5 ++ lnm/src/loop/lnm_loop.c | 1 + lnm/src/loop/lnm_loop_conn.c | 22 +++++ 7 files changed, 237 insertions(+) create mode 100644 lnm/Makefile create mode 100644 lnm/config.mk create mode 100644 lnm/include/lnm/common.h create mode 100644 lnm/include/lnm/loop.h create mode 100644 lnm/src/_include/lnm/loop_internal.h create mode 100644 lnm/src/loop/lnm_loop.c create mode 100644 lnm/src/loop/lnm_loop_conn.c diff --git a/lnm/Makefile b/lnm/Makefile new file mode 100644 index 0000000..716d82d --- /dev/null +++ b/lnm/Makefile @@ -0,0 +1,127 @@ +# https://spin.atomicobject.com/2016/08/26/makefile-c-projects/ was a great +# base for this Makefile + +-include config.mk + +LIB := $(BUILD_DIR)/$(LIB_FILENAME) + +SRCS != find '$(SRC_DIR)' -iname '*.c' +SRCS_H != find $(INC_DIRS) -iname '*.h' +SRCS_H_INTERNAL != find $(SRC_DIR) -iname '*.h' +SRCS_TEST != find '$(TEST_DIR)' -iname '*.c' +SRCS_EXAMPLE != find '$(EXAMPLE_DIR)' -iname '*.c' + +OBJS := $(SRCS:%=$(BUILD_DIR)/%.o) +OBJS_TEST := $(SRCS_TEST:%=$(BUILD_DIR)/%.o) +OBJS_EXAMPLE := $(SRCS_EXAMPLE:%=$(BUILD_DIR)/%.o) +DEPS := $(SRCS:%=$(BUILD_DIR)/%.d) $(SRCS_TEST:%=$(BUILD_DIR)/%.d) $(SRCS_EXAMPLE:%=$(BUILD_DIR)/%.d) + +BINS_TEST := $(OBJS_TEST:%.c.o=%) +BINS_EXAMPLE := $(OBJS_EXAMPLE:%.c.o=%) +TARGETS_TEST := $(BINS_TEST:%=test-%) +TARGETS_EXAMPLE := $(BINS_EXAMPLE:%=test-%) +TARGETS_MEM_TEST := $(BINS_TEST:%=test-mem-%) + +_CFLAGS := $(addprefix -I,$(INC_DIRS)) $(CFLAGS) -Wall -Wextra + +.PHONY: all +all: lib + + +# =====COMPILATION===== +# Utility used by the CI to lint +.PHONY: objs +objs: $(OBJS) + +.PHONY: lib +lib: $(LIB) +$(LIB): $(OBJS) + ar -rcs $@ $(OBJS) + +$(BUILD_DIR)/$(SRC_DIR)/%.c.o: $(SRC_DIR)/%.c + mkdir -p $(dir $@) + $(CC) -c $(_CFLAGS) $< -o $@ + + +# =====TESTING===== +.PHONY: test +test: $(TARGETS_TEST) + +.PHONY: test-mem +test-mem: $(TARGETS_MEM_TEST) + +.PHONY: $(TARGETS_TEST) +$(TARGETS_TEST): test-%: % + ./$^ + +.PHONY: $(TARGETS_MEM_TEST) +$(TARGETS_MEM_TEST): test-mem-%: % + valgrind --tool=memcheck --error-exitcode=1 --track-origins=yes --leak-check=full ./$^ + +.PHONY: build-test +build-test: $(BINS_TEST) + +$(BINS_TEST): %: %.c.o $(LIB) + $(CC) \ + $^ -o $@ + +# Along with the include directory, each test includes $(TEST_DIR) (which +# contains the acutest.h header file), and the src directory of the module it's +# testing. This allows tests to access internal methods, which aren't publicly +# exposed. +$(BUILD_DIR)/$(TEST_DIR)/%.c.o: $(TEST_DIR)/%.c + mkdir -p $(dir $@) + $(CC) $(_CFLAGS) -I$(TEST_DIR) \ + -I$(dir $(@:$(BUILD_DIR)/$(TEST_DIR)/%=$(SRC_DIR)/%)) \ + -c $< -o $@ + +# =====EXAMPLES===== +.PHONY: build-example +build-example: $(BINS_EXAMPLE) + +$(BINS_EXAMPLE): %: %.c.o $(LIB) + $(CC) \ + $^ -o $@ + +# Example binaries link the resulting library +$(BUILD_DIR)/$(EXAMPLE_DIR)/%.c.o: $(EXAMPLE_DIR)/%.c + mkdir -p $(dir $@) + $(CC) $(_CFLAGS) -I$(PUB_INC_DIR) -c $< -o $@ + +# =====MAINTENANCE===== +.PHONY: lint +lint: + clang-format -n --Werror $(SRCS) $(SRCS_H) $(SRCS_H_INTERNAL) $(SRCS_EXAMPLE) + +.PHONY: fmt +fmt: + clang-format -i $(SRCS) $(SRCS_H) $(SRCS_H_INTERNAL) $(SRCS_EXAMPLE) + +.PHONY: check +check: + mkdir -p $(BUILD_DIR)/cppcheck + cppcheck \ + $(addprefix -I,$(INC_DIRS)) \ + --cppcheck-build-dir=$(BUILD_DIR)/cppcheck \ + --error-exitcode=1 \ + --enable=warning,style \ + --inline-suppr \ + --check-level=exhaustive \ + --quiet \ + -j$(shell nproc) \ + $(SRCS) + +.PHONY: clean +clean: + rm -rf $(BUILD_DIR) + + +.PHONY: bear +bear: clean + bear -- make + bear --append -- make build-test + bear --append -- make build-example + + +# Make make aware of the .d files +-include $(DEPS) diff --git a/lnm/config.mk b/lnm/config.mk new file mode 100644 index 0000000..a946b42 --- /dev/null +++ b/lnm/config.mk @@ -0,0 +1,15 @@ +LIB_FILENAME = liblnm.a + +BUILD_DIR = build +SRC_DIR = src +TEST_DIR = test +EXAMPLE_DIR = example +PUB_INC_DIR = include +INC_DIRS = $(PUB_INC_DIR) src/_include + +# -MMD: generate a .d file for every source file. This file can be imported by +# make and makes make aware that a header file has been changed, ensuring an +# object file is also recompiled if only a header is changed. +# -MP: generate a dummy target for every header file (according to the docs it +# prevents some errors when removing header files) +CFLAGS ?= -MMD -MP -g diff --git a/lnm/include/lnm/common.h b/lnm/include/lnm/common.h new file mode 100644 index 0000000..658695a --- /dev/null +++ b/lnm/include/lnm/common.h @@ -0,0 +1,25 @@ +#ifndef LNM_COMMON +#define LNM_COMMON + +#define LNM_RES(x) \ + { \ + lnm_err res = x; \ + if (res != lnm_err_ok) \ + return res; \ + } + +#define LNM_RES2(x, e) \ + { \ + lnm_err res = x; \ + if (res != lnm_err_ok) { \ + e; \ + return res; \ + } \ + } + +typedef enum { + lnm_err_ok = 0, + lnm_err_failed_alloc, +} lnm_err; + +#endif diff --git a/lnm/include/lnm/loop.h b/lnm/include/lnm/loop.h new file mode 100644 index 0000000..f292ae8 --- /dev/null +++ b/lnm/include/lnm/loop.h @@ -0,0 +1,42 @@ +#ifndef LNM_LOOP +#define LNM_LOOP + +#include + +#include "lnm/common.h" + +#define LNM_LOOP_BUF_SIZE 4096 + +typedef enum { + lnm_loop_state_req = 0, + lnm_loop_state_res, + lnm_loop_state_end, +} lnm_loop_state; + +typedef struct { + int fd; + lnm_loop_state state; + void *ctx; + struct { + char buf[LNM_LOOP_BUF_SIZE]; + size_t size; + size_t read; + } r; + struct { + char buf[LNM_LOOP_BUF_SIZE]; + size_t size; + size_t written; + } w; +} lnm_loop_conn; + +typedef struct { + struct { + lnm_loop_conn **arr; + size_t len; + } conns; + void *gctx; + lnm_err (*ctx_init)(void **out, void *gctx); + void (*ctx_free)(void *ctx); +} lnm_loop; + +#endif diff --git a/lnm/src/_include/lnm/loop_internal.h b/lnm/src/_include/lnm/loop_internal.h new file mode 100644 index 0000000..afbb386 --- /dev/null +++ b/lnm/src/_include/lnm/loop_internal.h @@ -0,0 +1,5 @@ +#include "lnm/loop.h" + +lnm_err lnm_loop_conn_init(lnm_loop_conn **out, lnm_loop *l); + +void lnm_loop_conn_free(lnm_loop *l, lnm_loop_conn *conn); diff --git a/lnm/src/loop/lnm_loop.c b/lnm/src/loop/lnm_loop.c new file mode 100644 index 0000000..ef96614 --- /dev/null +++ b/lnm/src/loop/lnm_loop.c @@ -0,0 +1 @@ +#include "lnm/loop.h" diff --git a/lnm/src/loop/lnm_loop_conn.c b/lnm/src/loop/lnm_loop_conn.c new file mode 100644 index 0000000..49b86ad --- /dev/null +++ b/lnm/src/loop/lnm_loop_conn.c @@ -0,0 +1,22 @@ +#include "lnm/loop_internal.h" + +lnm_err lnm_loop_conn_init(lnm_loop_conn **out, lnm_loop *l) { + lnm_loop_conn *conn = calloc(1, sizeof(lnm_loop_conn)); + + if (conn == NULL) { + return lnm_err_failed_alloc; + } + + void *ctx; + LNM_RES2(l->ctx_init(&ctx, l->gctx), free(conn)); + + conn->ctx = ctx; + *out = conn; + + return lnm_err_ok; +} + +void lnm_loop_conn_free(lnm_loop *l, lnm_loop_conn *conn) { + l->ctx_free(conn->ctx); + free(conn); +}