如果TU中没有明确来自另一个TU的函数,我将看到LTO从TU中优化一些全局对象。
以下摘录试图描述所涉及的关键类和文件(请注意,这只是为了演示目的,不一定在所有地方都是完全准确的):
我有一个单例类Registrar,它维护已构造的Foo类型的所有对象的列表。为了避免构造失败的静态顺序,在构造第一个Foo类型的对象时,动态地构造该对象的实例。
// Registrar.hpp
class Registrar
{
public:
static Registrar * sRegistrar;
std::vector<Foo *> objectList;
Registrar() = default;
};接下来,我们有了类Foo。如上所述,该类的实例在Registrar中注册。
// Foo.hpp
class Foo
{
public:
Foo()
{
if (Registrar::sRegistrar == nullptr)
Registrar::sRegistrar = new Registrar();
Registrar::sRegistrar->objectList.push_back(this);
}
};Foo的实例是可以从多个文件创建的全局实例。在一个这样的文件中,我们碰巧定义了另一个从其他地方调用的函数:
// file1.hpp
void someFunctionThatIsCalledExplicitly()
{
doSomething();
}
namespace
{
__attribute__((used, retain))
Foo f1;
}但是在另一个文件中,我们只创建了一个Foo实例:
// file2.hpp
namespace
{
__attribute__((used, retain))
Foo f2;
}我看到的是,f2正在被优化,而f1没有优化,尽管为类Foo的所有声明添加了__attribute__((used, retain))。
我应该如何防止LTO优化这些实例?为什么这些属性没有什么区别?
编辑:我编写了一个小示例来再现上述问题。
#include <iostream>
#include "Registrar.hpp"
#ifdef FORCE_LINKAGE
extern int i;
#endif
extern void someFunctionThatIsCalledExplicitly();
int main()
{
#ifdef FORCE_LINKAGE
i++;
#endif
someFunctionThatIsCalledExplicitly();
if (Registrar::sRegistrar == nullptr)
{
std::cout << "No instances of foo";
}
else
{
std::cout << Registrar::sRegistrar->objectList.size() << " instances of foo\n";
}
return 0;
}#pragma once
class Foo
{
public:
Foo();
};#include "Foo.hpp"
#include "Registrar.hpp"
Foo::Foo()
{
if (Registrar::sRegistrar == nullptr)
{
Registrar::sRegistrar = new Registrar();
}
Registrar::sRegistrar->objectList.push_back(this);
}#pragma once
#include <vector>
#include "Foo.hpp"
class Registrar
{
public:
static Registrar * sRegistrar;
std::vector<Foo *> objectList;
Registrar() = default;
};#include "Registrar.hpp"
Registrar * Registrar::sRegistrar = nullptr;#include <iostream>
#include "Foo.hpp"
void someFunctionThatIsCalledExplicitly()
{
std::cout << "someFunctionThatIsCalledExplicitly() called\n";
}
namespace
{
__attribute__((used, retain))
Foo f1;
}#include "Foo.hpp"
#ifdef FORCE_LINKAGE
int i = 0;
#endif
namespace
{
__attribute__((used, retain))
Foo f2;
}CC = clang++
LIBTOOL = libtool
BUILDDIR = build
BINFILE = lto
BUILDFLAGS = -flto -std=c++17
LINKFLAGS = -flto
.PHONY: all
all: $(BUILDDIR) $(BINFILE)
.PHONY: force
force: def all
.PHONY: def
def:
$(eval BUILDFLAGS += -DFORCE_LINKAGE)
$(BINFILE): foo files
$(CC) -o $(BUILDDIR)/$@ $(LINKFLAGS) -L$(BUILDDIR) $(addprefix -l, $^)
foo: Foo.o main.o Registrar.o
$(LIBTOOL) $(STATIC) -o $(BUILDDIR)/lib$@.a $(addprefix $(BUILDDIR)/, $^)
files: File1.o File2.o
$(LIBTOOL) $(STATIC) -o $(BUILDDIR)/lib$@.a $(addprefix $(BUILDDIR)/, $^)
%.o: %.cpp
$(CC) $(BUILDFLAGS) -c -o $(addprefix $(BUILDDIR)/, $@) $<
.PHONY: $(BUILDDIR)
$(BUILDDIR):
mkdir -p $(BUILDDIR)
.PHONY: clean
clean:
rm -rf $(BUILDDIR)我有两个变体,一个类似于上面(我只看到一个实例),另一个通过声明其他地方引用的全局变量来强制链接(这里我看到了这两个实例):
$ make
$ ./build/lto
someFunctionThatIsCalledExplicitly() called
1 instances of foo
$ make force
$ ./build/lto
someFunctionThatIsCalledExplicitly() called
2 instances of foo发布于 2022-07-14 23:37:49
好的,我做了一些调查,而且链接.a库是这里的罪魁祸首,不是LTO,也不是任何其他优化。
这是在此之前提过的,参见:Static initialization and destruction of a static library's globals not happening with g++
当链接.o文件时(就像我在戈德波特上做的那样),一切都会进入并工作。
对于.a文件,只有引用的代码被链接,其余的则不链接。创建虚拟变量是一个解决办法,但正确的方法是将--whole-archive传递给链接器。
由于libtool的问题,我无法运行基于makefile的示例,但是请看一下我的CMake配置:
cmake_minimum_required(VERSION 3.18)
project(LINK)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
add_library(Files File1.cpp File2.cpp)
target_include_directories(Files
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
)
target_compile_definitions(Files PUBLIC ${FORCE})
add_executable(test Foo.cpp main.cpp Registrar.cpp)
# note the line below
target_link_libraries(test -Wl,--whole-archive Files -Wl,--no-whole-archive)
target_compile_definitions(test PUBLIC ${FORCE})当链接时,它将以以下方式调用命令:
g++ -o test -Wl, --whole-archive -l:libFiles.a -Wl, --no-whole-archive Foo.o Registrar.o main.o
https://stackoverflow.com/questions/72958278
复制相似问题