Function: make-process

make-process is a byte-compiled function defined in process.c.

Signature

(make-process &rest ARGS)

Documentation

Start a program in a subprocess. Return the process object for it.

This is similar to start-process, but arguments are specified as keyword/argument pairs. The following arguments are defined:

:name NAME -- NAME is name for process. It is modified if necessary
to make it unique.

:buffer BUFFER -- BUFFER is the buffer (or buffer-name) to associate
with the process. Process output goes at end of that buffer, unless you specify a filter function to handle the output. BUFFER may be also nil, meaning that this process is not associated with any buffer.

:command COMMAND -- COMMAND is a list starting with the program file
name, followed by strings to give to the program as arguments. If the program file name is not an absolute file name, make-process will look for the program file name in exec-path(var)/exec-path(fun) (which is a list of directories).

:coding CODING -- If CODING is a symbol, it specifies the coding
system used for both reading and writing for this process. If CODING is a cons (DECODING . ENCODING), DECODING is used for reading, and ENCODING is used for writing.

:noquery BOOL -- When exiting Emacs, query the user if BOOL is nil and
the process is running. If BOOL is not given, query before exiting.

:stop BOOL -- BOOL must be nil. The :stop key is ignored otherwise
and is retained for compatibility with other process types such as pipe processes. Asynchronous subprocesses never start in the stopped state. Use stop-process and continue-process to send signals to stop and continue a process.

:connection-type TYPE -- TYPE is control type of device used to
communicate with subprocesses. Values are pipe to use a pipe, pty to use a pty, or nil to use the default specified through process-connection-type.

:filter FILTER -- Install FILTER as the process filter.

:sentinel SENTINEL -- Install SENTINEL as the process sentinel.

:stderr STDERR -- STDERR is either a buffer or a pipe process attached
to the standard error of subprocess. Specifying this implies
:connection-type is set to pipe. If STDERR is nil, standard error
is mixed with standard output and sent to BUFFER or FILTER. (Note that specifying :stderr will create a new, separate (but associated) process, with its own filter and sentinel. See Info node (elisp) Asynchronous Processes for more details.)

:file-handler FILE-HANDLER -- If FILE-HANDLER is non-nil, then look
for a file name handler for the current buffer's default-directory and invoke that file name handler to make the process. If there is no such handler, proceed as if FILE-HANDLER were nil.

This function has :around advice: make-process@with-editor-process-filter.

Other relevant functions are documented in the process group.

Probably introduced at or before Emacs version 25.1.

Shortdoc

;; process
(make-process :name "foo" :command '("cat" "/tmp/foo"))
    e.g. => #<process foo>

Source Code

// Defined in /usr/src/emacs/src/process.c
// Skipping highlighting due to helpful-max-highlight.
{
  Lisp_Object buffer, name, command, program, proc, contact, current_dir, tem;
  Lisp_Object xstderr, stderrproc;
  ptrdiff_t count = SPECPDL_INDEX ();

  if (nargs == 0)
    return Qnil;

  /* Save arguments for process-contact and clone-process.  */
  contact = Flist (nargs, args);

  if (!NILP (Fplist_get (contact, QCfile_handler)))
    {
      Lisp_Object file_handler
        = Ffind_file_name_handler (BVAR (current_buffer, directory),
                                   Qmake_process);
      if (!NILP (file_handler))
        return CALLN (Fapply, file_handler, Qmake_process, contact);
    }

  buffer = Fplist_get (contact, QCbuffer);
  if (!NILP (buffer))
    buffer = Fget_buffer_create (buffer, Qnil);

  /* Make sure that the child will be able to chdir to the current
     buffer's current directory, or its unhandled equivalent.  We
     can't just have the child check for an error when it does the
     chdir, since it's in a vfork.  */
  current_dir = get_current_directory (true);

  name = Fplist_get (contact, QCname);
  CHECK_STRING (name);

  command = Fplist_get (contact, QCcommand);
  if (CONSP (command))
    program = XCAR (command);
  else
    program = Qnil;

  if (!NILP (program))
    CHECK_STRING (program);

  bool query_on_exit = NILP (Fplist_get (contact, QCnoquery));

  stderrproc = Qnil;
  xstderr = Fplist_get (contact, QCstderr);
  if (PROCESSP (xstderr))
    {
      if (!PIPECONN_P (xstderr))
	error ("Process is not a pipe process");
      stderrproc = xstderr;
    }
  else if (!NILP (xstderr))
    {
      CHECK_STRING (program);
      stderrproc = CALLN (Fmake_pipe_process,
			  QCname,
			  concat2 (name, build_string (" stderr")),
			  QCbuffer,
			  Fget_buffer_create (xstderr, Qnil),
			  QCnoquery,
			  query_on_exit ? Qnil : Qt);
    }

  proc = make_process (name);
  record_unwind_protect (start_process_unwind, proc);

  pset_childp (XPROCESS (proc), Qt);
  eassert (NILP (XPROCESS (proc)->plist));
  pset_type (XPROCESS (proc), Qreal);
  pset_buffer (XPROCESS (proc), buffer);
  pset_sentinel (XPROCESS (proc), Fplist_get (contact, QCsentinel));
  pset_filter (XPROCESS (proc), Fplist_get (contact, QCfilter));
  pset_command (XPROCESS (proc), Fcopy_sequence (command));

  if (!query_on_exit)
    XPROCESS (proc)->kill_without_query = 1;
  tem = Fplist_get (contact, QCstop);
  /* Normal processes can't be started in a stopped state, see
     Bug#30460.  */
  CHECK_TYPE (NILP (tem), Qnull, tem);

  tem = Fplist_get (contact, QCconnection_type);
  if (EQ (tem, Qpty))
    XPROCESS (proc)->pty_flag = true;
  else if (EQ (tem, Qpipe))
    XPROCESS (proc)->pty_flag = false;
  else if (NILP (tem))
    XPROCESS (proc)->pty_flag = !NILP (Vprocess_connection_type);
  else
    report_file_error ("Unknown connection type", tem);

  if (!NILP (stderrproc))
    {
      pset_stderrproc (XPROCESS (proc), stderrproc);

      XPROCESS (proc)->pty_flag = false;
    }

#ifdef HAVE_GNUTLS
  /* AKA GNUTLS_INITSTAGE(proc).  */
  verify (GNUTLS_STAGE_EMPTY == 0);
  eassert (XPROCESS (proc)->gnutls_initstage == GNUTLS_STAGE_EMPTY);
  eassert (NILP (XPROCESS (proc)->gnutls_cred_type));
#endif

  XPROCESS (proc)->adaptive_read_buffering
    = (NILP (Vprocess_adaptive_read_buffering) ? 0
       : EQ (Vprocess_adaptive_read_buffering, Qt) ? 1 : 2);

  /* Make the process marker point into the process buffer (if any).  */
  update_process_mark (XPROCESS (proc));

  USE_SAFE_ALLOCA;

  {
    /* Decide coding systems for communicating with the process.  Here
       we don't setup the structure coding_system nor pay attention to
       unibyte mode.  They are done in create_process.  */

    /* Qt denotes we have not yet called Ffind_operation_coding_system.  */
    Lisp_Object coding_systems = Qt;
    Lisp_Object val, *args2;

    tem = Fplist_get (contact, QCcoding);
    if (!NILP (tem))
      {
	val = tem;
	if (CONSP (val))
	  val = XCAR (val);
      }
    else
      val = Vcoding_system_for_read;
    if (NILP (val))
      {
	ptrdiff_t nargs2 = 3 + list_length (command);
	Lisp_Object tem2;
	SAFE_ALLOCA_LISP (args2, nargs2);
	ptrdiff_t i = 0;
	args2[i++] = Qstart_process;
	args2[i++] = name;
	args2[i++] = buffer;
	for (tem2 = command; CONSP (tem2); tem2 = XCDR (tem2))
	  args2[i++] = XCAR (tem2);
	if (!NILP (program))
	  coding_systems = Ffind_operation_coding_system (nargs2, args2);
	if (CONSP (coding_systems))
	  val = XCAR (coding_systems);
	else if (CONSP (Vdefault_process_coding_system))
	  val = XCAR (Vdefault_process_coding_system);
      }
    pset_decode_coding_system (XPROCESS (proc), val);

    if (!NILP (tem))
      {
	val = tem;
	if (CONSP (val))
	  val = XCDR (val);
      }
    else
      val = Vcoding_system_for_write;
    if (NILP (val))
      {
	if (EQ (coding_systems, Qt))
	  {
	    ptrdiff_t nargs2 = 3 + list_length (command);
	    Lisp_Object tem2;
	    SAFE_ALLOCA_LISP (args2, nargs2);
	    ptrdiff_t i = 0;
	    args2[i++] = Qstart_process;
	    args2[i++] = name;
	    args2[i++] = buffer;
	    for (tem2 = command; CONSP (tem2); tem2 = XCDR (tem2))
	      args2[i++] = XCAR (tem2);
	    if (!NILP (program))
	      coding_systems = Ffind_operation_coding_system (nargs2, args2);
	  }
	if (CONSP (coding_systems))
	  val = XCDR (coding_systems);
	else if (CONSP (Vdefault_process_coding_system))
	  val = XCDR (Vdefault_process_coding_system);
      }
    pset_encode_coding_system (XPROCESS (proc), val);
    /* Note: At this moment, the above coding system may leave
       text-conversion or eol-conversion unspecified.  They will be
       decided after we read output from the process and decode it by
       some coding system, or just before we actually send a text to
       the process.  */
  }


  pset_decoding_buf (XPROCESS (proc), empty_unibyte_string);
  eassert (XPROCESS (proc)->decoding_carryover == 0);
  pset_encoding_buf (XPROCESS (proc), empty_unibyte_string);

  XPROCESS (proc)->inherit_coding_system_flag
    = !(NILP (buffer) || !inherit_process_coding_system);

  if (!NILP (program))
    {
      Lisp_Object program_args = XCDR (command);

      /* If program file name is not absolute, search our path for it.
	 Put the name we will really use in TEM.  */
      if (!IS_DIRECTORY_SEP (SREF (program, 0))
	  && !(SCHARS (program) > 1
	       && IS_DEVICE_SEP (SREF (program, 1))))
	{
	  tem = Qnil;
	  openp (Vexec_path, program, Vexec_suffixes, &tem,
		 make_fixnum (X_OK), false, false);
	  if (NILP (tem))
	    report_file_error ("Searching for program", program);
	  tem = Fexpand_file_name (tem, Qnil);
	}
      else
	{
	  if (!NILP (Ffile_directory_p (program)))
	    error ("Specified program for new process is a directory");
	  tem = program;
	}

      /* Remove "/:" from TEM.  */
      tem = remove_slash_colon (tem);

      Lisp_Object arg_encoding = Qnil;

      /* Encode the file name and put it in NEW_ARGV.
	 That's where the child will use it to execute the program.  */
      tem = list1 (ENCODE_FILE (tem));
      ptrdiff_t new_argc = 1;

      /* Here we encode arguments by the coding system used for sending
	 data to the process.  We don't support using different coding
	 systems for encoding arguments and for encoding data sent to the
	 process.  */

      for (Lisp_Object tem2 = program_args; CONSP (tem2); tem2 = XCDR (tem2))
	{
	  Lisp_Object arg = XCAR (tem2);
	  CHECK_STRING (arg);
	  if (STRING_MULTIBYTE (arg))
	    {
	      if (NILP (arg_encoding))
		arg_encoding = (complement_process_encoding_system
				(XPROCESS (proc)->encode_coding_system));
	      arg = code_convert_string_norecord (arg, arg_encoding, 1);
	    }
	  tem = Fcons (arg, tem);
	  new_argc++;
	}

      /* Now that everything is encoded we can collect the strings into
	 NEW_ARGV.  */
      char **new_argv;
      SAFE_NALLOCA (new_argv, 1, new_argc + 1);
      new_argv[new_argc] = 0;

      for (ptrdiff_t i = new_argc - 1; i >= 0; i--)
	{
	  new_argv[i] = SSDATA (XCAR (tem));
	  tem = XCDR (tem);
	}

      create_process (proc, new_argv, current_dir);
    }
  else
    create_pty (proc);

  return SAFE_FREE_UNBIND_TO (count, proc);
}