Welcome to the Libmagicxx project! We appreciate your interest in contributing. Whether you are fixing bugs, adding features, improving documentation, or suggesting enhancements, your contributions are valuable and help make Libmagicxx better for everyone.
This guide provides everything you need to contribute successfully.
Table of Contents
Quick Reference
| Task | Command |
| Build & test (Clang) | ./scripts/workflows.sh -p linux-x86_64-clang-tests -c |
| Build & test (GCC) | ./scripts/workflows.sh -p linux-x86_64-gcc-tests -c |
| Format code | ./scripts/workflows.sh -p format-source-code |
| Build examples | ./scripts/workflows.sh -p linux-x86_64-clang-examples |
| Build documentation | ./scripts/workflows.sh -p documentation |
| List all presets | ./scripts/workflows.sh -l |
| Run specific test | ./build/tests/magicxx_tests --gtest_filter="TestName.*" |
| Initialize project | ./scripts/initialize.sh |
Code of Conduct
We expect all contributors to adhere to the Code of Conduct. Please read it to understand the standards of behavior we expect from our community.
Types of Contributions
| Type | Branch Prefix | PR Title Prefix | Description |
| π Bug Fix | bugfix/ | [BUGFIX] | Fix a bug in existing functionality |
| β¨ Enhancement | enhancement/ | [ENHANCEMENT] | Add new feature or improve existing one |
| π Documentation | documentation/ | [DOCUMENTATION] | Improve docs, comments, or examples |
| π§Ή Code Quality | quality/ | [QUALITY] | Refactoring, formatting, style improvements |
Development Workflow
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Contribution Workflow β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β 1. SETUP 2. DEVELOP β
β ββββββββββββββββββββ ββββββββββββββββββββ β
β β Fork repository βββββββββ>β Create branch β β
β β Clone locally β β (from main) β β
β β Start container β β β β
β β Run initialize.shβ β bugfix/my-fix β β
β ββββββββββββββββββββ ββββββββββ¬ββββββββββ β
β β β
β βΌ β
β 4. VALIDATE 3. CODE β
β ββββββββββββββββββββ ββββββββββββββββββββ β
β β Build & test β<βββββββββ Make changes β β
β β Format code β β Add/update tests β β
β β Update CHANGELOG β β Update docs β β
β β β β Commit often β β
β ββββββββββ¬ββββββββββ ββββββββββββββββββββ β
β β β
β βΌ β
β 5. SUBMIT 6. REVIEW β
β ββββββββββββββββββββ ββββββββββββββββββββ β
β β Push to fork βββββββββ>β Maintainer reviewβ β
β β (from host, not β β Address feedback β β
β β container) β β CI must pass β β
β β Create PR β β Merge! β β
β ββββββββββββββββββββ ββββββββββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Branch Strategy
- main: Development branch for next feature release.
- vX.Y.x: Stable release branches. All release tags (vX.Y.0, vX.Y.1, etc.) are created on these branches.
- Major/minor releases (vX.0.0, vX.Y.0) create a new vX.Y.x branch from main.
- Patch releases (vX.Y.Z) are tagged on existing vX.Y.x branches.
- All bugfix changes are also merged to main.
Project Structure
libmagicxx/
βββ include/magicxx/ # π¦ PUBLIC API - Header files
β βββ magic.hpp # The main header (Recognition::Magic class)
β
βββ sources/ # π§ IMPLEMENTATION
β βββ magic.cpp # Implementation of magic.hpp
β
βββ tests/ # π§ͺ UNIT TESTS (GoogleTest)
β βββ CMakeLists.txt # Test build configuration
β βββ main.cpp # Test runner entry point
β βββ magic_*_test.cpp # Test files (one per feature area)
β
βββ examples/ # π‘ EXAMPLES
β βββ CMakeLists.txt # Examples build configuration
β βββ magic_examples.cpp # Runnable usage examples
β
βββ cmake/ # βοΈ CMAKE CONFIGURATION
β βββ STYLE_GUIDE.md # CMake coding conventions
β βββ options.cmake # CMake option definitions
β βββ targets.cmake # Library target definitions
β βββ ... # Other CMake modules
β
βββ scripts/ # π οΈ UTILITY SCRIPTS
β βββ workflows.sh # Main build/test script
β βββ initialize.sh # Project initialization
β βββ launch_container.py # Development container launcher
β βββ ... # Other scripts
β
βββ databases/ # ποΈ MAGIC DATABASE FILES
β βββ magic # Source magic definitions
β βββ magic.mgc # Compiled magic database
β
βββ external/ # π EXTERNAL DEPENDENCIES (Git submodules)
β βββ file/ # libmagic (file command library)
β βββ googletest/ # GoogleTest framework
β βββ libgnurx/ # Regex library for Windows
β
βββ documentation/ # π DOXYGEN DOCUMENTATION
βββ .github/ # π CI/CD WORKFLOWS
βββ CMakeLists.txt # π Top-level CMake configuration
βββ CMakePresets.json # π― CMake workflow presets
βββ STYLE_GUIDE.md # π C++ coding conventions
βββ CHANGELOG.md # π Version history
βββ Containerfile # π³ Development container definition
Key Files for Contributors
| What You're Changing | Files to Modify |
| Public API | include/magicxx/magic.hpp |
| Implementation | sources/magic.cpp |
| Add a test | tests/magic_*_test.cpp (existing) or create new tests/magic_yourfeature_test.cpp |
| Add an example | examples/magic_examples.cpp |
| Fix a build issue | cmake/*.cmake or CMakeLists.txt |
| Update docs | README.md, documentation/, or Doxygen comments in .hpp |
Getting Started
Prerequisites (Host Machine)
Install these on your host machine (not the container):
Step-by-Step Setup
Step 1: Fork and Clone
# Fork on GitHub, then clone your fork
git clone https://github.com/YOUR-USERNAME/libmagicxx.git
cd libmagicxx
Step 2: Launch Development Container
# Linux/macOS
python ./scripts/launch_container.py
# Windows
python .\scripts\launch_container.py
# To update the container image (after Containerfile changes)
python ./scripts/launch_container.py -u
Step 3: Attach VS Code to Container
- Press Ctrl+Shift+P (or Cmd+Shift+P on macOS)
- Select "Dev Containers: Attach to Running Container..."
- Choose libmagicxx_dev_env
Step 4: Install VS Code Extensions (Inside Container)
Install these extensions in the container for best experience:
Step 5: Initialize the Project
# Inside the container terminal
./scripts/initialize.sh
This builds external dependencies (libmagic, GoogleTest) and prepares the build environment.
Step 6: Verify Setup
# Build and run all tests to verify everything works
./scripts/workflows.sh -p linux-x86_64-clang-tests -c
Expected output: All tests should pass.
Making Changes
Step 1: Create a Branch
# For a bug fix
git checkout -b bugfix/fix-null-pointer-crash
# For a new feature
git checkout -b enhancement/add-buffer-identification
# For documentation
git checkout -b documentation/improve-readme
# For code quality
git checkout -b quality/refactor-error-handling
Step 2: Understand the Code Style
All code must follow STYLE_GUIDE.md. Key rules:
Naming Conventions
class Magic {
public:
template <typename ContainerT>
static constexpr int MAX_SIZE = 100;
private:
magic_t m_handle;
int m_flag_count;
};
}
struct MagicFlagsTest : testing::Test { };
TEST_F(MagicFlagsTest, set_flags_returns_true_for_valid_magic) { }
std::string FileTypeT
String type representing the detected type of a file.
Definition magic.hpp:230
void SetFlags(FlagsMaskT flags_mask)
Set new flags for the Magic instance.
Definition magic.cpp:2674
Root namespace for the libmagicxx library.
File Naming
magic_feature.hpp # snake_case, .hpp for headers
magic_feature.cpp # snake_case, .cpp for source files
magic_feature_test.cpp # _test.cpp suffix for test files
CHANGELOG.md # SCREAMING_SNAKE_CASE for documentation files
Step 3: Make Your Changes
- Edit the appropriate files (see Key Files for Contributors)
- Add/update tests for any behavior changes
- Update documentation (Doxygen comments for API changes)
- Commit frequently with descriptive messages using component prefixes:
Commit Message Format
<Component>: <Brief description>
Component prefixes:
| Prefix | Use For |
| CI/CD: | GitHub Actions workflows, CI/CD pipelines, automation |
| CMake: | Build system, CMakeLists.txt, presets |
| Deps: | External dependencies updates |
| DevEnv: | Container, development environment setup |
| Docs: | Documentation, README, Doxygen comments |
| Examples: | Example code changes |
| Format: | Clang tools (.clang-format, .clang-tidy), code formatting |
| Magic: | Changes to Magic class, core library functionality |
| Release: | Version bumps, changelog, release preparation |
| Scripts: | Shell and Python scripts in scripts/ directory |
| Tests: | Test files, test infrastructure |
| Toolchains: | CMake toolchain files, compiler configurations |
| Utility: | Utility classes (ProgressTracker, Percentage) |
Examples:
git commit -m "Magic: Add buffer identification support"
git commit -m "Docs: Fix rendering issues in README"
git commit -m "CMake: Add new test preset for coverage"
git commit -m "Tests: Add regression test for empty path handling"
git commit -m "CI/CD: Trigger builds on push to main branch"
git commit -m "DevEnv: Update container to Fedora 43"
For multi-component changes, use the primary component or combine:
git commit -m "Magic, Tests: Add IdentifyBuffer with unit tests"
Step 4: Build and Test
# Build and run all tests
./scripts/workflows.sh -p linux-x86_64-clang-tests -c
# Or with GCC
./scripts/workflows.sh -p linux-x86_64-gcc-tests -c
Step 5: Format Your Code
./scripts/workflows.sh -p format-source-code
Step 6: Update CHANGELOG.md
Add your changes under the "Next Release" section:
## Next Release
+ **[ENHANCEMENT]** Magic: Add buffer identification support.
+ **[BUGFIX]** Magic: Fix null pointer crash when database not loaded.
+ **[DOCUMENTATION]** Docs: Improve README examples.
+ **[QUALITY]** Magic: Refactor error handling for consistency.
Writing Tests
Test File Organization
Each feature area has its own test file:
| Test File | What It Tests |
| magic_open_close_test.cpp | Open(), Close(), IsOpen() |
| magic_flags_test.cpp | GetFlags(), SetFlags() |
| magic_identify_file_test.cpp | IdentifyFile() |
| magic_identify_directory_test.cpp | IdentifyFiles() with directories |
| magic_identify_container_test.cpp | IdentifyFiles() with containers |
| magic_load_database_file_test.cpp | LoadDatabaseFile() |
| magic_parameters_test.cpp | GetParameter(), SetParameter() |
| magic_compile_test.cpp | Compile() |
| magic_check_test.cpp | Check() |
| magic_version_test.cpp | GetVersion() |
| magic_special_members_test.cpp | Copy, move, assignment |
| magic_progress_tracker_test.cpp | ProgressTracker |
| magic_percentage_test.cpp | Percentage utility class |
| magic_to_string_test.cpp | ToString() functions |
Test Structure Template
#include <gtest/gtest.h>
struct MagicYourFeatureTest : testing::Test {
protected:
MagicYourFeatureTest()
{
}
Magic m_closed_magic;
};
TEST_F(MagicYourFeatureTest, returns_expected_value_for_valid_input)
{
auto input = ;
auto result = m_valid_magic.YourFeature(input);
EXPECT_EQ(result, expected_value);
}
TEST_F(MagicYourFeatureTest, throws_exception_when_magic_is_closed)
{
}
TEST_F(MagicYourFeatureTest, noexcept_variant_returns_nullopt_when_closed)
{
auto result = m_closed_magic.YourFeature(std::nothrow);
EXPECT_FALSE(result.has_value());
}
Base exception class for all Magic-related errors.
Definition magic_exception.hpp:102
A modern C++23 wrapper for libmagic β the library that powers the Unix file command.
Definition magic.hpp:216
@ Mime
Definition magic.hpp:328
Main header file for the libmagicxx library.
Running Specific Tests
# Run all tests
./build/tests/magicxx_tests
# Run tests matching a pattern
./build/tests/magicxx_tests --gtest_filter="MagicFlagsTest.*"
# Run a specific test
./build/tests/magicxx_tests --gtest_filter="MagicFlagsTest.set_flags_returns_true_for_valid_magic"
# List all tests without running
./build/tests/magicxx_tests --gtest_list_tests
Writing Documentation
Doxygen Comments for Public API
Every public class, method, and type must have Doxygen documentation:
[[nodiscard]] FileTypeT IdentifyFile(const std::filesystem::path& file) const;
The @since Tag
The @since tag documents which version introduced the exact symbol name. This is important because users looking at documentation should be able to find the same symbol in the specified version.
**Rules for @since tags:**
- New API: Use the upcoming release version (e.g., @since 10.0.0)
- Renamed API (breaking change): Update to the new version. If you rename identify_file() to IdentifyFile(), change @since 5.0.0 to @since 10.0.0 because a user going back to v5.0.0 won't find IdentifyFile().
- Unchanged API: Keep the original @since tag.
Example β Renaming a method:
[[nodiscard]] FileTypeT IdentifyFile(const std::filesystem::path& file) const;
Building Documentation
./scripts/workflows.sh -p documentation
The generated documentation site is located at ./build/documentation/html/index.html. Open this file in your web browser to view the API documentation.
Build and Test Commands
Available Workflow Presets
Use ./scripts/workflows.sh -l to see the full list. Key presets for contributors:
Utility Presets
| Preset | Description |
| documentation | Generate Doxygen documentation |
| format-source-code | Format all source files |
| generate-source-package | Generate source package |
| generate-default-database-files | Generate default database files |
Linux Build Presets (Development Container)
| Preset | Description |
| linux-x86_64-clang | Build libraries (Clang, Release) |
| linux-x86_64-gcc | Build libraries (GCC, Release) |
| linux-x86_64-clang-debug | Build libraries (Clang, Debug) |
| linux-x86_64-gcc-debug | Build libraries (GCC, Debug) |
| linux-x86_64-clang-tests | Build + run tests (Clang, Release) |
| linux-x86_64-gcc-tests | Build + run tests (GCC, Release) |
| linux-x86_64-clang-tests-debug | Build + run tests (Clang, Debug) |
| linux-x86_64-gcc-tests-debug | Build + run tests (GCC, Debug) |
| linux-x86_64-clang-examples | Build examples (Clang, Release) |
| linux-x86_64-gcc-examples | Build examples (GCC, Release) |
| linux-x86_64-clang-examples-debug | Build examples (Clang, Debug) |
| linux-x86_64-gcc-examples-debug | Build examples (GCC, Debug) |
| linux-x86_64-clang-packages | Build packages (Clang, Release) |
| linux-x86_64-gcc-packages | Build packages (GCC, Release) |
Windows Build Presets (Cross-compilation)
| Preset | Description |
| windows-x86_64-clang | Build libraries (Clang, Release) |
| windows-x86_64-mingw64 | Build libraries (MinGW64, Release) |
| windows-x86_64-clang-debug | Build libraries (Clang, Debug) |
| windows-x86_64-mingw64-debug | Build libraries (MinGW64, Debug) |
| windows-x86_64-clang-tests | Build + run tests (Clang, Release) |
| windows-x86_64-mingw64-tests | Build + run tests (MinGW64, Release) |
| windows-x86_64-clang-tests-debug | Build + run tests (Clang, Debug) |
| windows-x86_64-mingw64-tests-debug | Build + run tests (MinGW64, Debug) |
| windows-x86_64-clang-examples | Build examples (Clang, Release) |
| windows-x86_64-mingw64-examples | Build examples (MinGW64, Release) |
| windows-x86_64-clang-examples-debug | Build examples (Clang, Debug) |
| windows-x86_64-mingw64-examples-debug | Build examples (MinGW64, Debug) |
| windows-x86_64-clang-packages | Build packages (Clang, Release) |
| windows-x86_64-mingw64-packages | Build packages (MinGW64, Release) |
Common Commands
# List all available presets
./scripts/workflows.sh -l
# Build and test with cache clearing (recommended for clean builds)
./scripts/workflows.sh -p linux-x86_64-clang-tests -c
# Build and test without clearing cache (faster incremental builds)
./scripts/workflows.sh -p linux-x86_64-clang-tests
# Build and run examples (examples are executed automatically)
./scripts/workflows.sh -p linux-x86_64-clang-examples
# Direct CMake workflow (alternative to scripts/workflows.sh)
cmake --workflow --preset linux-x86_64-clang-tests
Debugging
Debug Build
# Build with debug symbols
./scripts/workflows.sh -p linux-x86_64-clang-tests-debug -c
Using VS Code Debugger
The project includes pre-configured debug launchers in .vscode/launch.json:
- Install the LLDB DAP extension (for LLDB) or C/C++ Extension Pack (for GDB)
- Build with debug symbols: ./scripts/workflows.sh -p linux-x86_64-clang-tests-debug -c
- Open the Run and Debug panel (Ctrl+Shift+D)
- Select a launch configuration:
- GDB Debug β Debug using GDB
- LLDB Debug β Debug using LLDB
- Set breakpoints in your code
- Press F5 to start debugging
π‘ Tip: The debugger uses CMake's launch target. Select your target (e.g., magicxx_tests) from the CMake Tools status bar before debugging.
Creating a Pull Request
Before Submitting
Complete this checklist:
- Branch created from main (or release branch for bugfix)
- All tests pass: ./scripts/workflows.sh -p linux-x86_64-clang-tests
- Code formatted: ./scripts/workflows.sh -p format-source-code
- New tests added for new functionality
- Doxygen comments added for new public APIs
- Linked to an existing issue (or created one)
Push Your Changes
β οΈ Important: Git operations (push, pull, fetch) don't work inside the container. Use your host VS Code window for git operations.
Why? The container doesn't have access to your SSH keys or git credentials configured on your host machine. These are intentionally not shared for security reasons.
Recommended workflow:
- Keep your original VS Code window open (the one you used before attaching to the container)
- Develop in the container-connected VS Code window
- When ready to push, switch back to your original VS Code window (host)
- Push from the host using VS Code's Source Control panel (Ctrl+Shift+G) or the integrated terminal
# Or use the terminal in the host VS Code window:
cd libmagicxx
git add .
git commit -m "Magic: Brief description of changes"
git push origin your-branch-name
Create the Pull Request
- Go to your fork on GitHub
- Click "Compare & pull request"
- Fill in the PR template β it includes a checklist and description section
PR Title Format
[BUGFIX] Fix null pointer crash in IdentifyFile, Fixes issue #123.
[ENHANCEMENT] Add buffer identification support, Fixes issue #456.
[DOCUMENTATION] Improve README examples, Fixes issue #789.
[QUALITY] Refactor error handling for consistency, Fixes issue #012.
Reporting Issues
Before Creating an Issue
- Search existing issues to avoid duplicates
- Check if it's already fixed in main branch
Issue Templates
When creating an issue, use the appropriate template:
- Bug Report: For reporting bugs
- Feature Request: For suggesting new features
- Documentation: For documentation improvements
- Code Quality: For code quality or style issues
Tips for Good Reports
- Be specific: Include exact steps to reproduce, error messages, and system information
- Provide context: Explain what you were trying to accomplish
- Include versions: Libmagicxx version, compiler, OS
- Attach logs: Stack traces, build output, or screenshots if relevant
The issue templates will guide you through providing all necessary information.
Review Process
What Reviewers Look For
- Correctness: Does the code work as intended?
- Tests: Are there adequate tests?
- Style: Does it follow STYLE_GUIDE.md?
- Documentation: Are public APIs documented?
- ABI Stability: Do changes break binary compatibility?
Responding to Feedback
- Address each comment
- Push new commits (don't force-push during review)
- Reply to comments explaining your changes
- Request re-review when ready
After Merge
- The CI will run final checks
- Your changes appear in the next release
- You'll be credited in the release notes
Troubleshooting
Container Won't Start
# Check if Podman is running
podman ps
# Remove old container and rebuild
podman rm -f libmagicxx_dev_env
python ./scripts/launch_container.py -u
Build Fails with "No such file"
# Reinitialize the project (rebuilds external dependencies)
./scripts/initialize.sh
Tests Fail After Pulling Latest Changes
# Clean build from scratch
./scripts/workflows.sh -p linux-x86_64-clang-tests -c
Git Push Fails from Container
Git operations (push, pull, fetch) don't work inside the container. Exit the container first, then run git commands on your host machine.
Clangd Shows Wrong Errors
# Regenerate compile_commands.json
./scripts/workflows.sh -p linux-x86_64-clang -c
Code Formatting Changes Unexpected Files
Only your changes should be formatted. If formatting touches many files, someone may have committed unformatted code. Format and commit separately:
./scripts/workflows.sh -p format-source-code
git add .
git commit -m "Format code"
FAQ
Q: Do I need to sign a CLA?
No, we don't require a Contributor License Agreement. By submitting a PR, you agree your contributions are licensed under LGPL v3.
Q: Can I work on multiple issues at once?
Yes, create separate branches for each issue.
Q: How long until my PR is reviewed?
We aim to review PRs within a few days. Complex changes may take longer.
Q: What if CI fails?
Check the CI logs on GitHub. Common issues:
- Formatting: Run ./scripts/workflows.sh -p format-source-code
- Test failures: Run tests locally and fix
- Build errors: Check compiler output
Q: What C++ standard is required?
C++23. All code must compile with GCC 14+ and Clang 19+.
Q: How do I add a new CMake option?
- Add to cmake/options.cmake
- Follow conventions in cmake/STYLE_GUIDE.md
- Document in README.md
Q: What if I need help?
- Check existing issues and discussions
- Create a new issue with the "question" label
- Be specific about what you're trying to do
Thank You
Thank you for contributing to Libmagicxx! Your efforts help improve the project for everyone. Every contribution, no matter how small, is appreciated.
Happy coding! π