cmake_minimum_required(VERSION 3.10) project(SimpleRPCExample CXX C) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD_REQUIRED ON) # Generate compile_commands.json for code generation tools set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # include source includes include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) # find python interpreter find_package(Python3 COMPONENTS Interpreter REQUIRED) set(GENERATED_DIR ${CMAKE_BINARY_DIR}/generated) file(MAKE_DIRECTORY ${GENERATED_DIR}) set(RPC_GENERATOR ${CMAKE_CURRENT_SOURCE_DIR}/tools/generate_rpc.py) set(RPC_TEMPLATES ${CMAKE_CURRENT_SOURCE_DIR}/tools/templates) # helper to generate RPC code for an annotated header/source pair function(autocode_annotated_file OUT_BASENAME HEADER SOURCE) set(out_proxy_h "${GENERATED_DIR}/${OUT_BASENAME}.proxy.h") set(out_proxy_cpp "${GENERATED_DIR}/${OUT_BASENAME}.proxy.cpp") set(out_skeleton_h "${GENERATED_DIR}/${OUT_BASENAME}.skeleton.h") set(out_skeleton_cpp "${GENERATED_DIR}/${OUT_BASENAME}.skeleton.cpp") set(out_client_c_h "${GENERATED_DIR}/${OUT_BASENAME}Client_c.h") set(out_client_c_cpp "${GENERATED_DIR}/${OUT_BASENAME}Client_c.cpp") add_custom_command( OUTPUT ${out_proxy_h} ${out_proxy_cpp} ${out_skeleton_h} ${out_skeleton_cpp} ${out_client_c_h} ${out_client_c_cpp} COMMAND ${CMAKE_COMMAND} -E echo "Generating RPC stubs for ${OUT_BASENAME}..." COMMAND ${Python3_EXECUTABLE} ${RPC_GENERATOR} --out-dir ${GENERATED_DIR} --compile-commands ${CMAKE_BINARY_DIR}/compile_commands.json --templates ${RPC_TEMPLATES} --header ${HEADER} --source ${SOURCE} --out-base ${OUT_BASENAME} DEPENDS ${RPC_GENERATOR} ${RPC_TEMPLATES}/* ${HEADER} ${SOURCE} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMENT "Running RPC code generator for ${OUT_BASENAME}" VERBATIM ) # accumulate all generated files into a global property so we can # have one umbrella target that depends on all of them set_property(GLOBAL APPEND PROPERTY AUTOCODE_GENERATED_FILES ${out_proxy_h} ${out_proxy_cpp} ${out_skeleton_h} ${out_skeleton_cpp} ${out_client_c_h} ${out_client_c_cpp} ) endfunction() include_directories(${GENERATED_DIR}) # declare all annotated files here autocode_annotated_file(MyService ${CMAKE_CURRENT_SOURCE_DIR}/src/MyService.h ${CMAKE_CURRENT_SOURCE_DIR}/src/MyService.cpp ) # umbrella target that depends on all generated RPC files get_property(_all_generated GLOBAL PROPERTY AUTOCODE_GENERATED_FILES) add_custom_target(rpc_generated DEPENDS ${_all_generated}) # Server add_executable(server src/server.cpp src/MyService.cpp ${GENERATED_DIR}/MyService.skeleton.cpp ) add_dependencies(server rpc_generated) # Client add_executable(client src/client.cpp ${GENERATED_DIR}/MyService.proxy.cpp ) add_dependencies(client rpc_generated) # C bindings library add_library(rpc_client_c STATIC src/rpc_client_c.cpp ) target_include_directories(rpc_client_c PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include ${GENERATED_DIR} ) # C client add_executable(client_c src/client_c.c ${GENERATED_DIR}/MyServiceClient_c.cpp ) target_include_directories(client_c PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include ${GENERATED_DIR} ) target_link_libraries(client_c rpc_client_c ) add_dependencies(client_c rpc_generated)