代码之家  ›  专栏  ›  技术社区  ›  Jay Conrod

为什么属性(constructor)不能在静态库中工作?

  •  25
  • Jay Conrod  · 技术社区  · 15 年前

    在下面的示例中,程序应打印“foo called”:

    // foo.c
    #include <stdio.h>
    
    __attribute__((constructor)) void foo()
    {
        printf("foo called\n");
    }
    
    // main.c
    int main()
    {
        return 0;
    }
    

    如果程序是这样编译的,它会工作:

    gcc -o test main.c foo.c
    

    但是,如果foo.c被编译成一个静态库,那么程序将不打印任何内容。

    gcc -c main.c
    gcc -c foo.c
    as rcs foo.a foo.o
    gcc -o test foo.a main.o
    

    为什么会这样?

    2 回复  |  直到 8 年前
        1
  •  13
  •   Jay Conrod    15 年前

    链接器不将foo.a中的代码包含在最终程序中,因为main.o中没有引用该代码。如果 main.c 重写如下,程序将工作:

    //main.c
    
    void foo();
    
    int main()
    {
        void (*f)() = foo;
        return 0;
    }
    

    另外,当使用静态库编译时,gcc(或链接器)参数的顺序也很重要:库必须位于引用它的对象之后。

    gcc -o test main.o foo.a
    
        2
  •  3
  •   yerden roolebo    8 年前

    如前所述,来自存档的未引用符号不会使其成为输出二进制文件,因为链接器在默认情况下会丢弃它们。

    要在与静态库链接时重写此行为, --whole-archive / --no-whole-archive 可以使用链接器的选项,如下所示:

    gcc -c main.c
    gcc -c foo.c
    ar rcs foo.a foo.o
    gcc -o test -Wl,--whole-archive foo.a -Wl,--no-whole-archive main.o
    

    这可能导致二进制文件膨胀,因为来自 foo.a 将由链接器包含到输出中,但有时是合理的。