An open API service indexing awesome lists of open source software.

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!

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.