Code Formatting with clang-format
The Universal library provides clang-format configuration as a formatting tool for developers. It is not enforced in CI, allowing developers to maintain manual formatting where it improves readability.
Philosophy
Section titled “Philosophy”- clang-format is a helper tool, not a strict enforcer
- Use it for new code to maintain basic consistency
- Manual formatting is respected when it aids comprehension (aligned tables, structured enums, etc.)
- Developers decide when to apply formatting suggestions
Quick Start
Section titled “Quick Start”Installing clang-format
Section titled “Installing clang-format”Ubuntu/Debian:
sudo apt-get install clang-formatmacOS (Homebrew):
brew install clang-formatWindows: Download from LLVM releases or install via chocolatey:
choco install llvmUsing the Format Targets
Section titled “Using the Format Targets”After installing clang-format, the CMake configuration will automatically detect it and create formatting targets:
# Configure (format targets will be created automatically)cmake -B build
# Check what would be changed in headers (first 50 issues)make -C build format-headers-check
# Format only header filesmake -C build format-headers
# Format only test/application filesmake -C build format-tests
# Show what would be changed (first 50 issues)make -C build format-diff
# Format all source files (use with caution!)make -C build formatRecommendation: Use format-headers-check or format-diff to review suggestions before applying. Apply formatting selectively to files you’re actively working on.
Configuration
Section titled “Configuration”The .clang-format file in the repository root defines our code style:
- C++ Standard: C++20
- Indentation: Tabs (width 4)
- Line Length: 120 characters
- Brace Style: Attach (K&R style)
- Pointer Alignment: Left (
int* ptr) - Include Sorting: Enabled, grouped by category
IDE Integration
Section titled “IDE Integration”VS Code
Section titled “VS Code”- Install the C/C++ extension (Microsoft)
- Add to your
settings.json:
{ "C_Cpp.clang_format_style": "file", "editor.formatOnSave": true}- Go to Settings → Editor → Code Style → C/C++
- Click Set from… → Predefined Style → LLVM
- Check Enable ClangFormat
- Set clang-format binary path if needed
Vim/Neovim
Section titled “Vim/Neovim”Install vim-clang-format:
" In your .vimrcPlug 'rhysd/vim-clang-format'
" Format on saveautocmd FileType c,cpp,objc ClangFormatAutoEnable;; In your .emacs or init.el(require 'clang-format)(global-set-key (kbd "C-c f") 'clang-format-region)(global-set-key (kbd "C-c u") 'clang-format-buffer)
;; Format on save(add-hook 'before-save-hook 'clang-format-buffer)Pre-commit Hook (Optional)
Section titled “Pre-commit Hook (Optional)”To automatically format files before committing:
# Create pre-commit hookcat > .git/hooks/pre-commit << 'EOF'#!/bin/bash# Format changed C++ files with clang-format
files=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(cpp|hpp|h|cc|cxx)$')
if [ -n "$files" ]; then echo "Formatting modified C++ files..." clang-format -i $files git add $filesfiEOF
# Make it executablechmod +x .git/hooks/pre-commitCommand Line Usage
Section titled “Command Line Usage”Format specific files
Section titled “Format specific files”# Format a single fileclang-format -i include/sw/universal/number/posit/posit.hpp
# Format multiple filesclang-format -i file1.hpp file2.cpp file3.h
# Format all headers in a directoryfind include/sw/universal/number/posit -name "*.hpp" -exec clang-format -i {} \;Check formatting without modifying
Section titled “Check formatting without modifying”# Check a file (returns exit code 1 if not formatted)clang-format --dry-run --Werror file.hpp
# Show diff of what would changeclang-format --dry-run file.hpp | diff file.hpp -Format specific lines/regions
Section titled “Format specific lines/regions”# Format lines 10-50clang-format -i --lines=10:50 file.cpp
# Format changed lines (useful for partial formatting)git diff -U0 --no-color HEAD | clang-format-diff -i -p1CI Integration
Section titled “CI Integration”clang-format is NOT enforced in CI. The formatting check targets are provided for developer convenience only.
Developers are trusted to maintain reasonable code formatting. When in doubt:
- Follow the existing style in the file you’re editing
- Use clang-format suggestions as guidance, not requirements
- Prioritize readability over strict formatting rules
Formatting Guidelines
Section titled “Formatting Guidelines”What gets formatted
Section titled “What gets formatted”- All
.hppheader files ininclude/ - All
.cppsource files in tests and applications - All
.hC header files
What doesn’t get formatted
Section titled “What doesn’t get formatted”- Third-party code in
external/(if any) - Generated files in
build/ - Binary files
Common Patterns
Section titled “Common Patterns”Template Declarations:
// Well-formatted templatetemplate<unsigned nbits, unsigned es>class posit { // ...};Namespace Style:
// Compact namespace declarationnamespace sw { namespace universal {
// Code here
}} // namespace sw::universalInclude Organization:
// Grouped and sorted automatically#include <iostream> // C++ standard library#include <vector>
#include <universal/utility/compiler.hpp> // Universal utilities#include <universal/traits/number_traits.hpp> // Universal traits#include <universal/number/posit/posit.hpp> // Universal numbers
#include "local_header.hpp" // Local headersLong Function Signatures:
// Automatically wrappedtemplate<typename Real>void some_very_long_function_name_that_exceeds_line_limit( const Real& parameter1, const Real& parameter2, int another_param) { // Implementation}Troubleshooting
Section titled “Troubleshooting”clang-format not found
Section titled “clang-format not found”# Check if installedwhich clang-format
# Check version (we support 14+)clang-format --version
# If not found, install it (see Installing clang-format above)Format targets not available
Section titled “Format targets not available”# Reconfigure CMake to detect clang-formatrm -rf buildcmake -B build
# Check if clang-format was foundgrep "clang-format" build/CMakeCache.txtDifferent formatting results
Section titled “Different formatting results”- Ensure you’re using the same clang-format version as CI (16+ recommended)
- Check that
.clang-formatfile is in the repository root - Some older versions may format slightly differently
Merge conflicts in formatted code
Section titled “Merge conflicts in formatted code”# After resolving conflicts, reformatclang-format -i <conflicted-file>git add <conflicted-file>git commitQ: Do I need to format existing code I’m not changing? A: No. Never reformat code you’re not actively modifying.
Q: What if clang-format makes my code less readable? A: Don’t apply it! Manual formatting that improves readability is always preferred. You can also disable formatting for specific regions:
// clang-format offint matrix[3][3] = { {1, 0, 0}, {0, 1, 0}, {0, 0, 1}};// clang-format onQ: Do I have to use clang-format? A: No. It’s a tool to help with basic formatting consistency, not a requirement.
Q: When should I use clang-format? A: Use it when:
- Writing new files from scratch
- You want help with basic indentation and spacing
- Cleaning up obviously inconsistent formatting
Don’t use it when:
- Existing code has intentional manual alignment
- The suggestions make code harder to read
- You’re working in files with established formatting
Q: Why tabs instead of spaces?
A: The Universal codebase historically uses tabs for indentation, spaces for alignment (via UseTab: ForIndentation). This allows developers with different editor settings to view code at their preferred indent width.
Q: Can I use a different style for my fork?
A: Yes, modify .clang-format in your fork. However, try to maintain general consistency with the main repo style for easier merging.