GNU/Linux >> Tutoriales Linux >  >> Linux

Archivos .o frente a archivos .a

.o Los archivos son objetos. Son la salida del compilador y la entrada al enlazador/bibliotecario.

.a los archivos son archivos. Son grupos de objetos o bibliotecas estáticas y también se ingresan en el enlazador.

Contenido adicional

No noté la parte de "ejemplos" de su pregunta. Por lo general, usará un archivo MAKE para generar bibliotecas estáticas.

AR = ar 
CC = gcc

objects := hello.o world.o

libby.a: $(objects)
    $(AR) rcu [email protected] $(objects)

%.o: %.c
    $(CC) $(CFLAGS) -c $< -o [email protected]

Esto compilará hello.c y world.c en objetos y luego archivarlos en la biblioteca. Dependiendo de la plataforma, es posible que también deba ejecutar una utilidad llamada ranlib para generar la tabla de contenido en el archivo.

Una nota al margen interesante:.a los archivos son técnicamente archivos de archivo y no bibliotecas. Son análogos a los archivos zip sin compresión, aunque utilizan un formato de archivo mucho más antiguo. La tabla de contenido generada por utilidades como ranlib es lo que hace que un archivo sea una biblioteca . Archivos de almacenamiento de Java (.jar ) son similares en el sentido de que son archivos zip que tienen algunas estructuras de directorio especiales creadas por el archivador de Java.


Hay un aspecto más de vincular contra .a contra .o archivos:al vincular, todos .o s pasados ​​como argumentos se incluyen en el ejecutable final, mientras que las entradas de cualquier .a los argumentos solo se incluyen en la salida del enlazador si resuelven una dependencia de símbolo en el programa.

Más específicamente, cada .a archivo es un archivo que comprende múltiples .o archivos Puedes pensar en cada .o siendo una unidad atómica de código. Si el enlazador necesita un símbolo de una de estas unidades, la unidad completa es absorbida por el binario final; pero ninguno de los otros lo son a menos que también sean necesarios.

Por el contrario, cuando pasa un .o en la línea de comando, el enlazador lo absorbe porque lo solicitaste.

Para ilustrar esto, considere el siguiente ejemplo, donde tenemos una biblioteca estática que comprende dos objetos a.o y b.o . Nuestro programa solo hará referencia a símbolos de a.o . Compararemos cómo trata el enlazador pasar a.o y b.o juntos, frente a la biblioteca estática que comprende los mismos dos objetos.

// header.hh
#pragma once

void say_hello_a();
void say_hello_b();
// a.cc
#include "header.hh"
#include <iostream>

char hello_a[] = "hello from a";

void say_hello_a()
{
        std::cout << hello_a << '\n';
}
// b.cc
#include "header.hh"
#include <iostream>

char hello_b[] = "hello from b";

void say_hello_b()
{
        std::cout << hello_b << '\n';
}
// main.cc
#include "header.hh"

int main()
{
        say_hello_a();
}

Podemos compilar el código usando este Makefile:

.PHONY = compile archive link all clean

all: link

compile:
        @echo ">>> Compiling..."
        g++ -c a.cc b.cc main.cc

archive: compile
        @echo ">>> Archiving..."
        ar crs lib.a a.o b.o

link: archive
        @echo ">>> Linking..."
        g++ -o main_o main.o a.o b.o
        g++ -o main_a main.o lib.a

clean:
        rm *.o *.a main_a main_o

y obtenga dos ejecutables main_o y main_a que difieren en que el contenido de a.cc y b.cc donde se proporciona a través de dos .o s en el primer caso y mediante un .a en el segundo.

Por último, examinamos los símbolos de los ejecutables finales usando el nm herramienta:

$ nm --demangle main_o | grep hello
00000000000011e9 t _GLOBAL__sub_I_hello_a
000000000000126e t _GLOBAL__sub_I_hello_b
0000000000004048 D hello_a
0000000000004058 D hello_b
0000000000001179 T say_hello_a()
00000000000011fe T say_hello_b()
$ nm --demangle main_a | grep hello
00000000000011e9 t _GLOBAL__sub_I_hello_a
0000000000004048 D hello_a
0000000000001179 T say_hello_a()

y observa que main_a de hecho, carece de los símbolos innecesarios de b.o . Es decir, el enlazador no absorbió el contenido de b.o dentro del archivo lib.a porque ninguno de los símbolos de b.cc fueron referenciados.


Un archivo .o es el resultado de compilar una sola unidad de compilación (esencialmente, un archivo de código fuente, con archivos de encabezado asociados), mientras que un archivo .a es uno o más archivos .o empaquetados como una biblioteca.


La respuesta de D Shawley es buena, solo quería agregar un par de puntos porque otras respuestas reflejan una comprensión incompleta de lo que está pasando.

Tenga en cuenta que los archivos de almacenamiento (.a) no están restringidos a contener archivos de objetos (.o). Pueden contener archivos arbitrarios. No suele ser útil, pero vea la información de dependencia del enlazador dinámico incrustada en un archivo para un estúpido truco del enlazador.

Observe también que los archivos de objeto (.o) no son necesariamente el resultado de una sola unidad de compilación. Es posible vincular parcialmente varios archivos de objetos más pequeños en un solo archivo más grande.

http://www.mihaiu.name/2002/library_development_linux/ -- busque en esta página "parcial"


Linux
  1. ¿Cambiar el nombre de los archivos en el directorio?

  2. Comandos de búsqueda de Linux

  3. archivos de registro de Linux

  4. Usando rsync para sincronizar archivos

  5. wc archivos comprimidos con gzip?

Encuentra archivos grandes en Linux

Comando Rm en Linux

Mostrar archivos ocultos

Encontrar archivos en Ubuntu 22.04

Comando ls en Linux/UNIX

Cómo encontrar archivos en Debian