Generate C++ files based on input file name

C++ files will have names based on input file name, regardless of its
contents. For example, "PlatformProperties.sysprop" will yield
"PlatformProperties.sysprop.h" and "PlatformProperties.sysprop.cpp".
This is needed to support build system correctly because build system
should be able to deduct the exact paths of generated files.

In addition, as we're going to place source/header separately,
include-name option is added to correctly include generated header.
Build system will automatically feed appropriate path.

Bug: 80125326
Test: mma -j
Test: build a c++ shared library with sample .sysprop description file
Change-Id: I144e8b837c98b027eb2abdb89f6e809a2434a776
diff --git a/CppGen.cpp b/CppGen.cpp
index f4cd533..1532c41 100644
--- a/CppGen.cpp
+++ b/CppGen.cpp
@@ -221,7 +221,8 @@
 bool GenerateHeader(const sysprop::Properties& props,
                     std::string* header_result, std::string* err);
 bool GenerateSource(const sysprop::Properties& props,
-                    std::string* source_result, std::string* err);
+                    const std::string& include_name, std::string* source_result,
+                    std::string* err);
 
 std::string GetHeaderIncludeGuardName(const sysprop::Properties& props) {
   return "SYSPROPGEN_" + std::regex_replace(props.module(), kRegexDot, "_") +
@@ -315,11 +316,12 @@
   return true;
 }
 
-bool GenerateSource(const sysprop::Properties& props, std::string* source_result,
+bool GenerateSource(const sysprop::Properties& props,
+                    const std::string& include_name, std::string* source_result,
                     [[maybe_unused]] std::string* err) {
   CodeWriter writer(kIndent);
   writer.Write("%s", kGeneratedFileFooterComments);
-  writer.Write("#include \"%s.h\"\n\n", GetModuleName(props).c_str());
+  writer.Write("#include <%s>\n\n", include_name.c_str());
   writer.Write("%s", kCppSourceIncludes);
 
   std::string cpp_namespace = GetCppNamespace(props);
@@ -445,7 +447,8 @@
 
 bool GenerateCppFiles(const std::string& input_file_path,
                       const std::string& header_output_dir,
-                      const std::string& source_output_dir, std::string* err) {
+                      const std::string& source_output_dir,
+                      const std::string& include_name, std::string* err) {
   sysprop::Properties props;
 
   if (!ParseProps(input_file_path, &props, err)) {
@@ -458,14 +461,14 @@
     return false;
   }
 
-  if (!GenerateSource(props, &source_result, err)) {
+  if (!GenerateSource(props, include_name, &source_result, err)) {
     return false;
   }
 
-  std::string header_path =
-      header_output_dir + "/" + GetModuleName(props) + ".h";
-  std::string source_path =
-      source_output_dir + "/" + GetModuleName(props) + ".cpp";
+  std::string output_basename = android::base::Basename(input_file_path);
+
+  std::string header_path = header_output_dir + "/" + output_basename + ".h";
+  std::string source_path = source_output_dir + "/" + output_basename + ".cpp";
 
   if (!IsDirectory(header_output_dir) && !CreateDirectories(header_output_dir)) {
     *err = "Creating directory to " + header_output_dir +
diff --git a/CppGen.h b/CppGen.h
index 6dae6c0..241207c 100644
--- a/CppGen.h
+++ b/CppGen.h
@@ -21,6 +21,7 @@
 
 bool GenerateCppFiles(const std::string& input_file_path,
                       const std::string& header_output_dir,
-                      const std::string& source_output_dir, std::string* err);
+                      const std::string& source_output_dir,
+                      const std::string& include_name, std::string* err);
 
 #endif  // SYSTEM_TOOLS_SYSPROP_CPPGEN_H_
diff --git a/CppMain.cpp b/CppMain.cpp
index 012878a..0e35431 100644
--- a/CppMain.cpp
+++ b/CppMain.cpp
@@ -28,15 +28,16 @@
 namespace {
 
 struct Arguments {
-  std::string input_file_path_;
-  std::string header_output_dir_;
-  std::string source_output_dir_;
+  std::string input_file_path;
+  std::string header_output_dir;
+  std::string source_output_dir;
+  std::string include_name;
 };
 
 [[noreturn]] void PrintUsage(const char* exe_name) {
   std::printf(
       "Usage: %s [--header-output-dir dir] [--source-output-dir dir] "
-      "sysprop_file \n",
+      "[--include-name name] sysprop_file\n",
       exe_name);
   std::exit(EXIT_FAILURE);
 }
@@ -46,6 +47,7 @@
     static struct option long_options[] = {
         {"header-output-dir", required_argument, 0, 'h'},
         {"source-output-dir", required_argument, 0, 's'},
+        {"include-name", required_argument, 0, 'n'},
     };
 
     int opt = getopt_long_only(argc, argv, "", long_options, nullptr);
@@ -53,10 +55,13 @@
 
     switch (opt) {
       case 'h':
-        args->header_output_dir_ = optarg;
+        args->header_output_dir = optarg;
         break;
       case 's':
-        args->source_output_dir_ = optarg;
+        args->source_output_dir = optarg;
+        break;
+      case 'n':
+        args->include_name = optarg;
         break;
       default:
         PrintUsage(argv[0]);
@@ -73,9 +78,9 @@
     return false;
   }
 
-  args->input_file_path_ = argv[optind];
-  if (args->header_output_dir_.empty()) args->header_output_dir_ = ".";
-  if (args->source_output_dir_.empty()) args->source_output_dir_ = ".";
+  args->input_file_path = argv[optind];
+  if (args->header_output_dir.empty()) args->header_output_dir = ".";
+  if (args->source_output_dir.empty()) args->source_output_dir = ".";
 
   return true;
 }
@@ -90,9 +95,9 @@
     PrintUsage(argv[0]);
   }
 
-  if (!GenerateCppFiles(args.input_file_path_, args.header_output_dir_,
-                        args.source_output_dir_, &err)) {
+  if (!GenerateCppFiles(args.input_file_path, args.header_output_dir,
+                        args.source_output_dir, args.include_name, &err)) {
     LOG(FATAL) << "Error during generating cpp sysprop from "
-               << args.input_file_path_ << ": " << err;
+               << args.input_file_path << ": " << err;
   }
 }
diff --git a/tests/CppGenTest.cpp b/tests/CppGenTest.cpp
index ed88678..f9c5572 100644
--- a/tests/CppGenTest.cpp
+++ b/tests/CppGenTest.cpp
@@ -18,6 +18,7 @@
 #include <string>
 
 #include <android-base/file.h>
+#include <android-base/scopeguard.h>
 #include <android-base/test_utils.h>
 #include <gtest/gtest.h>
 
@@ -164,7 +165,7 @@
 constexpr const char* kExpectedSourceOutput =
     R"(// Generated by the sysprop generator. DO NOT EDIT!
 
-#include "PlatformProperties.h"
+#include <properties/PlatformProperties.sysprop.h>
 
 #include <cstring>
 #include <iterator>
@@ -479,23 +480,29 @@
 using namespace std::string_literals;
 
 TEST(SyspropTest, CppGenTest) {
-  TemporaryFile temp_file;
-
-  // strlen is optimized for constants, so don't worry about it.
-  ASSERT_EQ(write(temp_file.fd, kTestSyspropFile, strlen(kTestSyspropFile)),
-            strlen(kTestSyspropFile));
-  close(temp_file.fd);
-  temp_file.fd = -1;
-
   TemporaryDir temp_dir;
 
-  std::string err;
+  std::string temp_sysprop_path = temp_dir.path + "/PlatformProperties.sysprop"s;
   ASSERT_TRUE(
-      GenerateCppFiles(temp_file.path, temp_dir.path, temp_dir.path, &err));
+      android::base::WriteStringToFile(kTestSyspropFile, temp_sysprop_path));
+
+  auto sysprop_deleter = android::base::make_scope_guard(
+      [&] { unlink(temp_sysprop_path.c_str()); });
+
+  std::string err;
+  ASSERT_TRUE(GenerateCppFiles(temp_sysprop_path, temp_dir.path, temp_dir.path,
+                               "properties/PlatformProperties.sysprop.h", &err));
   ASSERT_TRUE(err.empty());
 
-  std::string header_output_path = temp_dir.path + "/PlatformProperties.h"s;
-  std::string source_output_path = temp_dir.path + "/PlatformProperties.cpp"s;
+  std::string header_output_path =
+      temp_dir.path + "/PlatformProperties.sysprop.h"s;
+  std::string source_output_path =
+      temp_dir.path + "/PlatformProperties.sysprop.cpp"s;
+
+  auto generated_file_deleter = android::base::make_scope_guard([&] {
+    unlink(header_output_path.c_str());
+    unlink(source_output_path.c_str());
+  });
 
   std::string header_output;
   ASSERT_TRUE(android::base::ReadFileToString(header_output_path,
@@ -506,7 +513,4 @@
   ASSERT_TRUE(android::base::ReadFileToString(source_output_path,
                                               &source_output, true));
   ASSERT_EQ(source_output, kExpectedSourceOutput);
-
-  unlink(header_output_path.c_str());
-  unlink(source_output_path.c_str());
 }