Files
c-relay/docs/c_utils_lib_implementation_plan.md

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:

  1. README.md - Main documentation
  2. LICENSE - MIT License
  3. VERSION - Version file (v0.1.0)
  4. .gitignore - Git ignore rules
  5. Makefile - Build system
  6. build.sh - Build script

Phase 2: Debug System Implementation

Step 2.1: Move Debug Files

Source files (from c-relay):

  • src/debug.cc_utils_lib/src/debug.c
  • src/debug.hc_utils_lib/include/c_utils/debug.h

Modifications needed:

  1. Update header guard in debug.h:

    #ifndef C_UTILS_DEBUG_H
    #define C_UTILS_DEBUG_H
    
  2. No namespace changes needed (keep simple API)

  3. 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:

  1. version_get_from_git() - Execute git describe --tags and parse
  2. version_generate_header() - Generate header file with macros
  3. version_compare() - Semantic version comparison
  4. version_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:

  1. Overview and purpose
  2. Quick start guide
  3. Installation instructions
  4. Usage examples
  5. API reference (brief)
  6. Integration guide
  7. Contributing guidelines
  8. 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:

  1. As git submodule
  2. Makefile integration
  3. Code examples
  4. 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:

  1. Update includes:

    // Old
    #include "debug.h"
    
    // New
    #include <c_utils/debug.h>
    
  2. Remove old debug files:

    git rm src/debug.c src/debug.h
    
  3. Update all files that use debug system:

    • src/main.c
    • src/config.c
    • src/dm_admin.c
    • src/websockets.c
    • src/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

  1. Review this plan with stakeholders
  2. Create repository structure
  3. Implement debug system
  4. Implement version utilities
  5. Create build system
  6. Write tests and examples
  7. Create documentation
  8. Integrate into c-relay
  9. Test thoroughly
  10. 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