.o files vs .a files

前端 未结 6 597
离开以前
离开以前 2021-01-30 16:20

What is the difference between these two file types. I see that my C++ app links against both types during the construction of the executable.

How to build .a files? li

6条回答
  •  栀梦
    栀梦 (楼主)
    2021-01-30 16:30

    There is one more aspect of linking against .a vs .o files: when linking, all .os passed as arguments are included in the final executable, whereas entries from any .a arguments are only included in the linker output if they resolve a symbol dependency in the program.

    More specifically, each .a file is an archive comprising multiple .o files. You can think of each .o being an atomic unit of code. If the linker needs a symbol from one of these units, the whole unit gets sucked into the final binary; but none of the others are unless they too are needed.

    In contrast, when you pass a .o on the command line, the linker sucks it in because you requested it.

    To illustrate this, consider the following example, where we have a static library comprising two objects a.o and b.o. Our program will only reference symbols from a.o. We will compare how the linker treats passing a.o and b.o together, vs. the static library which comprises the same two objects.

    // header.hh
    #pragma once
    
    void say_hello_a();
    void say_hello_b();
    
    // a.cc
    #include "header.hh"
    #include 
    
    char hello_a[] = "hello from a";
    
    void say_hello_a()
    {
            std::cout << hello_a << '\n';
    }
    
    // b.cc
    #include "header.hh"
    #include 
    
    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();
    }
    

    We can compile the code using this 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
    

    and obtain two executables main_o and main_a that differ in that the contents of a.cc and b.cc where provided through two .os in the first case and through a .a in the second.

    Lastly we examine the symbols of the final executables using the nm tool:

    $ 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()
    

    and observe that main_a is in fact lacking the unneeded symbols from b.o. That is, the linker did not suck in the contents of b.o within the archive lib.a because none of the symbols from b.cc were referenced.

提交回复
热议问题