Multiple Emacs Lisp config files lead to "free variable" and "function not known to be defined" warnings - emacs

I've been looking for emacs config files for a while, so that I learn how to structure my Emacs config in the most optimal way. Now i'm looking at purcell's config files which look very tidy and simple to read.
However, for every config file I've found there's always the same problem: "free variable"
and "function not known to be defined" warnings on all the included files. It is quite frustrating to see all the red underlines from flymake everytime, and it also makes me question if this really is the best way to write the config file.
Here's a file from the repository mentioned above:
;;; init-python.el --- Python editing -*- lexical-binding: t -*-
(setq auto-mode-alist
(append '(("SConstruct\\'" . python-mode)
("SConscript\\'" . python-mode))
auto-mode-alist))
;;WARNING: assignment to free variable ‘python-shell-interpreter’
(setq python-shell-interpreter "python3")
(require-package 'pip-requirements)
(when (maybe-require-package 'toml-mode)
(add-to-list 'auto-mode-alist '("poetry\\.lock\\'" . toml-mode)))
;;WARNING: reference to free variable ‘black’
(when (maybe-require-package 'reformatter)
(reformatter-define black :program "black" :args '("-")))
(provide 'init-python)
;;WARNING: the following functions are not known to be defined: require-package, maybe-require-package, reformatter-define
;;; init-python.el ends here
The python-shell-interpreter is a variable defined from the python-mode package.
The require-package and maybe-require-package are defined in a custom local file called init-elpa.el which is requires'd by the init.el file and thus they're not directly recognized by this file.
The black variable warning is the mostr "intricate": I guess it's caused by the fact that the reformatter package isn't included because maybe-require-package isn't included as well.
This gives me a headache. If I see it correctly, the root problem is the fact that the included files (init-python.el et al.) depend on stuff from the including file (init.el) without it being explicitly stated.
Is there a better way to structure an Emacs Lisp config among multiple files?

The python-shell-interpreter is a variable defined from the python-mode package.
Add (require 'python-mode) to the top of the file (or simply above the code which depends on that).
The require-package and maybe-require-package are defined in a custom local file called init-elpa.el
Add (require 'init-elpa) to the file (I'm assuming it provides the init-elpa feature).
which is require'd by the init.el file
This is fine -- require does nothing if the library in question has already been loaded. Even when there's an overarching init file loading other files, it's sensible for each file to require the things it needs (unless there are circular dependencies).
The black variable warning is the most "intricate": I guess it's caused by the fact that the reformatter package isn't included because maybe-require-package isn't included as well.
I'm guessing that reformatter-define is a macro and that the symbol black is not actually used as a variable. When only macros are required, one would typically (eval-when-compile (require 'reformatter)) but judging by the name maybe-require-package it's intended that reformatter might not be loadable at all. If that's all accurate, you can use this wrapper to cope with the false-positive:
(with-suppressed-warnings ((free-vars black))
...)
See C-hig (elisp)Compiler Errors for further information on handling byte-compilation warnings and errors.

Related

How does the "pdf-tools" package overrides "dired-find-file" method?

After installing pdf-tools the dired mode opens the pdf file with PDFView mode as major mode.
(use-package pdf-tools
:ensure t
:config
(pdf-tools-install t))
How does the pdf-tools package be able to accomplish this?
The Help for RET key in dried buffer says it is bound to dired-find-file
RET (translated from ) runs the command dired-find-file (found
in dired-mode-map), which is an interactive compiled Lisp function.
I searched for dired-find-file in pdf-tools installed elisp files and could not find any advice-add's?
Also please explain how can one go about finding arbitrary key bindings like this one?
What it modified is not directly related to dired, but to how Emacs decides to open files in general. The part of the code that is responsible for that is in pdf-tools-install-noverify, itself called by pdf-tools-install. The first two lines of the function are:
(add-to-list 'auto-mode-alist pdf-tools-auto-mode-alist-entry)
(add-to-list 'magic-mode-alist pdf-tools-magic-mode-alist-entry)
the relevant variables pdf-tools-<auto/magic>-mode-alist-entry being constants defined earlier in the file pdf-tools.el.
You can check the relevant documentation for auto-mode-alist and magic-mode-alist, but to sum up, the former is a mapping from "filenames" (or more precisely, file patterns -- typically, regexps matching file extensions) to major modes, and the latter is a mapping from "beginning of a buffer" to a major mode (see also this wikipedia page on magic numbers/file signatures).
As to how one can determine that: because it is not directly related to key bindings/advices/redefinition of functions, the only "general" option is to explore the "call stack" ! The package tells you to put (pdf-tools-install) somewhere in your init file to activate the package, so you can try to see what this function actually does -- and going a bit further, you see that it is essentially a wrapper around pdf-tools-install-noverify, which does the real job of setting everything up.

How do I make an interactive command automatically available?

I feel like this question is super basic, but I haven't been able to figure out how to automatically make a simple interactive command available in an Emacs session...
This is in ~/random/exploration/exploration.el.
;;; Code:
;;;###autoload
(defun exploration ()
"a test package"
(interactive)
(message "hi"))
(provide 'exploration)
;;; exploration.el ends here
This is in init.el:
(add-to-list 'load-path (expand-file-name "~/random/exploration"))
exploration isn't available via M-x though. I have to do M-: (require 'exploration) before it appears.
How would I make this command available automatically, like plugins do? I've been poring over the docs for load-path and autoload but can't figure out how to make this happen.
I want to do this so I can put other functions in exploration.el and have them only available after the user first does M-x exploration. That implies that exploration needs to be autoloaded.
Comments on any redundancies in what I've done here, or tips on how I could have debugged this on my own would also be welcome.
The ;;;###autloload comment is just a comment. When Emacs is built (or a suitably intelligent package manager installs your code as a package) it generates an actual autoload, but outside of that, you need to do it yourself.
(autoload 'exploration "exploration" nil t)
Specify an explicit path in the second parameter and you won't actually need the load-path manipulation to accomplish what you describe.
See also https://www.gnu.org/software/emacs/manual/html_node/eintr/Autoload.html
You have to either load the file instead of adding it to the load-path or you need to put (require 'exploration) to your init.el file after adding the folder to the load-path.
Use autoload function:
(autoload 'exploration "exploration")
If you don't modify load-path, you need an absolute path as the second argument.
Alternatively, install your script as a package, either through MELPA (assuming you can get it there), or locally with package-install-file. This will take care about autoloads for you.

irony-mode does not pick up include paths

I've recently started using irony-mode for completion in emacs (24.3.1). However, I seem unable to add additional system include paths to package.
I have this code in my config:
(defun ac-cc-mode-clang-hooks ()
(yas/minor-mode-on)
(auto-complete-mode 1)
;; avoid enabling irony-mode in modes that inherits c-mode, e.g: php-mode
(when (member major-mode irony-known-modes)
(irony-mode 1))
;; set compiler flags to include header files
(setq irony-compile-flags '("-Iinc"))
(irony-reload-flags))
(add-hook 'c++-mode-hook 'ac-cc-mode-clang-hooks)
(add-hook 'c-mode-hook 'ac-cc-mode-clang-hooks)
irony-mode is loaded correctly and completion works perfectly for include paths which the compiler knows explicitly (i.e. everything printed by echo "" | g++ -v -x c++ -E -) but the additional include path inc is not picked up (does not matter whether its a relative or absolute path).
However, if I add the information to the .clang_complete file and load it using C-c C-b the include path is recognised and used. Obviously this is a less than ideal setup because
I don't want to create a .clang_complete file for each single piece of code I'm working on
The .clang_complete file is not loaded automatically.
Is there some working method (which does not involve a per-project setup, I don't want to create project management files for each piece of code) for telling irony-mode where to look for header files?
You can take a look here: https://github.com/Sarcasm/irony-mode#i-got-an-error-due-to-stdargh-how-to-solve-this
The variable irony-libclang-additional-flags should meet your needs.
It should work without calling irony-reload-flags.
It's not a buffer-local variable though, so you don't need to put it in the hook.
I would recommend the following:
(setq irony-libclang-additional-flags
(append '("-I" "inc") irony-libclang-additional-flags))

Controlling verbosity of byte-compilation (CL library)

When byte-compiling several eLisp files in a batch the output from the compiler is cluttered with Warning: function `position' from cl package called at runtime warnings. I understand, although don't agree that much with the policy on cl package. But this makes spotting other, more useful warnings more difficult. So, while there's no real way to avoid the warning, is there a way to selectively shut off all warnings of a certain pattern?
EDIT: (attached an example)
create file called doodles.el
(require 'cl)
(eval-when-compile (require 'cl))
(dotimes (i 1)
(position ?\x "x"))
M-x byte-compile-file RET doodles.el
Switch to *Compile-Log* buffer:
doodles.el:1:1:Warning: cl package required at runtime
this is what you get.
You can control byte-compiler warnings with a Local variables block that sets the byte-compile-warnings variable. To turn off the CL-at-runtime warning, place this near the end of your module:
;; Local Variables:
;; byte-compile-warnings: (not cl-functions)
;; End:
The warning function position from cl package called at runtime is not there because of the policy on CL (well, it does have something to do with it, admittedly) but is pointing out an actual real problem: you use position in a file which does not (require 'cl). The file probably does (eval-when-compile (require 'cl)) which means CL is available during compilation (a.g. to expand CL macros), but will not be loaded at run time.
Often this does not result in a bug, because some other file somewhere does (require 'cl) for you, but that's just you being lucky.

Emacs c-mode autoloading failed

I want to load my file named "my-c-setup.el" when the c-mode is loading. So, I'm using the function "autoload".
With my python setup, it works well :
lang.el
(autoload 'python-mode "my-python-setup" "" t)
my-python-setup.el
(require 'python)
; ...
I'm trying to do the same with the c-mode, but i does not work :
lang.el
(autoload 'c-mode "my-c-setup" "" t)
my-c-setup.el
(setq c-basic-offset 4)
; ...
When I try to open a file in c-mode (test.c for example), I have the following error :
File mode specification error: (error "Autoloading failed to define function c-mode")
Autoload is not what you're looking for. What it does is simply load some code the first time it is needed, which is a handy way to extend Emacs' functionality while still keeping the start-up time low.
To solve your problem, we gotta think about what you really want to do: do you simply want some of your code to be loaded at some point, or do you want buffer-local customizations for ever buffer that is in c-mode?
If you simply want Emacs to load your code at start-up, either put your code directly into your .emacs file or use load-file or require instead of autoload:
load-file simply takes a file name, loads the lisp code in that file and evaluates it. So if your code is in a file named "/path/to/my-c-setup.el", you could put the following line in your .emacs, and the code will be loaded on every start-up:
(load-file "/path/to/my-c-setup.el")
Perhaps you don't want to give the absolute path name for every file you load. In that case, you could use the function load-library instead which is similar to load-file but tries to find the given filename in any of the directories stored in the variable load-path:
(add-to-list 'load-path "/path/to")
(load-library "my-c-setup.el")
The advantage is that you have to do the add-to-list part only once, and all subsequent calls to load-library will be able to find code in that directory.
An alternative way is the provide/require mechanism: you can make your .el-file "provide" some feature by putting a (provide 'feature) call in it, e.g.
(provide 'my-c-mode-customizations)
Then put an according (require 'feature) in your .emacs file, and your code will be loaded as well:
(require 'my-c-mode-customizations)
However, if you want your code only be loaded when c-mode is activated on a buffer, the way to achieve that is through Emacs' Hook mechanism:
A hook is a variable where you can
store a function or functions to be
called on a particular occasion by an
existing program.
Most major modes provide a customizable hook variable to which you can add functions that will be called whenever the major mode is invoked. For instance, c-mode provides c-mode-hook. In order for your own customizations to be called whenever c-mode is turned on for a buffer, put them in a function, say, my-c-mode-customizations and add the following line to your .emacs file:
(add-hook 'c-mode-hook 'my-c-mode-customizations)
Of course, you still need autoload for Emacs to actually find the definition of that function.
Lisp's autoload does not call a function when a file is loaded but tells lisp that the function is available and that the given file provides it. Whenever someone calls the (not yet defined) function, the file is loaded.
I think that c-mode is already defined and thus fails to re-register.
Autoload doesn't do what you think it does.
http://www.gnu.org/software/emacs/elisp/html_node/Autoload.html
What you probably want are mode-hooks or eval-after-load.
See eval-after-load vs. mode hook for the difference between the two.