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. If TYPE is a cons (INPUT . OUTPUT), then
INPUT will be used for standard input and OUTPUT for standard output
(and standard error if :stderr is nil).
: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. When specifying this, the
subprocess's standard error will always communicate via a pipe, no
matter the value of :connection-type. 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, command, program, proc, contact, current_dir, tem;
Lisp_Object xstderr, stderrproc;
specpdl_ref count = SPECPDL_INDEX ();
if (nargs == 0)
return Qnil;
CHECK_KEYWORD_ARGS (nargs);
/* Save arguments for process-contact and clone-process. */
contact = Flist (nargs, args);
if (!NILP (plist_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 = plist_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);
Lisp_Object name = get_required_string_keyword_param (contact, QCname);
command = plist_get (contact, QCcommand);
if (CONSP (command))
program = XCAR (command);
else
program = Qnil;
if (!NILP (program))
CHECK_STRING (program);
bool query_on_exit = NILP (plist_get (contact, QCnoquery));
stderrproc = Qnil;
xstderr = plist_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), plist_get (contact, QCsentinel));
pset_filter (XPROCESS (proc), plist_get (contact, QCfilter));
pset_command (XPROCESS (proc), Fcopy_sequence (command));
if (!query_on_exit)
XPROCESS (proc)->kill_without_query = 1;
tem = plist_get (contact, QCstop);
/* Normal processes can't be started in a stopped state, see
Bug#30460. */
CHECK_TYPE (NILP (tem), Qnull, tem);
tem = plist_get (contact, QCconnection_type);
if (CONSP (tem))
{
XPROCESS (proc)->pty_in = is_pty_from_symbol (XCAR (tem));
XPROCESS (proc)->pty_out = is_pty_from_symbol (XCDR (tem));
}
else
{
XPROCESS (proc)->pty_in = XPROCESS (proc)->pty_out =
is_pty_from_symbol (tem);
}
if (!NILP (stderrproc))
pset_stderrproc (XPROCESS (proc), stderrproc);
#ifdef HAVE_GNUTLS
/* AKA GNUTLS_INITSTAGE(proc). */
static_assert (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 = plist_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, NULL);
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);
}