Aprende-Vim/ch19_compile.md

294 lines
9.9 KiB
Markdown
Raw Normal View History

2021-03-07 20:16:05 +01:00
# Capítulo 19: Compilar
2021-03-07 20:16:05 +01:00
Compilar es un tema importante en muchos lenguajes de programación. En este capítulo, aprenderás cómo compilar desde Vim. También podrás ver formas de sacar partido del comando `:make` de Vim.
2021-03-07 20:16:05 +01:00
## Compilar desde la línea de comandos
2021-03-07 20:16:05 +01:00
Puedes utilizar el comando *bang* (`!`) para compilar. Si necesitas compilar tu archivo `.cpp` con `g++`, ejecuta:
```
2021-03-07 20:16:05 +01:00
:!g++ hola.cpp -o hola
```
2021-03-07 20:16:05 +01:00
Sin embargo, tener que escribir manualmente el nombre del archivo fuente y del archivo de salida todas las veces provoca que podamos cometer un error y además es tedioso. Por eso un archivo *makefile* nos puede ayudar con eso.
2021-03-07 20:16:05 +01:00
## El comando *make*
2021-03-07 20:16:05 +01:00
Vim tienes el comando `:make` para ejecutar un archivo *makefile*. Cuando lo ejecutas, Vim busca un archivo *makefile* en el directorio actual para ejecutarlo.
2021-03-07 20:16:05 +01:00
Crea un archivo llamado `makefile` en el directorio actual y escribe esto dentro del archivo:
```
all:
2021-03-07 20:16:05 +01:00
echo "Hola all"
foo:
2021-03-07 20:16:05 +01:00
echo "Hola foo"
list_pls:
ls
```
2021-03-07 20:16:05 +01:00
Ejecuta esto desde Vim:
```
:make
```
2021-03-07 20:16:05 +01:00
Vim lo ejecuta de la misma manera que si lo estuvieras ejecutando desde la terminal. El comando `:make` acepta parámetros igual que el comando de la terminal. Ejecuta:
```
:make foo
2021-03-07 20:19:45 +01:00
" Outputs "Hola foo"
:make list_pls
" Outputs the ls command result
```
2021-03-07 20:19:45 +01:00
El comando `:make` utiliza la ventana *quickfix* de Vim para almacenar cualquier error si has ejecutado mal un comando. Vamos a ejecutar un archivo objetivo inexistente:
```
2021-03-07 20:19:45 +01:00
:make noexistente
```
2021-03-07 20:19:45 +01:00
Deberías ver un error al ejecutar ese comando. Para ver ese error, ejecuta `:copen` para ver la ventana *quickfix*:
```
2021-03-07 20:19:45 +01:00
|| make: *** No rule to make target `noexistente'. Stop.
```
2021-03-07 20:36:41 +01:00
## Compilando con make
2021-03-07 20:36:41 +01:00
Vamos a utilizar un archivo *makefile* para compilar un programa `.cpp`. Primero vamos a crear un archivo llamado `hola.cpp`:
```
#include <iostream>
int main() {
2021-03-07 20:36:41 +01:00
std::cout << "¡Hola!\\n";
return 0;
}
```
2021-03-07 20:36:41 +01:00
Actualiza tu *makefile* para compilar y ejecutar el archivo `.cpp`:
```
all:
2021-03-07 20:36:41 +01:00
echo "compilar, ejecutar"
build:
2021-03-07 20:36:41 +01:00
g++ hola.cpp -o hola
run:
2021-03-07 20:36:41 +01:00
./hola
```
2021-03-07 20:36:41 +01:00
Ahora ejecuta:
```
:make build
```
2021-03-07 20:36:41 +01:00
El compilador `g++` compilará `./hola.cpp` y creará `./hola`. Después ejecuta:
```
:make run
```
2021-03-07 20:36:41 +01:00
Deberías ver `"!Hola!"` mostrado en la terminal.
2021-03-09 05:23:35 +01:00
## Programa diferente para make
2021-03-09 05:23:35 +01:00
Cuando ejecutas `:make`, Vim realmente ejecuta cualquier comando que esté configurado bajo la opción `makeprg`. Si ejecutas `:set makeprg?`, verás:
```
makeprg=make
```
2021-03-09 05:23:35 +01:00
El comando predeterminado de `:make` es el comando externo `make`. Para cambiar el comando `:make` para que ejecute `g++ {nombre_de_tu_archivo}` cada vez que lo ejecutas, ejecuta lo siguiente:
```
:set makeprg=g++\ %
```
2021-03-09 05:23:35 +01:00
El símbolo `\` es pars escapar el espacio después de `g++`. El símbolo `%` en Vim representa el archivo actual. El comando `g++\\ %` es equivalente a ejecutar `g++ hola.cpp`.
2021-03-09 05:23:35 +01:00
Ve al archivo `./hola.cpp` después ejecuta `:make`. Vim compila `hola.cpp` y crea el archivo `a.out` porque no has especificado un nombre para un archivo de salida. Vamos a cambiar eso para que le asigne un nombre al archivo de salida compilado con el nombre del archivo original menos la extensión. Añade o ejecuta esto a tu archivo vimrc:
```
set makeprg=g++\ %\ -o\ %<
```
2021-03-09 05:23:35 +01:00
Veamos en detalle el comando:
- `g++\ %` es lo mismo que hemos visto anteriormente. Es equivalente a ejecutar `g++ <tu_archivo>`.
- `-o` es la opción de salida.
- `%<` en Vim representa el nombre del archivo actual sin la extensión (`hola.cpp` se convierte en `hola`).
2021-03-09 05:23:35 +01:00
Cuando ejecutas `:make` desde dentro de `./hola.cpp`, este es compilado a `./hola`. Para ejecutar rápidamente `./hola` desde dentro de `./hola.cpp`, ejecuta `:!./%<`. De nuevo, esto es lo mismo que ejecutar `:!./{nombre_del_archivo_actual_menos_la_extensión}`.
2021-03-09 05:23:35 +01:00
Para más información puedes leer la información de Vim en `:h :compiler` o `:h write-compiler-plugin`.
2021-03-09 05:30:18 +01:00
## Compilado automático al guardar el archivo
2021-03-09 05:30:18 +01:00
Puedes hacer tu vida más sencilla automatizando el proceso de compilación. Recuerda que en Vim puedes utilizar `autocmd` para lanzar una acción automática basada en ciertos eventos. Para compilar automáticamente los archivos `.cpp` cada vez que guardes los cambios añade esto en tu archivo vimrc:
```
autocmd BufWritePost *.cpp make
```
2021-03-09 05:30:18 +01:00
Cada vez que guardes un archivo `.cpp` file, Vim ejecutará el comando `make`.
## Switching Compiler
Vim has a `:compiler` command to quickly switch compilers. Your Vim build probably comes with several pre-built compiler configurations. To check what compilers you have, run:
```
:e $VIMRUNTIME/compiler/<Tab>
```
You should see a list of compilers for different programming languages.
To use the `:compiler` command, suppose you have a ruby file, `hello.rb` and inside it has:
```
puts "Hello ruby"
```
Recall that if you run `:make`, Vim executes whatever command is assigned to `makeprg` (default is `make`). If you run:
```
:compiler ruby
```
Vim runs the `$VIMRUNTIME/compiler/ruby.vim` script and changes the `makeprg` to use the `ruby` command. Now if you run `:set makeprg?`, it should say `makeprg=ruby` (this depends on what is inside your `$VIMRUNTIME/compiler/ruby.vim` file or if you have another custom ruby compilers. Yours might be different). The `:compiler {your-lang}` command allows you to switch to different compilers quickly. This is useful if your project uses multiple languages.
You don't have to use the `:compiler` and `makeprg` to compile a program. You can run a test script, lint a file, send a signal, or anything you want.
## Creating A Custom Compiler
Let's create a simple Typescript compiler. Install Typescript (`npm install -g typescript`) to your machine. You should now have the `tsc` command. If you haven't played with typescript before, `tsc` compiles a Typescript file into a Javascript file. Suppose that you have a file, `hello.ts`:
```
const hello = "hello";
console.log(hello);
```
If you run `tsc hello.ts`, it will compile into `hello.js`. However, if you have the following expressions inside `hello.ts`:
```
const hello = "hello";
hello = "hello again";
console.log(hello);
```
This will throw an error because you can't mutate a `const` variable. Running `tsc hello.ts` will throw an error:
```
hello.ts:2:1 - error TS2588: Cannot assign to 'person' because it is a constant.
2 person = "hello again";
~~~~~~
Found 1 error.
```
To create a simple Typescript compiler, in your `~/.vim/` directory, add a `compiler` directory (`~/.vim/compiler/`), then create a `typescript.vim` file (`~/.vim/compiler/typescript.vim`). Put this inside:
```
CompilerSet makeprg=tsc
CompilerSet errorformat=%f:\ %m
```
The first line sets the `makeprg` to run the `tsc` command. The second line sets the error format to display the file (`%f`), followed by a literal colon (`:`) and an escaped space (`\ `), followed by the error message (`%m`). To learn more about the error formatting, check out `:h errorformat`.
You should also read some of the pre-made compilers to see how others do it. Check out `:e $VIMRUNTIME/compiler/<some-language>.vim`.
Because some plugins may interfere with the Typescript file, let's open the `hello.ts` without any plugin, using the `--noplugin` flag:
```
vim --noplugin hello.ts
```
Check the `makeprg`:
```
:set makeprg?
```
It should say the default `make` program. To use the new Typescript compiler, run:
```
:compiler typescript
```
When you run `:set makeprg?`, it should say `tsc` now. Let's put it to the test. Run:
```
:make %
```
Recall that `%` means the current file. Watch your Typescript compiler work as expected! To see the list of error(s), run `:copen`.
## Async Compiler
Sometimes compiling can take a long time. You don't want to be staring at a frozen Vim while waiting for your compilation process to finish. Wouldn't it be nice if you can compile asynchronously so you can still use Vim during compilation?
Luckily there are plugins to run async processes. The two big ones are:
- [vim-dispatch](https://github.com/tpope/vim-dispatch)
- [asyncrun.vim](https://github.com/skywind3000/asyncrun.vim)
In the remaining of this chapter, I will go over vim-dispatch, but I would strongly encourage you to try all of them out there.
*Vim and NeoVim actually supports async jobs, but they are beyond the scope of this chapter. If you're curious, check out `:h job-channel-overview.txt`.*
## Plugin: Vim-dispatch
Vim-dispatch has several commands, but the two main ones are `:Make` and `:Dispatch` commands.
### Async Make
Vim-dispatch's `:Make` command is similar to Vim's `:make`, but it runs asynchronously. If you are in a Javascript project and you need to run `npm t`, you might attempt to set your makeprg to be:
```
:set makeprg=npm\\ t
```
If you run:
```
:make
```
Vim will execute `npm t`, but you will be staring at the frozen screen while your JavaScript test runs. With vim-dispatch, you can just run:
```
:Make
```
Vim will run `npm t` asynchronously. This way, while `npm t` is running on a background process, you can continue doing whatever you were doing. Awesome!
### Async Dispatch
The `:Dispatch` command is like the `:compiler` and the `:!` command. It can run any external command asynchronously in Vim.
Assume that you are inside a ruby spec file and you need to run a test. Run:
```
:Dispatch bundle exec rspec %
```
Vim will asynchronously run the `rspec` command against the current file (`%`).
### Automating Dispatch
Vim-dispatch has `b:dispatch` buffer variable that you can configure to evaluate specific command automatically. You can leverage it with `autocmd`. If you add this in your vimrc:
```
autocmd BufEnter *_spec.rb let b:dispatch = 'bundle exec rspec %'
```
Now each time you enter a file (`BufEnter`) that ends with `_spec.rb`, running `:Dispatch` automatically executes `bundle exec rspec {your-current-ruby-spec-file}`.
## Learn Compile The Smart Way
In this chapter, you learned that you can use the `make` and `compiler` commands to run *any* process from inside Vim asynchronously to complement your programming workflow. Vim's ability to extend itself with other programs makes it powerful.