code: def main():
      p = argparse.ArgumentParser(usage=(__doc__ or "").strip())
  
      p.add_argument(
          "--no-force", action="store_false", dest="force", default=True
      )
      p.add_argument(
          "-o",
          "--outdir",
          type=str,
          help="Relative path to the output directory",
      )
      options = p.parse_args()
  
      names = []
  
      i_types, it_types, getter_code = get_thunk_type_set()
  
      # Generate *_impl.h for each compilation unit
      for unit_name, routines in COMPILATION_UNITS:
          thunks = []
          methods = []
  
          # Generate thunks and methods for all routines
          for line in routines.splitlines():
              line = line.strip()
              if not line or line.startswith("#"):
                  continue
  
              try:
                  name, args = line.split(None, 1)
              except ValueError as e:
                  raise ValueError(f"Malformed line: {line!r}") from e
  
              args = "".join(args.split())
              if "t" in args or "T" in args:
                  thunk, method = parse_routine(name, args, it_types)
              else:
                  thunk, method = parse_routine(name, args, i_types)
  
              if name in names:
                  raise ValueError(f"Duplicate routine {name!r}")
  
              names.append(name)
              thunks.append(thunk)
              methods.append(method)
  
          # Produce output
          if options.outdir:
              # Used by Meson (options.outdir == scipy/sparse/sparsetools)
              outdir = os.path.join(os.getcwd(), options.outdir)
  
          dst = os.path.join(outdir, unit_name + "_impl.h")
          if newer(__file__, dst) or options.force:
              if not options.outdir:
                  # Be silent if we're using Meson. TODO: add --verbose option
                  print(f"[generate_sparsetools] generating {dst!r}")
              with open(dst, "w") as f:
                  write_autogen_blurb(f)
                  f.write(getter_code)
                  for thunk in thunks:
                      f.write(thunk)
                  for method in methods:
                      f.write(method)
          else:
              if not options.outdir:
                  # Be silent if we're using Meson
                  print(
                      f"[generate_sparsetools] {dst!r} already up-to-date"
                  )
  
      # Generate code for method struct
      method_defs = ""
      for name in names:
          method_defs += (
              f"NPY_VISIBILITY_HIDDEN PyObject *{name}"
              f"_method(PyObject *, PyObject *);\n"
          )
  
      method_struct = (
          """\nstatic struct PyMethodDef sparsetools_methods[] = {"""
      )
      for name in names:
          method_struct += """
              {{"{name}", (PyCFunction){name}_method, METH_VARARGS, NULL}},""".format(
              **dict(name=name)
          )
      method_struct += """
          {NULL, NULL, 0, NULL}
      };"""
  
      # Produce sparsetools_impl.h
      dst = os.path.join(outdir, "sparsetools_impl.h")
      if newer(__file__, dst) or options.force:
          if not options.outdir:
              # Be silent if we're using Meson.
              print(f"[generate_sparsetools] generating {dst!r}")
          with open(dst, "w") as f:
              write_autogen_blurb(f)
              f.write(method_defs)
              f.write(method_struct)
      else:
          if not options.outdir:
              # Be silent if we're using Meson
              print(
                  f"[generate_sparsetools] {dst!r} already up-to-date"
              )
  
file_path: scipy/scipy/sparse/_generate_sparsetools.py
imports: import argparse
  import os
  from stat import ST_MTIME
label_desc: Use image node_id 4 for calling a global function with example usage: main() without return types