[v2] abicompat: Make the commands more pleasant

Message ID 20211111024245.25955-1-tangmeng@uniontech.com
State New
Headers
Series [v2] abicompat: Make the commands more pleasant |

Commit Message

tangmeng Nov. 11, 2021, 2:42 a.m. UTC
  This submission uses getopt_long to replace strcmp
to obtain the options and parameters, which will
bring the user a better experience.
For example, the command will undergo the following
changes:
# abicompat application lib1-path --lib-debug-info-dir1

  before prompt information:
    abicompat: wrong invocation
    try the --help option for more information
  now prompt information:
    abicompat: option '--lib-debug-info-dir1' requires an argument

Now it will be clearly pointed out which option is problematic.

In addition, options have been added for application,
lib1, and lib2, and some prompt messages have been added.

            * tests/test-abicompat.cc (main): Adapt to the change of command.
            * tools/abicompat.cc: Add a new enum and an option long_options.
              (parse_command_line): Use getopt_long to replace strcmp.
              (main): Cooperate with the changes of parsw_command_line.

Signed-off-by: tangmeng <tangmeng@uniontech.com>
---
 tests/test-abicompat.cc |   4 +-
 tools/abicompat.cc      | 260 ++++++++++++++++++++--------------------
 2 files changed, 135 insertions(+), 129 deletions(-)
  

Patch

diff --git a/tests/test-abicompat.cc b/tests/test-abicompat.cc
index a1339eef..33341ae1 100644
--- a/tests/test-abicompat.cc
+++ b/tests/test-abicompat.cc
@@ -242,9 +242,9 @@  main()
 	abicompat += " --suppressions " + suppression_path;
       abicompat += " " + abicompat_options;
 
-      cmd = abicompat + " " + in_app_path + " " + in_lib1_path;
+      cmd = abicompat + " --application-path " + in_app_path + " --lib-v1-path " + in_lib1_path;
       if (!in_lib2_path.empty())
-	cmd += string(" ") + in_lib2_path;
+	cmd += string(" --lib-v2-path ") + in_lib2_path;
 
       cmd += " > " + out_report_path;
 
diff --git a/tools/abicompat.cc b/tools/abicompat.cc
index addd03a9..5f62ae56 100644
--- a/tools/abicompat.cc
+++ b/tools/abicompat.cc
@@ -26,6 +26,7 @@ 
 /// library provides.
 
 #include <unistd.h>
+#include <getopt.h>
 #include <cassert>
 #include <cstdio>
 #include <cstdlib>
@@ -89,16 +90,61 @@  public:
   {}
 }; // end struct options
 
+enum
+{
+  APPLICATION_PATH_OPTION,
+  LIB_V1_PATH_OPTION,
+  LIB_V2_PATH_OPTION,
+  LIST_UNDEFINED_SYSMBOLS_OPTION,
+  SHOW_BASE_NAMES_OPTION,
+  APP_DEBUG_INFO_DIR_OPTION,
+  LIB_DEBUG_INFO_DIR1_OPTION,
+  LIB_DEBUG_INFO_DIR2_OPTION,
+  SUPPRESSIONS_OPTION,
+  NO_REDUNDANT_OPTION,
+  NO_SHOW_LOCS_OPTION,
+  REDUNDANT_OPTION,
+  WEAK_MODE_OPTION,
+  HELP_OPTION,
+  VERSION_OPTION
+};
+
+const option long_options[] =
+{
+  {"application-path", required_argument, NULL, APPLICATION_PATH_OPTION},
+  {"lib-v1-path", required_argument, NULL, LIB_V1_PATH_OPTION},
+  {"lib-v2-path", required_argument, NULL, LIB_V2_PATH_OPTION},
+  {"list-undefined-symbols", no_argument, NULL, LIST_UNDEFINED_SYSMBOLS_OPTION},
+  {"show-base-names", no_argument, NULL, SHOW_BASE_NAMES_OPTION},
+  {"app-debug-info-dir", required_argument, NULL, APP_DEBUG_INFO_DIR_OPTION},
+  {"appd", required_argument, NULL, APP_DEBUG_INFO_DIR_OPTION},
+  {"lib-debug-info-dir1", required_argument, NULL, LIB_DEBUG_INFO_DIR1_OPTION},
+  {"libd1", required_argument, NULL, LIB_DEBUG_INFO_DIR1_OPTION},
+  {"lib-debug-info-dir2", required_argument, NULL, LIB_DEBUG_INFO_DIR2_OPTION},
+  {"libd2", required_argument, NULL, LIB_DEBUG_INFO_DIR2_OPTION},
+  {"suppressions", required_argument, NULL, SUPPRESSIONS_OPTION},
+  {"suppr", required_argument, NULL, SUPPRESSIONS_OPTION},
+  {"no-redundant", no_argument, NULL, NO_REDUNDANT_OPTION},
+  {"no-show-locs", no_argument, NULL, NO_SHOW_LOCS_OPTION},
+  {"redundant", no_argument, NULL, REDUNDANT_OPTION},
+  {"weak-mode", no_argument, NULL, WEAK_MODE_OPTION},
+  {"help", no_argument, NULL, HELP_OPTION},
+  {"version", no_argument, NULL, VERSION_OPTION},
+  {NULL, 0, NULL, 0}
+};
+
 static void
 display_usage(const string& prog_name, ostream& out)
 {
   emit_prefix(prog_name, out)
     << "usage: " << prog_name
-    << " [options] [application-path] [lib-v1-path] [lib-v2-path]"
+    << " [options] --application-path [application-path] "
+    << "--lib-v1-path [lib-v1-path] --lib-v2-path [lib-v2-path]"
     << "\n"
     << " where options can be: \n"
-    << "  --help|-h  display this help message\n"
-    << "  --version|-v  show program version information and exit\n"
+    << "  --application-path  set the path to the application\n"
+    << "  --lib-v1-path  set the path to the lib-v1\n"
+    << "  --lib-v2-path  set the path to the lib-v2\n"
     << "  --list-undefined-symbols|-u  display the list of "
     "undefined symbols of the application\n"
     << "  --show-base-names|b  in the report, only show the base names "
@@ -115,122 +161,84 @@  display_usage(const string& prog_name, ostream& out)
     << "  --redundant  display redundant changes (this is the default)\n"
     << "  --weak-mode  check compatibility between the application and "
     "just one version of the library.\n"
+    << "  --help|-h  display this help message\n"
+    << "  --version|-v  show program version information and exit\n"
     ;
 }
 
 static bool
 parse_command_line(int argc, char* argv[], options& opts)
 {
-  if (argc < 2)
-    return false;
+  int c;
 
-  for (int i = 1; i < argc; ++i)
+  while ((c = getopt_long(argc, argv, "vhub", long_options, NULL)) != -1)
     {
-      if (argv[i][0] != '-')
-	{
-	  if (opts.app_path.empty())
-	    opts.app_path = argv[i];
-	  else if (opts.lib1_path.empty())
-	    opts.lib1_path = argv[i];
-	  else if (opts.lib2_path.empty())
-	    opts.lib2_path = argv[i];
-	  else
-	    return false;
-	}
-      else if (!strcmp(argv[i], "--version")
-	       || !strcmp(argv[i], "-v"))
-	{
-	  opts.display_version = true;
-	  return true;
-	}
-      else if (!strcmp(argv[i], "--list-undefined-symbols")
-	       || !strcmp(argv[i], "-u"))
-	opts.list_undefined_symbols_only = true;
-      else if (!strcmp(argv[i], "--show-base-names")
-	       || !strcmp(argv[i], "-b"))
-	opts.show_base_names = true;
-      else if (!strcmp(argv[i], "--app-debug-info-dir")
-	       || !strcmp(argv[i], "--appd"))
-	{
-	  if (argc <= i + 1
-	      || argv[i + 1][0] == '-')
-	    return false;
-	  // elfutils wants the root path to the debug info to be
-	  // absolute.
-	  opts.app_di_root_path =
-	    abigail::tools_utils::make_path_absolute(argv[i + 1]);
-	  ++i;
-	}
-      else if (!strcmp(argv[i], "--lib-debug-info-dir1")
-	       || !strcmp(argv[i], "--libd1"))
-	{
-	  if (argc <= i + 1
-	      || argv[i + 1][0] == '-')
-	    return false;
-	  // elfutils wants the root path to the debug info to be
-	  // absolute.
-	  opts.lib1_di_root_path =
-	    abigail::tools_utils::make_path_absolute(argv[i + 1]);
-	  ++i;
-	}
-      else if (!strcmp(argv[i], "--lib-debug-info-dir2")
-	       || !strcmp(argv[i], "--libd2"))
-	{
-	  if (argc <= i + 1
-	      || argv[i + 1][0] == '-')
-	    return false;
-	  // elfutils wants the root path to the debug info to be
-	  // absolute.
-	  opts.lib2_di_root_path =
-	    abigail::tools_utils::make_path_absolute(argv[i + 1]);
-	  ++i;
-	}
-      else if (!strcmp(argv[i], "--suppressions")
-	       || !strcmp(argv[i], "--suppr"))
-	{
-	  int j = i + 1;
-	  if (j >= argc)
-	    return false;
-	  opts.suppression_paths.push_back(argv[j]);
-	  ++i;
-	}
-      else if (!strcmp(argv[i], "--redundant"))
+      switch(c)
         {
-	  opts.show_redundant = true;
-	  opts.redundant_opt_set = true;
-	}
-      else if (!strcmp(argv[i], "--no-redundant"))
-        {
-  	  opts.show_redundant = false;
-	  opts.no_redundant_opt_set = true;
-	}
-      else if (!strcmp(argv[i], "--no-show-locs"))
-	opts.show_locs = false;
-      else if (!strcmp(argv[i], "--help")
-	       || !strcmp(argv[i], "-h"))
-	{
-	  opts.display_help = true;
-	  return true;
-	}
-      else if (!strcmp(argv[i], "--weak-mode"))
-	opts.weak_mode = true;
-      else
-	{
-	  opts.unknow_option = argv[i];
-	  return false;
-	}
-    }
-
-  if (!opts.list_undefined_symbols_only)
-    {
-      if (opts.app_path.empty()
-	  || opts.lib1_path.empty())
-	return false;
-      if (!opts.weak_mode && opts.lib2_path.empty())
-	opts.weak_mode = true;
-    }
-
-  return true;
+        case 'v':
+        case VERSION_OPTION:
+          opts.display_version = true;
+          break;
+        case 'h':
+        case HELP_OPTION:
+          opts.display_help = true;
+          break;
+        case APPLICATION_PATH_OPTION:
+          opts.app_path = optarg;
+          break;
+        case LIB_V1_PATH_OPTION:
+          opts.lib1_path = optarg;
+          break;
+        case LIB_V2_PATH_OPTION:
+          opts.lib2_path = optarg;
+          break;
+        case 'u':
+        case LIST_UNDEFINED_SYSMBOLS_OPTION:
+          opts.list_undefined_symbols_only = true;
+          break;
+        case 'b':
+        case SHOW_BASE_NAMES_OPTION:
+          opts.show_base_names = true;
+          break;
+        case APP_DEBUG_INFO_DIR_OPTION:
+          opts.app_di_root_path =
+            abigail::tools_utils::make_path_absolute(optarg);
+          break;
+        case LIB_DEBUG_INFO_DIR1_OPTION:
+          // elfutils wants the root path to the debug info to be
+          // absolute.
+          opts.lib1_di_root_path =
+            abigail::tools_utils::make_path_absolute(optarg);
+          break;
+        case LIB_DEBUG_INFO_DIR2_OPTION:
+          // elfutils wants the root path to the debug info to be
+          // absolute.
+          opts.lib2_di_root_path =
+            abigail::tools_utils::make_path_absolute(optarg);
+          break;
+        case SUPPRESSIONS_OPTION:
+          opts.suppression_paths.push_back(optarg);
+          break;
+        case NO_REDUNDANT_OPTION:
+          opts.show_redundant = false;
+          opts.no_redundant_opt_set = true;
+          break;
+        case NO_SHOW_LOCS_OPTION:
+          opts.show_locs = false;
+          break;
+        case REDUNDANT_OPTION:
+          opts.show_redundant = true;
+          opts.redundant_opt_set = true;
+          break;
+        case WEAK_MODE_OPTION:
+          opts.weak_mode = true;
+          break;
+        default:
+          display_usage(argv[0], cout);
+          return 1;
+        }
+  }
+  return 0;
 }
 
 using abigail::tools_utils::check_file;
@@ -615,23 +623,8 @@  main(int argc, char* argv[])
 {
   options opts(argv[0]);
 
-  if (!parse_command_line(argc, argv, opts))
-    {
-      if (!opts.unknow_option.empty())
-	{
-	  emit_prefix(argv[0], cerr)
-	    << "unrecognized option: " << opts.unknow_option << "\n"
-	    << "try the --help option for more information\n";
-	  return (abigail::tools_utils::ABIDIFF_USAGE_ERROR
-		  | abigail::tools_utils::ABIDIFF_ERROR);
-	}
-
-      emit_prefix(argv[0], cerr)
-	<< "wrong invocation\n"
-	<< "try the --help option for more information\n";
-      return (abigail::tools_utils::ABIDIFF_USAGE_ERROR
-	      | abigail::tools_utils::ABIDIFF_ERROR);
-    }
+  if (parse_command_line(argc, argv, opts) != 0)
+    return 1;
 
   if (opts.display_help)
     {
@@ -648,6 +641,19 @@  main(int argc, char* argv[])
       return 0;
     }
 
+  if (!opts.list_undefined_symbols_only)
+    {
+      if (opts.app_path.empty()
+        || opts.lib1_path.empty())
+        {
+          emit_prefix(argv[0], cerr)
+	    << "The application path and lib-v1 path options must be set!\n";
+           return false;
+	}
+      if (!opts.weak_mode && opts.lib2_path.empty())
+       opts.weak_mode = true;
+    }
+
   if (opts.weak_mode && !opts.lib2_path.empty())
     {
       emit_prefix(argv[0], cout)