Dear Readers!

In this post I’m sharing some thoughts on minor topics such as header file extensions and compiler flags, not because they are really worth mentioning by themselves, but simply because (despite their mundane nature) they still can cause some serious headaches. Let’s examine an excerpt from a compiler error message:

Make

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
CMakeFiles/tutprog.dir/ImgPaint.cpp.o: In function `ToolbarDrawer::ToolbarDrawer()':
/usr/include/opencv2/core/mat.inl.hpp:404: multiple definition of `ToolbarDrawer::ToolbarDrawer()'
CMakeFiles/tutprog.dir/main.cpp.o:/usr/include/opencv2/core/mat.inl.hpp:404: first defined here
CMakeFiles/tutprog.dir/ImgPaint.cpp.o: In function `ToolbarDrawer::ToolbarDrawer()':
/usr/include/opencv2/core/mat.inl.hpp:404: multiple definition of `ToolbarDrawer::ToolbarDrawer()'
CMakeFiles/tutprog.dir/main.cpp.o:/usr/include/opencv2/core/mat.inl.hpp:404: first defined here
CMakeFiles/tutprog.dir/ImgPaint.cpp.o: In function `ToolbarDrawer::getToolbarCols() const':
./ToolbarDrawer.cpp:22: multiple definition of `ToolbarDrawer::getToolbarCols() const'
CMakeFiles/tutprog.dir/main.cpp.o:./ToolbarDrawer.cpp:22: first defined here
CMakeFiles/tutprog.dir/ImgPaint.cpp.o: In function `ToolbarDrawer::getToolbarRows() const':
./ToolbarDrawer.cpp:27: multiple definition of `ToolbarDrawer::getToolbarRows() const'
CMakeFiles/tutprog.dir/main.cpp.o:./ToolbarDrawer.cpp:27: first defined here
CMakeFiles/tutprog.dir/ImgPaint.cpp.o: In function `ToolbarDrawer::selectDrawingShape(cv::Point_<int> const&)':
./ToolbarDrawer.cpp:32: multiple definition of `ToolbarDrawer::selectDrawingShape(cv::Point_<int> const&)'
CMakeFiles/tutprog.dir/main.cpp.o:./ToolbarDrawer.cpp:32: first defined here
CMakeFiles/tutprog.dir/ImgPaint.cpp.o: In function `ToolbarDrawer::setToolbarBackground()':

...

collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/tutprog.dir/build.make:216: tutprog] Error 1
make[1]: *** [CMakeFiles/Makefile2:68: CMakeFiles/tutprog.dir/all] Error 2
make: *** [Makefile:84: all] Error 2

The ellipsis hides quite more of the same, in fact several pages more. After encountering this flood of errors, one would immediately skim through the source files to check for redefinitions, but more surprisingly than not, there is a high chance that no redefinitions will be found. So what might be the problem? Everything seems fine. Maybe we were looking for the cause at the wrong place? Let’s examine the following snippet to deliver the point:

C++

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include "CanvasDrawer.hpp"
#include "ToolbarDrawer.hpp"
#include "ButtonDrawer.hpp"
#include <opencv2/core/mat.hpp>
#include <opencv2/core/types.cpp>
#include <opencv2/core/utility.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/video.hpp>
#include <string>

class MyClass {
public:
    MyClass();
    MyClass(cv::Mat stuff, int x, int y);
    
    int getXCoord() const;
    int getYCoord() const;
    void setXCoord(int x);
    void setYCoord(int y);
    cv::Mat& theStuff();
    
private:
    cv::Mat mStuff;
    int xCoord;
    int yCoord;
};

Did you notice the mistake? Belive it or not, this code is enough to produce error messages such as presented above. Let’s see the same code again with a slight modification:

C++

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include "CanvasDrawer.h"
#include "ToolbarDrawer.h"
#include "ButtonDrawer.h"
#include <opencv2/core/mat.h>
#include <opencv2/core/types.cpp>
#include <opencv2/core/utility.h>
#include <opencv2/imgproc.h>
#include <opencv2/video.h>
#include <string>

class MyClass {
public:
    MyClass();
    MyClass(cv::Mat stuff, int x, int y);
    
    int getXCoord() const;
    int getYCoord() const;
    void setXCoord(int x);
    void setYCoord(int y);
    cv::Mat& theStuff();
    
private:
    cv::Mat mStuff;
    int xCoord;
    int yCoord;
};

I admit it is still somewhat obscure, but the problem stands our far better than before. Not only that, but it is also far less likely that you would type three characters for the filename extension when only one is needed. In my opinion hpp and cpp are too much alike and in a weaker second of a day one might easily type the latter instead of the former. Obviously, if one uses existing libraries, there really is no choice, but if the choice is presented, I would prefer .h as an extension.

Topic 2

Another topic I chose for this post is the flags with which we compile our projects. When quickly creating a CMake file just to compile stuff with as little effort as possible (and because we are just compiling an excercise project), we can think that omitting a flag or two can’t hurt that much. Well, as mundane this seems to be (yet again), the implications can be quite severe:

CMake

1
2
3
4
5
# ...

set (CMAKE_CXX_FLAGS "-g -Og ${CMAKE_CXX_FLAGS}")

# ...

What can go wrong? We have some minor optimizations in place that do not affect debugging, and we have the debugging symbols as well. We can compile and debug if need be. Well that is most certainly true, but is it really necessary to launch the debugger immediately if something goes wrong? For instance, after making some streamlining in the code, one of my learning projects started to crash all of a sudden, and no matter how many times I went through the logic, I couldn’t see what was the problem. Well, as with Topic 1 in this post, it wasn’t the logic that had issues, but another quite banal thing: I fell through a function of non-void return type. One would expect (I most certainly did) that such a thing would stop the compilation process by default, but apparently it doesn’t. GCC will not say a word unless you explicitly ask it to be talkative with a few additional flags:

CMake

1
2
3
4
5
6
# ...

# -Weffc++ can also be included for some Scott Meyers wisdom
set (CMAKE_CXX_FLAGS "-g -Og -Wall -Wextra -Wshadow ${CMAKE_CXX_FLAGS}")

# ...

With these turned on I get a nice warning about falling through, which most certainly helps.

So the lessons of the day is as follows:
Topic 1:

Not always logic errors cause serious problems, sometimes typos can do equally great damage.

Topic 2:

Don’t expect the compiler to say anything (no matter how important that might seem to you) unless you explicitly ask it to do so.