Skip to content

Invoke capnp compile from mpgen #9

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 10 additions & 12 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>)
target_include_directories(mpgen PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> $<INSTALL_INTERFACE:include>)
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++
Expand Down
10 changes: 10 additions & 0 deletions include/mp/config.h.in
Original file line number Diff line number Diff line change
@@ -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
121 changes: 85 additions & 36 deletions src/mp/gen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <mp/config.h>
#include <mp/util.h>

#include <boost/optional.hpp>
#include <capnp/schema-parser.h>
#include <fstream>
Expand Down Expand Up @@ -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<const kj::StringPtr> import_paths)
void Generate(kj::StringPtr src_prefix,
kj::StringPtr include_prefix,
kj::StringPtr src_file,
kj::ArrayPtr<const kj::StringPtr> 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<std::string> 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";

Expand All @@ -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;
Expand Down Expand Up @@ -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";
Expand Down Expand Up @@ -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) {
Expand All @@ -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 << ")";
}
Expand Down Expand Up @@ -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();
Expand All @@ -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");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it be

-        fprintf(stderr, "Usage: " PROXY_BIN " SRC_PREFIX SRC_FILE [IMPORT_PATH...]\n");
+        fprintf(stderr, "Usage: " PROXY_BIN " SRC_PREFIX INCLUDE_PREFIX SRC_FILE [IMPORT_PATH...]\n");

?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it be

Good catch. Should be fixed in #80

exit(1);
}
std::vector<kj::StringPtr> 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;
}