-----Original Message-----
From: Kyle Edwards <kyle.edwa...@kitware.com> 
Sent: 13 September 2019 16:54
To: Stephen Morris <s-mor...@n-eos.com>; cmake@cmake.org
Subject: Re: [CMake] Preventing multiple definitions of metaObject methods

>Stephen,
>Could you post a minimally reproducible example with CMakeLists.txt and 
>accompanying source code? I am currently working on a Qt-based >project with 
>static libraries and have not encountered this issue.
>Kyle

It appears that the problem was due to a misunderstanding about how the PRIVATE 
keyword works in tergat_sources. I'd assumed that it should be used to identify 
the 'public headers' of a library (i.e. headers that should be included by the 
consumers of that library. It seems that this isn't the case, and even 'public' 
headers should be defined with the PRIVATE keyword.

Here are the simple demonstration files I wrote, four in all:

==== myTest.h ====

#ifndef MYTEST_HDR
#define MYTEST_HDR

class myTestWindow : public QMainWindow
{
    Q_OBJECT
public:
    myTestWindow()
    virtual ~myTestWindow();

signals:
    void readyToDisplay();

private slots:
    void showTitle();
};

#endif

==== myTest.cpp ====

#include <QtCore>
#include <QtWidgets>
#include "myTest.h"

myTestWindow::myTestWindow() : QMainWindow(nullptr)
{
    // Send the signal when ready to display
    (QTimer::singleShot(0, this, &myTestWindow::showTitle));
}

myTestWindow::~myTestWindow()
{}

void myTestWindow::showTitle()
{
    setWindowTitle(tr("This is a test window"));
}

#include "moc_myTest.cpp"

==== main.cpp ====

#include <QtCore>
#include <QtWidgets>

#include "myTest.h"

int main(int argc, char *argv[])
{
    QApplication * app = new QApplication (argc, argv);
    myTestWindow * win = new myTestWindow();
    win->show();
    app->exec();
    return 0;
}

==== CMakeLists.txt ====

cmake_minimum_required (VERSION 3.14)
project(myTest LANGUAGES CXX)

find_package(Qt5 COMPONENTS Core Gui Widgets REQUIRED PATHS 
"C:\\Qt\\5.12.3\\msvc2017_64\\lib\\cmake\\Qt5" NO_DEFAULT_PATH)
set (CMAKE_AUTOMOC ON)
set (CMAKE_AUTORCC ON)
set (CMAKE_AUTOUIC ON)

add_library(myTest_Lib STATIC)
target_sources(myTest_Lib PRIVATE myTest.cpp)
target_sources(myTest_Lib PUBLIC myTest.h)
target_link_libraries(myTest_Lib PUBLIC Qt5::Core Qt5::Widgets)
set_target_properties(myTest_Lib PROPERTIES OUTPUT_NAME myTest)

add_executable(myTest_Exe main.cpp)
target_include_directories(myTest_Exe PRIVATE ${CMAKE_LIST_DIR})
target_link_libraries(myTest_Exe PRIVATE myTest_Lib)
set_target_properties(myTest_Exe PROPERTIES OUTPUT_NAME myTest 
VS_DEBUGGER_ENVIRONMENT  "PATH=C:\\Qt\\5.12.3\\msvc2017_64\\bin;%PATH%") 


Compiling and running them as given here, with the line 
"target_sources(myTest_Lib PUBLIC myTest.h)" in the MakeLists.txt file, my 
library compiles cleanly but I get an error saying "'QMainWindow': base class 
undefined" when trying to compile the executable application. This is because 
the compiler encounters the Q_OBJECT macro in myTest.h, generates a new 
moc_myTest.cpp, then because it can't see that the original moc_myTest.cpp was 
compiled within the library it includes it in its own mocs_compilation.cpp 
file. The error occurs when trying to compile this file, since moc_myTest.cpp 
does not include <QMainWindow> anywhere.

If I try to fix this by adding the line "#include <QtWidgets/QMainWindow>" just 
above the class declaration in myTest.h, then the error changes to a bunch of 
'multiple definition' errors, as I reported in my original question on Friday.

However, if I just change  "target_sources(myTest_Lib PUBLIC myTest.h)" to  
"target_sources(myTest_Lib PRIVATE myTest.h)", then all the problems go away; 
it doesn't even matter whether I leave the redundant '#include' in myTest.h, 
everything compiles cleanly either way.

It seems that the matter of static vs. shared libraries in my initial question 
was a red herring - in my previous work with shared libraries I haven't used 
either the PUBLIC or PRIVATE keywords, but merely supplied add_library with a 
list of undifferentiated source files. This problem turns out to have been 
entirely a matter of the use of the PUBLIC keyword. I have obviously been using 
it incorrectly, though this leads me to wonder what its purpose is, if not for 
this.  
-- 

Powered by www.kitware.com

Please keep messages on-topic and check the CMake FAQ at: 
http://www.cmake.org/Wiki/CMake_FAQ

Kitware offers various services to support the CMake community. For more 
information on each offering, please visit:

CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html

Visit other Kitware open-source projects at 
http://www.kitware.com/opensource/opensource.html

Follow this link to subscribe/unsubscribe:
https://cmake.org/mailman/listinfo/cmake

Reply via email to