{"id":65,"date":"2009-10-28T22:47:19","date_gmt":"2009-10-28T20:47:19","guid":{"rendered":"http:\/\/www.blackhats.es\/wordpress\/?p=65"},"modified":"2022-08-20T18:26:12","modified_gmt":"2022-08-20T16:26:12","slug":"emacs-tags-etags-gnumake-automake-y-autoconf","status":"publish","type":"post","link":"https:\/\/www.blackhats.es\/wordpress\/?p=65","title":{"rendered":"Emacs TAGS, ETAGS, GNU\/make, Automake y Autoconf"},"content":{"rendered":"<p>Pr\u00e9viamente hemos comentado en otros art\u00edculos algunas opciones de usar Emacs como IDE para muchos de los lenguajes de programaci\u00f3n que conocemos, y as\u00ed poder usar un mismo entorno para todos ellos sin necesidad de ir cambiando, con el consiguiente tiempo perdido que ello conlleva.<\/p>\n<p>Comentamos en <a href=\"https:\/\/www.blackhats.es\/wordpress\/?p=37\" target=\"_blank\" rel=\"noopener\">art\u00edculos anteriores<\/a> el usar el <strong>c-mode<\/strong>, con los keystrokes habituales y m\u00e1s \u00fatiles. Tambi\u00e9n comentamos el <a href=\"https:\/\/www.blackhats.es\/wordpress\/?p=62\" target=\"_blank\" rel=\"noopener\">uso de CEDET<\/a> como un conjunto de utilidades destinadas a este fin. Aqu\u00ed comentaremos el uso de algunas t\u00e9cnicas espec\u00edficas para hacer de emacs un entorno c\u00f3modo para el desarrollo en c, y algunas otras que son generales a todos o la mayor\u00eda de lenguajes.<\/p>\n<p>Comentar que desde emacs tenemos funciones (algunas mapeadas y otras no) referentes a <strong>TAGS <\/strong>y <strong>ETAGS<\/strong>. La diferencia entre <strong>TAGS <\/strong>y <strong>ETAGS <\/strong>b\u00e1sicamente es que el formato de <strong>TAGS <\/strong>es un formato general que puede ser interpretado por distintas herramientas, mientras que <strong>ETAGS <\/strong>es espec\u00edfico de emacs. Comentar que existen m\u00e1s posibilidades desde emacs para trabajar con <strong>TAGS <\/strong>tales como <strong>Icicles<\/strong>, <strong>EtagsSelect<\/strong>, <strong>Vtags<\/strong>, etc.<\/p>\n<p>El comando <strong>etags <\/strong>puede ser usado desde consola para crear el fichero de <strong>ETAGS<\/strong> para un directorio tan s\u00f3lo ejecutando el comando:<\/p>\n<p style=\"padding-left: 30px;\"><strong>etags *.c *.h<\/strong><\/p>\n<p>O bien para todo el \u00e1rbol y subdirectorios del mismo y com\u00fan para c y c++ mediante:<\/p>\n<p style=\"padding-left: 30px;\"><strong>find . | egrep &#8216;\\.(h|c|hpp|cpp)$&#8217; | etags &#8211;<\/strong><\/p>\n<p>Antes de comenzar a explicar como usar <strong>ETAGS <\/strong>en emacs, debemos decir que es recomendable tener tres herramientas b\u00e1sicas instaladas (que por norma general vienen en cualquier distribuci\u00f3n de GNU moderna: <strong>GNU\/make<\/strong>, <strong>autoconf<\/strong> y <strong>automake<\/strong>. Realmente no es necesaria la instalaci\u00f3n de <strong>autoconf <\/strong>ni <strong>automake<\/strong>, pero decir que es interesante, debido a que automake genera los <strong>ETAGS <\/strong>autom\u00e1ticamente, y <strong>autoconf <\/strong>es una dependencia de <strong>automake<\/strong>. Antes de continuar dar\u00e9 una noci\u00f3n b\u00e1sica de ejemplo para trabajar con <strong>Makefiles<\/strong>.<\/p>\n<p>Aqu\u00ed podemos ver un ejemplo de Makefile lo m\u00e1s simple posible para <strong>un<\/strong> s\u00f3lo fichero <strong>.c<\/strong>:<\/p>\n<p style=\"padding-left: 30px;\"><span style=\"color: #0000ff;\"><em>main.o : main.c<\/em><\/span><\/p>\n<p style=\"padding-left: 90px;\"><span style=\"color: #0000ff;\"><em>gcc -c main.c<\/em><\/span><\/p>\n<p>Aqu\u00ed otro ejemplo esta vez con <strong>dos <\/strong>ficheros <strong>.c<\/strong>:<\/p>\n<p style=\"padding-left: 30px;\"><span style=\"color: #0000ff;\"><em>main : main.o foo.o<\/em><\/span><\/p>\n<p style=\"padding-left: 90px;\"><span style=\"color: #0000ff;\"><em>gcc main.o foo.o -o main<\/em><\/span><\/p>\n<p style=\"padding-left: 30px;\"><span style=\"color: #0000ff;\"><em>main.o : main.c<\/em><\/span><\/p>\n<p style=\"padding-left: 90px;\"><span style=\"color: #0000ff;\"><em>gcc -c main.c<\/em><\/span><\/p>\n<p style=\"padding-left: 30px;\"><span style=\"color: #0000ff;\"><em>foo.o : foo.c<\/em><\/span><\/p>\n<p style=\"padding-left: 90px;\"><span style=\"color: #0000ff;\"><em>gcc -c foo.c<\/em><\/span><\/p>\n<p>Aqu\u00ed otro ejemplo esta vez usando <strong>cabeceras <\/strong>propias <strong>.h<\/strong>:<\/p>\n<p style=\"padding-left: 30px;\"><em><span style=\"color: #0000ff;\">all : main.o list.o stack. <\/span><\/em><\/p>\n<p style=\"padding-left: 60px;\"><em><span style=\"color: #0000ff;\">gcc main.o list.o stack.o -o main<\/span><\/em><\/p>\n<p style=\"padding-left: 30px;\"><em><span style=\"color: #0000ff;\">clean :<\/span><\/em><\/p>\n<p style=\"padding-left: 60px;\"><em><span style=\"color: #0000ff;\">rm main.o list.o stack.o<\/span><\/em><\/p>\n<p style=\"padding-left: 30px;\"><em><span style=\"color: #0000ff;\">list.o : list.c list.h<\/span><\/em><\/p>\n<p style=\"padding-left: 60px;\"><em><span style=\"color: #0000ff;\">gcc -c list.c<\/span><\/em><\/p>\n<p style=\"padding-left: 30px;\"><em><span style=\"color: #0000ff;\">stack.o : stack.c stack.h<\/span><\/em><\/p>\n<p style=\"padding-left: 60px;\"><em><span style=\"color: #0000ff;\">gcc -c stack.c<\/span><\/em><\/p>\n<p style=\"padding-left: 30px;\"><em><span style=\"color: #0000ff;\">main.o : main.c list.h list.c stack.h stack.c<\/span><\/em><\/p>\n<p style=\"padding-left: 60px;\"><em><span style=\"color: #0000ff;\">gcc -c main.c<\/span><br \/>\n<\/em><\/p>\n<p>\u00c9ste \u00faltimo ejemplo se suele simplificar usando variables que se refieren a la lista de argumentos usados y al listado de objetos \u00fatil para cuando se tienen bastantes ficheros y par\u00e1metros para el compilador, tal que as\u00ed:<\/p>\n<p style=\"padding-left: 30px;\"><span style=\"color: #0000ff;\"><em>.SUFFIXES: .o .c<\/em><\/span><\/p>\n<p style=\"padding-left: 30px;\"><span style=\"color: #0000ff;\"><em>.c.o:<\/em><\/span><\/p>\n<p style=\"padding-left: 60px;\"><span style=\"color: #0000ff;\"><em>$(CC) -c $(CFLAGS) $&lt;<\/em><\/span><\/p>\n<p style=\"padding-left: 30px;\"><span style=\"color: #0000ff;\"><em>CC = @gcc<\/em><\/span><\/p>\n<p style=\"padding-left: 30px;\"><span style=\"color: #0000ff;\"><em>CFLAGS = -W -Wall -ansi -pedantic -Wbad-function-cast \\<\/em><\/span><\/p>\n<p style=\"padding-left: 90px;\"><span style=\"color: #0000ff;\"><em>-Wcast-align -Wcast-qual -Wchar-subscripts -Winline \\<\/em><\/span><\/p>\n<p style=\"padding-left: 90px;\"><span style=\"color: #0000ff;\"><em>-Wmissing-prototypes -Wnested-externs -Wpointer-arith \\<\/em><\/span><\/p>\n<p style=\"padding-left: 90px;\"><span style=\"color: #0000ff;\"><em>-Wredundant-decls -Wshadow -Wstrict-prototypes -Wwrite-strings<\/em><\/span><\/p>\n<p style=\"padding-left: 30px;\"><span style=\"color: #0000ff;\"><em>SRC = main.c list.c list.h stack.c stack.h circular.c circular.h double.c double.h queue.c queue.h tree.c tree.h avl.c avl.h<\/em><\/span><\/p>\n<p style=\"padding-left: 30px;\"><span style=\"color: #0000ff;\"><em>OBJ = main.o list.o stack.o circular.o double.o queue.o tree.o avl.o<\/em><\/span><\/p>\n<p style=\"padding-left: 30px;\"><span style=\"color: #0000ff;\"><em>all: $(OBJ)<\/em><\/span><\/p>\n<p style=\"padding-left: 60px;\"><span style=\"color: #0000ff;\"><em>$(CC) $(CFLAGS) $(OBJ) -o main<\/em><\/span><\/p>\n<p style=\"padding-left: 30px;\"><span style=\"color: #0000ff;\"><em>clean:<\/em><\/span><\/p>\n<p style=\"padding-left: 60px;\"><span style=\"color: #0000ff;\"><em>$(RM) $(OBJ) main<\/em><\/span><\/p>\n<p style=\"padding-left: 30px;\"><span style=\"color: #0000ff;\"><em>list.o: list.c list.h<\/em><\/span><\/p>\n<p style=\"padding-left: 60px;\"><span style=\"color: #0000ff;\"><em>$(CC) $(CFLAGS) -c list.c<\/em><\/span><\/p>\n<p style=\"padding-left: 30px;\"><span style=\"color: #0000ff;\"><em>stack.o: stack.c stack.h<\/em><\/span><\/p>\n<p style=\"padding-left: 60px;\"><span style=\"color: #0000ff;\"><em>$(CC) $(CFLAGS) -c stack.c<\/em><\/span><\/p>\n<p style=\"padding-left: 30px;\"><span style=\"color: #0000ff;\"><em>circular.o: circular.c circular.h<\/em><\/span><\/p>\n<p style=\"padding-left: 60px;\"><span style=\"color: #0000ff;\"><em>$(CC) $(CFLAGS) -c circular.c<\/em><\/span><\/p>\n<p style=\"padding-left: 30px;\"><span style=\"color: #0000ff;\"><em>double.o: double.c double.h<\/em><\/span><\/p>\n<p style=\"padding-left: 60px;\"><span style=\"color: #0000ff;\"><em>$(CC) $(CFLAGS) -c double.c<\/em><\/span><\/p>\n<p style=\"padding-left: 30px;\"><span style=\"color: #0000ff;\"><em>queue.o: queue.c queue.h<\/em><\/span><\/p>\n<p style=\"padding-left: 60px;\"><span style=\"color: #0000ff;\"><em>$(CC) $(CFLAGS) -c queue.c<\/em><\/span><\/p>\n<p style=\"padding-left: 30px;\"><span style=\"color: #0000ff;\"><em>tree.o: tree.c tree.h<\/em><\/span><\/p>\n<p style=\"padding-left: 60px;\"><span style=\"color: #0000ff;\"><em>$(CC) $(CFLAGS) -c tree.c<\/em><\/span><\/p>\n<p style=\"padding-left: 30px;\"><span style=\"color: #0000ff;\"><em>avl.o: avl.c avl.h<\/em><\/span><\/p>\n<p style=\"padding-left: 60px;\"><span style=\"color: #0000ff;\"><em>$(CC) $(CFLAGS) -c avl.c<\/em><\/span><\/p>\n<p style=\"padding-left: 30px;\"><span style=\"color: #0000ff;\"><em>main.o: $(SRC)<\/em><\/span><\/p>\n<p style=\"padding-left: 60px;\"><span style=\"color: #0000ff;\"><em>$(CC) $(CFLAGS) -c main.c <\/em><\/span><\/p>\n<p>Obviamente para \u00e9ste \u00faltimo ejemplo deberemos tener el c\u00f3digo organizado tal que as\u00ed:<\/p>\n<ul>\n<li>En las cabeceras (.h) deberemos incluir todas las macros, definici\u00f3n de tipos y prototipos de funciones.<\/li>\n<li>En los fuentes que se refieran a parte de la librer\u00eda creada (todos los .c excepto main.c) debemos incluir los includes correspondientes necesarios de la libc, as\u00ed como el include espec\u00edfico donde se implementen las funciones a las que hac\u00edamos referencia en los .h, es decir incluir list.h en list.c, stack.h en stack.c, etc. En dichos fuentes tambi\u00e9n debemos incluir la implementaci\u00f3n de cada funci\u00f3n declarada por su correspondiente .h (implementar los prototipos de funciones que ve\u00edamos en list.h, en list.c, declarar los prototipos de funciones que ve\u00edamos en stack.h, en stack.c, etc).<\/li>\n<li>En el fuente principal o que use dicha librer\u00eda (compuesta por cabeceras o .h) debemos incluir cada .h (tanto de la libc que necesitemos entre &lt;&gt; como los de nuestra librer\u00eda propia entre \u00ab\u00bb para cada .h). Acto seguido podremos usar aqu\u00ed cualquier funci\u00f3n declarada en nuestros .h e implementada en nuestros .c.<\/li>\n<\/ul>\n<p>Sabiendo el ABC de <strong>Makefiles <\/strong>y como trabajar con m\u00faltiples ficheros .c y .h propios y\/o ajenos a nuestro proyecto, ya podemos proceder a continuar con la herramienta <strong>GNU\/Make<\/strong>, para interpretar <strong>makefiles <\/strong>y as\u00ed poder construir el build mediante el comando <strong>make<\/strong>. La herramienta <strong>Automake<\/strong>, que adem\u00e1s soporta <strong>ETAGS <\/strong>y por lo tanto nos permitir\u00e1 crear dicho fichero de s\u00edmbolos al realizar el <strong>make <\/strong>autom\u00e1tico, y <strong>Autoconf<\/strong>, herramienta y dependencia necesaria para poder trabajar con <strong>Automake<\/strong>. Adem\u00e1s de ello podemos utilizar un <strong>bootstrap <\/strong>para generar el <strong>Makefile.am<\/strong> y as\u00ed tener todo el proceso automatizado desde el principio. Es decir que todo este entramado quedar\u00eda algo as\u00ed (donde -&gt; implica que genera, crea y\/o procesa):<\/p>\n<p style=\"padding-left: 30px;\"><span style=\"color: #0000ff;\">(.\/bootstrap)<\/span> -genera-&gt; <span style=\"color: #ff00ff;\">.\/configure<\/span><\/p>\n<p style=\"padding-left: 30px;\"><span style=\"color: #ff00ff;\">Makefile.am<\/span> -genera-&gt; <span style=\"color: #ff00ff;\">Makefile.in<\/span> <span style=\"color: #0000ff;\">(mediante automake)<\/span><\/p>\n<p style=\"padding-left: 30px;\"><span style=\"color: #ff00ff;\">Makefile<\/span><span style=\"color: #ff00ff;\">.in<\/span> -genera-&gt; <span style=\"color: #0000ff;\"><span style=\"color: #ff00ff;\">Makefile <\/span>(mediante <\/span><span style=\"color: #0000ff;\">.\/configure)<\/span><\/p>\n<p>En el caso de querer crear un <strong>tarball <\/strong>para distribuir el paquete, se aconseja inlcuir el <strong>configure<\/strong>, para evitar obligar a instalar dependencias como <strong>automake <\/strong>y <strong>autoconf <\/strong>en los ordenadores donde se distribuya, s\u00f3lo requerir\u00e1 <strong>GNU\/make<\/strong>.<\/p>\n<p>El <strong>bootstrap<\/strong> (extra\u00eddo del proyecto GNU PDF)<strong> <\/strong>debe tener un formato tal que <a href=\"http:\/\/bzr.savannah.gnu.org\/lh\/pdf\/libgnupdf\/branches\/trunk\/download\/head%3A\/bootstrap-20070705204143-sqvd5gkhqnab-3\/bootstrap\" target=\"_blank\" rel=\"noopener\">as\u00ed<\/a>:<\/p>\n<p style=\"text-align: left; padding-left: 30px;\"><em>#!\/bin\/sh<br \/>\n# $Id: bootstrap,v 1.6 2007\/11\/08 02:19:09 jemarch Exp $<br \/>\n# Created 2003-08-29, Karl Berry.\u00a0 Public domain.<\/em><\/p>\n<p style=\"padding-left: 30px;\"><em>if test \u00abx$1\u00bb = x-n; then<br \/>\nchicken=true<br \/>\necho \u00abOk, playing chicken; not actually running any commands.\u00bb<br \/>\nelse<br \/>\nchicken=<br \/>\nfi<\/em><\/p>\n<p style=\"padding-left: 30px;\"><em>echo \u00abBootstrapping the GNU PDF Library with:\u00bb<\/em><\/p>\n<p style=\"padding-left: 30px;\"><em># This overwrites lots of files with older versions.<br \/>\n# I keep the newest versions of files common between distributions up to<br \/>\n# date in CVS (see util\/srclist.txt), because it&#8217;s not trivial for every<br \/>\n# developer to do this.<br \/>\n#cmd=\u00bbautoreconf &#8211;verbose &#8211;force &#8211;install &#8211;include=m4&#8243;<\/em><\/p>\n<p style=\"padding-left: 30px;\"><em>: ${AUTORECONF=autoreconf}<br \/>\n: ${ACLOCAL=aclocal}<br \/>\n: ${LIBTOOLIZE=libtoolize}<br \/>\n: ${AUTOHEADER=autoheader}<br \/>\n: ${AUTOMAKE=automake}<br \/>\n: ${AUTOCONF=autoconf}<\/em><\/p>\n<p style=\"padding-left: 30px;\"><em># So instead:<br \/>\ncmd=\u00bb$AUTORECONF -i\u00bb<br \/>\necho \u00bb\u00a0 $cmd\u00bb<br \/>\n$chicken eval $cmd || exit 1<\/em><\/p>\n<p style=\"padding-left: 30px;\"><em>echo<br \/>\necho \u00abNow run configure with your desired options, for instance:\u00bb<br \/>\necho \u00bb\u00a0 .\/configure CFLAGS=-g\u00bb<br \/>\necho<\/em><\/p>\n<p style=\"text-align: left;\">Modific\u00e1ndolo y adapt\u00e1ndolo a las necesidades de cada uno. En caso de no tener las herramientas GNU\/make, automake y\/o autoconf instaladas pueden descargarse e instalarse de la siguiente manera:<\/p>\n<p style=\"text-align: left;\">Para descargar la \u00faltima versi\u00f3n de GNU\/make (<a href=\"http:\/\/www.gnu.org\/software\/make\/manual\/\" target=\"_blank\" rel=\"noopener\">manual<\/a>):<\/p>\n<p style=\"text-align: left; padding-left: 30px;\"><strong>cvs -z3 -d:ext:anonymous@cvs.savannah.gnu.org:\/sources\/make co make<\/strong><\/p>\n<p style=\"text-align: left;\">Para descargar la \u00faltima versi\u00f3n de Autoconf (<a href=\"http:\/\/www.gnu.org\/software\/autoconf\/\" target=\"_blank\" rel=\"noopener\">manual<\/a>):<\/p>\n<p style=\"text-align: left; padding-left: 30px;\"><strong>cvs -d :pserver:anonymous@pserver.git.sv.gnu.org:\/autoconf.git co -d autoconf HEAD<\/strong><\/p>\n<p style=\"text-align: left;\">Para descargar la \u00faltima versi\u00f3n de Automake (<a href=\"http:\/\/www.gnu.org\/software\/automake\/manual\/\" target=\"_blank\" rel=\"noopener\">manual<\/a>):<\/p>\n<p style=\"text-align: left; padding-left: 30px;\"><strong>cvs -d :pserver:anonymous@pserver.git.sv.gnu.org:\/automake.git checkout -d automake HEAD<\/strong><\/p>\n<p style=\"text-align: left;\">Los paquetes pueden ser actualizados mediante <strong>cvs update<\/strong> para obtener la \u00faltima versi\u00f3n.<\/p>\n<p style=\"text-align: left;\">Como Automake soporta y crea los <strong>ETAGS <\/strong>autom\u00e1ticamente, podemos aprovecharnos de esto en nuestro entorno emacs. Tenemos las siguientes funciones referentes a <strong>ETAGS<\/strong>:<\/p>\n<p style=\"text-align: left; padding-left: 30px;\"><strong>M-.<\/strong> : &#8216;<span style=\"color: #0000ff;\">find-tag<\/span>&#8216;; busca un s\u00edmbolo dado.<br \/>\n<strong>M-*<\/strong> : &#8216;<span style=\"color: #0000ff;\">pop-tag-mark<\/span>&#8216;; devuelve el cursor al punto de comienzo de b\u00fasqueda de s\u00edmbolos.<br \/>\n<strong>(sin keystroke asociada) <\/strong>: &#8216;<span style=\"color: #0000ff;\">tags-search<\/span>&#8216;; busca un s\u00edmbolo.<br \/>\n<strong>(sin keystroke asociada)<\/strong> : &#8216;<span style=\"color: #0000ff;\">tags-query-replace<\/span>&#8216;; reemplaza un s\u00edmbolo.<br \/>\n<strong>(sin keystroke asociada) <\/strong>: &#8216;<span style=\"color: #0000ff;\">tags-apropos<\/span>&#8216;; busca un s\u00edmbolo o parte de \u00e9l.<br \/>\n<strong>(sin keystroke asociada)<\/strong> : &#8216;<span style=\"color: #0000ff;\">list-tags<\/span>&#8216;; lista los s\u00edmbolos de un fichero.<br \/>\n<strong>M-,<\/strong> \u00f3 <strong>M-0 M-.<\/strong> : &#8216;<span style=\"color: #0000ff;\">tags-loop-continue<\/span>&#8216;; se desplaza al siguiente s\u00edmbolo buscado.<br \/>\n<strong>C-u &#8211; M-.<\/strong> ; se desplaza al anterior s\u00edmbolo buscado.<br \/>\n<strong>C-u M-<\/strong><strong>.<\/strong> ; se desplaza al siguiente s\u00edmbolo buscado.<br \/>\n<strong>C-x 4 .<\/strong> : &#8216;find-tag-other-window&#8217;; busca un s\u00edmbolo dado y crea una nueva ventana para ello.<br \/>\n<strong>C-u 5<\/strong><strong> .<\/strong> : &#8216;find-tag-other-frame&#8217;; busca un s\u00edmbolo dado y crea un nuevo frame para ello.<br \/>\n<strong>M-\/<\/strong> ; autocompleta mediante <strong>dabbrev<\/strong> (teniendo en cuenta los <strong>ETAGS<\/strong>).<br \/>\n<strong>M-\/ M-\/<\/strong> (o m\u00e1s repeticiones); autocomplea con la segunda, tercera, etc&#8230; opci\u00f3n.<\/p>\n<p style=\"text-align: left;\">Cuando nos referimos a un s\u00edmbolo nos referimos al nombre de funciones, variables, constantes o macros.<\/p>\n<p style=\"text-align: left;\">Para m\u00e1s informaci\u00f3n sobre como mantener programas de un tama\u00f1o considerable, se puede leer en el <a href=\"http:\/\/www.gnu.org\/software\/emacs\/manual\/html_node\/emacs\/Maintaining.html\" target=\"_blank\" rel=\"noopener\">manual de emacs \u00abhow to maintain large programs\u00bb<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Pr\u00e9viamente hemos comentado en otros art\u00edculos algunas opciones de usar Emacs como IDE para muchos de los lenguajes de programaci\u00f3n que conocemos, y as\u00ed poder usar un mismo entorno para todos ellos sin necesidad de ir cambiando, con el consiguiente tiempo perdido que ello conlleva. Comentamos en art\u00edculos anteriores el usar el c-mode, con los [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[17],"tags":[119,116,122,8,121,115,118,117,96,120],"class_list":["post-65","post","type-post","status-publish","format-standard","hentry","category-basic","tag-autoconf","tag-automake","tag-c","tag-emacs","tag-etags","tag-gnu","tag-gnumake","tag-make","tag-programming","tag-tags"],"_links":{"self":[{"href":"https:\/\/www.blackhats.es\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/65"}],"collection":[{"href":"https:\/\/www.blackhats.es\/wordpress\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.blackhats.es\/wordpress\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.blackhats.es\/wordpress\/index.php?rest_route=\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/www.blackhats.es\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=65"}],"version-history":[{"count":1,"href":"https:\/\/www.blackhats.es\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/65\/revisions"}],"predecessor-version":[{"id":779,"href":"https:\/\/www.blackhats.es\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/65\/revisions\/779"}],"wp:attachment":[{"href":"https:\/\/www.blackhats.es\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=65"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.blackhats.es\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=65"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.blackhats.es\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=65"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}