1

I'm creating an header-only library, and I would like to get warnings for it displayed during compilation. However, it seems that only warnings for the "main" project including the library get displayed, but not for the library itself.

Is there a way I can force the compiler to check for warnings in the included library?

// main.cpp
#include "MyHeaderOnlyLib.hpp"
int main() { ... }

// Compile
g++ ./main.cpp -Wall -Wextra -pedantic ...

// Warnings get displayed for main.cpp, but not for MyHeaderOnlyLib.hpp

I'm finding MyHeaderOnlyLib.hpp via a CMake script, using find_package. I've checked the command executed by CMake, and it's using -I, not -isystem.

I've tried both including the library with <...> (when it's in the /usr/include/ directory), or locally with "...".

Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416
  • What warnings are you expecting to get? Since the header is just inserted verbatim when you include it, there should be no difference. – molbdnilo May 08 '14 at 07:56
  • Example: using `-Wpadded` and `-Wpacked` shows warnings only for the main project. I copying (and renaming) one of structs that triggered the warning in the header-only library but it did not trigger a warning. @molbdnilo – Vittorio Romeo May 08 '14 at 08:02
  • 2
    Do like Boost: for each library, create a suite of unit tests and make sure those compile warning free and run erorr free. – TemplateRex May 08 '14 at 20:58
  • @TemplateRex: I already have unit tests in the headers themselves, I don't really want to move them to .cpp files - I'd just like a way (compiler flag?) to make sure warnings are checked for included header files as well. – Vittorio Romeo May 08 '14 at 21:15
  • 2
    How do you run your unit tests without .cpp file? Furthermore, especially with template-heavy code, the compiler will not find all errors without actually instantiating code. – TemplateRex May 09 '14 at 06:22
  • @TemplateRex: I call a `library::startTests();` function in any of the projects that contain the library to start the unit tests. – Vittorio Romeo May 09 '14 at 06:24
  • 1
    My preferred setup for header only code is as follows: relative to the main project MyLib directory, an `include/MyLib` directory with the header-only code, and an `test/MyLib` directory with almost full test coverage of unit tests in .cpp files. CMake just generates a Makefile, `make` compiles all the unit tests and finds compiler errors, and `ctest` runs all tests and finds bugs. Users of the library do not see the unit tests when including the main header in their own code, although they could also compile and run the tests to check their compiler. – TemplateRex May 09 '14 at 06:30
  • Can you post an example header and example .cxx file? -Wpadded sometimes only works when you create variables of the struct type in question. Is that maybe the only difference? Also have you tried -Wsystem-headers (just in case that it may be intrepreting it as system headers) – PlasmaHH May 15 '14 at 11:11

1 Answers1

2

I suppose that you have a template library and you are complaining about the lack of warnings from its compilation. Don't look for bad #include path, that would end up as an error. Unfortunately, without specialization (unless the templates are used by the .cpp), the compiler has no way to interpret the templates reliably, let alone produce sensible warnings. Consider this:

#include <vector>

template <class C>
struct T {
    bool pub_x(const std::vector<int> &v, int i)
    {
        return v.size() < i;
    }

    bool pub_y(const std::vector<int> &v, int i)
    {
        return v.size() < i;
    }
};

typedef T<int> Tint; // will not help

bool pub_z(const std::vector<int> &v, unsigned int i) // if signed, produces warning
{
    return v.size() < i;
}

class WarningMachine {
    WarningMachine() // note that this is private
    {
        //T<int>().pub_y(std::vector<int>(), 10); // to produce warning for the template
    }
};

int main()
{
    //Tint().pub_y(std::vector<int>(), 10); // to produce warning for the template
    return 0;
}

You can try it out in codepad. Note that the pub_z will immediately produce signed / unsigned comparison warning when compiled, despite never being called. It is a whole different story for the templates, though. Even if T::pub_y is called, T::pub_x still passes unnoticed without a warning. This depends on a compiler implementation, some compilers perform more aggressive checking once all the information is available, other tend to be lazy. Note that neither T::pub_x or T::pub_y depend on the template argument.

The only way to do it reliably is to specialize the templates and call the functions. Note that the code which does that does not need to be accessible for that (such as in WarningMachine), making it a candidate to be optimized away (but that depends), and also meaning that the values passed to the functions may not need to be valid values as the code will never run (that will save you allocating arrays or preparing whatever data the functions may need).

On the other hand, since you will have to write a lot of code to really check all the functions, you may as well pass valid data and check for result correctness and make it useful, instead of likely confusing the hell of anyone who reads the code after you (as is likely in the above case).

the swine
  • 10,713
  • 7
  • 58
  • 100