0

I'm working with ANTLR and want to generate the parser files during the generation process and only want to generate them if they are not only there or are out of date. This works and will only add the generation to the build if necessary:

add_custom_command(
  OUTPUT(ExpressionsParser.cpp)
  COMMAND java -jar ${ANTLR} -Dlanguage=Cpp -o ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/Expressions.g4
)

function(must_generate)
  message(">>> Start must_generate <<<")
  if (
    ${CMAKE_CURRENT_SOURCE_DIR}/Expressions.g4 IS_NEWER_THAN ${CMAKE_CURRENT_SOURCE_DIR}/ExpressionsParser.cpp)
      message(">>> Adding the custome generation command")
      add_library(
        parser_src OBJECT ExpressionsParser.cpp
      )
  endif()
  message(">>> End must_generate <<<")
endfunction()

must_generate()

However, what I really want is to determine whether the files need to be generated when I execute cmake --build build. The above solution only works if I rerun the configuration. Is there a way to make the decision during build?

  • 1
    `add_custom_command` should take care of that if you use `DEPENDS`. There's probably a dupe, but I'm having trouble finding it. – Stephen Newell Apr 18 '22 at 16:34
  • The add_custom_command does work, but gets executed only when I do ```cmake -S . -B build from the top level. – Gary Pollice Apr 18 '22 at 17:35
  • It should be target which depends on OUTPUT of `add_custom_command`, otherwise custom command won't be run: https://stackoverflow.com/questions/2937128/cmake-add-custom-command-not-being-run. It could be a custom target (`add_custom_target`) or `add_library`/`add_executable`. Note also, that `OUTPUT(ExpressionsParser.cpp)` is a **wrong syntax** of OUTPUT argument. It should be `OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/ExpressionsParser.cpp` instead (you need to use absolute path because CMake treats relative paths relative to the build directory). – Tsyvarev Apr 18 '22 at 18:04

1 Answers1

1

This solution isn't very satisfying, but it works. The CMakeLists.txt file now looks like this:

add_custom_command(
  OUTPUT(${CMAKE_CURRENT_SOURCE_DIR}/ExpressionsParser.cpp)
  # COMMAND java -jar ${ANTLR} -Dlanguage=Cpp -o ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/Expressions.g4
  WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
  COMMAND /bin/sh  ${CMAKE_CURRENT_SOURCE_DIR}/generate.sh
)

add_custom_target(generate_parser ALL
  DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/ExpressionsParser.cpp
)

The shell script determines if the grammar file is newer than the generated file and runs ANTLR if it is. If I uncomment the direct ANTLR invocation and comment out the script execution, this either always generates the source files or never does, depending upon the state of the files when I execute the CMake generation. Maybe there's a better way to test file timestamps or dependencies at runtime. Anyway, I've spend more time than I want to on this.