Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I make CMake run a python script before building, in order to generate files for my project to be used in the build?

Tags:

c++

cmake

I have a python script that parses all of the C++ source files in the project's directory, looks for some stuff in the files, and then generates a file. This python script works fine, but I want it to automatically run before building my C++ project.

So basically, I want this python script to run before every build, so if any .h or .cpp files have been changed. I'd also like it to run if the python script itself has been changed. I have the python script in question, genenums.py, in the same directory as my C++ source files such as main.cpp, etc.

I've tried experimenting with add_custom_command based on documentation, but I can't get cmake to ever run this python script in any instance. I'm not sure how to make this work right, as I'm new to cmake.

Here's my current cmake file:

cmake_minimum_required(VERSION 3.9)
project(enum_test)

set(CMAKE_CXX_STANDARD 17)

include_directories(include)

find_package( PythonInterp 2.7 REQUIRED )
find_package( PythonLibs 2.7 REQUIRED )

add_custom_command(
 COMMAND ${PYTHON_EXECUTABLE} genenums.py
 DEPENDS genenums.py $(CMAKE_CURRENT_BINARY_DIR)
 OUTPUT enums.h
 WORKING_DIRECTORY $(CMAKE_CURRENT_BINARY_DIR)
 COMMENT "Generating enums"
)

add_executable(enum_test main.cpp test.h test.cpp)
like image 587
irfna Avatar asked Feb 27 '18 22:02

irfna


1 Answers

Ok, I have a foolproof, non-ugly way to have cmake run any kind of commands right before a build to build a dependency, waiting until the commands are done before doing the build.

add_custom_target(
 run ALL
 COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/genenums.py ${CMAKE_CURRENT_SOURCE_DIR}
 BYPRODUCTS enums.h
 COMMENT "Generating enums"
)

add_dependencies(enum_test run)

The two key parts are the add_custom_target and add_dependencies, both are required to make this work. Place both after the add_executable in CMakeLists.txt. enum_test refers to the target created by add_executable (the first name in its list), so you'd set that to your project's name.

You can name the custom target to whatever you like (I used run here) by changing the run in both add_custom_target and add_dependencies to something else.

There's one additional catch with add_custom_target... WORKING_DIRECTORY in that did nothing for my python script. Even when I tried to set the WORKING_DIRECTORY to ${CMAKE_CURRENT_SOURCE_DIR}, the script executed in the default ${CMAKE_CURRENT_BINARY_DIR} anyway.

So for this one catch, whatever commands you're using need to be able to take a command line argument of ${CMAKE_CURRENT_SOURCE_DIR} and use that to operate in the source directory properly (assuming that's your goal). That's why I have ${CMAKE_CURRENT_SOURCE_DIR} at the end of this line:

 COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/genenums.py ${CMAKE_CURRENT_SOURCE_DIR}

Here's the full CMakeLists.txt with the working setup, should be fairly easy to adapt to any particular project's CMakeLists.txt.

cmake_minimum_required(VERSION 3.9)
project(enum_test)

set(CMAKE_CXX_STANDARD 17)

include_directories(include)

find_package( PythonInterp 2.7 REQUIRED )

add_executable(enum_test enums.h main.cpp test.h test.cpp)

add_custom_target(
 run ALL
 COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/genenums.py ${CMAKE_CURRENT_SOURCE_DIR}
 BYPRODUCTS enums.h
 COMMENT "Generating enums"
)

add_dependencies(enum_test run)
like image 79
irfna Avatar answered Oct 05 '22 03:10

irfna