You need to either set the default value of the variable, if you want it for every file:
(setq-default require-final-newline t)
;; or ...
(customize-set-variable 'require-final-newline t)
or to set it in the mode hook, if you only want it for files of that mode:
(add-hook 'some-mode-hook (lambda () (setq-local require-final-newline t)))
The reason that a bare
(setq require-final-newline t) does not work is that
require-final-newline is buffer-local in certain cases. A number of modes (most prominently
text-mode) do this:
(setq-local require-final-newline mode-require-final-newline)
That also affects their derived modes (e.g.
emacs-lisp-mode in the first case and
org-mode in the second). So in those mode,
require-final-newline is indeed buffer-local.
I don't know exactly how the loading and evaluation of the init file happens, but if it happens in such a buffer (e.g. in an
require-final-newline is indeed a buffer-local, so the
setq does not change the global default and your (future) buffer does not see the changed value. I suspect (but I don't know for sure) that this is the underlying cause of the failure of the bare
setq in your init file and why you need
EDIT: In answer to your question in the comment, I don't think there is a way to ask whether the variable is buffer-local in any buffer that exists in the current session, except by checking every buffer.
The problem is that any variable can be made buffer-local in a particular buffer, and nobody would know about that except that particular buffer: if you try to
setq from that buffer, you would only change the local value. So if you ask about the variable anywhere except in that buffer, it would say "not local". There are two functions
local-variable-is-set-p that do this kind of asking and they both say
nil for a buffer in e.g.
fundamental-mode for the variable
require-final-newline. You can check for local-ness in other buffers so you could write something like this to check every buffer:
(defun is-local (sym)
(dolist (buf (buffer-list))
(when (local-variable-p sym buf)
(throw 'found t)))
If you evaluate
(is-local 'require-final-newline) in any buffer, it says
t, because it is local in the
*scratch* buffer e.g.
But even this is not completely reliable: if during initialization a buffer is created and makes
require-final-newline buffer-local but then gets deleted, the loop above will not find it afterwards. If there is no other buffer with a buffer-local
require-final-newline, the function says
nil. You can check that by setting
fundamental, in a small init file that also contains the function above and the
require-final-newline, and invoking emacs with
emacs -Q -l /path/to/minimal.init.el. The
*scratch* buffer is now in fundamental mode and no other existing buffer (minibuffer, the Messages buffer etc) makes the variable buffer-local, so the function happily says
nil - but the
setq still does not work. To me, that indicates that the scenario I've been describing here is correct (but I can easily imagine being Horatio to someone's Hamlet :-) ).