Flycheck is an emacs library that does background compilation of source files. You can add your own "checkers" (ways of compiling certain files) with help from the manual.
I'm trying to add a compiler that needs to find a few files in a relative directory to the current file. I have a function that does that for me, called (process filename). When building the terminal command to execute for a file, you can use an (eval FORM) compute parameters on the fly. Here's the relevant part of my checker's definition:
(flycheck-declare-checker unity-csharp-flychecker
"given a c-sharp file, looks for the unity file and then tries to build it using mdtool."
:command '("mdtool" "build"
(eval '(process source-original)))
...)
source-original is a special symbol that is substituted for buffer-file-name at execution time.
Unfortunately when I try to use the checker, I get this error:
Invalid result from evaluation of (quote (process source-original)): (process source-original)
Am I using (eval) incorrectly here? How can I get access to source-original from within so I can pass it to (process)? Any help much appreciated.
This is the correct form:
(flycheck-declare-checker unity-csharp-flychecker
"given a c-sharp file, looks for the unity file and then tries to build it using mdtool."
:command '("mdtool" "build"
(eval (process buffer-file-name)))
...)
Thanks for Bruce Conner for getting me to remove the quote before (process ...). That gave me a new error:
Error: (void-variable source-original)
So I dug into the source and saw there is no symbol substitution before evaluation. I assumed because we were given symbols that just using buffer-file-name wouldn't work, but I tried it and it does. I don't know if there are ramifications for that approach down the road.
Related
I have a file functions called "myloaddefs.el". It has magic coments and forms under them just like the one below.
;;;###autoload
(defun an-awesome-function '()
(interactive)
"A descriptive comment." t)
;;; other descriptive comments and forms...
It's full path is ~/.emacs.d/core/myloaddefs.el.
I also have an autoloads file whose full path is ~/.emacs.d/.local/autoloads.el. I store its path in the variable my-autoload-file.
Before calling update-file-autoloads, my-autoload-file only has an empty comment ;; (making sure it's non-empty to avoid an error). Calling update-file-autoloads as I do below returns nil. And it when I check the my-autoload-file it was indeed updated with autoloads. Loading the 'my-autoload-filereturnst` and also seems successful.
(update-file-autoloads (concat my-core-dir "myloaddefs.el") t my-autoload-file) ; => nil
(load-file my-autoload-file) ; => t
However after calling an autoloaded interactive function with, M-x an-awesome-function I get "Cannot open load file: no such file or directory" "../core/myautoloads". This confuses me greatly because the directory and the file do exist. What could be wrong here?
The path to your autoload file needs to be on your load path since you are using relative paths to load the libraries (eg. ../core/autoloads). I would use expand-file-name anywhere you are creating a path instead of building them using concat.
Try (push (expand-file-name ".local" "~") load-path) prior to calling an-awesome-function (whose definition is incorrect).
I defined this macro:
(defmacro with-current-directory (directory &rest body)
"Set the working directory temporarily set to DIRECTORY and run BODY.
DIRECTORY is expanded"
`(let ((default-directory
,(file-name-as-directory
(expand-file-name (eval directory)))))
,#body))
which I use in some lisp functions that are loaded when emacs opens. I always get these warnings:
Eager macro-expansion failure: (void-variable repo-dir)
Eager macro-expansion failure: (wrong-type-argument stringp nil)
Which I understand is happening because those variables are not defined at load time, and emacs is trying to eval them. My question is, how do I avoid getting these warnings. Is there a way to define the macro so that doesn't happen? I cannot figure out how to use the value of the variable, and not the symbol for the variable itself.
Like this:
`(let ((default-directory
(file-name-as-directory (expand-file-name ,directory))))
Since directory is not the value, but the lisp expression that would evaluate to the value, you need to insert (using the comma operator) the expression into the expansion of the macro. If you put the comma before the call to file-name-as-directory, you would have to be able to compute the directory at macro expansion time based only on the tokens of the expression, which you can't do if directory refers to a variable name.
Looks like some beat me to it. Look at the other answer.
You should not be evaluating the file name expansion at expansion time. Also the eval call should not be there. The only thing that should happen during macro expansion is placing the value of directory inside the returned expression. Remove eval and place your comma in front of directory.
It's nice to know that anytime you're using eval, you're probably doing something wrong
I use this valgrind.el to run valgrind inside emacs. But the newest version of emacs has deprecated compile-internal. I don't know nearly enough about elisp to figure out how to convert the compile-internal call to a compilation-start call. This is what the original function call in question looks like:
(compile-internal command "No more errors" "valgrind")
I found this bit online that indicates possible usage of compilation-start:
(compilation-start command mode
#'(lambda (mode-name) (concat "*" buf-name "*")))
Any help would be appreciated!
I am not sure about what you tried and what the results were.
As per the documentation, I would replace the compile internal line by:
(compilation-start command nil (lambda (mode-name) "*valgrind*"))
A large project may have directory with several level depth. Emacs's default compile command is "make -k", if I modified a certain source code, then typed "M-x compile RET RET", it will execute "make -k" under the directory which the source code lies.
I think I can write a function to determine if the Makefile exist under current directory, if yes, keep searching under the parent directory until find the top level directory, then execute the building command, it would be right like my expectation.
However, I'm not very clearly how to start, could anyone give me some hints to start? Like the function or variable I may encounter. Thanks.
You can try to use something like:
(setq compile-command
'(let ((mf (locate-dominating-file default-directory "Makefile")))
(if mf (setq mf (file-name-directory mf)))
(concat (if (and mf (not (equal mf default-directory)))
(format "cd %s; "
(shell-quote-argument
(file-relative-name
(directory-file-name mf)))))
"make -k ")))
There is a smarter-compile in marmalade.
From the documentation....When you require it, you can specify a list of cons cells, each one like (TEST . COMMAND).
COMMAND is used for the compile-command when
the TEST succeeds.
TEST can be:
a string. In this case it is used as a regex,
and matched against the filename associated to the
buffer. The TEST succeeds when the regex matches.
a symbol, representing the major-mode. In this case
if the buffer uses that major mode, the TEST
succeeds.
a symbol, representing any function with a name not
ending in \"-mode\". In this case, the function is
called and if it returns non-nil, the TEST
succeeds.
a list of forms. In this case the forms are eval'd,
and if the return value is non-nil, the TEST
succeeds.
So you could produce a function that does the scan for makefile in parent directories,
and use that as your TEST.
According to the documentation, if the COMMAND is nil, then the package uses the result of the TEST as the compile command. Which means you would need only one function, returning a make command referencing the makefile in the appropriate directory.
Take a look at: http://emacswiki.org/emacs/CompileCommand
"C-h v compile-command" directly from emacs.
Here's a solution for people who prefer bash scripting over Emacs Lisp. In my .emacs I define a command which saves all buffers and runs a bash script which compiles the project.
(defun save-all-and-compile () (interactive)
(save-some-buffers 1)
(shell-command "make-and-run.sh &"))
(add-hook 'c-mode-common-hook (lambda ()
(local-set-key (kbd "<f5>") 'save-all-and-compile)))
For small projects the script could be as simple as
#!/bin/bash
make -j && ./<main>
where 'main' is the name of your executable. For larger projects one would first need to locate the root directory. Similarly, you could have different scripts (bound for different keys) for building and running the program. And then some more scripts for testing different parts of the project. But these are just details one can figure out for themselves.
Make sure the script is run asynchronously using '&'. This way the Async Shell Command buffer will open with the output from make and your project and will stay open.
EDIT
Based on the discussion below it appears I have initially overthought it and the solution is quite simple. Instead of passing the usual 'make' or 'make -k' to compile-command one could use a shell script which first navigates to the project's root directory and the builds.
(setq compile-command "script.sh")
After adding the following code in my .emacs file, comes up some error during startup of emacs. I am a newbie of emacs, is there some one can help me figure out where are the errors come from?
Added code in .emacs:
;; Auto-saving the Desktop
(require 'desktop)
(desktop-save-mode 1)
(defun my-desktop-save ()
(interactive)
;; Don't call desktop-save-in-desktop-dir, as it prints a message.
(if (eq (desktop-owner) (emacs-pid))
(desktop-save desktop-dirname)))
(add-hook 'auto-save-hook 'my-desktop-save)
Errors:
Looking at the function definition for what's breaking, it seems that the error is that prj-file is NIL in line 492. (The other expand-filename call in the function shouldn't ever have a nil, since it's the car of a non-nil list of filenames).
Now, prj-file is the first filename in /home/shenyan/Test/memcached-1.4.11 matching the regexp "\\(Root\\)?ProjStep.ede" and presumably there isn't one. Since memcached presumably doesn't have an EDE project file, what's gone wrong must be that line 508's call to ede-project-p did something weird when called with this subdirectory of /home/shenyan/Test/.
I can't work out exactly why that happened, but you can debug things quite easily. First bring up your *scratch* buffer to type emacs lisp easily. To check my guess, insert the following code into the buffer
(ede-directory-project-p "/home/shenyan/Test/memcached-1.4.11")
and run it by hitting C-x C-e with cursor on the closing bracket. If it returns nil I was wrong. Otherwise, you've found the culprit and should probably debug it further by hunting through the bits of ede-directory-project-p in ede-files.el.
Probably what's going on is that your /home/shenyan/Test/ directory has something that tells EDE to search subdirectories (or maybe that's the default?) and then the memcached subdirectory has a file whose name makes EDE think it should be searched for a project file. If you work out exactly what happened, you might consider submitting a bug to the EDE developers: they probably shouldn't error out if the project file doesn't exist.