https://github.com/pmiddend/smartincludes
Sort your C++ include lists like a boss!
https://github.com/pmiddend/smartincludes
cplusplus haskell pretty-print
Last synced: 10 months ago
JSON representation
Sort your C++ include lists like a boss!
- Host: GitHub
- URL: https://github.com/pmiddend/smartincludes
- Owner: pmiddend
- License: gpl-3.0
- Created: 2019-12-19T08:39:50.000Z (about 6 years ago)
- Default Branch: master
- Last Pushed: 2020-11-21T12:19:10.000Z (about 5 years ago)
- Last Synced: 2025-03-15T00:51:36.769Z (11 months ago)
- Topics: cplusplus, haskell, pretty-print
- Language: Haskell
- Size: 40 KB
- Stars: 1
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: Readme.org
- License: LICENSE
Awesome Lists containing this project
README
* smartincludes — order your C++ includes like a boss
[[https://travis-ci.com/pmiddend/smartincludes.svg?branch=master][https://travis-ci.com/pmiddend/smartincludes.svg?branch=master]]
** What is this?
smartincludes rewrites your C++ =#include= blocks. You know, the ones usually at the top of the file. In short:
- it sorts the includes
- removes duplicates
- optionally forms groups of includes and orders those by a “rank” system (see below)
- it optionally surrounds “external” includes with a special header
** Philosophy
smartincludes is based upon a few assumptions and good practices. These are described here:
*** Project-local warning flags
Special warning flags like =-Wall= or =-Wextra= are useful, and you should use them. However, we want to only apply them to /our/ headers, not somebody else’s, because usually, we cannot fix those “external” warnings easily.
In order to do that, we have to add special compiler commands before we include external headers, and also add special compiler commands /after/ we are done including those external headers.
So it looks like that
#+begin_src c++
#include
#include
#pragma magic begin
#include
#pragma magic end
here’s your code
#+end_src
Of course, adding those extra headers is tedious and error-prone. Wouldn’t it be great to have a program that adds those headers automatically? Well…you’re looking at it. For that, you have to have a separate header file which contains these =#pragma= magic commands. Let’s call those =myproject/external_begin.hpp= and =myproject/external_end.hpp= For example, the following command line auto-adds those headers:
#+begin_example
smartincludes --library myproject --external-header-pair myproject/external_begin.hpp,myproject/external_end.hpp myfile.cpp
#+end_example
How does it know which headers are external? Well, everything you specify using =--library= is automatically “not external”. The resulting file will look like this:
#+begin_src c++
#include
#include
#include
#include
#include
here’s your code
#+end_src
*** Sorting headers topologically
Adding the correct headers for your C++ source file is hard, since C++ lacks a real “module” system. If you have a class =foo= in file =foo.hpp= such as this:
#+begin_src cpp
class foo {};
#+end_src
and a class =bar= in =bar.hpp= that uses =foo=:
#+begin_src cpp
#include
class bar : foo {};
#+end_src
Then, of course, you need to include =foo.hpp=. However, if you have /another/ class =baz= which uses =foo=, you now have /two/ possibilities for including it =foo=. This, however wrong it might seem, is correct:
#+begin_src cpp
#include
class baz : foo {};
#+end_src
Because the compiler/preprocessor just “copy and pasting” text when compiling the latter fragment, you can go wild with transitive includes.
The code above compiles just fine, /until/ you rewrite something and =bar= not doesn’t need =foo= anymore. Including =bar.hpp= then doesn’t import =foo= and you get an error compiling. Bummer. This seems a bit trivial, because it is, but in bigger projects, this problem unveils in the following way:
#+begin_src cpp
#include
#include
#include
#include
#include
…
#+end_src
The code with this include order might “magically” compile, because, for example, =x.hpp= includes just the right things to make =y.hpp= further down compile, and then to make the whole source file compile. But as soon as you switch around your includes (swap =foo.hpp= and =bar.hpp=, for instance), it breaks.
To detect (not fix, mind you) these errors, we can at least order our includes so that the libraries that are /used/ by other libraries are included /first/, as such:
#+begin_src cpp
#include
#include
#include
#include
#include
#+end_src
This way, assuming =lib1, lib2, lib3= are “safe”, your project is “sort of safe” from mixups, too.
And this is exactly what the (repeatable) =--library= parameter is for: specifying which libraries are external to your app, and in which order the include blocks using this library should be placed.
** Installation
Currently, only installation via the [[https://nixos.org/nix/][Nix]] package manager is supported. This allows for reproducible, cross-platform builds. Building (and running, see last line) is as easy as:
#+begin_example
git clone https://github.com/pmiddend/smartincludes.git
cd smartincludes
nix-build
result/bin/smartincludes --help
#+end_example
** Usage
The command line parameters (which are shown when you run =smartincludes --help=) are described in detail above. The general usage is simply:
#+begin_example
smartincludes < $inputfile > $outputfile
#+end_example
It’ll read its input from stdin and write it to stdout.