Saturday, October 30, 2021

[SOLVED] Multiple definition linking c++ project build with cmake

Issue

First of all, Im sorry if this ends in a noob question, but Im getting a grasp with CMake and I cant find the problem here. Its a multiple definition error, but as long as I know I have:

  • Included correctly my headers (posted below).
  • Declared and not defined in the headers the variables that gives the errors.
  • In CMakeLists.txt included the headers and added to the executable the files correctly.

Obviusly some of this is a lie, because I get the next error when linking my executable:

CMakeFiles/helloworld.dir/src/test.cpp.o:(.bss+0x0): multiple definition of `b'
CMakeFiles/helloworld.dir/src/main.cpp.o:(.bss+0x0): first defined here   
CMakeFiles/helloworld.dir/src/test.cpp.o:(.bss+0x4): multiple definition of `_patata' 
CMakeFiles/helloworld.dir/src/main.cpp.o:(.bss+0x4): first defined here 

I have structured my C++ project like this;

  • /gui
    • CMakeLists.txt
    • /include/gui/
      test.h patata.h
    • /src/
      main.cpp test.cpp patata.cpp

In my CMakeLists.txt I include the folder with the headers and add an executable called helloworld to be built from the files in the src folder.

cmake_minimum_required (VERSION 3.1.0)
project(gui)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)

if(CMAKE_VERSION VERSION_LESS "3.7.0")
    set(CMAKE_INCLUDE_CURRENT_DIR ON)
endif()

set(CMAKE_PREFIX_PATH   ${CMAKE_PREFIX_PATH} $ENV{QTDIR})

# Dependencies
find_package(Qt5 COMPONENTS Widgets REQUIRED)

# Files
file(GLOB_RECURSE SRCS  "${PROJECT_SOURCE_DIR}/src/*.c*")

# Include
include_directories("${PROJECT_SOURCE_DIR}/include" "${PROJECT_BINARY_DIR}/src")

# Target
add_executable(helloworld
    ${SRCS}
)

# Libs
target_link_libraries(helloworld Qt5::Widgets)

# Logs
message(STATUS "SOURCES DIR => ${PROJECT_SOURCE_DIR}/src/")
message(STATUS "SOURCES FILES => ${SRCS}")

I have checked multiple times my headers, to be sure I didnt define anything on them and I even put guards:

test.h

#pragma once
#ifndef TEST_H
#define TEST_H

#include <string>
#include <gui/patata.h>

//std::string meh;
int b;
patata _patata;
std::string message();
#endif

test.cpp

#include <gui/test.h>
#include <gui/patata.h>

std::string message(){    
    //meh = "print";
    b=1;
    std::cout << b << std::endl;
    std::cout << _patata.rn() << std::endl;
    std::string meh = "snn";
    return meh;
}

I get the problem is in the linking, but I dont know why the linker see two definitions of the variables. Is the test.cpp compiled twice? If so, how can I prevent this? I think all the .cpp files should be added to the executable the compiler wouldnt be able to find the declarations, but maybe Im wrong on this.

My main.cpp looks like this:

#include <QCoreApplication>
#include <QDebug>
#include <gui/test.h>
#include <iostream>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    
    std::cout << message() << std::endl;
    qDebug() << "Hello World";
    
    return a.exec();
}

Solution

You have declared b and _patata in test.h. Since both test.cpp and main.cpp include test.h, then both test.cpp and main.cpp translation units have a global variable named b and _patata. Now there are two of each. There can only be one of each. The solution is to move int b; and patata _patata; into test.cpp since there is no need for them to be in test.h. Read up on C++ linkage rules.



Answered By - gnawbone.unhinged