C++ 为什么';以下重复符号的gcc报告错误?

C++ 为什么';以下重复符号的gcc报告错误?,c++,linux,gcc,compiler-construction,linker,C++,Linux,Gcc,Compiler Construction,Linker,我正在Ubuntu Linux上工作,以构建Android和Linux二进制文件。我有一个由两个共享库链接的静态库,静态库中有一个全局对象 据我所知,全局对象将同时存在于*。因此,并将导致问题,因为每个共享库中的函数符号访问不同的全局变量 (在构建两个共享库时,我在命令行中引用了静态库。我一直在使用-Wl,--whole archive和-Wl,-z,defs开关。因此共享库包含静态库的符号。) 因此,问题是: 在链接可执行文件时,为什么GCC/LD不报告这种情况下的重复符号错误 这是否意味着我

我正在Ubuntu Linux上工作,以构建Android和Linux二进制文件。我有一个由两个共享库链接的静态库,静态库中有一个全局对象

据我所知,全局对象将同时存在于
*。因此
,并将导致问题,因为每个共享库中的函数符号访问不同的全局变量

(在构建两个共享库时,我在命令行中引用了静态库。我一直在使用
-Wl,--whole archive
-Wl,-z,defs
开关。因此共享库包含静态库的符号。)

因此,问题是:

  • 在链接可执行文件时,为什么GCC/LD不报告这种情况下的重复符号错误
  • 这是否意味着我们永远不会链接到应用程序共享库中的同一个静态库和可执行文件本身
  • -----------------编辑1-----------------------

    正如Soha所说,我们不应该在静态库中拥有地位,或者应该提供一个共享库

    我认为有这样的限制是不好的,也是悲哀的:静态库不应该有地位,或者应该作为共享库提供

    原因是: 1.全局变量是常用的,例如在我的例子中,它是一个单例对象。 2.静态库可能由第三方提供。用户也可能使用另一个第三方提供的共享库,该第三方已经链接了静态库,例如boost。

    您说过:

    据我所知,全局对象将同时存在于*.so和*.so中,并且会引起问题,因为每个共享库中的函数符号访问不同的全局变量

    这是正确的。第一个.so使用的全局变量将不同于第二个.so使用的全局变量

    至于你的问题

    当链接可执行文件时,为什么GCC/LD不报告这种情况下的重复符号错误

    就可执行文件而言,它只关心.so库的接口。它不关心它们是使用相同的静态库创建的

    这是否意味着我们永远不会链接到应用程序共享库中的同一个静态库和可执行文件本身

    如果静态库没有状态,这是正常的。如果它们有状态,您必须判断该状态是在整个应用程序中是全局的,还是仅在共享库中

    如果状态需要在整个应用程序中是全局的,那么最好创建另一个提供对全局状态访问的共享库,而不是将其放在静态库中

    如果需要在每个共享库中维护状态,则可以将其放在静态库中。即便如此,创建一个提供数据访问的共享库将是一个更好的解决方案。

    您说过:

    据我所知,全局对象将同时存在于*.so和*.so中,并且会引起问题,因为每个共享库中的函数符号访问不同的全局变量

    这是正确的。第一个.so使用的全局变量将不同于第二个.so使用的全局变量

    至于你的问题

    当链接可执行文件时,为什么GCC/LD不报告这种情况下的重复符号错误

    就可执行文件而言,它只关心.so库的接口。它不关心它们是使用相同的静态库创建的

    这是否意味着我们永远不会链接到应用程序共享库中的同一个静态库和可执行文件本身

    如果静态库没有状态,这是正常的。如果它们有状态,您必须判断该状态是在整个应用程序中是全局的,还是仅在共享库中

    如果状态需要在整个应用程序中是全局的,那么最好创建另一个提供对全局状态访问的共享库,而不是将其放在静态库中

    如果需要在每个共享库中维护状态,则可以将其放在静态库中。即便如此,创建一个提供数据访问的共享库将是一个更好的解决方案。

    经验证据表明,共享库行为依赖于平台 下面是一些普通代码,演示了两个共享库,它们都定义了符号(函数)
    abc_123()
    ,以及调用同一函数的其他函数,以及使用这些函数的测试程序

    lib1.h lib2.h lib1a.c 在Linux上构建和运行 这是来自Ubuntu14.04LTSVM(托管在MacOSX10.9.3上),编译器是GCC4.8.2

    $ make -B SOEXT=so UFLAGS=-fPIC
    gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror -fPIC -c test1.c
    gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror -fPIC -c lib1a.c
    gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror -fPIC -c lib1b.c
    gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror -fPIC -c lib2a.c
    gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror -fPIC -c lib2b.c
    gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror -fPIC -shared -o library2.so lib2a.o lib2b.o
    gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror -fPIC -shared -o library1.so lib1a.o lib1b.o -L. -lrary2
    gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror -fPIC -o test1 test1.o -L. -lrary1 -lrary2
    $ LD_LIBRARY_PATH=$PWD:$LD_LIBRARY_PATH ./test1
    Cross-library linking and calling
    Main calling abc_123(29)
    Library 1:lib1a.c:15:abc_123() - 29
    Note this extra message
    Main calling def_345(45)
    Library 1:lib1b.c:17-->>def_345() - 45
    Library 2:lib2b.c:15-->>ghi_678() - 55
    Library 1:lib1a.c:15:abc_123() - 550
    Note this extra message
    Library 2:lib2b.c:17<<--ghi_678() - 55
    Library 1:lib1b.c:19<<--def_345() - 45
    Main calling ghi_678(57)
    Library 2:lib2b.c:15-->>ghi_678() - 57
    Library 1:lib1a.c:15:abc_123() - 570
    Note this extra message
    Library 2:lib2b.c:17<<--ghi_678() - 57
    Demonstration over
    $
    
    请注意,
    ghi_678()
    中的代码从
    library2.so
    调用
    abc_123()
    ,而不是在Linux上从
    library1.so
    调用的版本

    您可以玩反向链接顺序,然后看看会发生什么

    道德的 不要在多个共享库中构建包含相同功能的软件;如果在平台之间进行移植,您会感到困惑。

    共享库行为依赖于平台的经验证据 下面是一些普通代码,演示了两个共享库,它们都定义了符号(函数)
    abc_123()
    ,以及调用同一函数的其他函数,以及使用这些函数的测试程序

    lib1.h lib2.h lib1a.c 在Linux上构建和运行 这是来自Ubuntu14.04LTSVM(托管在MacOSX10.9.3上),编译器是GCC4.8.2

    $ make -B SOEXT=so UFLAGS=-fPIC
    gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror -fPIC -c test1.c
    gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror -fPIC -c lib1a.c
    gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror -fPIC -c lib1b.c
    gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror -fPIC -c lib2a.c
    gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror -fPIC -c lib2b.c
    gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror -fPIC -shared -o library2.so lib2a.o lib2b.o
    gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror -fPIC -shared -o library1.so lib1a.o lib1b.o -L. -lrary2
    gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror -fPIC -o test1 test1.o -L. -lrary1 -lrary2
    $ LD_LIBRARY_PATH=$PWD:$LD_LIBRARY_PATH ./test1
    Cross-library linking and calling
    Main calling abc_123(29)
    Library 1:lib1a.c:15:abc_123() - 29
    Note this extra message
    Main calling def_345(45)
    Library 1:lib1b.c:17-->>def_345() - 45
    Library 2:lib2b.c:15-->>ghi_678() - 55
    Library 1:lib1a.c:15:abc_123() - 550
    Note this extra message
    Library 2:lib2b.c:17<<--ghi_678() - 55
    Library 1:lib1b.c:19<<--def_345() - 45
    Main calling ghi_678(57)
    Library 2:lib2b.c:15-->>ghi_678() - 57
    Library 1:lib1a.c:15:abc_123() - 570
    Note this extra message
    Library 2:lib2b.c:17<<--ghi_678() - 57
    Demonstration over
    $
    
    请注意,
    ghi_678()
    中的代码从
    library2.so
    调用
    abc_123()
    ,而不是在Linux上从
    library1.so
    调用的版本

    您可以玩反向链接顺序,然后看看会发生什么

    道德的 不要构建软件
    #include <stdio.h>
    #include "lib1.h"
    
    void abc_123(int i)
    {
        printf("Library 1:%s:%d:%s() - %d\n", __FILE__, __LINE__, __func__, i);
        printf("Note this extra message\n");
    }
    
    #include <stdio.h>
    #include "lib1.h"
    #include "lib2.h"
    
    void def_345(int i)
    {
        printf("Library 1:%s:%d-->>%s() - %d\n", __FILE__, __LINE__, __func__, i);
        ghi_678(i+10);
        printf("Library 1:%s:%d<<--%s() - %d\n", __FILE__, __LINE__, __func__, i);
    }
    
    #include <stdio.h>
    #include "lib2.h"
    
    void abc_123(int i)
    {
        printf("Library 2:%s:%d:%s() - %d\n", __FILE__, __LINE__, __func__, i);
        printf("This is a completely different message\n");
    }
    
    #include <stdio.h>
    #include "lib2.h"
    
    void ghi_678(int i)
    {
        printf("Library 2:%s:%d-->>%s() - %d\n", __FILE__, __LINE__, __func__, i);
        abc_123(i * 10);
        printf("Library 2:%s:%d<<--%s() - %d\n", __FILE__, __LINE__, __func__, i);
    }
    
    #include <stdio.h>
    #include "lib1.h"
    #include "lib2.h"
    
    int main(void)
    {
        printf("Cross-library linking and calling\n");
        printf("Main calling abc_123(29)\n");
        abc_123(29);
        printf("Main calling def_345(45)\n");
        def_345(45);
        printf("Main calling ghi_678(57)\n");
        ghi_678(57);
        printf("Demonstration over\n");
        return 0;
    }
    
    CC     = gcc #/usr/bin/gcc
    WFLAG1 = -Wall
    WFLAG2 = -Wextra
    WFLAG3 = -Wmissing-prototypes
    WFLAG4 = -Wstrict-prototypes
    WFLAG5 = -Wold-style-definition
    WFLAG6 = -Werror
    WFLAGS = ${WFLAG1} ${WFLAG2} ${WFLAG3} ${WFLAG4} ${WFLAG5} ${WFLAG6}
    SFLAGS = -std=c11
    GFLAGS = -g
    OFLAGS = -O3
    UFLAGS = # Set on command line
    IFLAG1 = # -I${HOME}/inc
    IFLAGS = # ${IFLAG1}
    
    SOEXT   = dylib
    LDFLAG1 = -L.
    LDLIB1  = -lrary1
    LDLIB2  = -lrary2
    LDFLAGS = ${LDFLAG1}
    LDLIBS  = ${LDLIB1} ${LDLIB2}
    
    CFLAGS  = ${OFLAGS} ${GFLAGS} ${IFLAGS} ${SFLAGS} ${WFLAGS} ${UFLAGS}
    
    LNKSHLIB = -shared
    
    LIBRARY1 = library1.${SOEXT}
    LIBRARY2 = library2.${SOEXT}
    
    LIB1.o  = lib1a.o lib1b.o
    LIB2.o  = lib2a.o lib2b.o
    TEST1.o = test1.o
    
    PROGRAM = test1
    
    all: ${PROGRAM}
    
    ${PROGRAM}: ${TEST1.o} ${LIBRARY1} ${LIBRARY2}
        ${CC} ${CFLAGS} -o $@ ${TEST1.o} ${LDFLAGS} ${LDLIBS}
    
    ${LIBRARY1}: ${LIB1.o} ${LIBRARY2}
        ${CC} ${CFLAGS} ${LNKSHLIB} -o $@ ${LIB1.o} ${LDFLAGS} ${LDLIB2}
    
    ${LIBRARY2}: ${LIB2.o}
        ${CC} ${CFLAGS} ${LNKSHLIB} -o $@ ${LIB2.o}
    
    $ make -B SOEXT=so UFLAGS=-fPIC
    gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror -fPIC -c test1.c
    gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror -fPIC -c lib1a.c
    gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror -fPIC -c lib1b.c
    gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror -fPIC -c lib2a.c
    gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror -fPIC -c lib2b.c
    gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror -fPIC -shared -o library2.so lib2a.o lib2b.o
    gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror -fPIC -shared -o library1.so lib1a.o lib1b.o -L. -lrary2
    gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror -fPIC -o test1 test1.o -L. -lrary1 -lrary2
    $ LD_LIBRARY_PATH=$PWD:$LD_LIBRARY_PATH ./test1
    Cross-library linking and calling
    Main calling abc_123(29)
    Library 1:lib1a.c:15:abc_123() - 29
    Note this extra message
    Main calling def_345(45)
    Library 1:lib1b.c:17-->>def_345() - 45
    Library 2:lib2b.c:15-->>ghi_678() - 55
    Library 1:lib1a.c:15:abc_123() - 550
    Note this extra message
    Library 2:lib2b.c:17<<--ghi_678() - 55
    Library 1:lib1b.c:19<<--def_345() - 45
    Main calling ghi_678(57)
    Library 2:lib2b.c:15-->>ghi_678() - 57
    Library 1:lib1a.c:15:abc_123() - 570
    Note this extra message
    Library 2:lib2b.c:17<<--ghi_678() - 57
    Demonstration over
    $
    
    $ make -B
    gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror -c -o test1.o test1.c
    gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror -c -o lib1a.o lib1a.c
    gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror -c -o lib1b.o lib1b.c
    gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror -c -o lib2a.o lib2a.c
    gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror -c -o lib2b.o lib2b.c
    gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror -shared -o library2.dylib lib2a.o lib2b.o
    gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror -shared -o library1.dylib lib1a.o lib1b.o -L. -lrary2
    gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror -o test1 test1.o -L. -lrary1 -lrary2
    $ ./test1
    Cross-library linking and calling
    Main calling abc_123(29)
    Library 1:lib1a.c:15:abc_123() - 29
    Note this extra message
    Main calling def_345(45)
    Library 1:lib1b.c:17-->>def_345() - 45
    Library 2:lib2b.c:15-->>ghi_678() - 55
    Library 2:lib2a.c:16:abc_123() - 550
    This is a completely different message
    Library 2:lib2b.c:17<<--ghi_678() - 55
    Library 1:lib1b.c:19<<--def_345() - 45
    Main calling ghi_678(57)
    Library 2:lib2b.c:15-->>ghi_678() - 57
    Library 2:lib2a.c:16:abc_123() - 570
    This is a completely different message
    Library 2:lib2b.c:17<<--ghi_678() - 57
    Demonstration over
    $