Struggling with generated headers

I’m using SBE, which generates headers based on a schema (à la something like protobuf).

I can run it by hand like:

$ mkdir build/generated
$ java -Dsbe.target.language=CPP -Dsbe.output.dir=build/generated -jar ../simple-binary-encoding/sbe-all/build/libs/sbe-all-1.31.0-SNAPSHOT.jar config/schema.xml

Which gives me:

$ ls -R build/generated/
build/generated/:
test

build/generated/test:
MessageHeader.h  Thing.h

I can then write a tiny CMake file pointing explicitly at this directory, which builds fine:

add_executable(Test src/test.cpp)
target_include_directories(Test PUBLIC build/generated)

What I want is to automate fetching the code generation tool, building it, and generating the headers for inclusion.
I’ve been fumbling around and come up with the below, which seems to fetch the repo OK but then not do anything (and, naturally, I get a build error about missing headers):

include(FetchContent)
FetchContent_Declare(
  sbe
  GIT_REPOSITORY https://github.com/real-logic/simple-binary-encoding.git
  GIT_TAG        1.30.0
  )
FetchContent_MakeAvailable(sbe)

set(GENERATED_FILES ${CMAKE_BINARY_DIR}/generated)
set(LADDER_TEMPLATE config/schema.xml)
add_custom_command(
  OUTPUT ${GENERATED_FILES}
  COMMAND java ARGS -Dsbe.target.language=CPP -Dsbe.output.dir=${GENERATED_FILES} -jar sbe::sbe-jar ${LADDER_TEMPLATE}
  COMMENT "Generating SBE headers"
  DEPENDS ${LADDER_TEMPLATE}
  )

add_executable(Test src/test.cpp)
target_include_directories(Test PUBLIC ${GENERATED_FILES})

Bit new to CMake, so apologies if this is rudimentary. Any help very much appreciated.

You cannot list a directory as the OUTPUT of a custom command. You should instead list the individual files produced by the run, and then add those files into the target you’re building. So effectively something like this:

set(GENERATED_FILE_DIR ${CMAKE_BINARY_DIR}/generated)
set(GENERATED_FILES
  ${GENERATED_FILE_DIR}/test/MessageHeader.h
  ${GENERATED_FILE_DIR}/test/Thing.h
)
add_custom_command(
  OUTPUT ${GENERATED_FILES}
  COMMAND java ARGS -Dsbe.target.language=CPP -Dsbe.output.dir=${GENERATED_FILES} -jar sbe::sbe-jar ${LADDER_TEMPLATE}
  COMMENT "Generating SBE headers"
  DEPENDS ${LADDER_TEMPLATE}
  )

add_executable(Test src/test.cpp ${GENERATED_FILES})
target_include_directories(Test PUBLIC ${GENERATED_FILE_DIR})
1 Like

Thanks very much for the help, that’s got me most of the way. I’ve now got a file that looks like:

set(SBE_VER 1.30.0)

include(FetchContent)
FetchContent_Declare(
  sbe
  GIT_REPOSITORY https://github.com/real-logic/simple-binary-encoding.git
  GIT_TAG        ${SBE_VER}
  )
FetchContent_MakeAvailable(sbe)

set(GENERATED_FILE_DIR ${CMAKE_BINARY_DIR}/generated)
set(GENERATED_FILES
  ${GENERATED_FILE_DIR}/priceladder/MessageHeader.h
  ${GENERATED_FILE_DIR}/priceladder/Thing.h
)
set(LADDER_TEMPLATE config/schema.xml)
add_custom_command(
  OUTPUT ${GENERATED_FILES}
  COMMAND java ARGS 
    -Dsbe.target.language=CPP 
    -Dsbe.output.dir=${GENERATED_FILE_DIR} 
    -jar ${sbe_SOURCE_DIR}/sbe-all/build/libs/sbe-all-${SBE_VER}.jar 
    ${LADDER_TEMPLATE}
  COMMENT "Generating SBE headers"
  DEPENDS ${LADDER_TEMPLATE}
  )

add_executable(Test src/test.cpp)
target_include_directories(Test PUBLIC ${GENERATED_FILE_DIR})
target_link_libraries(Test PUBLIC sbe)

That sucessully builds my code but I was hoping not to have to explicitly list the path to it in the custom command.
I’m probably misunderstanding something but I thought I might be able to access it via the target here. I tried passing it to the command like this but it complains:

-jar sbe::sbe-jar

Is there something I can add to the third-party CMake file to let me do this?