"Multiple definition" error only for additional header file in Qt CMakeFile

I’m building Qt 5 with CMake. This worked fine so far until I added an additional header file with some message definitions. The header file is called “messages.h” and contains message_definitions::error_msgs_ string. I don’t explicitly include it in the CMakeFile.

Only this additional header file gives a “multiple definition” error. I’m clearly not including the header in any other file and it is included in the same way as the other three header files which don’t give any error. What is going on here?

The messages.h. header is included only in qrosnode.h. Overall I’m wondering why I get such an error only for messages.h.

Btw, the cs commands are macros from catkin_simple: https://github.com/catkin/catkin_simple

CMakeLists:

cmake_minimum_required(VERSION 2.8.3)
project(nav_gui)

find_package(catkin_simple REQUIRED)
catkin_simple(ALL_DEPS_REQUIRED)

add_definitions(-std=c++11 -fPIC -Wall -Wextra)


##################
# QT ENVIRONMENT #
##################
#set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
#set(CMAKE_AUTOUIC ON)

find_package(Qt5 COMPONENTS Core Quick Gui QuickControls2 REQUIRED)

############
# SECTIONS #
############

file(GLOB QT_RESOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} resources/*.qrc)

QT5_ADD_RESOURCES(QT_RESOURCES_CPP ${QT_RESOURCES})

include_directories(
    ${Qt5Core_INCLUDE_DIRS}
    ${Qt5Quick_INCLUDE_DIRS}
    ${Qt5Gui_INCLUDE_DIRS}
    ${Qt5QuickControls2_INCLUDE_DIRS}
    )

#############
# LIBRARIES #
#############

#cs_add_library(${PROJECT_NAME}
#    src/qros.cpp
#    src/qrosnode.cpp
#    src/imagewriter.cpp
#)

############
# BINARIES #
############
cs_add_executable(nav_gui_node 
                src/main.cpp 
                ${QT_RESOURCES_CPP} 
                ${QT_MOC_HPP}

                src/qros.cpp
                src/qrosnode.cpp
                src/imagewriter.cpp
                
                include/nav_gui/qros.h
                include/nav_gui/qrosnode.h
                include/nav_gui/imagewriter.h
                )

target_link_libraries(nav_gui_node
    Qt5::Core
    Qt5::Quick
    Qt5::Gui
    Qt5::QuickControls2
)

##########
# EXPORT #
##########
cs_install()
cs_export()

Error:

CMakeFiles/nav_gui_node.dir/src/qros.cpp.o:(.bss+0x0): multiple definition of `message_definitions::error_msgs_[abi:cxx11]'
CMakeFiles/nav_gui_node.dir/src/main.cpp.o:(.bss+0x0): first defined here
CMakeFiles/nav_gui_node.dir/src/qrosnode.cpp.o:(.bss+0x0): multiple definition of `message_definitions::error_msgs_[abi:cxx11]'
CMakeFiles/nav_gui_node.dir/src/main.cpp.o:(.bss+0x0): first defined here
CMakeFiles/nav_gui_node.dir/nav_gui_node_autogen/mocs_compilation.cpp.o:(.bss+0x0): multiple definition of `message_definitions::error_msgs_[abi:cxx11]'
CMakeFiles/nav_gui_node.dir/src/main.cpp.o:(.bss+0x0): first defined here

Furthermore, why can’t I add qros.cpp, qrosnode.cpp and imagewriter.cpp as a library with cs_add_library? This is what I normally do with my classes. Here I get the error:

CMakeFiles/nav_gui_node.dir/src/main.cpp.o: In function `main':
main.cpp:(.text.startup+0xa0a): undefined reference to `QROS::finished()'
main.cpp:(.text.startup+0xa5e): undefined reference to `QROS::staticMetaObject'
CMakeFiles/nav_gui_node.dir/src/main.cpp.o: In function `int qmlRegisterType<ImageWriter>(char const*, int, int, char const*)':
main.cpp:(.text._Z15qmlRegisterTypeI11ImageWriterEiPKciiS2_[_Z15qmlRegisterTypeI11ImageWriterEiPKciiS2_]+0x1c): undefined reference to `ImageWriter::staticMetaObject'
main.cpp:(.text._Z15qmlRegisterTypeI11ImageWriterEiPKciiS2_[_Z15qmlRegisterTypeI11ImageWriterEiPKciiS2_]+0x141): undefined reference to `ImageWriter::staticMetaObject'
main.cpp:(.text._Z15qmlRegisterTypeI11ImageWriterEiPKciiS2_[_Z15qmlRegisterTypeI11ImageWriterEiPKciiS2_]+0x16f): undefined reference to `ImageWriter::staticMetaObject'
main.cpp:(.text._Z15qmlRegisterTypeI11ImageWriterEiPKciiS2_[_Z15qmlRegisterTypeI11ImageWriterEiPKciiS2_]+0x363): undefined reference to `ImageWriter::staticMetaObject'
main.cpp:(.text._Z15qmlRegisterTypeI11ImageWriterEiPKciiS2_[_Z15qmlRegisterTypeI11ImageWriterEiPKciiS2_]+0x3d2): undefined reference to `ImageWriter::staticMetaObject'
CMakeFiles/nav_gui_node.dir/src/main.cpp.o: In function `QQmlPrivate::QQmlElement<ImageWriter>::~QQmlElement()':
main.cpp:(.text._ZN11QQmlPrivate11QQmlElementI11ImageWriterED2Ev[_ZN11QQmlPrivate11QQmlElementI11ImageWriterED5Ev]+0x24): undefined reference to `vtable for ImageWriter'
CMakeFiles/nav_gui_node.dir/src/main.cpp.o: In function `non-virtual thunk to QQmlPrivate::QQmlElement<ImageWriter>::~QQmlElement()':
main.cpp:(.text._ZN11QQmlPrivate11QQmlElementI11ImageWriterED2Ev[_ZN11QQmlPrivate11QQmlElementI11ImageWriterED5Ev]+0x80): undefined reference to `vtable for ImageWriter'
CMakeFiles/nav_gui_node.dir/src/main.cpp.o: In function `non-virtual thunk to QQmlPrivate::QQmlElement<ImageWriter>::~QQmlElement()':
main.cpp:(.text._ZN11QQmlPrivate11QQmlElementI11ImageWriterED0Ev[_ZN11QQmlPrivate11QQmlElementI11ImageWriterED5Ev]+0x30): undefined reference to `vtable for ImageWriter'
CMakeFiles/nav_gui_node.dir/src/main.cpp.o: In function `QQmlPrivate::QQmlElement<ImageWriter>::~QQmlElement()':
main.cpp:(.text._ZN11QQmlPrivate11QQmlElementI11ImageWriterED0Ev[_ZN11QQmlPrivate11QQmlElementI11ImageWriterED5Ev]+0x94): undefined reference to `vtable for ImageWriter'
CMakeFiles/nav_gui_node.dir/src/main.cpp.o:(.data.rel.ro._ZTIN11QQmlPrivate11QQmlElementI11ImageWriterEE[_ZTIN11QQmlPrivate11QQmlElementI11ImageWriterEE]+0x10): undefined reference to `typeinfo for ImageWriter'
CMakeFiles/nav_gui_node.dir/src/main.cpp.o:(.data.rel.ro._ZTVN11QQmlPrivate11QQmlElementI11ImageWriterEE[_ZTVN11QQmlPrivate11QQmlElementI11ImageWriterEE]+0x10): undefined reference to `ImageWriter::metaObject() const'
CMakeFiles/nav_gui_node.dir/src/main.cpp.o:(.data.rel.ro._ZTVN11QQmlPrivate11QQmlElementI11ImageWriterEE[_ZTVN11QQmlPrivate11QQmlElementI11ImageWriterEE]+0x18): undefined reference to `ImageWriter::qt_metacast(char const*)'
CMakeFiles/nav_gui_node.dir/src/main.cpp.o:(.data.rel.ro._ZTVN11QQmlPrivate11QQmlElementI11ImageWriterEE[_ZTVN11QQmlPrivate11QQmlElementI11ImageWriterEE]+0x20): undefined reference to `ImageWriter::qt_metacall(QMetaObject::Call, int, void**)'
CMakeFiles/nav_gui_node.dir/src/qros.cpp.o: In function `QROS::setPower(bool)':
qros.cpp:(.text+0x177): undefined reference to `QROS::powerChanged(bool)'
CMakeFiles/nav_gui_node.dir/src/qros.cpp.o: In function `QROS::resetLog()':
...

I hope someone can add some clarity here.

It looks like QT_MOC_HPP is never set. I expect that would fix the staticMetaObject and vtable errors.

As for the error_msgs_ error, could you show its declaration? I suspect that it’s not getting the right linker rules applied to it.

MOC is relatively new to me. I’m reading about it right now. Not totally sure what you mean by QT_MOC_HPP. I do set(CMAKE_AUTOMOC ON). It works with add_executable while also listing the header files. So what would be the difference with add_library?

I’m not doing something different than with my other header files apart from defining the string in the header file directly. This is my complete header file messages.h:

#ifndef MESSAGES_H_
#define MESSAGES_H_

namespace message_definitions {

std::string error_msgs_[5] = {"a sub component is in a fault state",
                                      "sub system states are inconsistant",
                                      "MD 1 in a fault state",
                                      "MD 2 in a fault state",
                                      "MD 3 in a fault state"};                                  
}

#endif  // MESSAGES_H_

It’s the “while also listing the header files” that is different. You have a variable name QT_MOC_HPP that you’re adding to your sources, but it is an empty list.

That’s the problem. Each of your source files sees this and embeds it since there’s no one source that has special instructions that “this is yours”, so the linker then says “you can’t define this multiple times”. You’ll need to move the definition into one place or make it constexpr or something to satisfy the ODR (one definition rule).

1 Like

Ok, in general I understand this. But this is also happening if I only include it in one source file? I added static, which solves this issue. Is this a valid solution?

Ooops, you’re right. But why do I even need to add any header files in add_executable? I was not doing this in any other packages. And even if I add the header files to add_library, it still gets me the undefined reference error.

Each TU will get its own copy of the string list. This is fine as long as you don’t require that the address of each error string is the same between TUs.

If you don’t list the headers, automoc doesn’t know which files to scan for Q_OBJECT and friends.

I suspect some other headers are likely missing in that case. Depends on the exact errors.

Between all the tries, I forgot to include the library again. Now it seems to work fine. Thanks!

So the list of header files is a moc related thing and not necessary in non-Qt building, right?

Yes, but I recommend listing them anyways; they’ll show up for IDE users and I personally find it better to be explicit in build systems.

1 Like