GNU bug report logs -
#79760
Missing ‘lexical-binding’ cookie warning for scripts
Previous Next
To reply to this bug, email your comments to 79760 AT debbugs.gnu.org.
Toggle the display of automated, internal messages from the tracker.
Report forwarded
to
bug-gnu-emacs <at> gnu.org:
bug#79760; Package
emacs.
(Mon, 03 Nov 2025 19:53:02 GMT)
Full text and
rfc822 format available.
Acknowledgement sent
to
Jonas Bernoulli <jonas <at> bernoul.li>:
New bug report received and forwarded. Copy sent to
bug-gnu-emacs <at> gnu.org.
(Mon, 03 Nov 2025 19:53:02 GMT)
Full text and
rfc822 format available.
Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):
Hello,
I get
Missing ‘lexical-binding’ cookie in "da-script"
warnings for scripts that have to place the cookie on the second line
because they look like this:
#!/bin/sh
":"; exec emacs -Q --script "$0" -- "$@" # -*- mode: emacs-lisp; lexical-binding: t; -*-
(... lisp goes here ...)
But when I visit such files, the local value of`lexical-binding' is t
as expected.
Cheers,
Jonas
Information forwarded
to
bug-gnu-emacs <at> gnu.org:
bug#79760; Package
emacs.
(Mon, 03 Nov 2025 20:27:01 GMT)
Full text and
rfc822 format available.
Message #8 received at 79760 <at> debbugs.gnu.org (full text, mbox):
> Date: Mon, 03 Nov 2025 20:52:20 +0100
> From: Jonas Bernoulli via "Bug reports for GNU Emacs,
> the Swiss army knife of text editors" <bug-gnu-emacs <at> gnu.org>
>
> Hello,
>
> I get
>
> Missing ‘lexical-binding’ cookie in "da-script"
>
> warnings for scripts that have to place the cookie on the second line
> because they look like this:
>
> #!/bin/sh
> ":"; exec emacs -Q --script "$0" -- "$@" # -*- mode: emacs-lisp; lexical-binding: t; -*-
> (... lisp goes here ...)
>
> But when I visit such files, the local value of`lexical-binding' is t
> as expected.
You expect the part after the # to be somehow passed to the Emacs that
is executed by "exec emacs"? That's a comment, as far as the shell is
concerned, isn't it? The Lisp code passed to Emacs is what starts
with (... lisp goes here ...), right? Or am I missing something?
Information forwarded
to
bug-gnu-emacs <at> gnu.org:
bug#79760; Package
emacs.
(Mon, 03 Nov 2025 21:43:02 GMT)
Full text and
rfc822 format available.
Message #11 received at 79760 <at> debbugs.gnu.org (full text, mbox):
"Eli Zaretskii" <eliz <at> gnu.org> writes:
>> Date: Mon, 03 Nov 2025 20:52:20 +0100
>> From: Jonas Bernoulli via "Bug reports for GNU Emacs,
>> the Swiss army knife of text editors" <bug-gnu-emacs <at> gnu.org>
>>
>> Hello,
>>
>> I get
>>
>> Missing ‘lexical-binding’ cookie in "da-script"
>>
>> warnings for scripts that have to place the cookie on the second line
>> because they look like this:
>>
>> #!/bin/sh
>> ":"; exec emacs -Q --script "$0" -- "$@" # -*- mode: emacs-lisp; lexical-binding: t; -*-
>> (... lisp goes here ...)
Can you try putting "(message "%S" lexical-binding)" there? Unless I
made a mistake copying this, the lexical-binding cookie doesn't actually
work.
>> But when I visit such files, the local value of`lexical-binding' is t
>> as expected.
So this is the unexpected part, right?
> You expect the part after the # to be somehow passed to the Emacs that
> is executed by "exec emacs"? That's a comment, as far as the shell is
> concerned, isn't it?
> The Lisp code passed to Emacs is what starts with (... lisp goes here
> ...), right? Or am I missing something?
No, the entire file is passed (by name) to Emacs, including the shebang
itself. Emacs discards it in lread.c, and the second line is valid Lisp.
I don't know whether this helps, but
#!/usr/bin/env -S emacs -x
;; -*- lexical-binding: t -*-
(message "%S" lexical-binding)
appears to work on a GNU/Linux system, where the GNU coreutils env is
installed in this standard location, but only with new emacs versions.
Maybe /bin/env should be used instead. Note that this useful feature
also allows you to pass extra command line parameters to emacs.
The problem is this code in lread.c:
if (ch != ';')
/* The first line isn't a comment, just give up. */
{
unreadchar (&source, ch);
return Cookie_None;
}
AFAIK, no valid shell script starts with a semicolon, so there's no way
to make this work with #!/bin/sh. Using zsh instead works.
Pip
Information forwarded
to
bug-gnu-emacs <at> gnu.org:
bug#79760; Package
emacs.
(Tue, 04 Nov 2025 19:41:01 GMT)
Full text and
rfc822 format available.
Message #14 received at 79760 <at> debbugs.gnu.org (full text, mbox):
Pip Cet <pipcet <at> protonmail.com> writes:
> "Eli Zaretskii" <eliz <at> gnu.org> writes:
>
>>> Date: Mon, 03 Nov 2025 20:52:20 +0100
>>> From: Jonas Bernoulli via "Bug reports for GNU Emacs,
>>> the Swiss army knife of text editors" <bug-gnu-emacs <at> gnu.org>
>>>
>>> Hello,
>>>
>>> I get
>>>
>>> Missing ‘lexical-binding’ cookie in "da-script"
>>>
>>> warnings for scripts that have to place the cookie on the second line
>>> because they look like this:
>>>
>>> #!/bin/sh
>>> ":"; exec emacs -Q --script "$0" -- "$@" # -*- mode: emacs-lisp; lexical-binding: t; -*-
>>> (... lisp goes here ...)
>
> Can you try putting "(message "%S" lexical-binding)" there? Unless I
> made a mistake copying this, the lexical-binding cookie doesn't actually
> work.
Yes you are absolutely right.
(Sorry, could not resist. I am in fact a human.)
>>> But when I visit such files, the local value of`lexical-binding' is t
>>> as expected.
>
> So this is the unexpected part, right?
In a way, yes. What I would like to do is to set the value and then
have that choice respected when the file is executed as a script and
also when it is visited in a buffer. When doing what I have done
above, it is not respected in the first case but not in the second.
That's worse than if this setting were just never respected.
>> You expect the part after the # to be somehow passed to the Emacs that
>> is executed by "exec emacs"? That's a comment, as far as the shell is
>> concerned, isn't it?
>
>> The Lisp code passed to Emacs is what starts with (... lisp goes here
>> ...), right? Or am I missing something?
>
> No, the entire file is passed (by name) to Emacs, including the shebang
> itself. Emacs discards it in lread.c, and the second line is valid Lisp.
>
> I don't know whether this helps, but
>
> #!/usr/bin/env -S emacs -x
> ;; -*- lexical-binding: t -*-
> (message "%S" lexical-binding)
I completely forgot about that (emacs -x). For the record, that was
added in Emacs 29.1. I going to use this instead of the hack above.
> appears to work on a GNU/Linux system, where the GNU coreutils env is
> installed in this standard location, but only with new emacs versions.
Setting lexical-binding does not seem to work on GNU GUIX using Emacs
31.0.50. On this distribution "/usr/bin/env" is a symlink to something
like "/gnu/store/f2rcir6yz0n74jaa6d0fm82f8flmwjnk-coreutils-9.1/bin/env".
Even if I use that explicitly, lexical-binding is still nil.
> Maybe /bin/env should be used instead. Note that this useful feature
> also allows you to pass extra command line parameters to emacs.
>
> The problem is this code in lread.c:
>
> if (ch != ';')
> /* The first line isn't a comment, just give up. */
> {
> unreadchar (&source, ch);
> return Cookie_None;
> }
>
> AFAIK, no valid shell script starts with a semicolon, so there's no way
> to make this work with #!/bin/sh. Using zsh instead works.
Seems to me this should be changed to also look at the second line
(at least when using "emacs -x").
By the way --and that's just something I though of right now-- maybe
this is an opportunity to *always* look at the second line as well.
That way, one could replace
;;; this-library-has-a-long-name.el --- And it also needs a long description -*- mode: lexical-binding: t;
with
;;; this-library-has-a-long-name.el --- And it also needs a long description
;; -*- lexical-binding: t;
(Of course we would not be able to actually use this for a few years,
except in new libraries that need at least Emacs 31 for other reasons
anyway.)
>
> Pip
Thanks!
Jonas
Information forwarded
to
bug-gnu-emacs <at> gnu.org:
bug#79760; Package
emacs.
(Wed, 05 Nov 2025 11:30:03 GMT)
Full text and
rfc822 format available.
Message #17 received at 79760 <at> debbugs.gnu.org (full text, mbox):
"Jonas Bernoulli" <jonas <at> bernoul.li> writes:
> Pip Cet <pipcet <at> protonmail.com> writes:
>
>> "Eli Zaretskii" <eliz <at> gnu.org> writes:
>>
>>>> Date: Mon, 03 Nov 2025 20:52:20 +0100
>>>> From: Jonas Bernoulli via "Bug reports for GNU Emacs,
>>>> the Swiss army knife of text editors" <bug-gnu-emacs <at> gnu.org>
>>>>
>>>> Hello,
>>>>
>>>> I get
>>>>
>>>> Missing ‘lexical-binding’ cookie in "da-script"
>>>>
>>>> warnings for scripts that have to place the cookie on the second line
>>>> because they look like this:
>>>>
>>>> #!/bin/sh
>>>> ":"; exec emacs -Q --script "$0" -- "$@" # -*- mode: emacs-lisp; lexical-binding: t; -*-
>>>> (... lisp goes here ...)
>>
>> Can you try putting "(message "%S" lexical-binding)" there? Unless I
>> made a mistake copying this, the lexical-binding cookie doesn't actually
>> work.
>
> Yes you are absolutely right.
> (Sorry, could not resist. I am in fact a human.)
>
>>>> But when I visit such files, the local value of`lexical-binding' is t
>>>> as expected.
>>
>> So this is the unexpected part, right?
>
> In a way, yes. What I would like to do is to set the value and then
> have that choice respected when the file is executed as a script and
> also when it is visited in a buffer. When doing what I have done
> above, it is not respected in the first case but not in the second.
> That's worse than if this setting were just never respected.
I agree.
>>> You expect the part after the # to be somehow passed to the Emacs that
>>> is executed by "exec emacs"? That's a comment, as far as the shell is
>>> concerned, isn't it?
>>
>>> The Lisp code passed to Emacs is what starts with (... lisp goes here
>>> ...), right? Or am I missing something?
>>
>> No, the entire file is passed (by name) to Emacs, including the shebang
>> itself. Emacs discards it in lread.c, and the second line is valid Lisp.
>>
>> I don't know whether this helps, but
>>
>> #!/usr/bin/env -S emacs -x
>> ;; -*- lexical-binding: t -*-
>> (message "%S" lexical-binding)
>
> I completely forgot about that (emacs -x). For the record, that was
> added in Emacs 29.1. I going to use this instead of the hack above.
If it worked, that would be a good idea :-)
>> appears to work on a GNU/Linux system, where the GNU coreutils env is
>> installed in this standard location, but only with new emacs versions.
>
> Setting lexical-binding does not seem to work on GNU GUIX using Emacs
> 31.0.50. On this distribution "/usr/bin/env" is a symlink to something
> like "/gnu/store/f2rcir6yz0n74jaa6d0fm82f8flmwjnk-coreutils-9.1/bin/env".
> Even if I use that explicitly, lexical-binding is still nil.
#!/usr/bin/env -S emacs --batch -l
works.
#!/usr/bin/env -S emacs -x
doesn't work.
This appears to be because of the code in startup.el.
I would not want to actually touch this code; I think we should merely
document the current behavior rather than changing it.
>> Maybe /bin/env should be used instead. Note that this useful feature
>> also allows you to pass extra command line parameters to emacs.
>>
>> The problem is this code in lread.c:
>>
>> if (ch != ';')
>> /* The first line isn't a comment, just give up. */
>> {
>> unreadchar (&source, ch);
>> return Cookie_None;
>> }
>>
>> AFAIK, no valid shell script starts with a semicolon, so there's no way
>> to make this work with #!/bin/sh. Using zsh instead works.
>
> Seems to me this should be changed to also look at the second line
> (at least when using "emacs -x").
I don't think we reach this code at all for emacs -x.
> By the way --and that's just something I though of right now-- maybe
> this is an opportunity to *always* look at the second line as well.
> That way, one could replace
>
> ;;; this-library-has-a-long-name.el --- And it also needs a long description -*- mode: lexical-binding: t;
>
> with
>
> ;;; this-library-has-a-long-name.el --- And it also needs a long description
> ;; -*- lexical-binding: t;
>
> (Of course we would not be able to actually use this for a few years,
> except in new libraries that need at least Emacs 31 for other reasons
> anyway.)
Maybe that's a good idea, but I think our priority here should be to
find a reliable way to run a shebang Elisp script with lexical binding
and document it.
Pip
Information forwarded
to
bug-gnu-emacs <at> gnu.org:
bug#79760; Package
emacs.
(Wed, 05 Nov 2025 15:01:02 GMT)
Full text and
rfc822 format available.
Message #20 received at 79760 <at> debbugs.gnu.org (full text, mbox):
> Date: Wed, 05 Nov 2025 11:29:42 +0000
> From: Pip Cet <pipcet <at> protonmail.com>
> Cc: Eli Zaretskii <eliz <at> gnu.org>, 79760 <at> debbugs.gnu.org
>
> Maybe that's a good idea, but I think our priority here should be to
> find a reliable way to run a shebang Elisp script with lexical binding
> and document it.
Why cannot the Lisp script begin with something like
(setq-default lexical-binding t)
?
In general, given that our long-term goal is to make lexical-binding
be non-nil by default, I'd prefer not to complicate Emacs due to
temporary problems that soon will go away.
Stefan, WDYT?
This bug report was last modified today.
Previous Next
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.