How do I run a python script every time in a CMake build?

Anthony picture Anthony · Mar 1, 2018 · Viewed 15.7k times · Source

Currently I have a need to run a Python script every time in CMake which generates a .qrc file. I can't use Qt Designer and I have to use CMake. set(CMAKE_AUTORCC ON) is being used and fails whenever a resource is added or a name is changed, thus the reason for the python script. The script itself already generates output and everything works after that, so I don't need output from CMake itself. I have currently tried the following:

include(FindPythonInterp)
set (py_cmd "QRC_Updater.py")
execute_process(
                  COMMAND ${PYTHON_EXECUTABLE} ${py_cmd}
                  WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
                  RESULT_VARIABLE py_result
               )
message(STATUS "Python result: ${py_result})

and it works, but it does not execute every time. It only executes when CMakeLists.txt is modified.

So after some searching, people suggested using

add_custom_target(...)

and

add_custom_command(...)

which I have also tried with this:

add_custom_target(
   always_run_target ALL
   DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/__header.h
   )

add_custom_command(
    OUTPUT
        ${CMAKE_CURRENT_BINARY_DIR}/__header.h
        ${CMAKE_CURRENT_BINARY_DIR}/header.h
    COMMAND ${PYTHON_EXECUTABLE} ${py_cmd}
    )

which doesn't run the script at all. I know it's not running the script because I have the file open in Notepad++ and it doesn't ask if I want to switch to the newer version of the file like it does after execute_process() runs. Other variations of add_custom_command() also don't run the script. There are no errors associated with this running except when I don't include ${PYTHON_EXECUTABLE} which results in "%1 is not a valid Win32 command". So how can I effectively get a Python script to run every single time in CMake?

EDIT: The answers here do not work. How to always run command when building regardless of any dependency?

Answer

Noki picture Noki · Mar 2, 2018

you need to add a dependency to custom command to inspect changes on OriginalHeader.h and regenerates __header.h and header.h if it changes.

add_executable(MyExe main.cpp ${CMAKE_CURRENT_BINARY_DIR}/__header.h)

add_custom_target(
        always_run_target ALL
        DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/__header.h
)

add_custom_command(
        OUTPUT
            ${CMAKE_CURRENT_BINARY_DIR}/__header.h
            ${CMAKE_CURRENT_BINARY_DIR}/header.h
        DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/OriginalHeader.h
        COMMAND python ${py_cmd}
)

I only changed the ${PYTHON_EXECUTABLE} with python. I was able to run this python script (below) that print, create a directory and generate two files __header.h and header.h every time a change is detected in OriginalHeader.h, or __header.h/header.h don't exists yet.

import os

print("TEST")

if not os.path.exists("TESTDIR"):
    os.makedirs("TESTDIR")
with open("header.h", 'w+'):
    os.utime("header.h", None)