简体   繁体   English

为什么 linker 在链接共享和 static 时不会抱怨多个定义

[英]Why linker does not complain about multiple definitions when linking against shared and static

I've encountered recently on a problem with static initialization fiasco in the code that I was developing.我最近在我正在开发的代码中遇到了 static 初始化失败的问题。 It made me realize my lack of knowledge about linking process and global variables initialization so I've found this this very interesting talks at cppcon about globals, linking and possible issue with having static library embedded in shared and linking both at the same time (with globals defined).这让我意识到我缺乏关于链接过程和全局变量初始化的知识,所以我在 cppcon 上发现了这个非常有趣的关于全局变量、链接以及将 static 库嵌入共享和同时链接的可能问题(与全局变量定义)。 What was basically said there is that when having following structure:基本上说的是,当具有以下结构时:

//static.hpp
#pragma once

#include <string>

extern std::string globalString;

//static.cpp
#include "static.hpp"

std::string globalString;

//shared.hpp
#pragma once

#include "static.hpp"
#include <string>

std::string& getGlobalString();

//shared.cpp
#include "shared.hpp"
#include "static.hpp"

std::string& getGlobalString(){
  return globalString;
}

//main.cpp
#include "static.hpp"
#include "shared.hpp"
#include <iostream>

int main(){
    std::cout << "Global variable: " << globalString <<  std::endl;
    std::cout << "Global var acccesed through shared lib: " << getGlobalString() << std::endl;
    return 0;
}

All compiled with:所有编译:

clang++ -c -std=c++14 -fpic static.cpp
clang++ -c -std=c++14 -fpic shared.cpp
clang++ -c -std=c++14 main.cpp
ar rsc libstatic.a static.o
clang++ -shared -o libshared.so shared.o -L./ -lstatic
clang++ -L./ -Wl,-rpath=./ main.o -lstatic -lshared

My lead to segmentation fault due to calling multiple times constructor and destructor of the same object.由于多次调用同一个 object 的构造函数和析构函数,导致分段错误。 This is surprising as I took this as invariant that every object constructor will be called exactly once!这是令人惊讶的,因为我认为每个 object 构造函数都将被调用一次是不变的!

  • What standard says about calling constructor/destructor multiple times?关于多次调用构造函数/析构函数的标准是什么?
  • If in that case the global of static i embedded in both main.o and libshared.so the does it mean that rule of having one definition is broken?如果在这种情况下,我将 static 的全局嵌入到 main.o 和 libshared.so 中,这是否意味着有一个定义的规则被打破了? Why linker does not complain about having second definition available while linking main?为什么 linker 在链接 main 时没有抱怨第二个定义可用?
  • One of suggested ways to establish construction and destruction order when having at least two global in separate translation unit would be to Initialize when first use.当在单独的翻译单元中至少有两个全局时,建立构造和销毁顺序的建议方法之一是在第一次使用时进行初始化。 This is however ensures only construction order as far as I understand.然而,据我所知,这只能确保施工顺序。 What about destruction order?毁灭令呢? How to control?如何控制?

This is surprising as I took this as invariant that every object constructor will be called exactly once!这是令人惊讶的,因为我认为每个 object 构造函数都将被调用一次是不变的!

In a properly constructed binary that would be true.在正确构造的二进制文件中,这是正确的。 It is not necessarily true in a binary with an ODR violation.在具有 ODR 违规的二进制文件中不一定正确。

What standard says about calling constructor/destructor multiple times?关于多次调用构造函数/析构函数的标准是什么?

The standard says that in a properly constructed program, constructor / destructor is called exactly once.该标准规定,在正确构造的程序中,构造函数/析构函数只被调用一次。 In a program with an ODR violation, anything can happen (undefined behavior).在违反 ODR 的程序中,任何事情都可能发生(未定义的行为)。

If in that case the global of static i embedded in both main.o and libshared.so the does it mean that rule of having one definition is broken?如果在这种情况下,我将 static 的全局嵌入到 main.o 和 libshared.so 中,这是否意味着有一个定义的规则被打破了?

Yes.是的。

Why linker does not complain about having second definition available while linking main?为什么 linker 在链接 main 时没有抱怨第二个定义可用?

As far as linker is concerned, there is nothing wrong with your program.就 linker 而言,你的程序没有问题。 From the linker perspective, defining a global in both static and shared library is perfectly kosher.从 linker 的角度来看,在 static 和共享库中定义一个全局是完美的。 See also this answer .另请参阅此答案

One of suggested ways to establish construction and destruction order when having at least two global in separate translation unit would be to Initialize when first use.当在单独的翻译单元中至少有两个全局时,建立构造和销毁顺序的建议方法之一是在第一次使用时进行初始化。 This is however ensures only construction order as far as I understand.然而,据我所知,这只能确保施工顺序。

Correct.正确的。 This is a solution for a different problem: two globals A and B defined in separate translation units.这是针对不同问题的解决方案:两个全局变量 A 和 B 在单独的翻译单元中定义。

You don't have that problem, you have a totally different one (ODR violation).你没有那个问题,你有一个完全不同的问题(违反 ODR)。

What about destruction order?毁灭令呢? How to control?如何控制?

In a properly constructed program, destruction order is guaranteed to be reverse of construction order.在正确构造的程序中,破坏顺序保证与构造顺序相反。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么 g++ 链接器会抱怨头文件? - Why does g++ linker complain about header file? 为什么链接器允许多个符号定义? - Why does linker allow multiple symbol definitions? 为什么链接程序不抱怨多个函数定义(仅对于模板函数)? - Why is the linker not complaining about multiple function definitions (only with templated functions)? 为什么ld链接器允许使用相同的方法定义多个类? - Why does the ld linker allow multiple class definitions with the same methods? 将构建的 libevent 作为 static 库链接时出现 Linker 错误,但在作为共享库链接时有效 - Linker errors when linking a built libevent as a static library, but works when linking as a shared library 为什么编译器会抱怨对齐? - Why does the compiler complain about the alignment? 为什么gcc抱怨我的循环? - Why does gcc complain about my loops? 为什么编译器抱怨这不是constexpr? - Why does the compiler complain about this not being a constexpr? 为什么当我不移动任何东西时,clang会抱怨删除的移动? - Why does clang complain about a deleted move ctor when I don't move anything? 为什么在使用 char * 时 sip 会抱怨意外类型“str”? - Why does sip complain about unexpected type 'str' when using a char *?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM