Removing usage of the abseil c++ library from IREE. (#6259)

Python abseil is still used within IREE and the tensorflow tools use
the C++ one for interop but that's fine as it's restricted to that
workspace and fetched using bazel magic.
Assuming this works the next change will remove the submodule.
diff --git a/BUILD.bazel b/BUILD.bazel
index 7e088b5..b1c56d6 100644
--- a/BUILD.bazel
+++ b/BUILD.bazel
@@ -9,8 +9,6 @@
 # matching.
 #
 #  "@absl_py//absl/"
-#  "@com_google_absl//absl/"
-#  "@com_google_absl//absl/"
 #  "@bazel_skylib//"
 #  "@com_google_benchmark//"
 #  "@cpuinfo//"
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7480687..c1db2b1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -183,7 +183,6 @@
 list(APPEND CMAKE_MODULE_PATH
   ${CMAKE_CURRENT_LIST_DIR}/build_tools/cmake/
   ${CMAKE_CURRENT_LIST_DIR}/bindings/python/build_tools/cmake/
-  ${CMAKE_CURRENT_LIST_DIR}/third_party/abseil-cpp/absl/copts/
 )
 
 #-------------------------------------------------------------------------------
diff --git a/bindings/python/iree/runtime/CMakeLists.txt b/bindings/python/iree/runtime/CMakeLists.txt
index 0185f8c..3369de0 100644
--- a/bindings/python/iree/runtime/CMakeLists.txt
+++ b/bindings/python/iree/runtime/CMakeLists.txt
@@ -27,7 +27,6 @@
     iree::modules::hal
     iree::vm
     iree::vm::bytecode_module
-    absl::optional
 )
 
 iree_py_library(
diff --git a/bindings/python/iree/runtime/binding.h b/bindings/python/iree/runtime/binding.h
index 180e90e..c015e76 100644
--- a/bindings/python/iree/runtime/binding.h
+++ b/bindings/python/iree/runtime/binding.h
@@ -7,25 +7,13 @@
 #ifndef IREE_BINDINGS_PYTHON_IREE_BINDING_H_
 #define IREE_BINDINGS_PYTHON_IREE_BINDING_H_
 
+#include <optional>
 #include <vector>
 
-#include "absl/types/optional.h"
 #include "iree/base/api.h"
 #include "pybind11/pybind11.h"
 #include "pybind11/stl.h"
 
-namespace pybind11 {
-namespace detail {
-#if !defined(ABSL_HAVE_STD_OPTIONAL)
-// Make absl::optional act like the future C++17 optional for pybind11.
-// If ABSL_HAVE_STD_OPTIONAL is defined then absl::optional == std::optional
-// and the default type caster is sufficient.
-template <typename T>
-struct type_caster<absl::optional<T>> : optional_caster<absl::optional<T>> {};
-#endif
-}  // namespace detail
-}  // namespace pybind11
-
 namespace iree {
 namespace python {
 
diff --git a/bindings/python/iree/runtime/vm.cc b/bindings/python/iree/runtime/vm.cc
index 9eb53f7..003dac6 100644
--- a/bindings/python/iree/runtime/vm.cc
+++ b/bindings/python/iree/runtime/vm.cc
@@ -6,7 +6,6 @@
 
 #include "bindings/python/iree/runtime/vm.h"
 
-#include "absl/types/optional.h"
 #include "bindings/python/iree/runtime/status_utils.h"
 #include "iree/base/api.h"
 #include "iree/base/status.h"
@@ -75,7 +74,7 @@
 //------------------------------------------------------------------------------
 
 VmContext VmContext::Create(VmInstance* instance,
-                            absl::optional<std::vector<VmModule*>> modules) {
+                            std::optional<std::vector<VmModule*>> modules) {
   iree_vm_context_t* context;
   if (!modules) {
     // Simple create with open allowed modules.
@@ -147,14 +146,14 @@
   return VmModule::CreateRetained(module);
 }
 
-absl::optional<iree_vm_function_t> VmModule::LookupFunction(
+std::optional<iree_vm_function_t> VmModule::LookupFunction(
     const std::string& name, iree_vm_function_linkage_t linkage) {
   iree_vm_function_t f;
   auto status = iree_vm_module_lookup_function_by_name(
       raw_ptr(), linkage, {name.data(), name.size()}, &f);
   if (iree_status_is_not_found(status)) {
     iree_status_ignore(status);
-    return absl::nullopt;
+    return std::nullopt;
   }
   CheckApiStatus(status, "Error looking up function");
   return f;
@@ -525,7 +524,7 @@
 
   py::class_<VmContext>(m, "VmContext")
       .def(py::init(&VmContext::Create), py::arg("instance"),
-           py::arg("modules") = absl::optional<std::vector<VmModule*>>())
+           py::arg("modules") = std::optional<std::vector<VmModule*>>())
       .def("register_modules", &VmContext::RegisterModules)
       .def_property_readonly("context_id", &VmContext::context_id)
       .def("invoke", &VmContext::Invoke);
diff --git a/bindings/python/iree/runtime/vm.h b/bindings/python/iree/runtime/vm.h
index 25bbfff..33da644 100644
--- a/bindings/python/iree/runtime/vm.h
+++ b/bindings/python/iree/runtime/vm.h
@@ -7,7 +7,8 @@
 #ifndef IREE_BINDINGS_PYTHON_IREE_RT_VM_H_
 #define IREE_BINDINGS_PYTHON_IREE_RT_VM_H_
 
-#include "absl/types/optional.h"
+#include <optional>
+
 #include "bindings/python/iree/runtime/binding.h"
 #include "bindings/python/iree/runtime/hal.h"
 #include "iree/base/api.h"
@@ -117,7 +118,7 @@
  public:
   static VmModule FromFlatbufferBlob(py::buffer flatbuffer_blob);
 
-  absl::optional<iree_vm_function_t> LookupFunction(
+  std::optional<iree_vm_function_t> LookupFunction(
       const std::string& name, iree_vm_function_linkage_t linkage);
 
   std::string name() const {
@@ -132,7 +133,7 @@
   // static, disallowing further module registration (and may be more
   // efficient).
   static VmContext Create(VmInstance* instance,
-                          absl::optional<std::vector<VmModule*>> modules);
+                          std::optional<std::vector<VmModule*>> modules);
 
   // Registers additional modules. Only valid for non static contexts (i.e.
   // those created without modules.
diff --git a/build_tools/bazel/iree.bazelrc b/build_tools/bazel/iree.bazelrc
index 6bfe8f4..226e4fd 100644
--- a/build_tools/bazel/iree.bazelrc
+++ b/build_tools/bazel/iree.bazelrc
@@ -320,10 +320,6 @@
 # Bazel gets confused and sometimes loses track of Bash.
 build:_msvc_base --action_env BAZEL_SH='bash'
 
-# Disable warnings for dependencies. We don't control these.
-# absl forces /W3 in their copts, so we exclude them to avoid D9025
-build:_msvc_base --per_file_copt=+external,-com_google_absl@/w
-
 # Find the source of truth for these in iree_copts.cmake.
 build:_msvc_base --copt=/DWIN32_LEAN_AND_MEAN
 build:_msvc_base --copt=/DNOMINMAX
diff --git a/build_tools/bazel/workspace.bzl b/build_tools/bazel/workspace.bzl
index 753d386..076c3a3 100644
--- a/build_tools/bazel/workspace.bzl
+++ b/build_tools/bazel/workspace.bzl
@@ -24,12 +24,6 @@
 
     maybe(
         native.local_repository,
-        name = "com_google_absl",
-        path = paths.join(iree_path, "third_party/abseil-cpp"),
-    )
-
-    maybe(
-        native.local_repository,
         name = "com_google_googletest",
         path = paths.join(iree_path, "third_party/googletest"),
     )
diff --git a/build_tools/bazel_to_cmake/bazel_to_cmake_targets.py b/build_tools/bazel_to_cmake/bazel_to_cmake_targets.py
index 7d04c4e..89422d7 100644
--- a/build_tools/bazel_to_cmake/bazel_to_cmake_targets.py
+++ b/build_tools/bazel_to_cmake/bazel_to_cmake_targets.py
@@ -11,9 +11,6 @@
     # Internal utilities to emulate various binary/library options.
     "//build_tools:default_linkopts": [],
 
-    # absl
-    "@com_google_absl//absl/flags:flag": ["absl::flags"],
-    "@com_google_absl//absl/flags:parse": ["absl::flags_parse"],
     # LLVM
     "@llvm-project//llvm:IPO": ["LLVMipo"],
     # MLIR
@@ -64,18 +61,6 @@
 }
 
 
-def _convert_absl_target(target):
-  # Default to a pattern substitution approach.
-  # Take "absl::" and append the name part of the full target identifier, e.g.
-  #   "@com_google_absl//absl/types:optional" -> "absl::optional"
-  #   "@com_google_absl//absl/types:span"     -> "absl::span"
-  if ":" in target:
-    target_name = target.rsplit(":")[-1]
-  else:
-    target_name = target.rsplit("/")[-1]
-  return ["absl::" + target_name]
-
-
 def _convert_mlir_target(target):
   # Default to a pattern substitution approach.
   # Take "MLIR" and append the name part of the full target identifier, e.g.
@@ -110,8 +95,6 @@
   """
   if target in EXPLICIT_TARGET_MAPPING:
     return EXPLICIT_TARGET_MAPPING[target]
-  if target.startswith("@com_google_absl//absl"):
-    return _convert_absl_target(target)
   if target.startswith("@llvm-project//llvm"):
     return _convert_llvm_target(target)
   if target.startswith("@llvm-project//mlir"):
diff --git a/build_tools/cmake/iree_copts.cmake b/build_tools/cmake/iree_copts.cmake
index 20939ff..a400a60 100644
--- a/build_tools/cmake/iree_copts.cmake
+++ b/build_tools/cmake/iree_copts.cmake
@@ -5,20 +5,6 @@
 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
 #-------------------------------------------------------------------------------
-# Abseil configuration
-#-------------------------------------------------------------------------------
-
-include(AbseilConfigureCopts)
-
-# By default Abseil strips string literals on mobile platforms, which means
-# we cannot run IREE binaries via command-line with proper options. Turn off
-# the stripping.
-# TODO(#3814): remove ABSL flags.
-if(ANDROID)
-  add_definitions(-DABSL_FLAGS_STRIP_NAMES=0)
-endif()
-
-#-------------------------------------------------------------------------------
 # C/C++ options as used within IREE
 #-------------------------------------------------------------------------------
 #
@@ -315,18 +301,7 @@
   )
 endif()
 
-# TODO(benvanik): remove the ABSL usage here; we aren't abseil.
-If(${IREE_ENABLE_THREADING})
-  iree_select_compiler_opts(_IREE_ABSL_LINKOPTS
-    ALL
-      "${ABSL_DEFAULT_LINKOPTS}"
-  )
-endif()
-
 iree_select_compiler_opts(IREE_DEFAULT_LINKOPTS
-  ALL
-    # TODO(benvanik): remove the ABSL usage here; we aren't abseil.
-    ${_IREE_ABSL_LINKOPTS}
   CLANG_OR_GCC
     # Required by all modern software, effectively:
     "-lm"
@@ -345,9 +320,6 @@
   set(IREE_TARGET_GUI_LINKOPTS "")
 endif()
 
-# TODO(benvanik): remove the ABSL usage here; we aren't abseil.
-set(IREE_TEST_COPTS "${ABSL_TEST_COPTS}")
-
 #-------------------------------------------------------------------------------
 # Size-optimized build flags
 #-------------------------------------------------------------------------------
diff --git a/build_tools/cmake/iree_python.cmake b/build_tools/cmake/iree_python.cmake
index a0c96a9..6adcb34 100644
--- a/build_tools/cmake/iree_python.cmake
+++ b/build_tools/cmake/iree_python.cmake
@@ -184,6 +184,9 @@
       "/GR"
   )
 
+  set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD 17)
+  set_property(TARGET ${_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
+
   target_compile_options(
     ${_NAME} PRIVATE
     ${ARG_COPTS}
@@ -191,7 +194,6 @@
     ${_RTTI_AND_EXCEPTION_COPTS}
   )
 
-
   # Link flags.
   if(UNIX AND NOT APPLE)  # Apple does not support linker scripts.
     if(ARG_UNIX_LINKER_SCRIPT)
diff --git a/build_tools/embed_data/BUILD b/build_tools/embed_data/BUILD
index 96d5664..e429ea1 100644
--- a/build_tools/embed_data/BUILD
+++ b/build_tools/embed_data/BUILD
@@ -18,9 +18,7 @@
     name = "generate_embed_data",
     srcs = ["generate_embed_data_main.cc"],
     deps = [
-        "@com_google_absl//absl/flags:flag",
-        "@com_google_absl//absl/flags:parse",
-        "@com_google_absl//absl/strings",
+        "//iree/base/internal:flags",
     ],
 )
 
diff --git a/build_tools/embed_data/CMakeLists.txt b/build_tools/embed_data/CMakeLists.txt
index 0e1bdc0..2a0d49e 100644
--- a/build_tools/embed_data/CMakeLists.txt
+++ b/build_tools/embed_data/CMakeLists.txt
@@ -10,9 +10,7 @@
   set_target_properties(generate_embed_data PROPERTIES OUTPUT_NAME generate_embed_data)
 
   target_link_libraries(generate_embed_data
-    absl::flags
-    absl::flags_parse
-    absl::strings
+    iree::base::internal::flags
   )
 
   install(TARGETS generate_embed_data
diff --git a/build_tools/embed_data/generate_embed_data_main.cc b/build_tools/embed_data/generate_embed_data_main.cc
index cf4807b..54ae2f1 100644
--- a/build_tools/embed_data/generate_embed_data_main.cc
+++ b/build_tools/embed_data/generate_embed_data_main.cc
@@ -4,37 +4,81 @@
 // See https://llvm.org/LICENSE.txt for license information.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
+#include <cctype>
 #include <fstream>
 #include <iomanip>
 #include <iostream>
+#include <string>
+#include <vector>
 
-#include "absl/flags/flag.h"
-#include "absl/flags/parse.h"
-#include "absl/strings/escaping.h"
-#include "absl/strings/str_split.h"
-#include "absl/strings/strip.h"
+#include "iree/base/internal/flags.h"
 
-ABSL_FLAG(std::string, identifier, "resources",
-          "name of the resources function");
-ABSL_FLAG(std::string, output_header, "", "output header file");
-ABSL_FLAG(std::string, output_impl, "", "output impl file");
-ABSL_FLAG(std::string, strip_prefix, "", "strip prefix from filenames");
-ABSL_FLAG(bool, flatten, false,
+IREE_FLAG(string, identifier, "resources", "name of the resources function");
+IREE_FLAG(string, output_header, "", "output header file");
+IREE_FLAG(string, output_impl, "", "output impl file");
+IREE_FLAG(string, strip_prefix, "", "strip prefix from filenames");
+IREE_FLAG(bool, flatten, false,
           "whether to flatten the directory structure (only include basename)");
 
-void GenerateExternCOpen(std::ofstream& f) {
+static std::string CEscape(const std::string& src) {
+  static const char kHexChar[] = "0123456789ABCDEF";
+  std::string dest;
+  bool last_hex_escape = false;  // true if last output char was \xNN.
+  for (unsigned char c : src) {
+    bool is_hex_escape = false;
+    switch (c) {
+      case '\n':
+        dest.append("\\n");
+        break;
+      case '\r':
+        dest.append("\\r");
+        break;
+      case '\t':
+        dest.append("\\t");
+        break;
+      case '\"':
+        dest.append("\\\"");
+        break;
+      case '\'':
+        dest.append("\\'");
+        break;
+      case '\\':
+        dest.append("\\\\");
+        break;
+      default:
+        // Note that if we emit \xNN and the src character after that is a hex
+        // digit then that digit must be escaped too to prevent it being
+        // interpreted as part of the character code by C.
+        if ((!isprint(c) || (last_hex_escape && isxdigit(c)))) {
+          dest.append(
+              "\\"
+              "x");
+          dest.push_back(kHexChar[c / 16]);
+          dest.push_back(kHexChar[c % 16]);
+          is_hex_escape = true;
+        } else {
+          dest.push_back(c);
+          break;
+        }
+    }
+    last_hex_escape = is_hex_escape;
+  }
+  return dest;
+}
+
+static void GenerateExternCOpen(std::ofstream& f) {
   f << "\n#if __cplusplus\n";
   f << "extern \"C\" {\n";
   f << "#endif // __cplusplus\n";
 }
 
-void GenerateExternCClose(std::ofstream& f) {
+static void GenerateExternCClose(std::ofstream& f) {
   f << "#if __cplusplus\n";
   f << "}\n";
   f << "#endif // __cplusplus\n\n";
 }
 
-void GenerateTocStruct(std::ofstream& f) {
+static void GenerateTocStruct(std::ofstream& f) {
   f << "#ifndef IREE_FILE_TOC\n";
   f << "#define IREE_FILE_TOC\n";
   GenerateExternCOpen(f);
@@ -47,17 +91,15 @@
   f << "#endif  // IREE_FILE_TOC\n";
 }
 
-bool GenerateHeader(const std::string& header_file,
-                    const std::vector<std::string>& toc_files) {
+static bool GenerateHeader(const std::string& header_file,
+                           const std::vector<std::string>& toc_files) {
   std::ofstream f(header_file, std::ios::out | std::ios::trunc);
   f << "#pragma once\n";  // Pragma once isn't great but is the best we can do.
   f << "#include <stddef.h>\n";
   GenerateTocStruct(f);
   GenerateExternCOpen(f);
-  f << "const iree_file_toc_t* " << absl::GetFlag(FLAGS_identifier)
-    << "_create();\n";
-  f << "static inline size_t " << absl::GetFlag(FLAGS_identifier)
-    << "_size() {\n";
+  f << "const iree_file_toc_t* " << FLAG_identifier << "_create();\n";
+  f << "static inline size_t " << FLAG_identifier << "_size() {\n";
   f << "  return " << toc_files.size() << ";\n";
   f << "}\n";
   GenerateExternCClose(f);
@@ -65,7 +107,7 @@
   return f.good();
 }
 
-bool SlurpFile(const std::string& file_name, std::string* contents) {
+static bool SlurpFile(const std::string& file_name, std::string* contents) {
   constexpr std::streamoff kMaxSize = 100000000;
   std::ifstream f(file_name, std::ios::in | std::ios::binary);
   // get length of file:
@@ -86,9 +128,9 @@
   return f.good();
 }
 
-bool GenerateImpl(const std::string& impl_file,
-                  const std::vector<std::string>& input_files,
-                  const std::vector<std::string>& toc_files) {
+static bool GenerateImpl(const std::string& impl_file,
+                         const std::vector<std::string>& input_files,
+                         const std::vector<std::string>& toc_files) {
   std::ofstream f(impl_file, std::ios::out | std::ios::trunc);
   f << "#include <stddef.h>\n";
   f << "#include <stdint.h>\n";
@@ -110,15 +152,18 @@
       std::cerr << "Error reading file " << input_files[i] << "\n";
       return false;
     }
-    absl::string_view remaining_contents = contents;
-    constexpr int kMaxBytesPerLine = 1024;
-    while (!remaining_contents.empty()) {
-      auto line = remaining_contents.substr(0, kMaxBytesPerLine);
-      for (char c : line) {
+    size_t remaining_offset = 0;
+    size_t remaining_length = contents.size();
+    constexpr size_t kMaxBytesPerLine = 1024;
+    while (remaining_length > 0) {
+      size_t line_length = std::min(remaining_length, kMaxBytesPerLine);
+      for (size_t j = 0; j < line_length; ++j) {
+        char c = contents[remaining_offset + j];
         f << std::to_string((uint8_t)c) << ",";
       }
       f << "\n";
-      remaining_contents = remaining_contents.substr(line.size());
+      remaining_offset += line_length;
+      remaining_length -= line_length;
     }
     f << "0,\n";  // NUL termination
     f << "};\n";
@@ -127,15 +172,14 @@
   assert(input_files.size() == toc_files.size());
   for (size_t i = 0, e = input_files.size(); i < e; ++i) {
     f << "  {\n";
-    f << "    \"" << absl::CEscape(toc_files[i]) << "\",\n";
+    f << "    \"" << CEscape(toc_files[i]) << "\",\n";
     f << "    file_" << i << ",\n";
     f << "    sizeof(file_" << i << ") - 1\n";
     f << "  },\n";
   }
   f << "  {NULL, NULL, 0},\n";
   f << "};\n";
-  f << "const struct iree_file_toc_t* " << absl::GetFlag(FLAGS_identifier)
-    << "_create() {\n";
+  f << "const struct iree_file_toc_t* " << FLAG_identifier << "_create() {\n";
   f << "  return &toc[0];\n";
   f << "}\n";
   f.close();
@@ -143,41 +187,42 @@
 }
 
 int main(int argc, char** argv) {
-  // Parse flags.
-  std::vector<char*> raw_positional_args = absl::ParseCommandLine(argc, argv);
+  // Parse flags, updating argc/argv with position arguments.
+  iree_flags_parse_checked(IREE_FLAGS_PARSE_MODE_DEFAULT, &argc, &argv);
   std::vector<std::string> input_files;
-  input_files.reserve(raw_positional_args.size() - 1);
-  // Skip program name.
-  for (size_t i = 1, e = raw_positional_args.size(); i < e; ++i) {
-    input_files.push_back(std::string(raw_positional_args[i]));
+  input_files.reserve(argc - 1);
+  for (size_t i = 1, e = argc; i < e; ++i) {  // Skip program name.
+    input_files.push_back(std::string(argv[i]));
   }
 
   // Generate TOC files by optionally removing a prefix.
   std::vector<std::string> toc_files;
   toc_files.reserve(input_files.size());
-  const std::string& strip_prefix = absl::GetFlag(FLAGS_strip_prefix);
+  const std::string& strip_prefix = FLAG_strip_prefix;
   for (const auto& input_file : input_files) {
     std::string toc_file = input_file;
     if (!strip_prefix.empty()) {
-      toc_file = std::string(absl::StripPrefix(toc_file, strip_prefix));
+      if (toc_file.find(strip_prefix) == 0) {
+        toc_file = toc_file.substr(strip_prefix.size());
+      }
     }
-    if (absl::GetFlag(FLAGS_flatten)) {
-      std::vector<std::string> comps =
-          absl::StrSplit(toc_file, absl::ByAnyChar("/\\"));
-      toc_file = comps.back();
+    if (FLAG_flatten) {
+      size_t slash_pos = toc_file.find_last_of("/\\");
+      if (slash_pos != std::string::npos) {
+        toc_file = toc_file.substr(slash_pos + 1);
+      }
     }
     toc_files.push_back(toc_file);
   }
-  if (!absl::GetFlag(FLAGS_output_header).empty()) {
-    if (!GenerateHeader(absl::GetFlag(FLAGS_output_header), toc_files)) {
+  if (strlen(FLAG_output_header) != 0) {
+    if (!GenerateHeader(FLAG_output_header, toc_files)) {
       std::cerr << "Error generating headers.\n";
       return 1;
     }
   }
 
-  if (!absl::GetFlag(FLAGS_output_impl).empty()) {
-    if (!GenerateImpl(absl::GetFlag(FLAGS_output_impl), input_files,
-                      toc_files)) {
+  if (strlen(FLAG_output_impl) != 0) {
+    if (!GenerateImpl(FLAG_output_impl, input_files, toc_files)) {
       std::cerr << "Error generating impl.\n";
       return 2;
     }