# Contributing to RPM RPM has a history that goes back over two decades and is used by many different distributions - some providing support for a decade or more. There are hundreds of thousands RPM packages in use out there. This makes changes to RPM difficult and they often require thorough consideration on the implications and on compatibility. So while we invite contributions from all sides - especially from the multitude of RPM based distributions - RPM by its very nature is not an easy project to get into. **When planning on any non-trivial amount of work on RPM, please check with us first to avoid situations where efforts goes wasted because it's not in line with RPM design and goals.** ## Submitting Patches Patches should be submitted via GitHub pull requests (PRs) or via `git send-email` to the rpm-maint@lists.rpm.org mailing list. Each PR should be a single atomic change, meaning that it should be merged or rejected as a unit. It is okay for a PR to contain multiple commits if later commits are dependent on earlier ones. If earlier commits do not depend on later ones, they (should/should not) be submitted separately. Pull requests should clearly state if the code is "ready for inclusion" or if further work is needed. Proof of concept or request for comment pull requests are fine but need to be labled as such. Information about the change should go into the commit message. This includes not only what is changed, but also why. The commit message needs to be self-contained. While references to GitHub tickets or external bug trackers are welcome the important information needs to be in the commit message itself. The rationale behind the change is often *more* important than the accompanying code! When changing existing code, it's equally important to understand why the code is the way it is now. Always check for history when suggesting change of behavior. When using GitHub pull requests enable "Allow edits from maintainers" to allow changes to your branch. Often changes are needed and allowing them in the branch in your repository keeps the discussion and changes within one place. Avoid updating the branch of the pull request if not necessary. On every change notifications are sent out to all maintainers and everyone contributing to the pull request. Keep your changes local or in another branch and only push to the branch of the pull request when you are ready for further feedback. This is a project with limited resources, please do not flood us. A pull request with failing CI tests will generally not be looked at. ## Coding Style ### Indentation RPM uses 8-space tabs. Indentation is 4 spaces, with each group of 8 or more leading spaces replaced by a tab. If in doubt, 'indent -kr' generally produces acceptable formatting. In Vim, this can be achieved with ```vim set shiftwidth=4 tabstop=8 softtabstop=4 ``` In Emacs use ``` (setq-default c-basic-offset 4 indent-tabs-mode t) ``` ### Comments Comments should be used sparingly and for subtle and non-obvious things only. One-liners are prefered for in-line comments, unless there is something really special or complicated. Longer comments can go into the doc strings of functions, but background information should generally go into the commit message instead. Always prefer self-explanatory code over comments! Many times well-named helper variables can make even complicated code read almost like plain English. Comments are always in `/* ... */`, never `//`. The two comment styles in rpm codebase are: `/* Short and sweet */` ``` /* * Multi-line comments should be formatted * like this. */ ``` ### Error handling Avoid multiple exit points from functions, these are an invitation to resource leaks, cause code duplication and require touching unrelated code when adding new features. As a ballpark rule: If you need to free resource in more than one place, think again, and if you need to free it in more than two places you're doing it wrong. For local variables, always initialize pointers on entry and free them on central exit point, using `goto exit` or `goto err` style jumps to get there from errors. Assuming failure and only setting to success just before the exit label often works well and is widely used in the codebase. RPM uses custom allocator functions in place of standard library malloc() and friends. These never return NULL (they abort the process on failure), so do not check for it. Also all "destructor" type functions in rpm accept NULL arguments, don't check for it separately. ### Miscellaneous While many details differ and lot of it does not apply at all, the [Linux kernel coding style document](https://www.kernel.org/doc/html/latest/process/coding-style.html) contains lots of excellent guidance on good C programming practises if you filter out what is kernel specific. ## API/ABI considerations Most of RPM functionality resides in public libraries, whose API and ABI need to be considered on in all changes. There are multiple levels of visibility in RPM: 1. Public API, which is described by our public C headers. If a symbol is not in a public header, it's not considered public regardless of its visibility. 2. Internal cross-library API, which is described by various non-public C headers but whose symbols are visible in our public ABI. 3. Internal per-library APIs, which are described by various non-public C headers and whose symbols are hidden from the ABI on platforms where supported (marked by `RPM_GNUC_INTERNAL`) 4. Statically scoped symbols in sources. Internals are generally free to change, but public API must be carefully preserved. Adding new public APIs is generally not a problem, removing and changing existing ones can only be done in major version bumps and even there should be done conservatively. People are annoyed when their code stops compiling. ABI compatibility in RPM is tracked with [libtool versioning](https://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html) Newly added symbols in the public ABI must prefixed with `rpm` except to maintain consistency where another pre-existing prefix (eg `header`) is used for historical reasons. All public APIs must be documented using Doxygen annotation. ## Translations Translations should be submitted through [Fedora Weblate](https://translate.fedoraproject.org/projects/rpm/), the upstream project cannot review translations.