GCC Compile Error
导言
遇到过的c++编译error
大型项目(许多git未跟踪的三方库+临时文件)重新编译报错
- 详细记录从干净git仓库编译的流程
- 及时git保存代码的修改
- 使用
git clean -dfx
来回退。其余make clean
和python 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
声明只是告诉编译器这个变量在别的地方定义,而不是在当前文件中定义。
要解决这个问题,你需要确保全局变量的定义仅存在于一个源文件中。以下是详细的步骤:
- 在头文件中声明全局变量
在头文件中使用 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
- 在源文件中定义全局变量
在一个源文件中定义这些全局变量。确保这个源文件中只包含变量的定义。
// 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
- 确保每个源文件只引用头文件,不重复定义变量
确保在其他源文件中(如 NPUGeneratorImpl.cpp
和 TensorType.cpp
)只包含头文件 ThreadUtils.h
,而不是在这些源文件中定义全局变量。这可以避免在多个编译单元中重复定义相同的全局变量。
- 检查和清理项目
如果你仍然遇到问题,检查项目中是否有重复的定义,可能是某些源文件中无意间重复了全局变量的定义。确保清理旧的编译文件(如使用 make clean
或 rm -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
关键点
-
at()
方法:std::map::at()
方法与operator[]
类似,但它是const
安全的,可以在const std::map
对象上使用。它还会在键不存在时抛出std::out_of_range
异常,而不是插入新元素。 -
避免修改操作:使用
const
修饰std::map
的对象表示你不希望它的内容被修改,因此应避免使用会改变其内容的操作,如operator[]
。
通过这种方式,你可以在不改变threadNames
的情况下访问其中的元素,并解决const
修饰符导致的编译错误。