diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ca1e2e..c76439e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,6 @@ capnp_generate_cpp(MP_PROXY_SRCS MP_PROXY_HDRS include/mp/proxy.capnp) set(MP_PUBLIC_HEADERS ${MP_PROXY_HDRS} - include/mp/proxy.h include/mp/proxy-io.h include/mp/proxy-types.h include/mp/proxy.capnp @@ -38,41 +37,40 @@ set_target_properties(multiprocess PROPERTIES install(TARGETS multiprocess EXPORT Multiprocess ARCHIVE DESTINATION lib PUBLIC_HEADER DESTINATION include/mp) add_executable(mpgen src/mp/gen.cpp) -target_include_directories(mpgen PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) +target_include_directories(mpgen PRIVATE $) target_include_directories(mpgen PUBLIC $ $) target_link_libraries(mpgen PRIVATE CapnProto::capnp-rpc) target_link_libraries(mpgen PRIVATE -L${capnp_LIBRARY_DIRS} capnpc) +target_link_libraries(mpgen PRIVATE multiprocess) set_target_properties(mpgen PROPERTIES INSTALL_RPATH_USE_LINK_PATH TRUE CXX_STANDARD 14 CXX_STANDARD_REQUIRED YES) install(TARGETS mpgen EXPORT Multiprocess RUNTIME DESTINATION bin) -configure_file(pkgconfig/libmultiprocess.pc.in "${CMAKE_CURRENT_BINARY_DIR}/libmultiprocess.pc" @ONLY) -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libmultiprocess.pc" DESTINATION "lib/pkgconfig") +configure_file(include/mp/config.h.in "${CMAKE_CURRENT_BINARY_DIR}/include/mp/config.h") +configure_file(pkgconfig/libmultiprocess.pc.in "${CMAKE_CURRENT_BINARY_DIR}/pkgconfig/libmultiprocess.pc" @ONLY) +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/pkgconfig/libmultiprocess.pc" DESTINATION "lib/pkgconfig") install(EXPORT Multiprocess DESTINATION lib/cmake/Multiprocess) -set(CAPNPC_IMPORT_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/include") -capnp_generate_cpp(FOO_PROXY_SRCS FOO_PROXY_HDRS src/mp/test/foo.capnp) - - if(BUILD_TESTING) add_custom_command( OUTPUT + src/mp/test/foo.capnp.h + src/mp/test/foo.capnp.c++ src/mp/test/foo.capnp.proxy.h src/mp/test/foo.capnp.proxy-server.c++ src/mp/test/foo.capnp.proxy-client.c++ src/mp/test/foo.capnp.proxy-types.c++ src/mp/test/foo.capnp.proxy-types.h - PRE_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory src/mp/test - COMMAND ${CMAKE_COMMAND} -E chdir src "${CMAKE_CURRENT_BINARY_DIR}/mpgen" mp/test/foo "${CMAKE_CURRENT_SOURCE_DIR}/src/mp/test/foo.capnp" "${CMAKE_CURRENT_SOURCE_DIR}/include" "${capnp_PREFIX}/include" + COMMAND mpgen "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/src" "${CMAKE_CURRENT_SOURCE_DIR}/src/mp/test/foo.capnp" "${CMAKE_CURRENT_SOURCE_DIR}/include" "${capnp_PREFIX}/include" DEPENDS src/mp/test/foo.capnp mpgen ) add_executable(mptest EXCLUDE_FROM_ALL - ${FOO_PROXY_HDRS} - ${FOO_PROXY_SRCS} ${MP_PROXY_HDRS} + src/mp/test/foo.capnp.h + src/mp/test/foo.capnp.c++ src/mp/test/foo.capnp.proxy.h src/mp/test/foo.capnp.proxy-server.c++ src/mp/test/foo.capnp.proxy-client.c++ diff --git a/include/mp/config.h.in b/include/mp/config.h.in new file mode 100644 index 0000000..ce8f1f7 --- /dev/null +++ b/include/mp/config.h.in @@ -0,0 +1,10 @@ +// Copyright (c) 2019 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef MP_CONFIG_H +#define MP_CONFIG_H + +#cmakedefine capnp_PREFIX "@capnp_PREFIX@" + +#endif // MP_CONFIG_H diff --git a/src/mp/gen.cpp b/src/mp/gen.cpp index 1981dda..7582534 100644 --- a/src/mp/gen.cpp +++ b/src/mp/gen.cpp @@ -2,6 +2,9 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include +#include + #include #include #include @@ -66,49 +69,95 @@ bool BoxedType(const ::capnp::Type& type) type.isFloat64() || type.isEnum()); } -void Generate(kj::StringPtr output_stem, kj::StringPtr input_schema, kj::ArrayPtr import_paths) +void Generate(kj::StringPtr src_prefix, + kj::StringPtr include_prefix, + kj::StringPtr src_file, + kj::ArrayPtr import_paths) { + std::string output_path; + if (src_prefix == ".") { + output_path = src_file; + } else if (!src_file.startsWith(src_prefix) || src_file.size() <= src_prefix.size() || + src_file[src_prefix.size()] != '/') { + throw std::runtime_error("src_prefix is not src_file prefix"); + } else { + output_path = src_file.slice(src_prefix.size() + 1); + } + + std::string include_path; + if (include_prefix == ".") { + include_path = src_file; + } else if (!src_file.startsWith(include_prefix) || src_file.size() <= include_prefix.size() || + src_file[include_prefix.size()] != '/') { + throw std::runtime_error("include_prefix is not src_file prefix"); + } else { + include_path = src_file.slice(include_prefix.size() + 1); + } + + std::string include_base = include_path; + std::string::size_type p = include_base.rfind("."); + if (p != std::string::npos) include_base.erase(p); + + std::vector args; + args.emplace_back(capnp_PREFIX "/bin/capnp"); + args.emplace_back("compile"); + args.emplace_back("--src-prefix="); + args.back().append(src_prefix.cStr(), src_prefix.size()); + for (const auto& import_path : import_paths) { + args.emplace_back("--import-path="); + args.back().append(import_path.cStr(), import_path.size()); + } + args.emplace_back("--output=" capnp_PREFIX "/bin/capnpc-c++"); + args.emplace_back(src_file); + int pid = fork(); + if (!pid) { + mp::ExecProcess(args); + } + int status = mp::WaitProcess(pid); + if (status) { + throw std::runtime_error("Invoking " capnp_PREFIX "/bin/capnp failed"); + } + capnp::SchemaParser parser; - auto file_schema = parser.parseDiskFile(input_schema, input_schema, import_paths); + auto file_schema = parser.parseDiskFile(src_file, src_file, import_paths); - const std::string stem = output_stem; - std::ofstream cpp_server(stem + ".capnp.proxy-server.c++"); - cpp_server << "// Generated by " PROXY_BIN " from " << input_schema << "\n\n"; - cpp_server << "#include <" << stem << ".capnp.proxy-types.h>\n"; + std::ofstream cpp_server(output_path + ".proxy-server.c++"); + cpp_server << "// Generated by " PROXY_BIN " from " << src_file << "\n\n"; + cpp_server << "#include <" << include_path << ".proxy-types.h>\n"; cpp_server << "#include <" << PROXY_TYPES << ">\n\n"; cpp_server << "namespace mp {\n"; - std::ofstream cpp_client(stem + ".capnp.proxy-client.c++"); - cpp_client << "// Generated by " PROXY_BIN " from " << input_schema << "\n\n"; - cpp_client << "#include <" << stem << ".capnp.proxy-types.h>\n"; + std::ofstream cpp_client(output_path + ".proxy-client.c++"); + cpp_client << "// Generated by " PROXY_BIN " from " << src_file << "\n\n"; + cpp_client << "#include <" << include_path << ".proxy-types.h>\n"; cpp_client << "#include <" << PROXY_TYPES << ">\n\n"; cpp_client << "namespace mp {\n"; - std::ofstream cpp_types(stem + ".capnp.proxy-types.c++"); - cpp_types << "// Generated by " PROXY_BIN " from " << input_schema << "\n\n"; - cpp_types << "#include <" << stem << ".capnp.proxy-types.h>\n"; + std::ofstream cpp_types(output_path + ".proxy-types.c++"); + cpp_types << "// Generated by " PROXY_BIN " from " << src_file << "\n\n"; + cpp_types << "#include <" << include_path << ".proxy-types.h>\n"; cpp_types << "#include <" << PROXY_TYPES << ">\n\n"; cpp_types << "namespace mp {\n"; - std::string guard = stem; + std::string guard = output_path; std::transform(guard.begin(), guard.end(), guard.begin(), [](unsigned char c) { return ('0' <= c && c <= '9') ? c : ('A' <= c && c <= 'Z') ? c : ('a' <= c && c <= 'z') ? c - 'a' + 'A' : '_'; }); - std::ofstream inl(stem + ".capnp.proxy-types.h"); - inl << "// Generated by " PROXY_BIN " from " << input_schema << "\n\n"; - inl << "#ifndef " << guard << "_CAPNP_PROXY_TYPES_H\n"; - inl << "#define " << guard << "_CAPNP_PROXY_TYPES_H\n\n"; - inl << "#include <" << stem << ".capnp.proxy.h>\n"; - inl << "#include <" << stem << "-types.h>\n\n"; + std::ofstream inl(output_path + ".proxy-types.h"); + inl << "// Generated by " PROXY_BIN " from " << src_file << "\n\n"; + inl << "#ifndef " << guard << "_PROXY_TYPES_H\n"; + inl << "#define " << guard << "_PROXY_TYPES_H\n\n"; + inl << "#include <" << include_path << ".proxy.h>\n"; + inl << "#include <" << include_base << "-types.h>\n\n"; inl << "namespace mp {\n"; - std::ofstream h(stem + ".capnp.proxy.h"); - h << "// Generated by " PROXY_BIN " from " << input_schema << "\n\n"; - h << "#ifndef " << guard << "_CAPNP_PROXY_H\n"; - h << "#define " << guard << "_CAPNP_PROXY_H\n\n"; - h << "#include <" << stem << ".h>\n"; - h << "#include <" << stem << ".capnp.h>\n"; + std::ofstream h(output_path + ".proxy.h"); + h << "// Generated by " PROXY_BIN " from " << src_file << "\n\n"; + h << "#ifndef " << guard << "_PROXY_H\n"; + h << "#define " << guard << "_PROXY_H\n\n"; + h << "#include <" << include_path << ".h>\n"; + h << "#include <" << include_base << ".h>\n"; h << "#include <" << PROXY_DECL << ">\n\n"; h << "namespace mp {\n"; @@ -117,10 +166,10 @@ void Generate(kj::StringPtr output_stem, kj::StringPtr input_schema, kj::ArrayPt message_namespace = value->getText(); } - std::string output_name = output_stem; - size_t output_slash = output_name.rfind("/"); + std::string base_name = include_base; + size_t output_slash = base_name.rfind("/"); if (output_slash != std::string::npos) { - output_name.erase(0, output_slash + 1); + base_name.erase(0, output_slash + 1); } std::ostringstream methods; @@ -182,7 +231,7 @@ void Generate(kj::StringPtr output_stem, kj::StringPtr input_schema, kj::ArrayPt for (const auto field : struc.getFields()) { auto field_name = field.getProto().getName(); add_accessor(field_name); - dec << " using " << Cap(field_name) << "Accessor = Accessor<" << output_name + dec << " using " << Cap(field_name) << "Accessor = Accessor<" << base_name << "_fields::" << Cap(field_name) << ", FIELD_IN | FIELD_OUT"; if (BoxedType(field.getType())) dec << " | FIELD_BOXED"; dec << ">;\n"; @@ -385,7 +434,7 @@ void Generate(kj::StringPtr output_stem, kj::StringPtr input_schema, kj::ArrayPt client_invoke << "MakeClientParam<"; } - client_invoke << "Accessor<" << output_name << "_fields::" << Cap(field_name) << ", " + client_invoke << "Accessor<" << base_name << "_fields::" << Cap(field_name) << ", " << field_flags.str() << ">>("; if (field.retval || field.args == 1) { @@ -405,7 +454,7 @@ void Generate(kj::StringPtr output_stem, kj::StringPtr input_schema, kj::ArrayPt } else { server_invoke_start << "MakeServerField<" << field.args; } - server_invoke_start << ", Accessor<" << output_name << "_fields::" << Cap(field_name) << ", " + server_invoke_start << ", Accessor<" << base_name << "_fields::" << Cap(field_name) << ", " << field_flags.str() << ">>("; server_invoke_end << ")"; } @@ -452,8 +501,8 @@ void Generate(kj::StringPtr output_stem, kj::StringPtr input_schema, kj::ArrayPt } } - h << methods.str() << "namespace " << output_name << "_fields {\n" - << accessors.str() << "} // namespace " << output_name << "_fields\n" + h << methods.str() << "namespace " << base_name << "_fields {\n" + << accessors.str() << "} // namespace " << base_name << "_fields\n" << dec.str(); cpp_server << def_server.str(); @@ -475,13 +524,13 @@ void Generate(kj::StringPtr output_stem, kj::StringPtr input_schema, kj::ArrayPt int main(int argc, char** argv) { if (argc < 3) { - fprintf(stderr, "Usage: " PROXY_BIN " OUTPUT_STEM INPUT_SCHEMA [IMPORT_PATH...]\n"); + fprintf(stderr, "Usage: " PROXY_BIN " SRC_PREFIX SRC_FILE [IMPORT_PATH...]\n"); exit(1); } std::vector import_paths; - for (size_t i = 3; i < argc; ++i) { + for (size_t i = 4; i < argc; ++i) { import_paths.push_back(argv[i]); } - Generate(argv[1], argv[2], {import_paths.data(), import_paths.size()}); + Generate(argv[1], argv[2], argv[3], {import_paths.data(), import_paths.size()}); return 0; }