def _generate_doxygen(doxygen_input):
    '''
    This method executes doxygen based off of the specified input.  By the time this
    method is executed, it is assumed that Doxygen is intended to be run in the
    **current working directory**.  Search for ``returnPath`` in the implementation of
    :func:`~exhale.configs.apply_sphinx_configurations` for handling of this aspect.

    This method is intended to be called by :func:`~exhale.deploy.generateDoxygenXML`,
    which is in turn called by :func:`~exhale.configs.apply_sphinx_configurations`.

    Two versions of the
    doxygen command can be executed:

    1. If ``doxygen_input`` is exactly ``"Doxyfile"``, then it is assumed that a
       ``Doxyfile`` exists in the **current working directory**.  Meaning the command
       being executed is simply ``doxygen``.
    2. For all other values, ``doxygen_input`` represents the arguments as to be
       specified on ``stdin`` to the process.

    **Parameters**
        ``doxygen_input`` (str)
            Either the string ``"Doxyfile"`` to run vanilla ``doxygen``, or the
            selection of doxygen inputs (that would ordinarily be in a ``Doxyfile``)
            that will be ``communicate``d to the ``doxygen`` process on ``stdin``.

            .. note::

               If using Python **3**, the input **must** still be a ``str``.  This
               method will convert the input to ``bytes`` as follows:

               .. code-block:: py

                  if sys.version[0] == "3":
                      doxygen_input = bytes(doxygen_input, "utf-8")

    **Return**
        ``str`` or ``None``
            If an error occurs, a string describing the error is returned with the
            intention of the caller raising the exception.  If ``None`` is returned,
            then the process executed without error.  Example usage:

            .. code-block:: py

               status = _generate_doxygen("Doxygen")
               if status:
                   raise RuntimeError(status)

            Though a little awkward, this is done to enable the intended caller of this
            method to restore some state before exiting the program (namely, the working
            directory before propagating an exception to ``sphinx-build``).
    '''
    if not isinstance(doxygen_input, six.string_types):
        return "Error: the `doxygen_input` variable must be of type `str`."

    doxyfile = doxygen_input == "Doxyfile"
    try:
        # Setup the arguments to launch doxygen
        if doxyfile:
            args   = ["doxygen"]
            kwargs = {}
        else:
            args   = ["doxygen", "-"]
            kwargs = {"stdin": PIPE}

        if configs._on_rtd:
            # On RTD, any capturing of Doxygen output can cause buffer overflows for
            # even medium sized projects.  So it is disregarded entirely to ensure the
            # build will complete (otherwise, it silently fails after `cat conf.py`)
            devnull_file     = open(os.devnull, "w")
            kwargs["stdout"] = devnull_file
            kwargs["stderr"] = STDOUT
        else:
            # TL;DR: strictly enforce that (verbose) doxygen output doesn't cause the
            # `communicate` to hang due to buffer overflows.
            #
            # See excellent synopsis:
            # https://thraxil.org/users/anders/posts/2008/03/13/Subprocess-Hanging-PIPE-is-your-enemy/
            if six.PY2:
                tempfile_kwargs = {}
            else:
                # encoding argument introduced in python 3
                tempfile_kwargs = {"encoding": "utf-8"}
            tempfile_kwargs["mode"] = "r+"
            tmp_out_file = tempfile.TemporaryFile(
                prefix="doxygen_stdout_buff", **tempfile_kwargs
            )
            tmp_err_file = tempfile.TemporaryFile(
                prefix="doxygen_stderr_buff", **tempfile_kwargs
            )

            # Write to the tempfiles over PIPE to avoid buffer overflowing
            kwargs["stdout"] = tmp_out_file
            kwargs["stderr"] = tmp_err_file

        # Note: overload of args / kwargs, Popen is expecting a list as the first
        #       parameter (aka no *args, just args)!
        doxygen_proc = Popen(args, **kwargs)

        # Communicate can only be called once, arrange whether or not stdin has value
        if not doxyfile:
            # In Py3, make sure we are communicating a bytes-like object which is no
            # longer interchangeable with strings (as was the case in Py2).
            if sys.version[0] == "3":
                doxygen_input = bytes(doxygen_input, "utf-8")
            comm_kwargs = {"input": doxygen_input}
        else:
            comm_kwargs = {}

        # Waits until doxygen has completed
        doxygen_proc.communicate(**comm_kwargs)

        # Print out what was written to the tmpfiles by doxygen
        if not configs._on_rtd and not configs.exhaleSilentDoxygen:
            # Doxygen output (some useful information, mostly just enumeration of the
            # configurations you gave it {useful for debugging...})
            if tmp_out_file.tell() > 0:
                tmp_out_file.seek(0)
                print(tmp_out_file.read())
            # Doxygen error (e.g. any warnings, or invalid input)
            if tmp_err_file.tell() > 0:
                # Making them stick out, ideally users would reduce this output to 0 ;)
                # This will print a yellow [~] before every line, but not make the
                # entire line yellow because it's definitively not helpful
                prefix = utils._use_color(
                    utils.prefix("[~]", " "), utils.AnsiColors.BOLD_YELLOW, sys.stderr
                )
                tmp_err_file.seek(0)
                sys.stderr.write(utils.prefix(prefix, tmp_err_file.read()))

        # Close the file handles opened for communication with subprocess
        if configs._on_rtd:
            devnull_file.close()
        else:
            # Delete the tmpfiles
            tmp_out_file.close()
            tmp_err_file.close()

        # Make sure we had a valid execution of doxygen
        exit_code = doxygen_proc.returncode
        if exit_code != 0:
            raise RuntimeError("Non-zero return code of [{0}] from 'doxygen'...".format(exit_code))
    except Exception as e:
        return "Unable to execute 'doxygen': {0}".format(e)

    # returning None signals _success_
    return None