CMake generated source is not compiled

550 Views Asked by At

I added code to generate a file using the MOC executable from QT. When I try to build it, the file is generated, but it doesn't get compiled.

find_program (QT_UIC uic)
find_program (QT_MOC moc)

set(TARGET_LIBRARY support_qt_${UNICODE_FLAG}${STATIC_FLAG}${BUILD_TYPE_FLAG})

# Enable the build directory as an include path as well, required for
# qt moc generated files.
set(CMAKE_INCLUDE_CURRENT_DIR ON)

find_package(Qt5Widgets REQUIRED)
find_package(Qt5Core REQUIRED)
find_package(Qt5Gui REQUIRED)

include_directories(${Qt5Widgets_INCLUDES})
include_directories("..")

set(SUPPORT_SOURCE
    ${CMAKE_CURRENT_SOURCE_DIR}/support_qt_dll_api.h
    ${CMAKE_CURRENT_SOURCE_DIR}/supportlib_qt_namespace.h
    ${CMAKE_CURRENT_SOURCE_DIR}/dll_main.cpp
)

if (STATIC_BUILD)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DBUILD_SUPPORT_QT_STATIC")
else (NOT STATIC_BUILD)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DBUILD_SUPPORT_QT_DLL")
endif()

if (UNICODE_BUILD)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUNICODE")
endif()

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -pedantic -Wextra")

set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3")

add_subdirectory (logging)
add_subdirectory (models)
add_subdirectory (window)

#QT5_WRAP_UI(QT_UI_HEADERS ${QT_UI_SOURCES} )

# Process each .ui file and create a dependency to the
# the corresponding .h file.
set(GENERATED_SOURCES "")
foreach(ui_file ${SUPPORT_SOURCE})
    get_filename_component(ui_ext ${ui_file} EXT)
    string(TOLOWER ${ui_ext} ui_ext)

    set(ui_dependency "")
    string(REPLACE "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" ui_gen_file ${ui_file})
    if( ${ui_ext} STREQUAL ".ui" )
        string(REGEX REPLACE ".ui$" ".h" ui_gen_file "${ui_gen_file}")
        add_custom_command(
            #PRE_BUILD
            OUTPUT "${ui_gen_file}"
            COMMAND ${QT_UIC} -g cpp -o "${ui_gen_file}" "${ui_file}"
            MAIN_DEPENDENCY "${ui_file}"
            COMMENT "Generating UI: ${ui_gen_file}"
        )

        # A .ui File always has a .moc file with it.
        string(REGEX REPLACE ".h$" ".moc" ui_gen_file "${ui_gen_file}")
        set(ui_ext ".moc")
    endif()

    if( ${ui_ext} STREQUAL ".moc" )
        string(REGEX REPLACE ".moc$" ".cpp" ui_gen_file "${ui_gen_file}")
        set(GENERATED_SOURCES "${GENERATED_SOURCES} ${ui_gen_file}")
        add_custom_command(
            #PRE_BUILD
            OUTPUT "${ui_gen_file}"
            COMMAND ${QT_MOC} -o "${ui_gen_file}" -f "${ui_file}" "${ui_file}"
            MAIN_DEPENDENCY "${ui_file}"
            COMMENT "Generating MOC: ${ui_gen_file}"
        )

        set(GENERATED_SOURCE "${GENERATED_SOURCE} ${ui_gen_file}")
        #message("Generated: ${ui_gen_file}")
    endif()

endforeach()

set_source_files_properties(${GENERATED_SOURCES} PROPERTIES GENERATED TRUE)
add_library(${TARGET_LIBRARY} ${BUILD_TYPE} ${SUPPORT_SOURCE} ${GENERATED_SOURCES})
target_link_libraries(${TARGET_LIBRARY} Qt5::Widgets)

set_target_properties(${TARGET_LIBRARY} PROPERTIES
                      RUNTIME_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH}
                      ARCHIVE_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH}
                      LIBRARY_OUTPUT_DIRECTORY ${LIBRARY_OUTPUT_PATH}
)

When I remove the ${GENERATED_SOURCES} from the append_library I get this error:

CMake Error at support_qt/CMakeLists.txt:109 (add_library):
  Cannot find source file:

     D:/src/c/support_lib/build/support_qt/logging/logging_dialog_box_gui.cpp D:/src/c/support_lib/b
uild/support_qt/logging/logging_dialog_box_gui.cpp

  Tried extensions .c .C .c++ .cc .cpp .cxx .m .M .mm .h .hh .h++ .hm .hpp
  .hxx .in .txx

CMake Error: CMake can not determine linker language for target: support_qt_ad
CMake Error: Cannot determine link language for target "support_qt_ad".

I have seen other postings where similar scripts were shown using add_custom_command but when I do it like this, I get:

mingw32-make[2]: *** No rule to make target 'support_qt/ D:/src/c/support_lib/build/support_qt/loggi
ng/logging_dialog_box_gui.cpp D:/src/c/support_lib/build/support_qt/logging/logging_dialog_box_gui.c
pp', needed by 'support_qt/CMakeFiles/support_qt_ad.dir/_D_/src/c/support_lib/build/support_qt/loggi
ng/logging_dialog_box_gui.cpp_D_/src/c/support_lib/build/support_qt/logging/logging_dialog_box_gui.c
pp.obj'.  Stop.
CMakeFiles\Makefile2:236: recipe for target 'support_qt/CMakeFiles/support_qt_ad.dir/all' failed
mingw32-make[1]: *** [support_qt/CMakeFiles/support_qt_ad.dir/all] Error 2
makefile:74: recipe for target 'all' failed
mingw32-make: *** [all] Error 2

and the file is not compiled only generated.

Update:

I also tried set(CMAKE_AUTOMOC ON) and the generated cpp gets compiled, but only once. When the moc is modified, or the included ui file, it doesn't update it. It would be helpfull to see a fully working example. When I google I only find snippets. :(

1

There are 1 best solutions below

2
On

It should be enough to set: SET(CMAKE_AUTOMOC ON) to instruct CMake to run moc automatically when needed (requires CMake 2.8.6+). Don't forget to remove the ${GENERATED_SOURCES} from the append_library.

Also add QT5_WRAP_UI macro, for example:

FILE (GLOB_RECURSE project_UIS *.ui)
QT5_WRAP_UI(project_FORM_HDR ${project_UIS})

ADD_LIBRARY(${project_LIB} ${project_SRCS} ${project_FORM_HDR})

EDIT: Fully working example. For simplicity some irrelevant to Qt stuff omitted.

LIST (APPEND CMAKE_PREFIX_PATH "/opt/Qt5.4.1/5.4/gcc_64")

# Instruct CMake to run moc automatically when needed.
SET(CMAKE_AUTOMOC ON)
# Find includes in corresponding build directories
SET(CMAKE_INCLUDE_CURRENT_DIR ON)

# Widgets finds its own dependencies (QtGui and QtCore).
FIND_PACKAGE(Qt5Widgets REQUIRED)

FILE (GLOB_RECURSE project_SRCS *.cpp *.cxx *.cc *.C *.c *.h *.hpp)
SET (project_LIBS Qt5::Widgets)
SET (project_BIN ${APP_NAME})

FILE (GLOB_RECURSE project_UIS *.ui)
QT5_WRAP_UI(project_FORM_HDR ${project_UIS})

ADD_EXECUTABLE(${project_BIN} ${project_SRCS} ${project_FORM_HDR})
TARGET_LINK_LIBRARIES(${project_BIN} ${project_LIBS})