| Tip of the day: You can add a Webhook that is called on certain log events. This can be used to automate things or to notify you in case of trouble. |
Dev:Coding guidelines
This article explains how to setup your development environment and how to contribute code to UnrealIRCd.
Getting started
Setting up the development environment
When developing, always build with AddressSanitizer enabled. See the question near the end of ./Config. AddressSanitizer (ASan) catches memory issues the moment they happen. Without ASan the IRCd may crash hours later without any meaningful trace.
If you are going to use Visual Studio Code - like the main dev - then check out Dev:Visual Studio Code. This also helps you with automatic indent/formatting.
The Doxygen docs show the UnrealIRCd API. This may be a good place to start if you are looking for something in particular (used as a reference guide).
Most of our docs regarded to programming assume you are writing a 3rd party module, eg:
- Dev:Module has some good words on how to start, including an howto on writing your first 3rd party mod
- Dev:Module API contains some of the module API
In general, reading existing UnrealIRCd code may help understanding how things work in UnrealIRCd. It's usually best to read something clear and self-contained, like a module (or a 3rd party module).
When to discuss first
At UnrealIRCd, a PR is for code that is ready to be merged, it is not intended to propose or discuss a change.
Please discuss the following changes on the bugtracker before you start working:
- Feature suggestions
- Major cleaning/rewriting of existing code
- Changes to the protocol (both client and server), no matter how small the change is
- Breaking the module API
This way, the main coders may still suggest to do things in a particular way or indicate that we don't want such a change.
Anything not in the list above, such as bugfixes and small improvements, can be submitted as a patch/PR immediately.
Code style
Code formatting
Code formatting is fully automated.
The rules live in the .clang-format file in the source and you apply them by running make format (this requires clang-format major version 21).
The easiest way is to let your editor format on save, see Dev:Visual Studio Code. Pull requests containing unformatted code will be rejected by the CI.
A few things are deliberately not auto-formatted: hand-formatted tables and similar are surrounded by /* clang-format off */ and /* clang-format on */ markers.
Only use these markers when manual layout genuinely is more readable, such as in large data tables.
Git pre-commit hook
Developers with commit access are assumed to have a git pre-commit hook that refuses unformatted code.
Save the following as .git/hooks/pre-commit and make it executable (chmod +x):
#!/bin/sh # Check-only hook: refuse to commit code that is not clang-formatted. # Never modifies anything. Bypass once with: git commit --no-verify output=$(git clang-format --staged --diff 2>/dev/null) case "$output" in ""|"no modified files to format"*|"clang-format did not modify any files"*) exit 0 ;; *) echo "ERROR: Commit rejected: staged changes are not clang-formatted." echo "Run 'make format', review the result, and commit again." echo "(Bypass once with: git commit --no-verify)" exit 1 ;; esac
This requires git-clang-format, which comes with clang-format on most distributions.
Again, you should use clang version 21 here. If you have multiple clang versions installed, then tell it which one to use with: git config clangFormat.binary clang-format-21
Major restructuring or cleanups
If you want to restructure or clean up existing code beyond a bug or isolated feature you are working on, then you MUST discuss it first. The stable tree is often not really suitable for such things, especially if we are talking multiple files etc.
Also be careful with cleanups in general: if something looks redundant or useless at first sight, look again. It may indeed be useless, but it may also be a subtle thing that creates great bugs when 'cleaned up'.
Comments
Comment your code. It will help the next person reading it, and it will help you when you look at your own code two years later. If there is some obscure pitfall in the code, then DO mention it. Don't just hope the next author will see it like you did.
For documenting functions and struct members we use doxygen style comments: /** Like this */.
Regular comments use /* this style */.
Using // is acceptable for a short single-line remark, but multi-line comments always use /* */.
Don't mass-convert comments from one style to the other.
Writing good code
String handling
Be careful about overflows, do not do any unchecked string copies.
Instead of strcpy, strcat and sprintf, use the length-checking functions: strlcpy, strlcat and snprintf/ircsnprintf.
If you are copying or writing character-by-character in a loop, for example using *p++ = x;, then be very sure about your size counting.
Often it is better to avoid such code altogether and simply use strlcat and similar functions for everything.
Memory
Use safe_alloc, safe_free, safe_strdup and safe_strldup. These functions properly initialize memory (such as structs) with zeroes.
Do NOT use malloc, calloc, free or strdup directly.
Logging
All (new) code uses unreal_log() for logging and server notices (snomasks, etc). Don't use legacy calls. Exceptions are config_warn/config_error in config code.
Readability comes first
When writing or optimizing code, readability and stability come FIRST, speed comes after that.
We prefer readable code over a highly optimized routine that nobody understands, is difficult to extend, and might have several bugs.
Portability
The minimum is a C99 compiler, which ./configure enforces. In practice the code is built as C17 with GNU extensions on *NIX.
Code must also compile on Windows with Visual Studio 2019, so don't use exotic compiler-specific extensions.
Enums
- Use enums rather than #define constants whenever possible. It is cleaner and it aids debugging. For bit flags, we still use defines.
Before you commit
Test your code
Very important: TEST your code before committing or doing a Pull Request. Not just that it compiles, but also that it does what you want. Yes, also that one line change that you are 100% sure about breaks nothing :-)
For bigger changes or if you are dealing with any memory stuff, please run with AddressSanitizer (see ./Config).
There is also a test suite which the CI runs on every push and pull request.
Copyright
- New files must contain a proper copyright header. UnrealIRCd is GNU GPLv2 or later, so it must be compatible.
- If code from other people or projects is used, it MUST be properly credited (and again, the license must permit it).
Security issues
If you found a security issue, then do NOT report or discuss it on the public bug tracker. Also do not submit a fix as a PR. See Policy: Handling of security issues for how to report it privately.
IMPORTANT: A crash issue that a regular user can trigger is considered a security issue! Follow the procedure above.
Submitting patches
You can submit patches either as a Pull Request (PR) on GitHub or by attaching a patch file (diff -u) at a bug item at the bugtracker.
It really helps if your pull request references an entry on https://bugs.unrealircd.org/, since that is where development is coordinated and discussion takes place. If there is no bug# then a PR is more likely to be overlooked (sorry).
Make sure you target your PR for UnrealIRCd 6, so the unreal60_dev branch
Use of AI
Did you use AI? Don't worry, we use AI ourselves as well. But please check out our policy on the use of AI to see if you need to disclose this. It also contains a FAQ covering three common cases.
Developers with commit access
The following applies to developers who commit directly to the repository, including when merging someone else's pull request.
Changes that need prior discussion
The rules about discussing changes also apply to developers. Especially since commits go in directly, without any review.
Commit messages
The following applies to commits from yourself and if you merge someones PR:
- The first line of the commit message is a short summary of max 70 characters. This is what GitHub and
git log --onelineshow in commit overviews, so it must make sense on its own. - The rest of the commit message should explain what you changed and why.
- If there is a related item on bugs.unrealircd.org you end the commit message with:
Reported by XYZ in https://bugs.unrealircd.org/view.php?id=####
It is important to credit people: they have taken the time to report an issue/feature so they deserve credit.
After committing
If the commit relates to a bug# on bugs.unrealircd.org:
- Mark the issue as 'Resolved' and set the 'Fixed in version' to the future release
- In the comment on the bug tracker copy-paste the commit reference: at least the github URL to the commit, but preferably the copy-paste of 'git log' that is relevant
Version files
Do not touch version.c.SH or version.h.
Those are for the head coders, as part of doing releases.