跳转至

GCC Compile Error

导言

遇到过的c++编译error

大型项目(许多git未跟踪的三方库+临时文件)重新编译报错

  • 详细记录从干净git仓库编译的流程
  • 及时git保存代码的修改
  • 使用git clean -dfx来回退。其余make cleanpython setup.py clean都不靠谱,毕竟具体操作也是人写的,很可能过时,未维护了。

git clean -dfx注意事项

  • 命令是删除多余的文件和目录(包括.gitignore里),对于已跟踪文件里的修改不会还原,但是新文件和目录会被删除。
  • 建议先git stash或者git stage保存。

选项说明:

  • -d 选项表示同时删除未跟踪的目录。
  • -f 选项表示强制执行,即使未跟踪的文件和目录与已跟踪的文件同名也会被删除。
  • -x 选项表示删除所有未跟踪的文件(包括那些.gitignore文件中指定忽略的文件)。
libxxx.so: undefined symbol
ImportError: /home/anaconda3/envs/t00906153_bindCore/lib/python3.8/site-packages/torch_npu/lib/libtorch_npu.so: undefined symbol: _ZN7c10_npu17SetThreadAffinityEi
  • c++filt _ZNK4Json5ValueixEPKc得到unwind的函数名。
  • nm -gD libxxx.so |grep name 确定 是否未定义
  • 编译环境的不同会导致,编译选项多了-D_GLIBCXX_USE_CXX11_ABI=1,会让函数在wind的过程中的结尾有类似__cxx1112basic_,这细微的差别会导致匹配不上。
  • fzf查看编译中间变量.o是否生成
    • 如果没有,很可能是make时没有添加cpp, 或者cmake没有添加新文件
Error: multiple definition
CMakeFiles/torch_npu.dir/torch_npu/csrc/utils/TensorType.cpp.o:(.bss+0x58): multiple definition of c10_npu::threadNameToType'
CMakeFiles/torch_npu.dir/torch_npu/csrc/aten/NPUGeneratorImpl.cpp.o:(.bss+0xb0): first defined here
CMakeFiles/torch_npu.dir/torch_npu/csrc/utils/TensorType.cpp.o:(.bss+0x28): multiple definition of c10_npu::threadNames'
CMakeFiles/torch_npu.dir/torch_npu/csrc/aten/NPUGeneratorImpl.cpp.o:(.bss+0x80): first defined here

这种错误通常发生在全局变量在多个源文件中定义了不止一次。即使你使用了 extern 关键字,在多个源文件中定义全局变量时仍然会产生“multiple definition”错误。extern 声明只是告诉编译器这个变量在别的地方定义,而不是在当前文件中定义。

要解决这个问题,你需要确保全局变量的定义仅存在于一个源文件中。以下是详细的步骤:

  1. 在头文件中声明全局变量

在头文件中使用 extern 声明全局变量,而不定义它们。确保在所有需要引用这些变量的源文件中都包含这个头文件,但不要在头文件中定义它们。

// ThreadUtils.h
#pragma once
#include <map>
#include <string>

namespace c10_npu {

enum ThreadType {
    Release_thread = 1,
    ACL_thread = 2,
    Forward_thread = 3,
    Backward_thread = 3
};

// 使用 extern 声明全局变量
extern const std::map<ThreadType, std::string> threadNames;
extern const std::map<std::string, ThreadType> threadNameToType;

}  // namespace c10_npu
  1. 在源文件中定义全局变量

在一个源文件中定义这些全局变量。确保这个源文件中只包含变量的定义。

// ThreadUtils.cpp
#include "ThreadUtils.h"

namespace c10_npu {

// 在一个源文件中定义全局变量
const std::map<ThreadType, std::string> threadNames = {
    {Release_thread, "Release_thread"},
    {ACL_thread, "ACL_thread"},
    {Forward_thread, "Other_thread"},
    {Backward_thread, "Other_thread"}
};

const std::map<std::string, ThreadType> threadNameToType = {
    {"Release_thread", Release_thread},
    {"ACL_thread", ACL_thread},
    {"Other_thread", Forward_thread}  // Forward_thread 和 Backward_thread 映射为 "Other_thread"
};

}  // namespace c10_npu
  1. 确保每个源文件只引用头文件,不重复定义变量

确保在其他源文件中(如 NPUGeneratorImpl.cppTensorType.cpp)只包含头文件 ThreadUtils.h,而不是在这些源文件中定义全局变量。这可以避免在多个编译单元中重复定义相同的全局变量。

  1. 检查和清理项目

如果你仍然遇到问题,检查项目中是否有重复的定义,可能是某些源文件中无意间重复了全局变量的定义。确保清理旧的编译文件(如使用 make cleanrm -rf build),然后重新编译项目,以确保没有残留的旧文件导致冲突。

总结

  • 使用 extern 在头文件中声明全局变量。
  • 在一个源文件中定义这些全局变量。
  • 确保其他源文件只包含头文件而不重复定义全局变量。
  • 清理项目并重新编译。

这些步骤将帮助你解决“multiple definition”错误。

error: passing ‘const std::map >’ as ‘this’ argument
/root/document/shaojie/github/v2.1.0-6.0.rc2/torch_npu/csrc/core/npu/NPUQueue.cpp:517:63: error: passing ‘const std::map<c10_npu::ThreadType, std::basic_string<char> >’ as ‘this’ argument discards qualifiers [-fper
missive]
    if (prctl(PR_SET_NAME, (threadNames[ThreadType::ACL_thread])) != 0) {
                                                              ^

这个错误是由于你尝试将一个const修饰的std::map对象的元素传递给需要修改该对象的方法。具体来说,std::map::operator[]返回的引用是可修改的,但是你试图在const std::map对象上调用它,这导致了错误。

解决方案 如果你不需要修改threadNames这个std::map,而只是需要访问其元素,可以使用std::map::at()方法代替operator[]at()方法是一个const方法,可以在const std::map上安全地调用。

以下是修正后的代码:

#include "ThreadUtils.h"

namespace c10_npu {

const std::map<ThreadType, std::string> threadNames = {
    {Release_thread, "Release_thread"},
    {ACL_thread, "ACL_thread"},
    {Forward_thread, "Other_thread"},
    {Backward_thread, "Other_thread"}
};

const std::map<std::string, ThreadType> threadNameToType = {
    {"Release_thread", Release_thread},
    {"ACL_thread", ACL_thread},
    {"Other_thread", Forward_thread}  // Forward_thread 和 Backward_thread 映射为 "Other_thread"
};

// 在代码中,使用at()方法访问map的值
void setThreadName() {
    if (prctl(PR_SET_NAME, threadNames.at(ThreadType::ACL_thread).c_str()) != 0) {
        // 错误处理代码
    }
}

}  // namespace c10_npu

关键点

  1. at()方法std::map::at()方法与operator[]类似,但它是const安全的,可以在const std::map对象上使用。它还会在键不存在时抛出std::out_of_range异常,而不是插入新元素。

  2. 避免修改操作:使用const修饰std::map的对象表示你不希望它的内容被修改,因此应避免使用会改变其内容的操作,如operator[]

通过这种方式,你可以在不改变threadNames的情况下访问其中的元素,并解决const修饰符导致的编译错误。

参考文献

评论