CFLAG 里面指定 -D_GLIBCXX_USE_CXX11_ABI=0,
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_GLIBCXX_USE_CXX11_ABI=0")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_GLIBCXX_USE_CXX11_ABI=0")
1、先用旧版本gcc编译整套代码。
2、然后修改要单独编译的可执行文件的makefile或者CmakeLIST.TXT,增加-D_GLIBCXX_USE_CXX11_ABI=0编译连接选项。
3、然后删除之前被编译出来的可执行文件。
4、变更为新版本的gcc(gcc-5.1以上)
4、重新编译make xxxapp。
注: 更新gcc编译器,不需要更新stdc++
为什么我们需要-D_GLIBCXX_USE_CXX11_ABI=0
当您尝试构建 tensorflow 时,会提示您需要添加“-D_GLIBCXX_USE_CXX11_ABI=0”标志,如果您使用的是 GCC 5 或更高版本,以保持您构建的 tensorflow 和官方 tensorflow 构建的兼容性。
官方 TensorFlow 包是使用 GCC 4 构建的,并使用较旧的 ABI。对于 GCC 5 及更高版本,使用以下命令使您的构建与旧 ABI 兼容:–cxxopt=”-D_GLIBCXX_USE_CXX11_ABI=0”。ABI 兼容性确保针对官方 TensorFlow 包构建的自定义操作继续与 GCC 5 构建包一起使用
非常详细和正式地解释ABI
. 长话短说,根据我的理解,这是编译器之间的协议/协议,关于如何从另一个编译单元找到路由/符号,以及如何传递参数,获取例程之间的返回值,如何解释函数/符号名称(来源文件和编译器中间二进制文件对于相同的函数/类具有不同的名称)。
如果您的软件的所有代码/组件都是从您机器上的单个编译器编译的,则 ABI 兼容性根本不是问题,因为编译器将处理所有脏细节。但是,如果您正在编写一个将分发给各种用户的库,将有许多潜在的配置/环境,那么 ABI 绝对是您需要考虑的重要事项之一。
假设您正在用 C++ 编写一个库,并且您不想分发库的源代码。您可以将其编译为动态库(linux 中的.so 文件),然后将动态库和头文件提供给您的用户。用户然后使用他/她的编译器将他/她的源文件编译为目标文件,然后使用您的动态库将他/她的目标文件再次链接到可执行文件/库。问题来了:
- 假设您使用的是版本 X 的 GCC 编译器,但用户使用的是另一个版本 Y。在这种情况下,Y 需要知道 X 编译的库的二进制格式。
关于 C++11_ABI 标志
这里的文章对此进行了解释。https://developers.redhat.com/blog/2015/02/05/gcc5-and-the-c11-abi/。
基本思想是
依赖第三方库或仍然使用旧 ABI 的插件接口的用户可以使用 -D_GLIBCXX_USE_CXX11_ABI=0 构建他们的代码,一切都应该正常工作。在大多数情况下,很明显何时需要这个标志是因为链接器的错误抱怨涉及“__cxx11”的未解析符号
例子
步骤 1. 编写并编译 lib
假设您正在编写一个只有一个 cpp 文件的库mylib.cpp
,并通过以下方式导出您的 APImylib.h
//mylib.cpp
#include <string> #include <iostream> void print_string(const std::string & a) {
std::cout <<__FILE__ << __LINE__ << " content of a:" << a << std::endl;
}
#ifndef __MYLIB_H #define __MYLIB_H #include <string> void print_string(const std::string & a);
#endif
使用以下命令将 cpp 文件编译为动态库。
g++ -fPIC mylib.cpp -shared -o libmy.so
步骤 2. 编写并编译和应用
假设您的应用程序的cpp 文件以 命名myapp.cpp
,并且它与步骤1 中的mylib.cpp
和mylib.h
和mylib.so
在同一目录中。具有以下内容。
#include <string> #include "mylib.h" int main(){
print_string("FromMyApp");
return 0;
}
使用以下命令将cpp文件编译为可执行文件。
g++ myapp.cpp -o myapp -lmy -L./ -I./
该命令将myapp
在当前目录下生成一个exectuble,该 exetuble 运行良好,您只需执行它即可。
Step 3. 更改库的 ABI 会影响应用程序
但是如果我将 libary 编译命令更改为以下命令会怎样
g++ -fPIC mylib.cpp -shared -o libmy.so -D_GLIBCXX_USE_CXX11_ABI=0
在此之后,如果我执行与 step.2 中相同的命令来编译 app g++ myapp.cpp -lmy -L./ -o myapp
。编译器给出以下错误
/tmp/ccDPFccW.o: In function `main': myapp.cpp:(.text+0x43): undefined reference to `print_string(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)'
collect2: error: ld returned 1 exit status
这明显表明我需要使用与 libary 编译命令相同的编译标志。
g++ myapp.cpp -lmy -L./ -o myapp -D_GLIBCXX_USE_CXX11_ABI=0
4. 回到 tensorflow 的例子。
现在让我们回到 tensorflow 示例,因为官方预构建的 tensorflow 库 (.so) 是由较旧的 GCC 编译的,(这等于较新版本的 GCC wht 标志 -DGLIBCXX_USE_CXX11_ABI=0)。因此,如果使用官方 tensorflow 的现有上级应用程序/库希望由 NO CXX 11 ABI 编译,如果您希望应用程序/库也与您编译的 tensorflow 一起使用,那么您要么需要使用较旧的编译器编译它,要么使用带有标志的新编译器-DGLIBCXX_USE_CXX11_ABI=0
。