Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CMake copy if original file changed

Tags:

cmake

In CMake I have a folder containing predefined Gettext catalogs, which at build time I copy to a folder and then modify them. But the problem is that every time I run the target it'll copy the predefined file on the local copy (which is probably modified). Is there a way to copy if the file is different to a state it was before, otherwise leave it alone?

I was also thinking that a way to do this would be to copy them across at CMake generation time, but I feel a little weary of doing that as people may delete the folders and screw things up. Also I don't know how to perform commands at generation time, only at build time.

like image 456
Jookia Avatar asked Dec 08 '11 16:12

Jookia


3 Answers

I believe you should be able to use a custom command that depends on the file. Something like:

add_custom_command(
    OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/output.file
    COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/input.file ${CMAKE_CURRENT_BINARY_DIR}/output.file
    MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/input.file)

Let me know if that doesn't do it. It might help to provide the CMake code you're currently using.

You might also try "${CMAKE_COMMAND} -E copy_if_different"; it's not clear to me whether this would be different given the dependencies of the command, but I could certainly be missing something, or it could be different if you're not using "make" output.


In case you want to try doing the copy at "generation time" (when you run cmake), you can use this command (I think my syntax is correct but I didn't test it):

file(COPY
    ${CMAKE_CURRENT_SOURCE_DIR}/input.file
    DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/)

Using INSTALL instead of COPY gives slightly different behavior.

If you need to run an arbitrary process at generation time, try the execute_process command.

Of course for details see the CMake documentation.

like image 71
Sam Hartsfield Avatar answered Sep 24 '22 07:09

Sam Hartsfield


Another option is to use configure_file with COPYONLY argument.

configure_file(input_file output_file COPYONLY)

This won't perform any variable substitution and will copy "input_file" when you run make. But it triggers a cmake run and this may be undesirable because of time consumption.

like image 35
HeyYO Avatar answered Sep 21 '22 07:09

HeyYO


Alrighty, I managed to fix this a while back but forgot about this answer. Sorry all the people who've skipped over this and not had the answer!

# ----- Copy and merge across the po files that come with the source.

message("Copying and updating stock translations...")

file(GLOB poFiles "${stockDir}/*.po")

foreach(file ${poFiles})
  # Get the language name, like en_US or zh_CN from the name of the po file, so
  # 'en_US.po' or 'zh_CN.po' become 'en_US' or 'zh_CN.po'
  get_filename_component(langName ${file} NAME_WE)

  set(newFile "${langDir}/${langName}.po")

  if(NOT EXISTS ${newFile})
    execute_process(COMMAND ${MSGMERGE_EXECUTABLE}
      "--output-file" ${newFile} ${file} ${potFile}
      OUTPUT_QUIET ERROR_VARIABLE error RESULT_VARIABLE ret)

    if(ret) # Have to do this hack as msgmerge prints to stderr.
      message(SEND_ERROR "${error}")
    endif()

    message(" '${langName}' copied.")
  elseif(${file} IS_NEWER_THAN ${newFile})
     execute_process(COMMAND ${MSGMERGE_EXECUTABLE}
       "--update" ${newFile} ${file}
       OUTPUT_QUIET ERROR_VARIABLE error RESULT_VARIABLE ret)

     if(ret) # Have to do this hack as msgmerge prints to stderr.
       message(SEND_ERROR "${error}")
     endif()

     message(" '${langName}' merged.")
  endif()
endforeach()

stockDir is the directory containing the stocked po files that aren't meant to be user edited (unless committing to the repo). langDir is in the build directory under 'lang'. It goes through, and either copies or updates it based on the files' age.

like image 5
Jookia Avatar answered Sep 23 '22 07:09

Jookia