refactor
This commit is contained in:
+37
-20
@@ -6,6 +6,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED 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)
|
||||
@@ -16,38 +17,54 @@ 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)
|
||||
|
||||
# inputs to parse
|
||||
set(RPC_INPUTS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/MyService.h
|
||||
)
|
||||
# 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")
|
||||
|
||||
# command to run generator
|
||||
add_custom_command(
|
||||
add_custom_command(
|
||||
OUTPUT
|
||||
${GENERATED_DIR}/MyService.proxy.h
|
||||
${GENERATED_DIR}/MyService.proxy.cpp
|
||||
${GENERATED_DIR}/MyService.skeleton.h
|
||||
${GENERATED_DIR}/MyService.skeleton.cpp
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "Generating RPC stubs..."
|
||||
${out_proxy_h}
|
||||
${out_proxy_cpp}
|
||||
${out_skeleton_h}
|
||||
${out_skeleton_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}
|
||||
${RPC_INPUTS}
|
||||
DEPENDS ${RPC_GENERATOR} ${RPC_TEMPLATES} ${RPC_INPUTS}
|
||||
--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"
|
||||
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}
|
||||
)
|
||||
endfunction()
|
||||
|
||||
include_directories(${GENERATED_DIR})
|
||||
|
||||
add_custom_target(rpc_generated DEPENDS
|
||||
${GENERATED_DIR}/MyService.proxy.h
|
||||
${GENERATED_DIR}/MyService.proxy.cpp
|
||||
${GENERATED_DIR}/MyService.skeleton.h
|
||||
${GENERATED_DIR}/MyService.skeleton.cpp
|
||||
# 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
|
||||
|
||||
@@ -20,17 +20,21 @@ project/
|
||||
├── CMakeLists.txt
|
||||
├── README.md
|
||||
├── src
|
||||
│ ├── client.cpp # пример клиента, использующего MyServiceProxy и IpcPipeChannel
|
||||
│ ├── server.cpp # пример сервера, использующего MyServiceSkeleton и IpcPipeChannel
|
||||
│ ├── client.cpp
|
||||
│ ├── common
|
||||
│ │ ├── ipc
|
||||
│ │ │ ├── IpcChannel.h
|
||||
│ │ │ ├── IpcMessage.h
|
||||
│ │ │ └── IpcPipeChannel.h
|
||||
│ │ ├── proxy
|
||||
│ │ │ └── ProxyMarshaller.h
|
||||
│ │ └── rpc
|
||||
│ │ ├── rpc_export.h
|
||||
│ │ ├── RpcInvoker.h
|
||||
│ │ └── RpcSerializer.h
|
||||
│ ├── MyService.cpp
|
||||
│ ├── MyService.h
|
||||
│ ├── rpc_export.h
|
||||
│ └── rpc
|
||||
│ ├── IpcMessage.h # типизированное IPC‑сообщение (add<T>/get<T>)
|
||||
│ ├── IpcPipeChannel.h# реализация RpcChannel поверх FIFO
|
||||
│ ├── RpcChannel.h # абстрактный канал для RPC
|
||||
│ ├── ProxyMarshaller.h # клиентское ядро RPC (call<Ret>(method, args...))
|
||||
│ └── RpcInvoker.h # серверное ядро RPC (dispatch)
|
||||
│ └── server.cpp
|
||||
├── tools
|
||||
│ ├── generate_rpc.py
|
||||
│ └── templates
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "IpcChannel.h"
|
||||
#include <ipc/IpcChannel.h>
|
||||
|
||||
class ProxyMarshaller {
|
||||
public:
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "IpcMessage.h"
|
||||
#include <ipc/IpcMessage.h>
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <rpc_export.h>
|
||||
#include <rpc/rpc_export.h>
|
||||
|
||||
// annotate with clang attribute or via comment annotation recognized by libclang
|
||||
// Use ANNOTATE attribute supported by clang: __attribute__((annotate("export")))
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
#include "MyService.proxy.h"
|
||||
#include "rpc/IpcPipeChannel.h"
|
||||
#include "ipc/IpcPipeChannel.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
#include "MyService.h"
|
||||
#include "MyService.skeleton.h"
|
||||
|
||||
#include "rpc/IpcPipeChannel.h"
|
||||
#include "ipc/IpcPipeChannel.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
|
||||
+75
-18
@@ -73,11 +73,22 @@ def load_compile_flags(compile_commands_path, src_path):
|
||||
if skip_next:
|
||||
skip_next = False
|
||||
continue
|
||||
if tok.endswith('g++') or tok.endswith('clang++') or tok.endswith('clang') or tok.endswith('g++') or tok.endswith('cc'):
|
||||
# skip the compiler binary itself
|
||||
if (
|
||||
tok.endswith("g++")
|
||||
or tok.endswith("clang++")
|
||||
or tok.endswith("clang")
|
||||
or tok.endswith("cc")
|
||||
or tok.endswith("c++")
|
||||
):
|
||||
continue
|
||||
if tok == "-c":
|
||||
skip_next = True
|
||||
continue
|
||||
# drop output file flag: -o <file>
|
||||
if tok == "-o":
|
||||
skip_next = True
|
||||
continue
|
||||
filtered.append(tok)
|
||||
return filtered
|
||||
return []
|
||||
@@ -183,7 +194,13 @@ def main():
|
||||
p = argparse.ArgumentParser()
|
||||
p.add_argument("--out-dir", "-o", required=True)
|
||||
p.add_argument("--compile-commands", "-c", default=None)
|
||||
p.add_argument("inputs", nargs="+")
|
||||
p.add_argument("--header", required=True, help="C++ header file to scan for exported RPC classes")
|
||||
p.add_argument("--source", required=True, help="C++ source file to use for resolving compile flags (from compile_commands.json)")
|
||||
p.add_argument(
|
||||
"--out-base",
|
||||
required=True,
|
||||
help="Base name for generated files: <out-base>.proxy.[h|cpp], <out-base>.skeleton.[h|cpp]",
|
||||
)
|
||||
p.add_argument("--templates", "-t", default=os.path.join(os.path.dirname(__file__), "templates"))
|
||||
args = p.parse_args()
|
||||
|
||||
@@ -199,28 +216,68 @@ def main():
|
||||
except Exception as e:
|
||||
print("WARNING: cannot set libclang path:", e)
|
||||
|
||||
index = Index.create()
|
||||
all_classes = []
|
||||
# determine compile flags from the source file (which is what appears in compile_commands.json)
|
||||
if not os.path.exists(args.header):
|
||||
print("ERROR: header file not found:", args.header)
|
||||
return 1
|
||||
if not os.path.exists(args.source):
|
||||
print("ERROR: source file not found:", args.source)
|
||||
return 1
|
||||
|
||||
for inp in args.inputs:
|
||||
if not os.path.exists(inp):
|
||||
print("WARN: input file not found:", inp)
|
||||
continue
|
||||
compile_args = load_compile_flags(args.compile_commands, inp)
|
||||
# ensure -x c++ if missing
|
||||
compile_args = load_compile_flags(args.compile_commands, args.source)
|
||||
if not any(a.startswith("-x") for a in compile_args):
|
||||
compile_args = ["-x", "c++", "-std=c++17"] + compile_args
|
||||
print("Parsing", inp, "with args:", compile_args)
|
||||
classes = parse_file(index, inp, compile_args)
|
||||
all_classes.extend(classes)
|
||||
|
||||
if not all_classes:
|
||||
print("No exported classes/methods found. Nothing to generate.")
|
||||
print("Parsing", args.header, "with args:", compile_args)
|
||||
|
||||
index = Index.create()
|
||||
classes = parse_file(index, args.header, compile_args)
|
||||
|
||||
if not classes:
|
||||
print("No exported classes/methods found in header. Nothing to generate.")
|
||||
return 0
|
||||
|
||||
# render templates
|
||||
render_templates(all_classes, out_dir, args.templates)
|
||||
print("Generated files for classes:", ", ".join(c.name for c in all_classes))
|
||||
# For this PoC we expect a single exported service per header.
|
||||
# If there are multiple, refuse to guess which one should define the filenames.
|
||||
if len(classes) > 1:
|
||||
print(
|
||||
"ERROR: multiple exported classes found in header; "
|
||||
"current generator expects exactly one when using --out-base."
|
||||
)
|
||||
for c in classes:
|
||||
print(" -", c.name)
|
||||
return 1
|
||||
|
||||
# render templates using the single discovered class but the user‑provided base name
|
||||
cls = classes[0]
|
||||
|
||||
env = Environment(
|
||||
loader=FileSystemLoader(args.templates),
|
||||
autoescape=False,
|
||||
trim_blocks=True,
|
||||
lstrip_blocks=True,
|
||||
)
|
||||
|
||||
proxy_h = env.get_template("proxy.h.j2")
|
||||
proxy_cpp = env.get_template("proxy.cpp.j2")
|
||||
skeleton_h = env.get_template("skeleton.h.j2")
|
||||
skeleton_cpp = env.get_template("skeleton.cpp.j2")
|
||||
|
||||
base = args.out_base
|
||||
|
||||
with open(f"{out_dir}/{base}.proxy.h", "w") as f:
|
||||
f.write(proxy_h.render(cls=cls))
|
||||
|
||||
with open(f"{out_dir}/{base}.proxy.cpp", "w") as f:
|
||||
f.write(proxy_cpp.render(cls=cls))
|
||||
|
||||
with open(f"{out_dir}/{base}.skeleton.h", "w") as f:
|
||||
f.write(skeleton_h.render(cls=cls))
|
||||
|
||||
with open(f"{out_dir}/{base}.skeleton.cpp", "w") as f:
|
||||
f.write(skeleton_cpp.render(cls=cls))
|
||||
|
||||
print("Generated files for class", cls.name, "into base", base)
|
||||
return 0
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include "{{ cls.name }}.proxy.h"
|
||||
#include "rpc/ProxyMarshaller.h"
|
||||
#include "proxy/ProxyMarshaller.h"
|
||||
|
||||
class {{ cls.name }}Proxy::Impl {
|
||||
public:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "rpc/IpcChannel.h"
|
||||
#include "ipc/IpcChannel.h"
|
||||
|
||||
class {{ cls.name }}Proxy {
|
||||
public:
|
||||
|
||||
Reference in New Issue
Block a user