Reputation: 323
I'd like to compile and run a single c source file on a keypress such as <F5>
, now I've looked at several ways of accomplishing this and most involve using a Makefile. However, every example I've found on a generic Makefile require editing the TARGET or compiling all source files in the working directory. This led me to the question if I could run a regexp and replace the first line of the Makefile from any source file I'm working on.
<F5>
<file>
.c working on.<file>
There may be a simpler way of accomplishing this without editing the Makefile, but I've exhausted myself with trying to make a generic enough makefile to do it.
The regexp I have that would select the correct line:
^TARGET\s[=]\s.*
Upvotes: 1
Views: 2990
Reputation: 32446
Here is a simplified version of a function I bind to C-c C-C in my c-mode-map
. It just compiles the file, runs it with output to the compilation buffer, and then removes the compiled program. Note that you can string together multiple shell commands in your compile-command
to run/cleanup etc. With a prefix it will prompt for compilation command as normal.
(defun my-compile-and-run (arg)
"Compile, run (output to compilation buffer), remove program."
(interactive "P")
(let* ((out (concat (file-name-sans-extension
(file-name-nondirectory buffer-file-name))))
(command
(concat "gcc -std=c11 " ;other flags, etc.
buffer-file-name " -o " out
"; ./" out ;run executable
"; rm " out))) ;clean up
(unless arg
(setq-local compilation-read-command nil))
(setq-local compile-command command)
(call-interactively 'compile)))
You can get more creative with your compile-command
as well. If you actually wanted to run it through a makefile, for example,
CURRENT ?=
EXE = $(CURRENT:.c=)
target: ${CURRENT}
gcc -ansi -Wall -pedantic -O3 ${CURRENT} -o ${EXE}
run-target: target
${EXE}
clean-target:
$(RM) ${EXE}
You could then compile from emacs by just setting the compile-command
to set the CURRENT
variable to the buffers name and call whichever make targets you want, eg.
(defun my-compile-and-run (arg)
"Compile, run (output to compilation buffer), remove program."
(interactive "P")
(when (file-exists-p "Makefile")
(let ((command (concat "make CURRENT=\"" ;set current target
(shell-quote-argument buffer-file-name)
;run and clean program
"\" run-target clean-target")))
(unless arg
(setq-local compilation-read-command nil))
(setq-local compile-command command)
(call-interactively 'compile))))
Typically you want to set the compile-command
in you mode-hooks or as a local variable like @phils shows in the .dirs-locals.el or the other alternative ways to define emacs local variables.
Upvotes: 0
Reputation: 9437
I use multi-compile. Here's my config:
(use-package multi-compile
:config
(defun locate-repo-dir (&optional file-or-dir)
"Find the root of the version control repository."
(let* ((file-or-dir (or file-or-dir (buffer-file-name) default-directory))
(file-dir (if (file-directory-p file-or-dir)
file-or-dir
(file-name-directory file-or-dir)))
(root-dir (vc-call-backend (vc-deduce-backend) 'root file-dir)))
root-dir))
(dolist (e '(("%cflags" . (or (getenv "CFLAGS") "-Wall -g3 -std=c11"))
("%cxxflags" . (or (getenv "CXXFLAGS") "-Wall -g3"))
("%repo-dir" . (locate-repo-dir))))
(add-to-list 'multi-compile-template e))
(setq multi-compile-alist
'((".*" . (("make-simple" .
"make -k")
("make-repo" .
"make -k --no-print-directory -C '%repo-dir'")
("make-top" .
"make -k --no-print-directory -C '%make-dir'")))
(c-mode . (("c-simple" .
"gcc -o '%file-sans' %cflags '%file-name'")
("c-simple32" .
"gcc -o '%file-sans' %cflags -m32 '%file-name'")))
(c++-mode . (("c++-simple" .
"g++ -o '%file-sans' %cxxflags '%file-name'")))))
:bind (("C-c b" . multi-compile-run))
)
The c-simple option is exactly what I use for single-file C programs.
Upvotes: 1
Reputation: 73344
You could create a .dir-locals.el
file in your project directory with something like:
((c-mode . ((eval . (setq-local compile-command
(format "gcc -std=c99 -Wall -Wextra -Wpedantic -Werror %s"
(shell-quote-argument (file-name-nondirectory
buffer-file-name))))))))
Then you can just bind <f5> to compile
and it will do the appropriate thing.
Making compile
do "the right thing" means that you can consistently use the same command in all projects whenever you need to compile (or perform any vaguely analogous activity, depending on what the current project happens to be).
Upvotes: 2
Reputation: 21364
For testing small programs, I often use this bash script that cleans up after itself:
#!/bin/bash
gcc -std=c99 -Wall -Wextra -Wpedantic -Werror $1 -o tempout &&\
./tempout && rm tempout
I have this saved in an executable file called crepl
, and I can use it by entering at the command line:
> crepl my_program.c
I use the -Werror
flag so that code with warnings will not execute. This is pretty primitive, and won't work when libraries must be linked, but it is useful for simple small programs.
Upvotes: 1