13 KiB
c_utils_lib Implementation Plan
Overview
This document provides a step-by-step implementation plan for creating the c_utils_lib library and integrating it into the c-relay project.
Phase 1: Repository Setup & Structure
Step 1.1: Create Repository Structure
Location: Create outside c-relay project (sibling directory)
# Create directory structure
mkdir -p c_utils_lib/{include,src,examples,tests,docs,bin}
cd c_utils_lib
# Create subdirectories
mkdir -p include/c_utils
mkdir -p tests/results
Step 1.2: Initialize Git Repository
cd c_utils_lib
git init
git branch -M main
Step 1.3: Create Core Files
Files to create:
README.md- Main documentationLICENSE- MIT LicenseVERSION- Version file (v0.1.0).gitignore- Git ignore rulesMakefile- Build systembuild.sh- Build script
Phase 2: Debug System Implementation
Step 2.1: Move Debug Files
Source files (from c-relay):
src/debug.c→c_utils_lib/src/debug.csrc/debug.h→c_utils_lib/include/c_utils/debug.h
Modifications needed:
-
Update header guard in
debug.h:#ifndef C_UTILS_DEBUG_H #define C_UTILS_DEBUG_H -
No namespace changes needed (keep simple API)
-
Add header documentation:
/** * @file debug.h * @brief Debug and logging system with configurable verbosity levels * * Provides a simple, efficient logging system with 5 levels: * - ERROR: Critical errors * - WARN: Warnings * - INFO: Informational messages * - DEBUG: Debug messages * - TRACE: Detailed trace with file:line info */
Step 2.2: Create Main Header
File: include/c_utils/c_utils.h
#ifndef C_UTILS_H
#define C_UTILS_H
/**
* @file c_utils.h
* @brief Main header for c_utils_lib - includes all utilities
*
* Include this header to access all c_utils_lib functionality.
* Alternatively, include specific headers for modular usage.
*/
// Version information
#define C_UTILS_VERSION "v0.1.0"
#define C_UTILS_VERSION_MAJOR 0
#define C_UTILS_VERSION_MINOR 1
#define C_UTILS_VERSION_PATCH 0
// Include all utilities
#include "debug.h"
#include "version.h"
#endif /* C_UTILS_H */
Phase 3: Version Utilities Implementation
Step 3.1: Design Version API
File: include/c_utils/version.h
#ifndef C_UTILS_VERSION_H
#define C_UTILS_VERSION_H
#include <time.h>
/**
* @brief Version information structure
*/
typedef struct {
int major;
int minor;
int patch;
char git_hash[41]; // SHA-1 hash (40 chars + null)
char build_date[32]; // ISO 8601 format
char version_string[64]; // "vX.Y.Z" format
} version_info_t;
/**
* @brief Extract version from git tags
* @param version Output version structure
* @return 0 on success, -1 on error
*/
int version_get_from_git(version_info_t* version);
/**
* @brief Generate version header file for a project
* @param output_path Path to output header file
* @param prefix Prefix for macros (e.g., "MY_APP")
* @return 0 on success, -1 on error
*/
int version_generate_header(const char* output_path, const char* prefix);
/**
* @brief Compare two versions
* @return -1 if v1 < v2, 0 if equal, 1 if v1 > v2
*/
int version_compare(const version_info_t* v1, const version_info_t* v2);
/**
* @brief Format version as string
* @param version Version structure
* @param buffer Output buffer
* @param buffer_size Size of output buffer
* @return Number of characters written
*/
int version_to_string(const version_info_t* version, char* buffer, size_t buffer_size);
#endif /* C_UTILS_VERSION_H */
Step 3.2: Implement Version Utilities
File: src/version.c
Key functions to implement:
version_get_from_git()- Executegit describe --tagsand parseversion_generate_header()- Generate header file with macrosversion_compare()- Semantic version comparisonversion_to_string()- Format version string
Step 3.3: Create Version Generation Script
File: bin/generate_version
#!/bin/bash
# Generate version header for a project
OUTPUT_FILE="$1"
PREFIX="$2"
if [ -z "$OUTPUT_FILE" ] || [ -z "$PREFIX" ]; then
echo "Usage: $0 <output_file> <prefix>"
exit 1
fi
# Get version from git
if [ -d .git ]; then
VERSION=$(git describe --tags --always 2>/dev/null || echo "v0.0.0")
GIT_HASH=$(git rev-parse --short HEAD 2>/dev/null || echo "unknown")
else
VERSION="v0.0.0"
GIT_HASH="unknown"
fi
# Parse version
CLEAN_VERSION=$(echo "$VERSION" | sed 's/^v//' | cut -d- -f1)
MAJOR=$(echo "$CLEAN_VERSION" | cut -d. -f1)
MINOR=$(echo "$CLEAN_VERSION" | cut -d. -f2)
PATCH=$(echo "$CLEAN_VERSION" | cut -d. -f3)
BUILD_DATE=$(date -u +"%Y-%m-%d %H:%M:%S UTC")
# Generate header
cat > "$OUTPUT_FILE" << EOF
/* Auto-generated by c_utils_lib version system */
/* DO NOT EDIT - This file is automatically generated */
#ifndef ${PREFIX}_VERSION_H
#define ${PREFIX}_VERSION_H
#define ${PREFIX}_VERSION "v${CLEAN_VERSION}"
#define ${PREFIX}_VERSION_MAJOR ${MAJOR}
#define ${PREFIX}_VERSION_MINOR ${MINOR}
#define ${PREFIX}_VERSION_PATCH ${PATCH}
#define ${PREFIX}_GIT_HASH "${GIT_HASH}"
#define ${PREFIX}_BUILD_DATE "${BUILD_DATE}"
#endif /* ${PREFIX}_VERSION_H */
EOF
echo "Generated $OUTPUT_FILE with version v${CLEAN_VERSION}"
Phase 4: Build System
Step 4.1: Create Makefile
File: Makefile
# c_utils_lib Makefile
CC = gcc
AR = ar
CFLAGS = -Wall -Wextra -std=c99 -O2 -g
INCLUDES = -Iinclude
# Directories
SRC_DIR = src
INCLUDE_DIR = include
BUILD_DIR = build
EXAMPLES_DIR = examples
TESTS_DIR = tests
# Source files
SOURCES = $(wildcard $(SRC_DIR)/*.c)
OBJECTS = $(SOURCES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%.o)
# Output library
LIBRARY = libc_utils.a
# Default target
all: $(LIBRARY)
# Create build directory
$(BUILD_DIR):
mkdir -p $(BUILD_DIR)
# Compile source files
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c | $(BUILD_DIR)
$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
# Create static library
$(LIBRARY): $(OBJECTS)
$(AR) rcs $@ $^
@echo "Built $(LIBRARY)"
# Build examples
examples: $(LIBRARY)
$(MAKE) -C $(EXAMPLES_DIR)
# Run tests
test: $(LIBRARY)
$(MAKE) -C $(TESTS_DIR)
$(TESTS_DIR)/run_tests.sh
# Install to system (optional)
install: $(LIBRARY)
install -d /usr/local/lib
install -m 644 $(LIBRARY) /usr/local/lib/
install -d /usr/local/include/c_utils
install -m 644 $(INCLUDE_DIR)/c_utils/*.h /usr/local/include/c_utils/
@echo "Installed to /usr/local"
# Uninstall from system
uninstall:
rm -f /usr/local/lib/$(LIBRARY)
rm -rf /usr/local/include/c_utils
@echo "Uninstalled from /usr/local"
# Clean build artifacts
clean:
rm -rf $(BUILD_DIR) $(LIBRARY)
$(MAKE) -C $(EXAMPLES_DIR) clean 2>/dev/null || true
$(MAKE) -C $(TESTS_DIR) clean 2>/dev/null || true
# Help
help:
@echo "c_utils_lib Build System"
@echo ""
@echo "Targets:"
@echo " all Build static library (default)"
@echo " examples Build examples"
@echo " test Run tests"
@echo " install Install to /usr/local"
@echo " uninstall Remove from /usr/local"
@echo " clean Clean build artifacts"
@echo " help Show this help"
.PHONY: all examples test install uninstall clean help
Step 4.2: Create Build Script
File: build.sh
#!/bin/bash
# c_utils_lib build script
set -e
case "$1" in
lib|"")
echo "Building c_utils_lib..."
make
;;
examples)
echo "Building examples..."
make examples
;;
test)
echo "Running tests..."
make test
;;
clean)
echo "Cleaning..."
make clean
;;
install)
echo "Installing..."
make install
;;
*)
echo "Usage: ./build.sh [lib|examples|test|clean|install]"
exit 1
;;
esac
echo "Done!"
Phase 5: Examples & Tests
Step 5.1: Create Debug Example
File: examples/debug_example.c
#include <c_utils/debug.h>
int main() {
// Initialize with INFO level
debug_init(DEBUG_LEVEL_INFO);
DEBUG_INFO("Application started");
DEBUG_WARN("This is a warning");
DEBUG_ERROR("This is an error");
// This won't print (level too high)
DEBUG_LOG("This debug message won't show");
// Change level to DEBUG
g_debug_level = DEBUG_LEVEL_DEBUG;
DEBUG_LOG("Now debug messages show");
// Change to TRACE to see file:line info
g_debug_level = DEBUG_LEVEL_TRACE;
DEBUG_TRACE("Trace with file:line information");
return 0;
}
Step 5.2: Create Version Example
File: examples/version_example.c
#include <c_utils/version.h>
#include <stdio.h>
int main() {
version_info_t version;
// Get version from git
if (version_get_from_git(&version) == 0) {
char version_str[64];
version_to_string(&version, version_str, sizeof(version_str));
printf("Version: %s\n", version_str);
printf("Git Hash: %s\n", version.git_hash);
printf("Build Date: %s\n", version.build_date);
}
return 0;
}
Step 5.3: Create Test Suite
File: tests/test_debug.c
#include <c_utils/debug.h>
#include <stdio.h>
#include <string.h>
int test_debug_init() {
debug_init(DEBUG_LEVEL_INFO);
return (g_debug_level == DEBUG_LEVEL_INFO) ? 0 : -1;
}
int test_debug_levels() {
// Test that higher levels don't print at lower settings
debug_init(DEBUG_LEVEL_ERROR);
// Would need to capture stdout to verify
return 0;
}
int main() {
int failed = 0;
printf("Running debug tests...\n");
if (test_debug_init() != 0) {
printf("FAIL: test_debug_init\n");
failed++;
} else {
printf("PASS: test_debug_init\n");
}
if (test_debug_levels() != 0) {
printf("FAIL: test_debug_levels\n");
failed++;
} else {
printf("PASS: test_debug_levels\n");
}
return failed;
}
Phase 6: Documentation
Step 6.1: Create README.md
Key sections:
- Overview and purpose
- Quick start guide
- Installation instructions
- Usage examples
- API reference (brief)
- Integration guide
- Contributing guidelines
- License
Step 6.2: Create API Documentation
File: docs/API.md
Complete API reference with:
- Function signatures
- Parameter descriptions
- Return values
- Usage examples
- Common patterns
Step 6.3: Create Integration Guide
File: docs/INTEGRATION.md
How to integrate into projects:
- As git submodule
- Makefile integration
- Code examples
- Migration from standalone utilities
Phase 7: Integration with c-relay
Step 7.1: Add as Submodule
cd /path/to/c-relay
git submodule add <repo-url> c_utils_lib
git submodule update --init --recursive
Step 7.2: Update c-relay Makefile
# Add to c-relay Makefile
C_UTILS_LIB = c_utils_lib/libc_utils.a
# Update includes
INCLUDES += -Ic_utils_lib/include
# Update libs
LIBS += -Lc_utils_lib -lc_utils
# Add dependency
$(C_UTILS_LIB):
cd c_utils_lib && ./build.sh lib
# Update main target
$(TARGET): $(C_UTILS_LIB) ...
Step 7.3: Update c-relay Source Files
Changes needed:
-
Update includes:
// Old #include "debug.h" // New #include <c_utils/debug.h> -
Remove old debug files:
git rm src/debug.c src/debug.h -
Update all files that use debug system:
src/main.csrc/config.csrc/dm_admin.csrc/websockets.csrc/subscriptions.c- Any other files using DEBUG_* macros
Step 7.4: Test Integration
cd c-relay
make clean
make
./make_and_restart_relay.sh
Verify:
- Compilation succeeds
- Debug output works correctly
- No functionality regressions
Phase 8: Version System Integration
Step 8.1: Update c-relay Makefile for Versioning
# Add version generation
src/version.h: .git/refs/tags/*
c_utils_lib/bin/generate_version src/version.h C_RELAY
# Add dependency
$(TARGET): src/version.h ...
Step 8.2: Update c-relay to Use Generated Version
Replace hardcoded version in src/main.h with:
#include "version.h"
// Use C_RELAY_VERSION instead of hardcoded VERSION
Timeline Estimate
- Phase 1: Repository Setup - 1 hour
- Phase 2: Debug System - 2 hours
- Phase 3: Version Utilities - 4 hours
- Phase 4: Build System - 2 hours
- Phase 5: Examples & Tests - 3 hours
- Phase 6: Documentation - 3 hours
- Phase 7: c-relay Integration - 2 hours
- Phase 8: Version Integration - 2 hours
Total: ~19 hours
Success Criteria
- c_utils_lib builds successfully
- All tests pass
- Examples compile and run
- c-relay integrates successfully
- Debug output works in c-relay
- Version generation works
- Documentation complete
- No regressions in c-relay functionality
Next Steps
- Review this plan with stakeholders
- Create repository structure
- Implement debug system
- Implement version utilities
- Create build system
- Write tests and examples
- Create documentation
- Integrate into c-relay
- Test thoroughly
- Publish to GitHub
Notes
- Keep the API simple and intuitive
- Focus on zero external dependencies
- Prioritize learning value in code comments
- Make integration as easy as possible
- Document everything thoroughly