Skip to content

Commit

Permalink
Merge #9: Invoke capnp compile from mpgen
Browse files Browse the repository at this point in the history
f89e4b3 Invoke capnp compile from mpgen (Russell Yanofsky)

Pull request description:

  This simplifies multiprocess build code somewhat (bitcoin/bitcoin#16367) so it only has to invoke one code generator instead of two, and is probably a little more future proof in that is should make it possible to change capnp options without any requiring changes outside libmultiprocess.

Top commit has no ACKs.

Tree-SHA512: 64534ec8d020eaf6a2dd351e4e48bf3a7a9897c126db1585c259950070b513aa9a416204e64ad1ab16717f41c534b9aafced4844039ed1f9037550946533445e
  • Loading branch information
ryanofsky committed Aug 6, 2019
2 parents dee0711 + f89e4b3 commit 9cd1a5a
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 48 deletions.
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");
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;
}

0 comments on commit 9cd1a5a

Please sign in to comment.