C99 Compliant Style Guide
A style guide and linter to help enforcing better practices when writing C99.
Jump to: Usage, Options, Integration, FAQ
You can install comply
straight from the source:
$ python setup.py install
console
$ python3 setup.py install
PATH
automatically to your ~/.profile
or ~/.bash_profile
. However, in case it didn’t, it should look something like this:bash
PATH="/Library/Frameworks/Python.framework/Versions/3.6/bin:${PATH}"
export PATH
PYTHONPATH
variable and have it point to the site-packages
directory of your Python version; for example, for a Python 3.6 installation, the variable could look like this:bash
export PYTHONPATH="${PYTHONPATH}/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages"
comply
and make sure that you get rid of everything, you can run the installation again using the additional --record
argument to save a list of all installed files:console
$ python setup.py install --record installed_files.txt
C is a great language; it gives you a lot of power, control and a degree of freedom that allow you to do things your own way.
That freedom, however, can often lead to bad, or at the very least, unconventional, practices.
The Compliant style can be applied to mitigate this concern. It is comprised of a set of sensible (but opinionated) rules that vary in focus. Spanning in theme, from formatting to design and structure, these rules must all be satisfied for a project to be regarded as being of the Compliant style.
You might not like some of them, but each rule has thought and reasoning behind it.
You can read more about the rules on the project page.
Disclaimer
I created this project for my own sake, and the proposed guidelines are fully based on my personal convictions of what is “the correct style”.
Additionally, this is a work in progress; it is under constant development and breaking changes may happen frequently.
When installed, you can run comply
on the command line and provide it with single files or entire directories:
$ comply mylib.h mylib.c
If provided with a directory, comply
will automatically traverse the entire directory and run on each appropriate file found inside (also in sub-directories):
$ comply mylib/src/
Keep in mind that comply
is not a compiler and will run its checks even if your code contains errors.
comply
without having to first install it.comply
. The script is found at the root of the project.console
$ python path/to/comply/run.py src.h src.c --reporter=human
console
$ cd path/to/comply
$ python -m comply path/to/src/
Compliant Style Guide
Usage:
comply <input>... [--reporter=<name>] [--check=<rule>]... [--except=<rule>]...
[--limit=<amount>] [--strict] [--only-severe] [--verbose]
[--profile]
comply -h | --help
comply --version
Options:
-r --reporter=<name> Specify type of reported output [default: human]
-i --limit=<amount> Limit the amount of reported violations
-s --strict Increase severity for less severe rules
-P --profile Show profiling/benchmark results
-v --verbose Show diagnostic messages
-h --help Show program help
--version Show program version
Options (non-compliant):
-e --only-severe Only run checks for rules of high severity
-I --check=<rule> Only run checks for specific rules
-E --except=<rule> Don't run checks for specific rules
comply
can be integrated as a Run Script Build Phase in Xcode to have violations reported directly in the IDE:
You have two options for making this happen:
comply
has been installed to:console
$ which comply
console
/Library/Frameworks/Python.framework/Versions/3.6/bin/comply
<executable>
with the path to the comply
executable that you just found.shell
export PYTHONIOENCODING=UTF-8
<executable> "${SRCROOT}" --reporter=xcode
shell
export PYTHONIOENCODING=UTF-8
/Library/Frameworks/Python.framework/Versions/3.6/bin/comply "${SRCROOT}" --reporter=xcode
PYTHONIOENCODING=UTF-8
is needed to allow Unicode characters to be output in Xcode’s message log.shell
export PYTHONIOENCODING=UTF-8
python path/to/comply/run.py "${SRCROOT}" --reporter=xcode
Now, every time you build, comply
will be run on every file and directory within the root of your project.
You can change or add arguments as you like, but --reporter=xcode
is required for violations to be displayed as pop-ups.
Does your project comply? Let it be known!
You can use this badge in your own project’s README.md
:
[](https://github.com/jhauberg/comply)
No. This is intentional.
The core idea behind this project is to define a single, ubiquitous style and guideline; it should not differ across Compliant codebases.
The arguments
--except
and--check
(which allow you to exclude, or include, certain rules) contradict the philosophy of the project, but are made available for debugging purposes.
comply
find bugs in my code?No. Unless you consider style issues as bugs, comply
will not find bugs in your code.
That kind of static code analysis is out of scope for this project and excellent tools already exist for the job (cppcheck, PC-lint to name a few).
comply
automatically “fix” my code?No. This is left as a task for a human.
While many rules are only related to the textual representation of code, some do require more thought, consideration and human judgment to fix- a larger task than simply applying a different formatting.
There is a point to be made in the usefulness of automatic formatting, see Black or gofmt, but for the time being that is out of scope for this project.
comply
do any pre-processing of C sources?No. This is intentional.
Pre-processing is difficult and is a project in its own. It is also a solved problem- but comes at the cost of adding a large dependency (and all the complexity it involves) for one of the huge compiler toolchains (clang
, gcc
etc.).
Avoiding dependencies, especially complex ones, makes comply
much leaner, easier to use and more portable.
Because it does not even attempt to deal with the pre-processing, it does not need to know about any include paths, standard library or anything like that either. You can just point and shoot at any C source file.
However, the downside is that pre-processor directives (e.g. #define
), which are widely and commonly used, won’t be resolved properly when comply
looks at it. This means that macros can cause a lot of trouble and very likely cause false-positives.
If you feel like it, you can always run something like clang -E
on your source to have it pre-processed before letting comply
have a look. But that can be a whole deal in itself.
comply
parse the C-language?At its core, comply
does not try to parse and tokenize the C-language.
Like with the lack of pre-processing, this is deliberate.
Instead, each rule apply pattern-matching (Regex) to find violations. This can be problematic for some edge-cases (of which C has a lot), but generally works out and makes it simple and clear to understand how a rule works and what it looks for.
comply
when we have clang-tidy
(among others)?The answer to that is simply to get a different perspective.
These tools- while similar in nature- are not identical, and both will look at your codebase differently, offering unique insights. There’s no reason why you couldn’t just use both.
However, objectively, clang-tidy
and clang-format
is without question the more mature and seasoned choices for general linting purposes. They are also much larger beasts, require configuration and can be daunting at first glance.
This is a Free Open-Source Software project released under the MIT License.
Logo with courtesy of game-icons.net