blob: b5ce0396a232dd83ca1c98556eaff72f2923167b [file] [log] [blame]
// Part of the Crubit project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// Parses C++ headers and generates:
// * a Rust source file with bindings for the C++ API
// * a C++ source file with the implementation of the bindings
#include <memory>
#include <string>
#include <vector>
#include "base/init_google.h"
#include "base/logging.h"
#include "devtools/cymbal/common/clang_tool.h"
#include "rs_bindings_from_cc/frontend_action.h"
#include "rs_bindings_from_cc/ir.h"
#include "rs_bindings_from_cc/ir_from_cc.h"
#include "rs_bindings_from_cc/src_code_gen.h"
#include "file/base/filesystem.h"
#include "file/base/helpers.h"
#include "file/base/options.h"
#include "third_party/absl/container/flat_hash_map.h"
#include "third_party/absl/flags/flag.h"
#include "third_party/absl/strings/string_view.h"
#include "third_party/absl/strings/substitute.h"
#include "third_party/llvm/llvm-project/clang/include/clang/Frontend/FrontendAction.h"
#include "util/task/status.h"
ABSL_FLAG(std::string, rs_out, "",
"output path for the Rust source file with bindings");
ABSL_FLAG(std::string, cc_out, "",
"output path for the C++ source file with bindings implementation");
ABSL_FLAG(std::string, ir_out, "",
"(optional) output path for the JSON IR. If not present, the JSON IR "
"will not be dumped.");
ABSL_FLAG(std::vector<std::string>, public_headers, std::vector<std::string>(),
"public headers of the cc_library this tool should generate bindings "
"for, in a format suitable for usage in google3-relative quote "
"include (#include \"\").");
int main(int argc, char* argv[]) {
InitGoogle(argv[0], &argc, &argv, true);
auto rs_out = absl::GetFlag(FLAGS_rs_out);
QCHECK(!rs_out.empty()) << "please specify --rs_out";
auto cc_out = absl::GetFlag(FLAGS_cc_out);
QCHECK(!cc_out.empty()) << "please specify --cc_out";
auto public_headers = absl::GetFlag(FLAGS_public_headers);
QCHECK(!public_headers.empty())
<< "please specify at least one header in --public_headers";
auto ir_out = absl::GetFlag(FLAGS_ir_out); // Optional.
if (absl::StatusOr<rs_bindings_from_cc::IR> ir =
rs_bindings_from_cc::IrFromCc(
{},
std::vector<absl::string_view>(public_headers.begin(),
public_headers.end()),
std::vector<absl::string_view>(argv, argv + argc));
ir.ok()) {
if (!ir_out.empty()) {
CHECK_OK(file::SetContents(ir_out, ir->ToJson().dump(/*indent=*/2),
file::Defaults()));
}
rs_bindings_from_cc::Bindings bindings =
rs_bindings_from_cc::GenerateBindings(*ir);
CHECK_OK(file::SetContents(rs_out, bindings.rs_api, file::Defaults()));
CHECK_OK(file::SetContents(cc_out, bindings.rs_api_impl, file::Defaults()));
return 0;
}
file::Delete(rs_out, file::Defaults()).IgnoreError();
file::Delete(cc_out, file::Defaults()).IgnoreError();
if (!ir_out.empty()) {
file::Delete(ir_out, file::Defaults()).IgnoreError();
}
return 1;
}