QtProtobufGen.cmake 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. function(qtprotobuf_link_archive TARGET GENERATED_TARGET)
  2. set_target_properties(${qtprotobuf_generate_TARGET} PROPERTIES LINKER_LANGUAGE CXX)
  3. set_target_properties(${TARGET} PROPERTIES LINK_DIRECTORIES "$<TARGET_FILE_DIR:${GENERATED_TARGET}>")
  4. get_target_property(EXISTING_FLAGS ${TARGET} LINK_FLAGS)
  5. if(WIN32)
  6. if("${EXISTING_FLAGS}" STREQUAL "EXISTING_FLAGS-NOTFOUND")
  7. set_target_properties(${TARGET} PROPERTIES LINK_FLAGS "/WHOLEARCHIVE:${GENERATED_TARGET}")
  8. else()
  9. set_target_properties(${TARGET} PROPERTIES LINK_FLAGS "${EXISTING_FLAGS} /WHOLEARCHIVE:${GENERATED_TARGET}")
  10. endif()
  11. else()
  12. target_link_libraries(${TARGET} PRIVATE
  13. -Wl,--whole-archive $<TARGET_FILE:${GENERATED_TARGET}> -Wl,--no-whole-archive)
  14. endif()
  15. target_include_directories(${TARGET} PRIVATE $<TARGET_PROPERTY:${GENERATED_TARGET},INCLUDE_DIRECTORIES>)
  16. add_dependencies(${TARGET} ${GENERATED_TARGET})
  17. endfunction()
  18. function(qtprotobuf_generate)
  19. set(options)
  20. set(oneValueArgs OUT_DIR TARGET GENERATED_TARGET MULTI QML COMMENTS GENERATED_HEADERS_VAR)
  21. set(multiValueArgs GENERATED_HEADERS EXCLUDE_HEADERS PROTO_FILES PROTO_INCLUDES)
  22. cmake_parse_arguments(qtprotobuf_generate "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  23. if(DEFINED qtprotobuf_generate_GENERATED_TARGET)
  24. set(GENERATED_TARGET_NAME ${qtprotobuf_generate_GENERATED_TARGET})
  25. elseif(DEFINED qtprotobuf_generate_TARGET)
  26. set(GENERATED_TARGET_NAME ${qtprotobuf_generate_TARGET}_qtprotobuf_gen)
  27. else()
  28. message(FATAL_ERROR "Either TARGET or GENERATED_TARGET must be specified")
  29. endif()
  30. set(GEN_TARGET ${GENERATED_TARGET_NAME}_generate)
  31. set(GENERATED_HEADERS ${qtprotobuf_generate_GENERATED_HEADERS})
  32. if(NOT DEFINED QTPROTOBUF_EXECUTABLE)
  33. set(QTPROTOBUF_EXECUTABLE "${QTPROTOBUF_EXECUTABLE_INSTALL}")
  34. endif()
  35. set(GENERATION_TYPE "SINGLE")
  36. if("${qtprotobuf_generate_MULTI}" STREQUAL "TRUE")
  37. set(GENERATION_TYPE "MULTI")
  38. #TODO: add globalenums by default. But it's better to verify if proto file contains any global enum
  39. set(GENERATED_HEADERS ${GENERATED_HEADERS} globalenums.h)
  40. endif()
  41. set(GENERATION_OPTIONS ${GENERATION_TYPE})
  42. if("${qtprotobuf_generate_QML}" STREQUAL "TRUE")
  43. message(STATUS "Enabled QML generation for ${GENERATED_TARGET_NAME}")
  44. set(GENERATION_OPTIONS "${GENERATION_OPTIONS}:QML")
  45. endif()
  46. if("${qtprotobuf_generate_COMMENTS}" STREQUAL "TRUE")
  47. message(STATUS "Enabled COMMENTS generation for ${GENERATED_TARGET_NAME}")
  48. set(GENERATION_OPTIONS "${GENERATION_OPTIONS}:COMMENTS")
  49. endif()
  50. find_program(GO_EXECUTABLE "go")
  51. if (GO_EXECUTABLE STREQUAL GO_EXECUTABLE-NOTFOUND)
  52. message(FATAL_ERROR "Golang is mandatory dependency for QtProtobuf. Please install it and ensure that it's accessible by PATH environment variable")
  53. endif()
  54. set(PROTO_INCLUDES ${qtprotobuf_generate_PROTO_INCLUDES})
  55. foreach(PROTO_FILE IN LISTS qtprotobuf_generate_PROTO_FILES)
  56. get_filename_component(BASE_DIR ${PROTO_FILE} DIRECTORY)
  57. set(PROTO_INCLUDES -I"${BASE_DIR}" ${PROTO_INCLUDES})
  58. execute_process(COMMAND ${GO_EXECUTABLE} run ${PROTO_PARSER} ${PROTO_FILE} ${GENERATION_TYPE} OUTPUT_VARIABLE GENERATED_HEADERS_PART ERROR_VARIABLE PARSER_ERROR)
  59. set(GENERATED_HEADERS ${GENERATED_HEADERS} ${GENERATED_HEADERS_PART})
  60. endforeach()
  61. if(NOT "${PARSER_ERROR}" STREQUAL "")
  62. message(FATAL_ERROR "Go parser error ${PARSER_ERROR}")
  63. endif()
  64. if(DEFINED qtprotobuf_generate_GENERATED_HEADERS)
  65. set(GENERATED_HEADERS ${qtprotobuf_generate_GENERATED_HEADERS})
  66. endif()
  67. foreach(EXCLUDE_HEADER IN LISTS qtprotobuf_generate_EXCLUDE_HEADERS)
  68. list(REMOVE_ITEM GENERATED_HEADERS ${EXCLUDE_HEADER})
  69. endforeach()
  70. list(REMOVE_DUPLICATES GENERATED_HEADERS)
  71. if(NOT DEFINED qtprotobuf_generate_OUT_DIR)
  72. set(OUT_DIR ${CMAKE_CURRENT_BINARY_DIR})
  73. else()
  74. set(OUT_DIR ${qtprotobuf_generate_OUT_DIR})
  75. endif()
  76. file(MAKE_DIRECTORY ${OUT_DIR})
  77. unset(QTPROTOBUF_GENERATED_SOURCES)
  78. unset(QTPROTOBUF_GENERATED_HEADERS)
  79. foreach(GENERATED_HEADER IN LISTS GENERATED_HEADERS)
  80. get_filename_component(GENERATED_BASENAME ${GENERATED_HEADER} NAME)
  81. string(REGEX REPLACE "\\.[^.]*$" "" GENERATED_BASENAME ${GENERATED_BASENAME})
  82. list(APPEND QTPROTOBUF_GENERATED_SOURCES ${OUT_DIR}/${GENERATED_BASENAME}.cpp)
  83. list(APPEND QTPROTOBUF_GENERATED_HEADERS ${OUT_DIR}/${GENERATED_BASENAME}.h)
  84. set_property(SOURCE ${OUT_DIR}/${GENERATED_BASENAME}.cpp PROPERTY SKIP_AUTOMOC ON)
  85. endforeach()
  86. if(WIN32)
  87. set(PROTOC_COMMAND set QT_PROTOBUF_OPTIONS=${GENERATION_OPTIONS}&& $<TARGET_FILE:protobuf::protoc>)
  88. else()
  89. set(PROTOC_COMMAND "QT_PROTOBUF_OPTIONS=${GENERATION_OPTIONS}" $<TARGET_FILE:protobuf::protoc>)
  90. endif()
  91. add_custom_command(
  92. OUTPUT ${QTPROTOBUF_GENERATED_SOURCES} ${QTPROTOBUF_GENERATED_HEADERS}
  93. COMMAND ${PROTOC_COMMAND}
  94. --plugin=protoc-gen-${GENERATOR_TARGET}=${QTPROTOBUF_EXECUTABLE}
  95. --${GENERATOR_TARGET}_out=${OUT_DIR}
  96. ${PROTO_INCLUDES}
  97. ${qtprotobuf_generate_PROTO_FILES}
  98. WORKING_DIRECTORY ${OUT_DIR}
  99. DEPENDS ${qtprotobuf_generate_PROTO_FILES} ${QTPROTOBUF_EXECUTABLE}
  100. COMMENT "Generating QtProtobuf ${GENERATED_TARGET_NAME} sources..."
  101. )
  102. add_custom_target(${GEN_TARGET} DEPENDS ${QTPROTOBUF_GENERATED_SOURCES} ${QTPROTOBUF_GENERATED_HEADERS} ${qtprotobuf_generate_PROTO_FILES})
  103. if(NOT "${qtprotobuf_generate_GENERATED_HEADERS_VAR}" STREQUAL "")
  104. set(${qtprotobuf_generate_GENERATED_HEADERS_VAR} ${QTPROTOBUF_GENERATED_HEADERS} PARENT_SCOPE)
  105. endif()
  106. qt5_wrap_cpp(MOC_SOURCES ${QTPROTOBUF_GENERATED_HEADERS})
  107. list(APPEND GENERATED_SOURCES ${MOC_SOURCES})
  108. set_source_files_properties(${QTPROTOBUF_GENERATED_SOURCES} PROPERTIES GENERATED TRUE)
  109. add_library(${GENERATED_TARGET_NAME} ${QTPROTOBUF_GENERATED_SOURCES} ${MOC_SOURCES})
  110. add_dependencies(${GENERATED_TARGET_NAME} ${GEN_TARGET})
  111. target_include_directories(${GENERATED_TARGET_NAME} PUBLIC ${OUT_DIR} PRIVATE ${Qt5Core_INCLUDE_DIRS}
  112. $<TARGET_PROPERTY:${QTPROTOBUF_COMMON_NAMESPACE}::QtProtobuf,INTERFACE_INCLUDE_DIRECTORIES>
  113. $<TARGET_PROPERTY:${QTPROTOBUF_COMMON_NAMESPACE}::QtGrpc,INTERFACE_INCLUDE_DIRECTORIES> ${OUT_DIR})
  114. if(NOT WIN32)
  115. target_include_directories(${GENERATED_TARGET_NAME} PRIVATE
  116. $<TARGET_PROPERTY:${QTPROTOBUF_COMMON_NAMESPACE}::QtProtobufWellKnownTypes,INTERFACE_INCLUDE_DIRECTORIES>)
  117. endif()
  118. if(DEFINED qtprotobuf_generate_TARGET)
  119. qtprotobuf_link_archive(${qtprotobuf_generate_TARGET} ${GENERATED_TARGET_NAME})
  120. endif()
  121. endfunction()