C and C++ have the concept of a "compilation unit", which is essentially "all the code in the file you tell me to compile plus all the files it includes".
The original pipeline for C compilation was to first run the "pre-processor" to read in all of the code, process the macros and defines etc, and output the resulting code into a single file (from memory, a .i file for intermediate)
foo.cpp
#include "foo1.h"
FOO {
#include "foo2.h"
}
foo1.h
extern "C" int puts(const char*);
#define FOO int main()
foo2.h
puts("Hello, world\n");
Compile with g++ -Wall -E -o foo.i foo.cpp
and g++ -Wall -o foo.exe foo.i
The foo.i
file looks like this:
# 1 "foo.cpp"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 30 "/usr/include/stdc-predef.h" 3 4
# 1 "/usr/include/x86_64-linux-gnu/bits/predefs.h" 1 3 4
# 31 "/usr/include/stdc-predef.h" 2 3 4
# 1 "<command-line>" 2
# 1 "foo.cpp"
# 1 "foo1.h" 1
extern "C" int puts(const char*);
# 2 "foo.cpp" 2
int main() {
# 1 "foo2.h" 1
puts("Hello, world!\n");
# 5 "foo.cpp" 2
}
This is a compilation unit. The process is simplified these days, the pre-processor being built in to the compiler itself, but the notion of a compilation unit still remains.
The problem with your code is that you are defining - not just declaring - IF_DEBUG_ENABLED
in a header file, and thus potentially in multiple compilation units. When the linker tries to combine the compiled units into an executable, it's finding multiple instances of a variable with the same name. The linker has no way to tell that they were supposed to be the same thing.
To create a global variable or function visible between multiple compilation units (source files), you need a header declaration/prototype and a source-file definition/instance.
header
extern bool IF_DEBUG_ENABLED; // variable declaration.
extern void herp(); // function prototype, but
void herp(); // the extern is optional for functions.
To be able to use either of these, you now need to back them up with a implementation.
source file
bool IF_DEBUG_ENABLED = true;
This is, assuming that you want it to be a run-time variable. Another option you have is to use a #define, just like the guard you were using:
constant.h
#ifndef CONSTANT_H // poor choice, there may be a CONSTANT_H somewhere else.
#define CONSTANT_H 1
...
#define IF_DEBUG_ENABLED // comment out to disable
#endif
source:
#if defined(IF_DEBUG_ENABLED)
qDebug() << message;
#endif
This option doesn't allow you to change IF_DEBUG_ENABLED during run-time, the "qDebug() << message" code is only written to the executable if IF_DEBUG_ENABLED is defined at compile time.
Lastly, instead of using the #if ... #define ... #endif guard method, you can replace all three with a single line at the start of the file:
constant.h:
#pragma once //<<-- compiler implements a guard for you.
#include <QString>
class Debug
{
public:
static void Log(QString Message);
};