emilk / loguru

A lightweight C++ logging library

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to prevent multiple definition errors?

slhck opened this issue · comments

This may not be an issue with loguru per se but more an issue with my little C++ experience, but I haven't found any easy way to prevent multiple definition errors when using loguru in both a static library and the main program.

In my main C++ program main.cpp, I use:

#include "utils.h"

#ifndef LOGURU_INCLUDED
#define LOGURU_INLUDED 1
#define LOGURU_WITH_STREAMS 1
#include <loguru.cpp>
#endif

But I also have a static helper library that uses loguru, too. It includes the same in its utils.h header file:

#ifndef LOGURU_INCLUDED
#define LOGURU_INLUDED 1
#define LOGURU_WITH_STREAMS 1
#include <loguru.cpp>
#endif

The linker however errors with various multiple definition issues:

/builddir/../include/loguru/loguru.cpp:1865: multiple definition of loguru::signal_handler(int, siginfo_t*, void*)'; src/main.p/main.cpp.o:/builddir/../include/loguru/loguru.cpp:1865: first defined here`

What can I do to prevent this?

Only #include <loguru.cpp> in ONE of your .cpp files (e.g. main.cpp). Everywhere else #include <loguru.hpp>. And there is no need for the LOGURU_INCLUDED lines.

Hm, unfortunately that didn't work. I actually include loguru in the header file, in utils.h – which then again gets included in several C++ files:

utils.h:

#define LOGURU_WITH_STREAMS 1
#include <loguru.cpp>

main.cpp:

#include "utils.h"

#include <loguru.hpp>

This leads to the multiple definition errors above. The command that gets executed while building, plus the first error:

c++  -o src/main src/main.p/main.cpp.o -Wl,--as-needed -Wl,--no-undefined -Wl,--start-group src/utils/libutils.a -pthread -ldl /usr/lib/libndi.so -Wl,--end-group
/usr/bin/ld: src/utils/libutils.a(utils.cpp.o): in function `loguru::textprintf(char const*, ...)':
/builddir/../include/loguru/loguru.cpp:439: multiple definition of `loguru::textprintf(char const*, ...)'; src/main.p/main.cpp.o:/builddir/../include/loguru/loguru.cpp:439: first defined here
...

When I include loguru.cpp in my utils.cpp file (i.e. not the header) and include loguru.hpp in the main.cpp file, I get other errors:

../src/main.cpp:101:9: error: ‘INFO’ was not declared in this scope
  101 |   LOG_S(INFO) << "Connected to server at " << host << ":" << port;

You need #define LOGURU_WITH_STREAMS 1 above #include <loguru.hpp> too

That doesn't do it either. I have:

utils.h:

#define LOGURU_WITH_STREAMS 1
#include <loguru.cpp>

main.cpp:

#include "utils.h"

#define LOGURU_WITH_STREAMS 1
#include <loguru.hpp>

Errors:

c++  -o src/main src/main.p/main.cpp.o -Wl,--as-needed -Wl,--no-undefined -Wl,--start-group src/utils/libutils.a -pthread -ldl /usr/lib/libndi.so -Wl,--end-group
/usr/bin/ld: src/utils/libutils.a(utils.cpp.o): in function `loguru::textprintf(char const*, ...)':
/builddir/../include/loguru/loguru.cpp:439: multiple definition of `loguru::textprintf(char const*, ...)'; src/main.p/main.cpp.o:/builddir/../include/loguru/loguru.cpp:439: first defined here
/usr/bin/ld: src/utils/libutils.a(utils.cpp.o):(.bss+0x0): multiple definition of `loguru::g_stderr_verbosity'; src/main.p/main.cpp.o:(.bss+0x0): first defined here
/usr/bin/ld: src/utils/libutils.a(utils.cpp.o):(.data+0x0): multiple definition of `loguru::g_colorlogtostderr'; src/main.p/main.cpp.o:(.data+0x0): first defined here
/usr/bin/ld: src/utils/libutils.a(utils.cpp.o):(.bss+0x4): multiple definition of `loguru::g_flush_interval_ms'; src/main.p/main.cpp.o:(.bss+0x4): first defined here
...

I am generally a bit unsure when and where to include the header vs. the implementation. My assumption would be that I need to include the loguru implementation only once, in the static library's header, and when I need it further, only include the loguru header … which is what I did above, if I'm not mistaken.

As I wrote earlier, only include loguru.cpp in ONE .cpp file. utils.h is a .h file. This is also described in https://github.com/emilk/loguru#compiling

loguru.cpp has the definitions, so having in a header mean you will have the definitions repeated for every compile unit that includes the header

Thank you, here's what finally worked:

utils.h: Include nothing

utils.cpp:

#define LOGURU_WITH_STREAMS 1
#include <loguru.cpp>

main.cpp:

#include "utils.h"

#define LOGURU_WITH_STREAMS 1
#include <loguru.hpp>

For me, the sentence:

Just include <loguru.hpp> where you want to use Loguru. Then either compile and link with loguru.cpp or in one .cpp file: #include <loguru.cpp>

was a bit ambiguous. Perhaps:

Just include <loguru.hpp> where you want to use Loguru. Then, either compile and link with loguru.cpp, or additionally include #include <loguru.cpp> in at most one .cpp file in your project.

Or maybe replace "project" with "compile unit" (but I wouldn't have understood the latter, to be honest).