Qmake to cmake grief with Qt 6.1 - no mocs to be seen
-
Hello everyone!
I’m struggling with transferring a project of mine from qmake to CMake. For some reason, despite many many attempts and scouring the both cmake and Qt6 documentation, I have not managed to have the system create the moc files as it should. Not having those moc files means no signal implementation, which also means that compiling fails at the first sign of emit <signal> command. I have tried putting #include “moc_<basename>.cpp” into the top of the header file as well as placing #include “<basename>.moc” to the top of the source file. I’ve also tried without these include statements. Obviously header files do contain Q_OBJECT macro. Is the macro fussy about where exactly it wants to be located in the header file? No matter what I’ve done, the autogenerated directory that should house the moc files according to CMake documentation is empty. The one time I did manage to make files appear there, the compiler proceeded to complain about not recognizing the class names in the autogenerated files that had – to my knowledge – correct includes by default. I haven’t been able to replicate the appearance of the files.
Please note that for reasons unrelated to this case I am unable to divulge all the information, and because of this the names of classes and the project as well as some paths have been heavily edited. As such, please overlook any discrepancies in class name spelling and general naming conventions, because any mistakes and poor practices in those are with 95% certainty the result of the censoring process and not indicative of the conventions in actual code. Also, if absolutely necessary I can provide examples of the sort of code that the actual classes contain but I do not see that as necessary as I’ve isolated the problem to specifically emit commands. Also the error messages included mentions about vtables which according to documentation indicated issues with moc files.
After running cmake CMakeLists.txt, I get the following output:
-- The CXX compiler identification is GNU 9.3.0 -- Check for working CXX compiler: /usr/bin/c++ -- Check for working CXX compiler: /usr/bin/c++ -- works -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Detecting CXX compile features -- Detecting CXX compile features - done CMake Warning (dev) at /path/to/root/externals/QAMQP-master/CMakeLists.txt:3 (project): Policy CMP0048 is not set: project() command manages VERSION variables. Run "cmake --help-policy CMP0048" for policy details. Use the cmake_policy command to set the policy and suppress this warning. The following variable(s) would be set to empty: PROJECT_VERSION PROJECT_VERSION_MAJOR PROJECT_VERSION_MINOR This warning is for project developers. Use -Wno-dev to suppress it. -- The C compiler identification is GNU 9.3.0 -- Check for working C compiler: /usr/bin/cc -- Check for working C compiler: /usr/bin/cc -- works -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Detecting C compile features -- Detecting C compile features - done -- Could NOT find PkgConfig (missing: PKG_CONFIG_EXECUTABLE) -- Looking for pthread.h -- Looking for pthread.h - found -- Performing Test CMAKE_HAVE_LIBC_PTHREAD -- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Failed -- Check if compiler accepts -pthread -- Check if compiler accepts -pthread - yes -- Found Threads: TRUE -- Performing Test HAVE_STDATOMIC -- Performing Test HAVE_STDATOMIC - Success -- Found WrapAtomic: TRUE -- Found OpenSSL: /usr/lib/x86_64-linux-gnu/libcrypto.so (found version "1.1.1f") -- Found WrapOpenSSLHeaders: TRUE -- Configuring done -- Generating done -- Build files have been written to: /path/to/root/Task 2/myWorkProject
running make in working directory gives me following output (I’ve omitted the error messages as it’s pretty clear to me what the error is)
Scanning dependencies of target myWorkProject_autogen [ 4%] Automatic MOC and UIC for target myWorkProject [ 4%] Built target myWorkProject_autogen Scanning dependencies of target myWorkProject [ 8%] Building CXX object CMakeFiles/myWorkProject.dir/myWorkProject_autogen/mocs_compilation.cpp.o [ 13%] Building CXX object CMakeFiles/myWorkProject.dir/sources/class_A.cpp.o [ 17%] Building CXX object CMakeFiles/myWorkProject.dir/sources/class_B.cpp.o [ 21%] Building CXX object CMakeFiles/myWorkProject.dir/sources/class_C.cpp.o [ 26%] Building CXX object CMakeFiles/myWorkProject.dir/sources/class_D.cpp.o [ 30%] Building CXX object CMakeFiles/myWorkProject.dir/sources/main.cpp.o [ 34%] Linking CXX executable build/run/myWorkProject --error messages omitted by OP--
my working directory tree before running cmake is the following
. ├── CMakeLists.txt ├── headers │ ├── class_A.h │ ├── class_B.h │ ├── class_C.h │ ├── class_D.h │ └── globals.h ├── sources │ ├── class_A.cpp │ ├── class_B.cpp │ ├── class_C.cpp │ ├── main.cpp │ └── class_D.cpp
After running cmake with
cmake CMakeLists.txt
. ├── CMakeCache.txt ├── CMakeFiles │ ├── 3.16.3 │ │ ├── CMakeCCompiler.cmake │ │ ├── CMakeCXXCompiler.cmake │ │ ├── CMakeDetermineCompilerABI_C.bin │ │ ├── CMakeDetermineCompilerABI_CXX.bin │ │ ├── CMakeSystem.cmake │ │ ├── CompilerIdC │ │ │ ├── CMakeCCompilerId.c │ │ │ ├── a.out │ │ │ └── tmp │ │ └── CompilerIdCXX │ │ ├── CMakeCXXCompilerId.cpp │ │ ├── a.out │ │ └── tmp │ ├── CMakeDirectoryInformation.cmake │ ├── CMakeError.log │ ├── CMakeOutput.log │ ├── CMakeRuleHashes.txt │ ├── CMakeTmp │ ├── Makefile.cmake │ ├── Makefile2 │ ├── TargetDirectories.txt │ ├── cmake.check_cache │ ├── progress.marks │ ├── myWorkProject.dir │ │ ├── DependInfo.cmake │ │ ├── build.make │ │ ├── cmake_clean.cmake │ │ ├── depend.make │ │ ├── flags.make │ │ ├── link.txt │ │ ├── progress.make │ │ ├── sources │ │ └── myWorkProject_autogen │ └── myWorkProject_autogen.dir │ ├── AutogenInfo.json │ ├── DependInfo.cmake │ ├── build.make │ ├── cmake_clean.cmake │ └── progress.make ├── CMakeLists.txt ├── Makefile ├── build │ ├── CMakeFiles │ │ ├── CMakeDirectoryInformation.cmake │ │ ├── progress.marks │ │ ├── qamqp-test.dir │ │ │ ├── DependInfo.cmake │ │ │ ├── build.make │ │ │ ├── cmake_clean.cmake │ │ │ ├── depend.make │ │ │ ├── flags.make │ │ │ ├── link.txt │ │ │ ├── progress.make │ │ │ ├── qamqp-test_autogen │ │ │ └── src │ │ ├── qamqp-test_autogen.dir │ │ │ ├── AutogenInfo.json │ │ │ ├── DependInfo.cmake │ │ │ ├── build.make │ │ │ ├── cmake_clean.cmake │ │ │ └── progress.make │ │ ├── qamqp.dir │ │ │ ├── DependInfo.cmake │ │ │ ├── build.make │ │ │ ├── cmake_clean.cmake │ │ │ ├── depend.make │ │ │ ├── flags.make │ │ │ ├── link.txt │ │ │ ├── progress.make │ │ │ ├── qamqp_autogen │ │ │ └── src │ │ │ └── qamqp │ │ └── qamqp_autogen.dir │ │ ├── AutogenInfo.json │ │ ├── DependInfo.cmake │ │ ├── build.make │ │ ├── cmake_clean.cmake │ │ └── progress.make │ ├── Makefile │ ├── cmake_install.cmake │ ├── lib │ └── run ├── cmake_install.cmake ├── headers │ ├── class_A.h │ ├── class_B.h │ ├── class_C.h │ ├── class_D.h │ └── globals.h ├── sources │ ├── class_A.cpp │ ├── class_B.cpp │ ├── class_C.cpp │ ├── main.cpp │ └── class_D.cpp ├── myWorkProject.pro └── myWorkProject.pro.user 26 directories, 77 files
And after running make with
make
. ├── CMakeCache.txt ├── CMakeFiles │ ├── 3.16.3 │ │ ├── CMakeCCompiler.cmake │ │ ├── CMakeCXXCompiler.cmake │ │ ├── CMakeDetermineCompilerABI_C.bin │ │ ├── CMakeDetermineCompilerABI_CXX.bin │ │ ├── CMakeSystem.cmake │ │ ├── CompilerIdC │ │ │ ├── CMakeCCompilerId.c │ │ │ ├── a.out │ │ │ └── tmp │ │ └── CompilerIdCXX │ │ ├── CMakeCXXCompilerId.cpp │ │ ├── a.out │ │ └── tmp │ ├── CMakeDirectoryInformation.cmake │ ├── CMakeError.log │ ├── CMakeOutput.log │ ├── CMakeRuleHashes.txt │ ├── CMakeTmp │ ├── Makefile.cmake │ ├── Makefile2 │ ├── Progress │ │ ├── 16 │ │ ├── 17 │ │ ├── 18 │ │ ├── 19 │ │ ├── 20 │ │ ├── 21 │ │ ├── 22 │ │ ├── 23 │ │ └── count.txt │ ├── TargetDirectories.txt │ ├── cmake.check_cache │ ├── progress.marks │ ├── myWorkProject.dir │ │ ├── CXX.includecache │ │ ├── DependInfo.cmake │ │ ├── build.make │ │ ├── cmake_clean.cmake │ │ ├── depend.internal │ │ ├── depend.make │ │ ├── flags.make │ │ ├── link.txt │ │ ├── progress.make │ │ ├── sources │ │ │ ├── class_A.cpp.o │ │ │ ├── class_B.cpp.o │ │ │ ├── class_C.cpp.o │ │ │ ├── main.cpp.o │ │ │ └── class_D.cpp.o │ │ └── myWorkProject_autogen │ │ └── mocs_compilation.cpp.o │ └── myWorkProject_autogen.dir │ ├── AutogenInfo.json │ ├── AutogenUsed.txt │ ├── DependInfo.cmake │ ├── ParseCache.txt │ ├── build.make │ ├── cmake_clean.cmake │ ├── depend.internal │ ├── depend.make │ └── progress.make ├── CMakeLists.txt ├── Makefile ├── build │ ├── CMakeFiles │ │ ├── CMakeDirectoryInformation.cmake │ │ ├── progress.marks │ │ ├── qamqp-test.dir │ │ │ ├── DependInfo.cmake │ │ │ ├── build.make │ │ │ ├── cmake_clean.cmake │ │ │ ├── depend.make │ │ │ ├── flags.make │ │ │ ├── link.txt │ │ │ ├── progress.make │ │ │ ├── qamqp-test_autogen │ │ │ └── src │ │ ├── qamqp-test_autogen.dir │ │ │ ├── AutogenInfo.json │ │ │ ├── DependInfo.cmake │ │ │ ├── build.make │ │ │ ├── cmake_clean.cmake │ │ │ └── progress.make │ │ ├── qamqp.dir │ │ │ ├── DependInfo.cmake │ │ │ ├── build.make │ │ │ ├── cmake_clean.cmake │ │ │ ├── depend.make │ │ │ ├── flags.make │ │ │ ├── link.txt │ │ │ ├── progress.make │ │ │ ├── qamqp_autogen │ │ │ └── src │ │ │ └── qamqp │ │ └── qamqp_autogen.dir │ │ ├── AutogenInfo.json │ │ ├── DependInfo.cmake │ │ ├── build.make │ │ ├── cmake_clean.cmake │ │ └── progress.make │ ├── Makefile │ ├── cmake_install.cmake │ ├── lib │ └── run ├── cmake_install.cmake ├── dirStructAfterCMake.txt ├── dirStructAfterMake.txt ├── dirStructBeforeCMake.txt ├── headers │ ├── class_A.h │ ├── class_B.h │ ├── class_C.h │ ├── class_D.h │ └── globals.h ├── sources │ ├── class_A.cpp │ ├── class_B.cpp │ ├── class_C.cpp │ ├── main.cpp │ └── class_D.cpp ├── myWorkProject.pro ├── myWorkProject.pro.user └── myWorkProject_autogen ├── include ├── moc_predefs.h └── mocs_compilation.cpp 29 directories, 100 files
contents of moc_compilation (I have not touched this file)
// This file is autogenerated. Changes will be overwritten. // No files found that require moc or the moc files are included enum some_compilers { need_more_than_nothing };
The project also uses external library that lives under /../../externals/ . . . . (relative path from the working directory)
When talking about “working directory”, I mean the directory CMakeLists.txt resides in. Project is configured for Qt 6.1.0 and the CMake version I’m running is 3.16.3. The OS of the development machine is Ubuntu 20.04. The project was originally created with QtCreator using qmake as the build system and I'm attempting to make the transfer without having to recreate the project, and so that the project can be built and ran from the terminal
finally, contents of the CMakeLists.txt
cmake_minimum_required(VERSION 3.16.0) project(myWorkProject VERSION 0.9 LANGUAGES CXX) 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(srcDir ${CMAKE_CURRENT_SOURCE_DIR}/sources) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/build/archive) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/build/lib) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/build/run) set(externalLib ${CMAKE_CURRENT_SOURCE_DIR}/../../externals/externalLib/lib.so) set(libIncludes ${CMAKE_CURRENT_SOURCE_DIR}/../../externals/externalLib/src/beef/) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../externals/externalLib/ build) set(CMAKE_PREFIX_PATH "/opt/Qt/6.1.0/gcc_64/") set(Qt6_DIR "/opt/Qt/6.1.0") find_package(Qt6 COMPONENTS Core REQUIRED) find_package(Qt6 COMPONENTS Network REQUIRED) set(sourceList ${srcDir}/class_A.cpp ${srcDir}/class_B.cpp ${srcDir}/class_C.cpp ${srcDir}/class_D.cpp ${srcDir}/main.cpp) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/headers ${libIncludes}) add_executable(myWorkProject ${sourceList}) target_link_libraries(myWorkLib PRIVATE Qt6::Core Qt6::Network ${externalLib})
Any help is appreciated, please ask if you require more information.
-
Try adding the headers of your classes to
sourceList
, it's best practice to add them anywayP.S.
set(CMAKE_PREFIX_PATH "/opt/Qt/6.1.0/gcc_64/")
set(Qt6_DIR "/opt/Qt/6.1.0")This is terrible practice.
You are also using a lot of flimsy relative paths as well as pre-CMake3 concepts (e.g.
include_directories
should usetarget_include_directories
instead;AUTOMOC
,AUTORCC
,AUTOUIC
,CMAKE_*_OUTPUT_DIRECTORY
,CXX_STANDARD
should all be target properties, not globals) -
Try adding the headers of your classes to
sourceList
, it's best practice to add them anywayP.S.
set(CMAKE_PREFIX_PATH "/opt/Qt/6.1.0/gcc_64/")
set(Qt6_DIR "/opt/Qt/6.1.0")This is terrible practice.
You are also using a lot of flimsy relative paths as well as pre-CMake3 concepts (e.g.
include_directories
should usetarget_include_directories
instead;AUTOMOC
,AUTORCC
,AUTOUIC
,CMAKE_*_OUTPUT_DIRECTORY
,CXX_STANDARD
should all be target properties, not globals)@VRonin Thank you for the informative reply!
So, I understand that the best practice is to grab all of your sources AND headers, and add them to add_executable? Why is this not mentioned in the Qt documentation at all?
What makes the lines you quoted so terrible? I attempted, repeatedly, to add the prefix to /etc/environment but it failed to register, which is why I had to do it that way. Again, any help with that is appreciated.
Concerning the final paragraph, did I understand correctly that I should replace "include_directories" with "target_include_directories"? Also, how does one make those things into target properties? Also, what do you mean by flimsy relative paths, and how does one make these flimsy paths stronger?
I am extremely green when it comes to cmake, so I'll gladly take on all the advice you have and respectfully ask you to explain things like you would to someone who just learned that cmake exists yesterday ^^;
-
@VRonin Thank you for the informative reply!
So, I understand that the best practice is to grab all of your sources AND headers, and add them to add_executable? Why is this not mentioned in the Qt documentation at all?
What makes the lines you quoted so terrible? I attempted, repeatedly, to add the prefix to /etc/environment but it failed to register, which is why I had to do it that way. Again, any help with that is appreciated.
Concerning the final paragraph, did I understand correctly that I should replace "include_directories" with "target_include_directories"? Also, how does one make those things into target properties? Also, what do you mean by flimsy relative paths, and how does one make these flimsy paths stronger?
I am extremely green when it comes to cmake, so I'll gladly take on all the advice you have and respectfully ask you to explain things like you would to someone who just learned that cmake exists yesterday ^^;
@yaulenfea said in Qmake to cmake grief with Qt 6.1 - no mocs to be seen:
Why is this not mentioned in the Qt documentation at all?
This is a CMake thing, nothing to do with Qt. Not documenting best practices is a staple of CMake unfortunately
what do you mean by flimsy relative paths, and how does one make these flimsy paths stronger?
Do you have control over externalLib? does it come with a CMake export target (this is usually a folder
externalLib/lib/cmake
)? Is it a popular library like boost, zlib, etc.?Concerning the final paragraph, did I understand correctly that I should replace "include_directories" with "target_include_directories"? Also, how does one make those things into target properties?
Streamlining:
cmake_minimum_required(VERSION 3.16) project(myWorkProject LANGUAGES CXX) find_package(Qt6 COMPONENTS Core Network REQUIRED) set(sourceList sources/class_A.cpp sources/class_B.cpp sources/class_C.cpp sources/class_D.cpp sources/class_A.h sources/class_B.h sources/class_C.h sources/class_D.h sources/main.cpp) add_executable(myWorkProject ${sourceList}) set_target_properties(myWorkProject PROPERTIES AUTOMOC ON AUTOUIC ON AUTORCC ON CXX_STANDARD 17 CXX_STANDARD_REQUIRED ON VERSION 0.9.0 EXPORT_NAME "myWorkProject" ARCHIVE_OUTPUT_DIRECTORY "lib" LIBRARY_OUTPUT_DIRECTORY "lib" RUNTIME_OUTPUT_DIRECTORY "bin" ) target_include_directories(myWorkProject PRIVATE headers ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries(myWorkLib PRIVATE Qt6::Core Qt6::Network)
-
@yaulenfea said in Qmake to cmake grief with Qt 6.1 - no mocs to be seen:
Why is this not mentioned in the Qt documentation at all?
This is a CMake thing, nothing to do with Qt. Not documenting best practices is a staple of CMake unfortunately
what do you mean by flimsy relative paths, and how does one make these flimsy paths stronger?
Do you have control over externalLib? does it come with a CMake export target (this is usually a folder
externalLib/lib/cmake
)? Is it a popular library like boost, zlib, etc.?Concerning the final paragraph, did I understand correctly that I should replace "include_directories" with "target_include_directories"? Also, how does one make those things into target properties?
Streamlining:
cmake_minimum_required(VERSION 3.16) project(myWorkProject LANGUAGES CXX) find_package(Qt6 COMPONENTS Core Network REQUIRED) set(sourceList sources/class_A.cpp sources/class_B.cpp sources/class_C.cpp sources/class_D.cpp sources/class_A.h sources/class_B.h sources/class_C.h sources/class_D.h sources/main.cpp) add_executable(myWorkProject ${sourceList}) set_target_properties(myWorkProject PROPERTIES AUTOMOC ON AUTOUIC ON AUTORCC ON CXX_STANDARD 17 CXX_STANDARD_REQUIRED ON VERSION 0.9.0 EXPORT_NAME "myWorkProject" ARCHIVE_OUTPUT_DIRECTORY "lib" LIBRARY_OUTPUT_DIRECTORY "lib" RUNTIME_OUTPUT_DIRECTORY "bin" ) target_include_directories(myWorkProject PRIVATE headers ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries(myWorkLib PRIVATE Qt6::Core Qt6::Network)