I want to ban use of iostreams in a code base I have (for various reasons). Is there a way I can inspect symbol files or force the compiler to emit an error when that API is used?
This is a nasty hack, but it should work.
The C standard (and consequently the C++ standard as well) allows preprocessor tokens in #include
directives. This is also known as "computed includes".
Thus, adding something like -Diostream
to CFLAGS
inside your makefile (or to compiler options in your IDE's project settings) should reliably break the build if someone tries to use iostream.
Of course, with an empty macro, the error message will not be very informative, but you could instead use something like -Diostream=DUDE_DONT_USE_IOSTREAM
, which will show an error like: DUDE_DONT_USE_IOSTREAM: file not found
.
It's also something that you can turn off again without much hassle if you change your mind later. Just remove the build option.
A simple approach is provide a dummy iostream
implementation that does nothing but throw a compile-time error.
The following example assumes a GCC toolchain - I imagine the process is similar with other compilers.
First, create your dummy iostream file:
#error 'Use of iostream is prohibited'
Some dummy application code to demonstrate:
#include <iostream>
int main (int argc, char** argv) {
std::cout << "foo!";
return 0;
}
Compile as follows (assuming the dummy iostream
and main.cpp
are in the working directory):
g++ -I. main.cpp
Compilation fails with the following errors:
In file included from main.cpp:2:0:
./iostream:1:2: error: #error 'Use of iostream is prohibited'
main.cpp: In function 'int main(int, char**)':
main.cpp:4:2: error: 'cout' is not a member of 'std'
Added bonus: symbols usually declared in that file (e.g. cout
here) are undefined, and so get flagged in the compiler output as well. As such, you also get pointers to exactly where you're using your prohibited API.
UPDATE: Instructions for Visual C++ 2012.
As @RaymondChen points out in the comments below, a solution tailored to Visual C++ is likely more useful to the OP. As such, the following outlines the process I went through to achieve the same as the above under Visual C++ 2012.
First, create a new console project, using the above C++ code. Also create the dummy iostream header I described above, and place it in a directory somewhere easy to find (I put mine in the main project source directory).
Now, in the Solution Explorer, right click on the project node and select "Properties" from the drop-down list. In the dialog that appears, select "VC++ Directories" from the tree on the left. Prepend the directory containing the dummy iostream file into the list of include directories that appears on the right, separated from the other directories with a semicolon:
Here, my project was called TestApp1, and I just prepended its main directory to the $(IncludePath)
that was already there. Note that it is important to prepend rather than append - the order of the directories in the list determines the search order, so if $(IncludePath)
appears before your custom directory, the system header will be used in preference to your dummy header - not what you want.
Click OK, and rebuild the project.
For me, doing so resulted in the following errors in the VC++ console (edited slightly for brevity):
error C1189: #error : 'Use of iostream is prohibited'
IntelliSense: #error directive: 'Use of iostream is prohibited'
IntelliSense: namespace "std" has no member "cout"
Note that IntelliSense also picks up the (now) illegal use of cout
- it is highlighted with an error mark in the editor.
Your idea to inspect symbol files is feasible and very realistic. virtual ~ios_base();
is a single method that all streams will inherit, and which can't easily be inlined since it's virtual and non-trivial. Its presence in an object file is therefore a very strong indication of IOstream use.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With