Un archivo de archivo (archive) es un archivo que agrupa subarchivos con nombre llamados miembros. Los archivos de archivo se gestionan con el programa ar y se usan principalmente como bibliotecas de subrutinas para el enlazado.
Cada uno de los miembros de un archivo de archivo puede usarse como objetivo o prerrequisito (prerequisite) de make. El miembro llamado member dentro del archivo de archivo archive se especifica así:
archive(member)
Esta forma de escribir solo puede usarse en objetivos y prerrequisitos, ¡no en las recetas (recipe)! La mayoría de los programas que se emplean en las recetas no admiten esta sintaxis y no pueden actuar directamente sobre los miembros de un archivo. Solo ar y otros programas diseñados especialmente para operar sobre archivos de archivo pueden hacerlo. Por tanto, una receta válida para actualizar un objetivo que sea un miembro de archivo probablemente deba usar ar. Por ejemplo, la siguiente regla indica que se cree el miembro hack.o en el archivo de archivo foolib copiando el archivo hack.o:
foolib(hack.o) : hack.o
ar cr foolib hack.o
De hecho, casi todos los objetivos que son miembros de archivo se actualizan justamente de esta manera, por lo que existe una regla implícita que lo hace automáticamente. [Importante] Si el archivo de archivo todavía no existe, hay que añadir el indicador ‘c’ a ar.
Para especificar varios miembros del mismo archivo de archivo, puede escribir todos los nombres de los miembros juntos entre paréntesis. Por ejemplo, si escribe lo siguiente:
foolib(hack.o kludge.o)
significa lo mismo que si hubiera escrito:
foolib(hack.o) foolib(kludge.o)
En las referencias a miembros de archivo también puede usar comodines al estilo del shell. Consulte Usar caracteres comodín en los nombres de archivo. Por ejemplo, ‘foolib(*.o)’ se expande a todos los miembros existentes del archivo de archivo foolib cuyo nombre termina en ‘.o’; por ejemplo, ‘foolib(hack.o) foolib(kludge.o)’.
Recuerde que un objetivo con la forma a(m) representa el miembro llamado m dentro del archivo de archivo a.
Cuando make busca una regla implícita para un objetivo de este tipo, como característica especial considera no solo las reglas que coinciden con el objetivo real a(m), sino también las reglas implícitas que coinciden con (m).
Gracias a esto coincide una regla especial cuyo objetivo es (%). Esta regla actualiza el objetivo a(m) copiando el archivo m dentro del archivo de archivo. Por ejemplo, actualiza el objetivo miembro de archivo foo.a(bar.o) copiando el archivo bar.o dentro del archivo de archivo foo.a como un miembro llamado bar.o.
Cuando esta regla se encadena con otras, el resultado es muy potente. Por eso, si existe un archivo bar.c, basta con escribir ‘make "foo.a(bar.o)"’ (las comillas son necesarias para evitar que el shell interprete ‘(’ y ‘)’ con un significado especial), aunque no haya ningún makefile, para que se ejecute la siguiente receta:
cc -c bar.c -o bar.o ar r foo.a bar.o rm -f bar.o
Aquí make ha concebido el archivo bar.o como un archivo intermedio. Consulte Cadenas de reglas implícitas.
Las reglas implícitas como esta se escriben usando la variable automática ‘$%’. Consulte Variables automáticas.
El nombre de un miembro dentro de un archivo de archivo no puede contener un nombre de directorio, pero en un makefile puede resultar útil simular que sí lo contiene. Si escribe el objetivo miembro de archivo foo.a(dir/file.o), make realizará la actualización automática con esta receta:
ar r foo.a dir/file.o
lo que tiene el efecto de copiar el archivo dir/file.o en un miembro llamado file.o. En relación con este tipo de uso, pueden ser útiles las variables automáticas %D y %F.
Un archivo de archivo que se usa como biblioteca normalmente contiene un miembro especial llamado __.SYMDEF que mantiene un directorio de los nombres de los símbolos externos definidos por todos los demás miembros. Después de actualizar cualquier otro miembro, hay que actualizar __.SYMDEF para que resuma correctamente los demás miembros. Esto se hace ejecutando el programa ranlib:
ranlib archivefile
Normalmente pondría esta orden en la regla del archivo de archivo y haría que todos los miembros del archivo de archivo fueran prerrequisitos de esa regla. Por ejemplo, escribiría lo siguiente:
libfoo.a: libfoo.a(x.o y.o …)
ranlib libfoo.a
Con esto se actualizan los miembros de archivo x.o, y.o, etc., y a continuación, ejecutando ranlib, se actualiza el miembro __.SYMDEF, que es el directorio de símbolos. Las reglas para actualizar los miembros no se muestran aquí; lo más probable es que pueda omitirlas y dejar el trabajo a la regla implícita que copia archivos dentro del archivo de archivo, descrita en la sección anterior.
Tenga en cuenta que esto no es necesario si usa el programa ar de GNU, ya que el ar de GNU actualiza el miembro __.SYMDEF automáticamente.
Las reglas incorporadas para actualizar archivos de archivo son incompatibles con las compilaciones en paralelo. Estas reglas (exigidas por el estándar POSIX) añaden cada archivo objeto al archivo de archivo a medida que se compila. Cuando la ejecución en paralelo está activada, esto provoca que varias órdenes ar intenten actualizar el mismo archivo de archivo simultáneamente, lo cual no está admitido.
Si quiere usar compilaciones en paralelo con archivos de archivo, puede anular las reglas predeterminadas añadiendo estas líneas a su makefile:
(%) : % ; %.a : ; $(AR) $(ARFLAGS) $@ $?
La primera línea cambia la regla que actualiza cada objeto individual del archivo de archivo para que no haga nada. La segunda línea cambia la regla predeterminada de construcción del archivo de archivo para que actualice todos los objetos desactualizados ($?) con una sola orden.
Por supuesto, los prerrequisitos de su biblioteca todavía deben declararse usando la sintaxis de archivo de archivo:
libfoo.a: libfoo.a(x.o y.o …)
Si prefiere escribir una regla explícita, puede usar lo siguiente:
libfoo.a: libfoo.a(x.o y.o …)
$(AR) $(ARFLAGS) $@ $?
También puede escribir un tipo especial de regla de sufijo para tratar con archivos de archivo. Para una explicación completa de las reglas de sufijo, consulte Reglas de sufijo a la antigua usanza. Las reglas de sufijo para archivos de archivo están obsoletas en GNU make, porque las reglas de patrón para archivos de archivo son un mecanismo más general (consulte Regla implícita para objetivos que son miembros de archivo). No obstante, se conservan por compatibilidad con otros make.
Para escribir una regla de sufijo para archivos de archivo, basta con escribir una regla de sufijo usando el sufijo de objetivo ‘.a’ (el sufijo habitual de los archivos de archivo). Por ejemplo, esta es la regla de sufijo a la antigua usanza para actualizar una biblioteca de archivo a partir de archivos fuente en C:
.c.a:
$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $*.o
$(AR) r $@ $*.o
$(RM) $*.o
Esto funciona exactamente igual que si hubiera escrito la siguiente regla de patrón:
(%.o): %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $*.o
$(AR) r $@ $*.o
$(RM) $*.o
De hecho, esto es justo lo que hace make cuando ve una regla de sufijo con ‘.a’ como sufijo de objetivo. Toda regla de doble sufijo de la forma ‘.x.a’ se convierte en una regla de patrón cuyo patrón de objetivo es ‘(%.o)’ y cuyo patrón de prerrequisito es ‘%.x’.
Como puede que quiera usar ‘.a’ como sufijo de algún otro tipo de archivo, make también convierte las reglas de sufijo para archivos de archivo en reglas de patrón de la manera habitual (consulte Reglas de sufijo a la antigua usanza). Así, una regla de doble sufijo ‘.x.a’ produce dos reglas de patrón: ‘(%.o): %.x’ y ‘%.a: %.x’.