diff --git a/.github/workflows/test-integration.yml b/.github/workflows/test-integration.yml index 6cf61d8..ca4df7f 100644 --- a/.github/workflows/test-integration.yml +++ b/.github/workflows/test-integration.yml @@ -1,6 +1,7 @@ # Tests packages: # - CMake # - Meson +# - vcpkg name: Integration Tests @@ -24,6 +25,9 @@ jobs: sudo apt update sudo apt install -y meson ninja-build + - name: Set VCPKG_ROOT + run: echo "VCPKG_ROOT=$(dirname $(realpath $(which vcpkg)))" >> $GITHUB_ENV + - name: Test Meson Package run: pwsh -File ./tests/integration/packaging/test_meson.ps1 @@ -32,3 +36,6 @@ jobs: - name: Test CMake + CPM run: pwsh -File ./tests/integration/cpm/test_cpm.ps1 + + - name: Test vcpkg Port + run: pwsh -File ./tests/integration/vcpkg/test_vcpkg.ps1 diff --git a/AGENTS.md b/AGENTS.md index 6269463..96913ce 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,318 +1,143 @@ -# AGENTS.md - AI Assistant Guide for Microlog +# AI Instructions -This document helps AI coding assistants (Claude, GitHub Copilot, ChatGPT, etc.) understand the microlog project structure and contribute effectively. +## Code Review Instructions -## Project Overview +You are performing a comprehensive code review with focus on modern best practices and modernization opportunities. -**microlog** is an extensible and configurable logging library for embedded and desktop applications in C/C++. It emphasizes: -- Universal design for embedded and desktop -- Zero-cost abstraction: no feature = no compiled code -- Two-file core (ulog.h + ulog.c) -- Extension-based architecture -- Static and dynamic allocation modes +### Scope -**Base Repository**: [https://github.com/an-dr/microlog](https://github.com/an-dr/microlog) -**License**: MIT -**Language**: C (C++ compatible) -**Build Systems**: CMake, Meson, CPM +Analyze the following: +- **Default**: Changes compared to `master` or `main` branch +- **Custom diff**: If specified, use the provided diff/range +- **Full codebase**: If explicitly requested, review everything -## Project Structure +### Context -``` -microlog/ -├── src/ -│ └── ulog.c # Single-file implementation (~3000 lines, section-based) -├── include/ -│ └── ulog.h # Public API header -├── extensions/ # Optional add-ons using only public API -├── tests/ -│ ├── unit/ # Unit tests (doctest framework) -│ └── integration/ # Package integration tests -├── example/ # Usage examples -├── doc/ # Documentation -└── scripts/ # Build and release scripts (PowerShell) -``` - -## Core Architecture - -### Logging Flow - -``` -ulog_info("message") - → ulog_log() - → Creates ulog_event - → output_handle_all() - → Iterates handlers: - - output_stdout_handler() - - output_file_handler() - - User custom handlers - → log_print_event() - → vprint()/print() to targets -``` - -See [doc/design.md](doc/design.md) for detailed diagrams. - -### Code Organization - -The library uses a **section-based architecture** in a single file ([src/ulog.c](src/ulog.c)): - -```c -/* ============================================================================ - Feature: (`prefix_*`, depends on: ) -============================================================================ */ -#if ULOG_HAS_FEATURE_NAME -// Private functions and data -// Public function implementations -#else // ULOG_HAS_FEATURE_NAME -// Disabled stubs (with warnings if ULOG_BUILD_WARN_NOT_ENABLED=1) -#endif // ULOG_HAS_FEATURE_NAME -``` - -Each section is self-contained and depends only on core functionality or explicitly stated dependencies. See [doc/code.md](doc/code.md) for examples. - -## Key Concepts - -### Build-Time Configuration - -Features are controlled via compile-time defines (no feature = no code): - -| Define | Default | Purpose | -| --------------------------- | -------------------------- | ------------------------------------- | -| ULOG_BUILD_COLOR | 0 | ANSI color codes | -| ULOG_BUILD_TIME | 0 | Timestamps | -| ULOG_BUILD_PREFIX_SIZE | 0 | Custom prefix (0 = disabled) | -| ULOG_BUILD_SOURCE_LOCATION | 1 | file:line output | -| ULOG_BUILD_LEVEL_SHORT | 0 | Short level names (T/D/I/W/E/F) | -| ULOG_BUILD_TOPICS_MODE | ULOG_BUILD_TOPICS_MODE_OFF | Topic filtering mode (STATIC/DYNAMIC) | -| ULOG_BUILD_EXTRA_OUTPUTS | 0 | File/custom outputs | -| ULOG_BUILD_DYNAMIC_CONFIG | 0 | Runtime toggles (enables all) | -| ULOG_BUILD_WARN_NOT_ENABLED | 1 | Warning stubs for disabled APIs | - -Example (CMake): -```cmake -target_compile_definitions(microlog PRIVATE ULOG_BUILD_COLOR=1) -``` +- **Language**: [Auto-detect from code] +- **Domain**: [User specifies - e.g., "web backend", "embedded systems", "data pipeline", "CLI tool"] +- **Default if not specified**: Modern generic programming in the detected language -### Log Levels +### Review Focus -8 levels (ascending severity): `ULOG_LEVEL_0` ... `ULOG_LEVEL_7` +Perform a critical review covering: -Default aliases: -- `ULOG_LEVEL_TRACE` (0) - Execution tracing -- `ULOG_LEVEL_DEBUG` (1) - Debug info -- `ULOG_LEVEL_INFO` (2) - General information -- `ULOG_LEVEL_WARN` (3) - Warnings -- `ULOG_LEVEL_ERROR` (4) - Recoverable errors -- `ULOG_LEVEL_FATAL` (5) - Critical failures -- Levels 6-7 are user-defined +1. **Modernization** 🚀 + - Outdated language features (use modern equivalents) + - Legacy patterns that have better alternatives + - Deprecated APIs or libraries + - Missing modern safety features (e.g., async/await, RAII, null-safety) + - Opportunities to use newer language versions -Custom levels can be set via `ulog_level_set_new_levels()`. +2. **Security** 🔒 + - Input validation and sanitization + - Authentication/authorization flaws + - Injection vulnerabilities (SQL, command, XSS) + - Cryptographic misuse + - Dependency vulnerabilities -### Topics +3. **Architecture & Structure** 🏗️ + - Separation of concerns + - Unnecessary complexity or over-engineering + - Tight coupling and hidden dependencies + - Module boundaries and interfaces + - SOLID principles violations + - Technical debt (document, don't just complain) -Optional subsystem-based filtering (e.g., "network", "storage"): +4. **Code Quality** ✨ + - Unclear logic or confusing code + - Error handling completeness + - Edge cases and boundary conditions + - Resource management (memory, connections, files) + - Magic numbers and hardcoded values + - Type safety opportunities -- **Static allocation**: `ULOG_BUILD_TOPICS_MODE=ULOG_BUILD_TOPICS_MODE_STATIC` + `ULOG_BUILD_TOPICS_STATIC_NUM=N` (fixed count) -- **Dynamic allocation**: `ULOG_BUILD_TOPICS_MODE=ULOG_BUILD_TOPICS_MODE_DYNAMIC` (heap) +5. **Modern Best Practices** 📚 + - Idiomatic code for the language + - Standard library usage vs reinventing + - Proper async/concurrency patterns + - Immutability where applicable + - Functional vs imperative style appropriateness + - Testing patterns and testability -Usage: -```c -ulog_topic_add("network", ULOG_OUTPUT_ALL, true); -ulog_topic_info("network", "Connected"); -``` - -### Outputs - -- **STDOUT** (always available): `ULOG_OUTPUT_STDOUT` -- **FILE**: Add via `ulog_output_add_file(fp, level)` -- **Custom handlers**: Add via `ulog_output_add(handler_fn, arg, level)` +### Output Format -Each output has independent level filtering. +Create a new file `Code Review - [Date/PR/Commit].md` -### Thread Safety +Content: -Inject external locks via `ulog_lock_set_fn()`: - -```c -typedef ulog_status (*ulog_lock_fn)(bool lock, void *udata); ``` - -See `extensions/ulog_lock_*.h` for platform helpers (pthread, FreeRTOS, Windows, etc.). - -## Coding Guidelines - -### Style ([doc/style.md](doc/style.md)) - -- **Formatting**: clang-format (see [.clang-format](.clang-format)) -- **Naming**: - - Public API: `ulog_feature_action()` (e.g., `ulog_topic_add`) - - Private functions: `feature_action()` (e.g., `topic_add_internal`) - - Structs: `feature_data_t` (private), `ulog_feature_t` (public) -- **Sections**: Clearly marked with header comments -- **Macros**: Guard disabled features with `#if ULOG_HAS_FEATURE` - -### Testing - -- **Unit tests**: [tests/unit/](tests/unit/) (doctest framework) -- **Integration tests**: [tests/integration/](tests/integration/) (CMake/Meson packages) -- Run via: `./scripts/run_tests.ps1` (PowerShell) - -Update tests when modifying features! - -## Extensions ([extensions/README.md](extensions/README.md)) - -Extensions use **only the public API** and are not part of distributed packages. Users copy-paste and adapt them. - -**Available**: -- `ulog_syslog.h/.c` - RFC 5424 severity levels -- `ulog_lock_pthread.h/.c` - POSIX threads -- `ulog_lock_freertos.h/.c` - FreeRTOS -- `ulog_lock_cmsis.h/.c` - CMSIS-RTOS2 -- `ulog_lock_threadx.h/.c` - Azure ThreadX -- `ulog_lock_win.h/.c` - Windows Critical Sections -- `ulog_generic_interface.h` - Generic logger interface (header-only) - -**Creating extensions**: -1. Create `extensions/ulog_.h/.c` -2. Use only `ulog.h` API -3. Provide enable/disable functions returning `ulog_status` -4. Document in header and update `extensions/README.md` - -## Common Tasks for AI Assistants - -### Adding a New Feature - -1. **Check dependencies**: Does it need new build options? -2. **Update header** ([include/ulog.h](include/ulog.h)): - - Add public API declarations - - Add macros if needed -3. **Update source** ([src/ulog.c](src/ulog.c)): - - Add section with `#if ULOG_HAS_FEATURE_NAME` - - Implement private functions - - Implement public functions - - Add disabled stubs in `#else` block -4. **Add tests** in [tests/unit/](tests/unit/) -5. **Update docs** ([doc/features.md](doc/features.md)) -6. **Update CHANGELOG.md** - -### Modifying Existing Features - -1. **Read the section** in [src/ulog.c](src/ulog.c) (search for feature name) -2. **Check build config** - what needs to be enabled? -3. **Understand dependencies** - section header lists them -4. **Modify carefully** - sections should remain encapsulated -5. **Update tests and docs** - -### Debugging Build Issues - -- **Feature not compiling?** Check `ULOG_BUILD_*` defines -- **Linker errors?** Feature disabled but called (check `ULOG_HAS_*` guards) -- **Runtime warnings?** `ULOG_BUILD_WARN_NOT_ENABLED=1` shows when disabled features are called - -### Working with Tests - -- Unit tests use doctest (C++ framework) -- Test files in [tests/unit/](tests/unit/) -- Run: `meson test -C build` or `ctest --test-dir build` -- CI runs on every PR ([.github/workflows/workflow-tests.yml](.github/workflows/workflow-tests.yml)) - -### Release Process - -1. Update [version](version) file -2. Update [CHANGELOG.md](CHANGELOG.md) -3. Run build scripts in [scripts/](scripts/) to generate packages -4. CI workflow [.github/workflows/workflow-release.yml](.github/workflows/workflow-release.yml) creates release - -## Important Constraints - -### DO NOT: -- ❌ Add dependencies (library is dependency-free except standard C) -- ❌ Break two-file core principle (extensions are separate) -- ❌ Add features that compile by default (use opt-in defines) -- ❌ Break backward compatibility without major version bump -- ❌ Add platform-specific code to core (use extensions) - -### DO: -- ✅ Keep features encapsulated in sections -- ✅ Use `ULOG_HAS_*` guards for all feature code -- ✅ Provide disabled stubs with `ULOG_BUILD_WARN_NOT_ENABLED` -- ✅ Document in headers and [doc/features.md](doc/features.md) -- ✅ Add tests for new functionality -- ✅ Follow existing code style (run clang-format) -- ✅ Consider embedded constraints (static allocation, size) - -## Example Scenarios - -### User wants colored timestamps - -**Current**: `ULOG_BUILD_COLOR=1` colors level names, `ULOG_BUILD_TIME=1` adds timestamps -**Request**: Color timestamps differently - -**Approach**: -1. Check Color section in [src/ulog.c](src/ulog.c) -2. Modify `color_print()` to accept time parameter -3. Update `log_print_event()` to pass time to color handler -4. Add configuration option if needed -5. Test with different terminals - -### Porting to new RTOS - -**Extension approach**: -1. Study existing lock extensions in [extensions/](extensions/) -2. Create `extensions/ulog_lock_mynewrtos.h/.c` -3. Implement: - ```c - ulog_status ulog_lock_mynewrtos_enable(void); - ulog_status ulog_lock_mynewrtos_disable(void); - ``` -4. Document usage in header -5. Submit PR (optional) - -## Quick Reference - -### Key Files -- [README.md](README.md) - Project overview -- [CONTRIBUTING.md](CONTRIBUTING.md) - Contribution guidelines -- [doc/features.md](doc/features.md) - Feature documentation -- [doc/design.md](doc/design.md) - Architecture -- [doc/code.md](doc/code.md) - Code organization -- [doc/style.md](doc/style.md) - Coding standards -- [CHANGELOG.md](CHANGELOG.md) - Version history - -### API Overview -```c -// Basic logging -ulog_trace/debug/info/warn/error/fatal("message %d", value); - -// With topics (requires ULOG_BUILD_TOPICS_MODE != ULOG_BUILD_TOPICS_MODE_OFF) -ulog_topic_info("network", "Connected"); - -// Configuration -ulog_output_level_set(ULOG_OUTPUT_STDOUT, ULOG_LEVEL_INFO); -ulog_lock_set_fn(my_lock_fn, lock_data); -ulog_time_set_fn(my_time_fn, time_data); -ulog_prefix_set_fn(my_prefix_fn); - -// Outputs (requires ULOG_BUILD_EXTRA_OUTPUTS > 0) -ulog_output_id id = ulog_output_add_file(fp, level); -ulog_output_id id = ulog_output_add(handler, arg, level); -ulog_output_remove(id); - -// Cleanup -ulog_cleanup(); // Free all dynamic resources +# Code Review - [Date/PR/Commit] + +## 🎯 Summary +[2-3 sentence overview: what changed, overall quality, critical issues count] + +## ⚠️ Critical Issues +[Security vulnerabilities, breaking bugs, must-fix before merge] +- **[File:Line]** - [Issue description] + - Impact: [what breaks/risk] + - Fix: [concrete solution with code example] + +## 🔧 High Priority +[Bugs, poor practices, architectural concerns that should be addressed] +- **[File:Line]** - [Issue] + - Why: [reasoning] + - Suggestion: [specific improvement with code example] + +## 🚀 Modernization Opportunities +[Outdated patterns, better modern alternatives, language feature upgrades] +- **[File:Line]** - [What's outdated] + - Modern approach: [code example showing better way] + - Why it matters: [concrete benefit] + +## 💡 Improvements +[Code quality, maintainability, nice-to-haves] +- **[File:Line]** - [Observation] + - Better approach: [alternative with reasoning] + +## 📝 Technical Debt +[Document what's hacky/temporary and why it exists] +- **[Area/Module]** - [Debt description] + - Reason: [why we accepted it] + - Future work: [what should be done eventually] + +## ✅ Positives +[What's done well - be specific, not generic praise] +- [Good pattern/decision and why it matters] + +## 🏁 Verdict +- [ ] Approved - ship it +- [ ] Approved with minor comments +- [ ] Changes required +- [ ] Major rework needed + +[Final recommendation and reasoning] ``` -## Resources - -- **Repository**: https://github.com/an-dr/microlog -- **Issues**: https://github.com/an-dr/microlog/issues -- **Releases**: https://github.com/an-dr/microlog/releases -- **Credits**: Based on [rxi/log.c](https://github.com/rxi/log.c) - -## Version - -This AGENTS.md reflects microlog v7.0.0 architecture. Check [CHANGELOG.md](CHANGELOG.md) for updates. - ---- - -**For AI Assistants**: When in doubt, prefer conservative changes. The library values simplicity, portability, and zero-cost abstractions. Always test across embedded and desktop scenarios. When suggesting changes, explain the embedded impact (code size, RAM usage, static vs dynamic allocation). +### Review Guidelines + +- **Be specific**: File:Line references, concrete code examples +- **Be opinionated**: State what's wrong and what's better +- **No hedging**: "This might be..." → "This is a problem because..." +- **Show, don't tell**: Provide code snippets for suggestions +- **Modern first**: If there's a newer, better way - flag it +- **Context matters**: Consider team size, project phase, constraints +- **Honest tradeoffs**: Sometimes "good enough" is correct—acknowledge it +- **No fluff**: Skip generic advice, focus on this code + +### Language-Specific Awareness + +Detect language and apply modern idioms: +- **Python**: Type hints, f-strings, dataclasses, async/await, walrus operator +- **JavaScript/TypeScript**: ES6+, async/await, optional chaining, nullish coalescing +- **C++**: C++17/20/23 features, smart pointers, ranges, concepts +- **Rust**: Idiomatic ownership, error handling, iterators, async +- **Java**: Streams, Optional, var, records, sealed classes +- **C#**: LINQ, async/await, pattern matching, nullable reference types +- **Go**: Contexts, generics (1.18+), error wrapping +- **[Other]**: Apply modern standards for detected language + +## Code Debugging Instructions + +- Investigate the code. Try to figure this out. +- I you are not sure or it is getting too complicates, make experiments to gather more data. Don't waste tokens for endless internal discussions +- If build-run required the user involvement, ask the user to participate. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..4a73cfb --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +Read AGENTS.md diff --git a/CMakeLists.txt b/CMakeLists.txt index e0cf012..375cc0c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -92,9 +92,7 @@ endif() # ---------------------------------------------------------------------------- set(ULOG_INSTALL_INCLUDE_IN ${ULOG_CONFIGURED_DIR}/include) set(ULOG_INSTALL_SRC_IN ${ULOG_CONFIGURED_DIR}/src/ulog.c) -set(ULOG_INSTALL_INCLUDE_DST - ${CMAKE_INSTALL_PREFIX}/${ULOG_INSTALL_INCLUDE_DIR}) -set(ULOG_INSTALL_SRC_DST ${CMAKE_INSTALL_PREFIX}/${ULOG_INSTALL_SRC_DIR}) +set(ULOG_CMAKE_INSTALL_DIR lib/cmake/${PROJECT_NAME}) install( TARGETS ${PROJECT_NAME} @@ -103,8 +101,8 @@ install( # Headers (they are sources, not artifacts so copy them explicitly) install(DIRECTORY ${ULOG_INSTALL_INCLUDE_IN} - DESTINATION ${ULOG_INSTALL_INCLUDE_DST}) -install(FILES ${ULOG_INSTALL_SRC_IN} DESTINATION ${ULOG_INSTALL_SRC_DST}) + DESTINATION ${ULOG_INSTALL_INCLUDE_DIR}) +install(FILES ${ULOG_INSTALL_SRC_IN} DESTINATION ${ULOG_INSTALL_SRC_DIR}) # ---------------------------------------------------------------------------- # Packing @@ -120,11 +118,11 @@ include(CMakePackageConfigHelpers) # We have a custom Targets file below. Original is generated like this: install( # EXPORT ${PROJECT_NAME}Targets NAMESPACE ${PROJECT_NAME}:: DESTINATION # ${CMAKE_INSTALL_PREFIX}) -install(FILES ${ULOG_TARGETS_FILE} DESTINATION ${CMAKE_INSTALL_PREFIX}) +install(FILES ${ULOG_TARGETS_FILE} DESTINATION ${ULOG_CMAKE_INSTALL_DIR}) # Make a config file using targets based on the template configure_package_config_file(${ULOG_CONFIG_FILE_IN} ${ULOG_CONFIG_FILE_OUT} - INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}) + INSTALL_DESTINATION ${ULOG_CMAKE_INSTALL_DIR}) # Make a version file write_basic_package_version_file( @@ -133,5 +131,5 @@ write_basic_package_version_file( COMPATIBILITY SameMajorVersion) install(FILES ${ULOG_CONFIG_FILE_OUT} ${ULOG_VERSION_FILE_OUT} - ${CMAKE_CURRENT_LIST_DIR}/LICENSE - DESTINATION ${CMAKE_INSTALL_PREFIX}) + DESTINATION ${ULOG_CMAKE_INSTALL_DIR}) +install(FILES ${CMAKE_CURRENT_LIST_DIR}/LICENSE DESTINATION .) diff --git a/ports/README.md b/ports/README.md new file mode 100644 index 0000000..8d6d079 --- /dev/null +++ b/ports/README.md @@ -0,0 +1 @@ +vcpkg port files diff --git a/ports/microlog/portfile.cmake b/ports/microlog/portfile.cmake new file mode 100644 index 0000000..0effdb1 --- /dev/null +++ b/ports/microlog/portfile.cmake @@ -0,0 +1,27 @@ +# This overlay port installs microlog from the local source tree. +# For the official vcpkg registry, see the release artifacts which +# contain a portfile with the correct REF and SHA512. + +set(SOURCE_PATH "${CMAKE_CURRENT_LIST_DIR}/../..") + +vcpkg_cmake_configure( + SOURCE_PATH "${SOURCE_PATH}" +) + +vcpkg_cmake_install() + +# Relocate cmake package config files to the vcpkg-standard location and +# correct PACKAGE_PREFIX_DIR to point at the installed package root. +vcpkg_cmake_config_fixup(CONFIG_PATH "lib/cmake/${PORT}") + +# microlog is source-distributed (no compiled artifacts); remove debug copy and empty lib/ +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug") +file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/lib") + +# Remove the LICENSE that cmake installed to prefix root (replaced by vcpkg_install_copyright) +file(REMOVE "${CURRENT_PACKAGES_DIR}/LICENSE") + +# Install the usage file +file(INSTALL "${CMAKE_CURRENT_LIST_DIR}/usage" DESTINATION "${CURRENT_PACKAGES_DIR}/share/${PORT}") + +vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE") diff --git a/ports/microlog/usage b/ports/microlog/usage new file mode 100644 index 0000000..e2454a5 --- /dev/null +++ b/ports/microlog/usage @@ -0,0 +1,23 @@ +microlog provides CMake targets: + + find_package(microlog CONFIG REQUIRED) + target_link_libraries(main PRIVATE microlog::microlog) + +The library compiles ulog.c into your project at build time. +Optional compile definitions (pass via target_compile_definitions): + + ULOG_BUILD_COLOR=1 # ANSI color output + ULOG_BUILD_TIME=1 # timestamp in each log line + ULOG_BUILD_SOURCE_LOCATION=0 # disable file:line prefix (default: 1) + ULOG_BUILD_LEVEL_SHORT=1 # short level tags: D/I/W/E (default: DEBUG/INFO/…) + ULOG_BUILD_PREFIX_SIZE=64 # enable custom per-output prefix (bytes; 0=off) + ULOG_BUILD_EXTRA_OUTPUTS=4 # number of extra output handlers (0=off) + ULOG_BUILD_WARN_NOT_ENABLED=0 # suppress stub warnings for disabled features (default: 1) + ULOG_BUILD_TOPICS_MODE= # enable topics + ULOG_BUILD_TOPICS_MODE_OFF/ ULOG_BUILD_TOPICS_MODE_STATIC / ULOG_BUILD_TOPICS_MODE_DYNAMIC + ULOG_BUILD_TOPICS_STATIC_NUM=8 # number of static topics (requires TOPICS_MODE=STATIC) + ULOG_BUILD_DYNAMIC_CONFIG=1 # runtime feature toggle API (overrides other flags) + ULOG_BUILD_DISABLED=1 # replace all log calls with ((void)0) no-ops + ULOG_BUILD_CONFIG_HEADER_ENABLED=1 # load settings from ulog_config.h instead of defines + +# Full documentation: https://github.com/an-dr/microlog diff --git a/ports/microlog/vcpkg.json b/ports/microlog/vcpkg.json new file mode 100644 index 0000000..bd4daca --- /dev/null +++ b/ports/microlog/vcpkg.json @@ -0,0 +1,17 @@ +{ + "name": "microlog", + "version": "7.0.1", + "description": "Extensible and configurable logging library for embedded and desktop applications with multi-output and logging topics", + "homepage": "https://github.com/an-dr/microlog", + "license": "MIT", + "dependencies": [ + { + "name": "vcpkg-cmake", + "host": true + }, + { + "name": "vcpkg-cmake-config", + "host": true + } + ] +} diff --git a/scripts/build_vcpkg_port.ps1 b/scripts/build_vcpkg_port.ps1 new file mode 100644 index 0000000..aaf3ee9 --- /dev/null +++ b/scripts/build_vcpkg_port.ps1 @@ -0,0 +1,93 @@ + +<# +.SYNOPSIS + Generates a vcpkg registry port for microlog with the correct SHA512 hash. + +.DESCRIPTION + Downloads the GitHub source tarball for a given tag, computes its SHA512, + and writes a ready-to-use portfile.cmake + vcpkg.json + usage into dist/vcpkg-port/. + + Can be run locally or from CI. + +.PARAMETER Tag + The git tag to build the port for (e.g. "v7.0.0"). + Defaults to the tag matching the version in the version file. + +.EXAMPLE + .\scripts\build_vcpkg_port.ps1 + .\scripts\build_vcpkg_port.ps1 -Tag v7.0.0 +#> + +param( + [string]$Tag +) + +$ErrorActionPreference = "Stop" +Set-Location "$PSScriptRoot/.." + +$RepoRoot = (Resolve-Path ".").Path +$OutDir = Join-Path $RepoRoot "dist/vcpkg-port" + +# Read version from source if no tag provided +if (-not $Tag) { + $Version = (Get-Content (Join-Path $RepoRoot "version") -Raw).Trim() + $Tag = "v$Version" +} + +$Version = $Tag.TrimStart("v") +$Url = "https://github.com/an-dr/microlog/archive/refs/tags/${Tag}.tar.gz" + +Write-Host "Tag: $Tag" +Write-Host "Version: $Version" +Write-Host "URL: $Url" + +# Download and compute SHA512 +Write-Host "Downloading tarball..." +$TempFile = [System.IO.Path]::GetTempFileName() +try { + Invoke-WebRequest -Uri $Url -OutFile $TempFile -UseBasicParsing + $Hash = (Get-FileHash -Path $TempFile -Algorithm SHA512).Hash.ToLower() + Write-Host "SHA512: $Hash" +} finally { + Remove-Item $TempFile -ErrorAction SilentlyContinue +} + +# Generate output +if (Test-Path $OutDir) { Remove-Item $OutDir -Recurse -Force } +New-Item -ItemType Directory -Path $OutDir | Out-Null + +# portfile.cmake +$Portfile = @" +vcpkg_from_github( + OUT_SOURCE_PATH SOURCE_PATH + REPO an-dr/microlog + REF "$Tag" + SHA512 $Hash +) + +vcpkg_cmake_configure( + SOURCE_PATH "`${SOURCE_PATH}" +) + +vcpkg_cmake_install() + +vcpkg_cmake_config_fixup(CONFIG_PATH "lib/cmake/microlog") + +file(REMOVE_RECURSE "`${CURRENT_PACKAGES_DIR}/debug") +file(REMOVE_RECURSE "`${CURRENT_PACKAGES_DIR}/lib") +file(REMOVE "`${CURRENT_PACKAGES_DIR}/LICENSE") + +vcpkg_install_copyright(FILE_LIST "`${SOURCE_PATH}/LICENSE") +"@ + +Set-Content -Path (Join-Path $OutDir "portfile.cmake") -Value $Portfile -NoNewline + +# vcpkg.json (update version from overlay template) +$OverlayJson = Get-Content (Join-Path $RepoRoot "ports/microlog/vcpkg.json") -Raw +$RegistryJson = $OverlayJson -replace '"version":\s*"[^"]*"', "`"version`": `"$Version`"" +Set-Content -Path (Join-Path $OutDir "vcpkg.json") -Value $RegistryJson -NoNewline + +# usage file (copy from overlay port verbatim) +Copy-Item (Join-Path $RepoRoot "ports/microlog/usage") (Join-Path $OutDir "usage") + +Write-Host "Generated port in: $OutDir" diff --git a/scripts/publish_vcpkg_port.ps1 b/scripts/publish_vcpkg_port.ps1 new file mode 100644 index 0000000..b134a37 --- /dev/null +++ b/scripts/publish_vcpkg_port.ps1 @@ -0,0 +1,94 @@ + +<# +.SYNOPSIS + Publishes the microlog vcpkg port to a local vcpkg registry clone. + +.DESCRIPTION + Builds the port artifacts (via build_vcpkg_port.ps1), copies them into the + vcpkg registry at $VcpkgPath, stages the changes, and updates the version + database with `vcpkg x-add-version`. + + Requires vcpkg to be bootstrapped (vcpkg.exe must exist in $VcpkgPath). + +.PARAMETER Tag + The git tag to publish (e.g. "v7.0.1"). + Defaults to the version in the version file. + +.PARAMETER VcpkgPath + Path to the local vcpkg registry clone. + Defaults to "../vcpkg" relative to the microlog repo root. + +.EXAMPLE + .\scripts\publish_vcpkg_port.ps1 + .\scripts\publish_vcpkg_port.ps1 -Tag v7.0.1 + .\scripts\publish_vcpkg_port.ps1 -VcpkgPath C:\src\vcpkg +#> + +param( + [string]$Tag, + [string]$VcpkgPath +) + +$ErrorActionPreference = "Stop" +Set-Location "$PSScriptRoot/.." +$RepoRoot = (Resolve-Path ".").Path + +# Resolve version / tag +if (-not $Tag) { + $Version = (Get-Content (Join-Path $RepoRoot "version") -Raw).Trim() + $Tag = "v$Version" +} +$Version = $Tag.TrimStart("v") + +# Resolve vcpkg path +if (-not $VcpkgPath) { + $VcpkgPath = Join-Path $RepoRoot "../vcpkg" +} +$VcpkgPath = (Resolve-Path $VcpkgPath).Path +$VcpkgExe = Join-Path $VcpkgPath "vcpkg.exe" + +Write-Host "Tag: $Tag" +Write-Host "Version: $Version" +Write-Host "Vcpkg: $VcpkgPath" + +# ── Step 1: Build port artifacts ───────────────────────────────────────────── +Write-Host "" +Write-Host "==> Building port artifacts..." +& (Join-Path $PSScriptRoot "build_vcpkg_port.ps1") -Tag $Tag + +$PortSrc = Join-Path $RepoRoot "dist/vcpkg-port" +$PortDst = Join-Path $VcpkgPath "ports/microlog" + +# ── Step 2: Copy port files into registry ──────────────────────────────────── +Write-Host "" +Write-Host "==> Copying port to: $PortDst" +if (Test-Path $PortDst) { Remove-Item $PortDst -Recurse -Force } +Copy-Item $PortSrc $PortDst -Recurse + +# ── Step 3: Stage port directory ───────────────────────────────────────────── +Write-Host "" +Write-Host "==> Staging port files..." +git -C $VcpkgPath add "ports/microlog" + +# ── Step 4: Update version database ────────────────────────────────────────── +Write-Host "" +Write-Host "==> Updating version database..." +if (-not (Test-Path $VcpkgExe)) { + Write-Error ( + "vcpkg.exe not found at '$VcpkgExe'.`n" + + "Bootstrap vcpkg first: .\bootstrap-vcpkg.bat`n" + + "Then re-run this script." + ) + exit 1 +} +& $VcpkgExe x-add-version microlog --overwrite-version + +# ── Step 5: Stage version database changes ─────────────────────────────────── +Write-Host "" +Write-Host "==> Staging version database..." +git -C $VcpkgPath add "versions/" + +Write-Host "" +Write-Host "Done. Changes staged in: $VcpkgPath" +Write-Host "Review : git -C '$VcpkgPath' diff --cached" +Write-Host "Commit : git -C '$VcpkgPath' commit -m 'Add microlog $Version'" diff --git a/src/ulog.c b/src/ulog.c index e876295..239b0ea 100644 --- a/src/ulog.c +++ b/src/ulog.c @@ -1799,7 +1799,7 @@ void ulog_log(ulog_level level, const char *file, int line, const char *topic, ulog_event ev = {0}; va_start(ev.message_format_args, message); - // IMPORTANT: filling the events should be after the vs_start for compatibility + // IMPORTANT: filling the events should be after the va_start for compatibility // with the VS ARM64 compiler behavior log_fill_event(&ev, message, level, file, line, topic_id); diff --git a/tests/integration/vcpkg/CMakeLists.txt b/tests/integration/vcpkg/CMakeLists.txt new file mode 100644 index 0000000..f19dd0c --- /dev/null +++ b/tests/integration/vcpkg/CMakeLists.txt @@ -0,0 +1,9 @@ +cmake_minimum_required(VERSION 3.15) +project(example_vcpkg C) + +find_package(microlog CONFIG REQUIRED) + +add_executable(example_vcpkg example.c) +target_link_libraries(example_vcpkg PRIVATE microlog::microlog) + +install(TARGETS example_vcpkg) diff --git a/tests/integration/vcpkg/example.c b/tests/integration/vcpkg/example.c new file mode 100644 index 0000000..f121351 --- /dev/null +++ b/tests/integration/vcpkg/example.c @@ -0,0 +1,6 @@ +#include "ulog.h" + +int main(void) { + ulog_info("Test message from vcpkg port test"); + return 0; +} diff --git a/tests/integration/vcpkg/test_vcpkg.ps1 b/tests/integration/vcpkg/test_vcpkg.ps1 new file mode 100644 index 0000000..a821b40 --- /dev/null +++ b/tests/integration/vcpkg/test_vcpkg.ps1 @@ -0,0 +1,56 @@ +# ************************************************************************* +# +# Copyright (c) 2025 Andrei Gramakov. All rights reserved. +# +# This file is licensed under the terms of the MIT license. +# For a copy, see: https://opensource.org/licenses/MIT +# +# site: https://agramakov.me e-mail: mail@agramakov.me +# +# ************************************************************************* + +$ErrorActionPreference = "Stop" +Push-Location $PSScriptRoot + +try { + + # Require VCPKG_ROOT + if (-not $env:VCPKG_ROOT) { + Write-Error "VCPKG_ROOT is not set. Please install vcpkg and set the environment variable." + } + $VcpkgExe = Join-Path $env:VCPKG_ROOT "vcpkg" + $VcpkgToolchain = Join-Path $env:VCPKG_ROOT "scripts/buildsystems/vcpkg.cmake" + + $RepoRoot = (Resolve-Path "$PSScriptRoot/../../..").Path + $OverlayPorts = Join-Path $RepoRoot "ports" + + # Install microlog via overlay port + Write-Host "Installing microlog via overlay port..." + & $VcpkgExe install microlog "--overlay-ports=$OverlayPorts" + if ($LASTEXITCODE -ne 0) { + Write-Host "vcpkg install failed with exit code $LASTEXITCODE" + exit $LASTEXITCODE + } + + # Build the consumer test project + cmake -B ./build -DCMAKE_TOOLCHAIN_FILE="$VcpkgToolchain" + if ($LASTEXITCODE -ne 0) { + Write-Host "CMake configure failed with exit code $LASTEXITCODE" + exit $LASTEXITCODE + } + cmake --build ./build --verbose + if ($LASTEXITCODE -ne 0) { + Write-Host "Build failed with exit code $LASTEXITCODE" + exit $LASTEXITCODE + } + +} catch { + + Write-Host "An error occurred: $_" + Pop-Location + exit 1 # Exit the script with a non-zero code to indicate failure + +} + +Write-Host "`n[OK] Test completed successfully." +Pop-Location