Theolodis
Theolodis

Reputation: 5102

CMake: Install files not yet created at configuration time

I do have a project with a Protobuf interface that I need to compile and install for Python using CMake.

My CMakeLists.txt looks like below:

file(GLOB PROTO_INPUT "*.proto")
add_custom_target(BuildPythonInterface ALL
  protoc -I=${CMAKE_CURRENT_SOURCE_DIR} --python_out=${CMAKE_CURRENT_BINARY_DIR} ${PROTO_INPUT}
  DEPENDS ${PROTO_INPUT})
file(GLOB PROTOBUF_INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/*_pb2.py")
LIST(APPEND PROTOBUF_INTERFACE "${INIT_PY}" )
install(FILES ${PROTOBUF_INTERFACE} DESTINATION "lib/python2.7/site-packages/${PROJECT_NAME}/proto/")

It does indeed work like a charm, when running it twice, but if I delete my build directory and start configering it from the scratch, then the protobuf-interface files for Python are not being found by file(GLOB PROTOBUF_INTERFACE "${CMAKE_CURRENT_BINARY_DIR}/*_pb2.py") as they are not yet existent, until the make all command is run once.

Is there a way to make CMake execute the above code line after having run the build once? Or maybe an other (cleaner?) way of doing this?

Upvotes: 2

Views: 797

Answers (1)

The preferred CMake way of doing this would be to list both input and output files explicitly instead of using file(GLOB). There are multiple reasons for this; what you're facing is one of them; the fact that with GLOB, adding a file does not cause an automatic re-run of CMake (and thus the file is not picked up) is another.

Nevertheless, if GLOBs are the best way to go in your specific scenario (as you mentioned in comments), you can solve this by using install(DIRECTORY) instead of installing files. Something like this:

file(GLOB PROTO_INPUT "*.proto")

add_custom_target(BuildPythonInterface ALL
  protoc -I=${CMAKE_CURRENT_SOURCE_DIR} --python_out=${CMAKE_CURRENT_BINARY_DIR}/ToBeInstalled ${PROTO_INPUT}
  DEPENDS ${PROTO_INPUT})

install(
  DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/ToBeInstalled/
  DESTINATION "lib/python2.7/site-packages/${PROJECT_NAME}/proto/"
  FILES_MATCHING PATTERN "*_pb2.py"
)

install(FILES ${INIT_PY} DESTINATION "lib/python2.7/site-packages/${PROJECT_NAME}/proto/")

Notice the trailing slash in the DIRECTORY argument. It's important: if it wasn't present, the name ToBeInstalled would be appended to the destination directory. With the trailing slash, this appending is suppressed.

Upvotes: 3

Related Questions