2

I am trying to compile some Qt project, including the QCustomPlot library. As a minimum example, i set up a project consisting of:

qcustomplot.h
qcustomplot.cpp
CMakeLists.txt
../cmake/QCustomPlot.cmake

The original project is bigger, but the problem is already reproducible with only those files.

The CMakeLists.txt contains this code:

cmake_minimum_required(VERSION 3.6)

set(CMAKE_AUTOMOC ON)
include(../cmake/QCustomPlot.cmake)

function(findqt)                                       #(1)
  find_package(Qt5Core)
  find_package(Qt5Gui)
  find_package(Qt5Widgets)
  find_package(Qt5PrintSupport)
endfunction()                                          #(1)

findqt()                                               #(1)
#find_package(Qt5Core)                                 #(2)

add_library(
  Plots
  src/qcustomplot.h
  src/qcustomplot.cpp
)


function(linkqt)                                       #(3)
  qt5_use_modules(Plots Core Gui Widgets PrintSupport)
endfunction()                                          #(3)
linkqt()                                               #(3)

If either all lines marked (1) or all lines marked (3) are commented out, that means calling find_package() or qt5_use_modules() at file scope, i get a project containing the two qcustomplot files and an additional Plots_automoc.cpp. The additional file is autogenerated and contains the necessary #include "moc_qcustomplot.cpp" and the project compiles and links properly.

However as soon as i move all qt related commands into functions, the automoc.cpp file is no longer generated and no longer part of the project, which leads to quite a few unresolved external symbol during linking.

Calling only a single find_package() on files scope (like line (2)) resolves the issue and generates the automoc file again.

Why does simply moving the calls into a function change the automoc behaviour like this and how can i achieve to still move them into functions?

A little bit background: I already have quite a few targets in my project, expect the number to grow rapidly and want to avoid code redundancy. Also people not really trained with CMake are supposed to use it. Thats why i'm trying to move all those Qt related commands into functions and provide a command like this:

add_my_target(
  targetName
  SOURCES qcustomplot.h qcustomplot.cpp
  QT Core Gui Widgets PrintSupport
  BOOST filesystem
)

With the exception of Qt, i already achieved this...

I also tried using

target_link_libraries(${projectName} ${Qt5_Core_LIBRARIES} ...
//or
target_link_libraries(${projectName} Qt5::Core ...

it leads to the same result, as long as not at least one find_package() call is directly on files scope, no automoc is generated.

I am using CMake 3.6.2, Qt 5.7, Visual Studio 2015 and Win 10.

Additional example oLen got most of my underlying confusion sorted out with his answer, but one case remains:

cmake_minimum_required(VERSION 3.6)
set(CMAKE_AUTOMOC ON)

function(doit)                        #(4)
  find_package(Qt5Core)

  add_library(
    Plots
    qcustomplot.h
    qcustomplot.cpp
    )

  qt5_use_modules(Plots Core Gui Widgets PrintSupport)
endfunction()                         #(4)

doit()                                #(4)

Using the lines marked with (4) to put all the generation of the target into a function allows CMake to run properly, i.e. qt5_use_modules() is defined, able to find all the modules and link them (e.g. include directories are set properly). Nowhere outside the function do i rely on variables set by any of the Qt functions. But still automoc does not generate the needed .cpp file. Commenting the marked lines out runs automoc again.

Anedar
  • 4,235
  • 1
  • 23
  • 41

1 Answers1

2

The problem is that CMake functions introduce a scope, so that the variables defined in the find_package are not available outside the function.

An easy solution to your problem is to use CMake macros - you can think of them as the CMake equivalent of C macros. The variables declared there will also be available outside the macro scope.

In your case, this means replacing function by macro and endfunction by endmacro.

oLen
  • 5,177
  • 1
  • 32
  • 48
  • For this minimal example your solution might be suitable, but for the bigger project behind it it is not. Besides that, i can call all `find_package()` deep inside the nested functions and can use the defined variables like Qt5_Core_LIBRARIES somewhere completely different. Only the AUTOMOC fails to generate that single file. – Anedar Aug 21 '17 at 11:51
  • @Anedar Can you specify in your question why a `macro` is not suitable? – oLen Aug 21 '17 at 11:54
  • @Anedar as for `Qt5Core_LIBRARIES` still being defined, I just tested it and the variables do not remain defined when I use a `function`, which means that my answer is correct in this respect. In your case it might still be there because of the cache or because it comes from elsewhere. – oLen Aug 21 '17 at 12:00
  • Ok, i got most of it, but see the additonal example which still doesn' t work, even though i do not rely on variables set by any of the Qt functions. – Anedar Aug 21 '17 at 12:34
  • Your additional example is really intriguing and I do not understand why it behaves like this. Having a macro does solve this but I don't get why it doesn't work with a function. – oLen Aug 21 '17 at 13:04