Collect2.exe: error: ld returned 1 exit status - maybe I do not understand, what I am doing

I have three files:
main.cpp

#include <Arduino.h>
#include "test.h"
void setup() {
  Serial.begin(115200);
}
void loop() {
  do_something();
  Serial.println(doppelt_definiert);
}

test.h

#ifndef _test_h_
    #define _test_h_
    int doppelt_definiert;
    void do_something();
#endif

test.cpp

#include <Arduino.h>
#include "test.h"
void do_something(){
    doppelt_definiert = 5;
    Serial.println("\ndone");
}

When I compile this, I get this Errors:

 *  Executing task in folder Linker-Fehler-Test: C:\Users\gerdh\.platformio\penv\Scripts\platformio.exe run 

Processing nodemcuv2 (platform: espressif8266; board: nodemcuv2; framework: arduino)
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------Verbose mode can be enabled via `-v, --verbose` option
CONFIGURATION: https://docs.platformio.org/page/boards/espressif8266/nodemcuv2.html
PLATFORM: Espressif 8266 (4.2.1) > NodeMCU 1.0 (ESP-12E Module)
HARDWARE: ESP8266 80MHz, 80KB RAM, 4MB Flash
PACKAGES:
 - framework-arduinoespressif8266 @ 3.30102.0 (3.1.2)
 - tool-esptool @ 1.413.0 (4.13)
 - tool-esptoolpy @ 1.30000.201119 (3.0.0)
 - toolchain-xtensa @ 2.100300.220621 (10.3.0)
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 39 compatible libraries
Scanning dependencies...
No dependencies
Building in release mode
Compiling .pio\build\nodemcuv2\src\main.cpp.o
Compiling .pio\build\nodemcuv2\src\test.cpp.o
Linking .pio\build\nodemcuv2\firmware.elf
c:/users/gerdh/.platformio/packages/toolchain-xtensa/bin/../lib/gcc/xtensa-lx106-elf/10.3.0/../../../../xtensa-lx106-elf/bin/ld.exe: .pio\build\nodemcuv2\src\test.cpp.o:(.bss.doppelt_definiert+0x0): multiple definition 
of `doppelt_definiert'; .pio\build\nodemcuv2\src\main.cpp.o:(.bss.doppelt_definiert+0x0): first defined here
collect2.exe: error: ld returned 1 exit status
*** [.pio\build\nodemcuv2\firmware.elf] Error 1

But: If I do not include test.h in the test.cpp file, I get

Compiling .pio\build\nodemcuv2\src\test.cpp.o
src\test.cpp: In function 'void do_something()':
src\test.cpp:4:5: error: 'doppelt_definiert' was not declared in this scope

if I do not include test.h in main.cpp, I get

Compiling .pio\build\nodemcuv2\src\main.cpp.o
Compiling .pio\build\nodemcuv2\src\test.cpp.o
src\main.cpp: In function 'void loop()':
src\main.cpp:7:3: error: 'do_something' was not declared in this scope
    7 |   do_something();
      |   ^~~~~~~~~~~~
src\main.cpp:8:18: error: 'doppelt_definiert' was not declared in this scope
    8 |   Serial.println(doppelt_definiert);

How I have to fix this, or where I am thinking wrong?

Greetings
Gerd

You have to declare doppelt_definiert as extern in “test.h” and define it in "test.cpp":

test.h

#ifndef _test_h_
#define _test_h_

extern int doppelt_definiert;
void do_something();

#endif

test.cpp

#include <Arduino.h>
#include "test.h"

int doppelt_definiert;

void do_something(){
    doppelt_definiert = 5;
    Serial.println("\ndone");
}

If the double_defined variable is not used from outside the “test.cpp”, the declaration in the “test.h” can be left out. To avoid naming conflicts with other translation units, this can then be defined as static in “test.cpp”:

static int double_defined;

This means that the variable is then only accessible within “test.cpp”.

See also Using extern in a header file - #5 by gfvalvo - Programming Questions - Arduino Forum

Thank you. I did not know … But now I understand, what it does.