本地开发时,可以通过指定–no-release-bcloud参数跳过release.bcloud脚本的执行。
尽量避免依赖一些大型模块,例如baidu/third-party/cuda,该代码库体积高达7G。bcloud分布式集群上已经部署了cuda,无需再通过依赖模块的方式来引入,直接使用宿主机上的环境即可。
编译过程
预处理、编译和汇编操作都是针对每一个编译单元分别进行的,即可以理解为编译器总是遍历每一个.cc文件,并对其分别执行预处理(头文件展开、宏定义替换、处理宏开关等)、编译(语法检查、生成汇编文件)和汇编(从汇编文件生成机器码文件)操作,得到ojbect文件。在gcc/g++命令后接多个.cc文件,即会分别对每个.cc文件加以处理。
预处理阶段会包头文件找不到、变量/函数未定义错误,编译阶段会报语法错误。
编译过程只依赖于第三方依赖的头文件搜索路径,链接过程只依赖于第三方库的搜索路径,源文件间从来不相互依赖。
gcc/g++编译参数
常用参数:
param | demo | Usage |
---|---|---|
-x | -x c or -x c++ |
显式指定编译语言 |
-o | -o main |
显式指定编译输出名称 |
-E | -E main -o main.i |
只对编译对象进行预处理 |
-S | -S main -o main.s |
只对编译对象进行汇编 |
-c | -c main.cc or -c main.s |
从源文件或汇编文件生成对象文件 |
-v | 显式打印编译过程 |
宏定义:
1 | -Dmacro // #define macro |
指定头文件搜索路径:
1 | -Idir |
在.cc文件中include头文件时候, gcc/g++ 会先在当前目录查找你所制定的头文件, 如果没有找到, 他回到默认的头文件目录找, 如果使用 -I 制定了目录,他会先在你所制定的目录查找, 然后再按常规的顺序去找。如果-I指定的目录中包含了多个不同版本的同名头文件,以靠前的-I指定的为准。
调试信息:
1 | -C # 在预处理的时候, 不删除注释信息 |
参数传递:
1 | -Wa,option # 此选项传递 option 给汇编程序; 如果 option 中间有逗号, 就将 option 分成多个选项, 然 后传递给会汇编程序。 |
链接库:
1 | -lcurse # 指定编译时使用libcurse.so/libcurse.a库 |
优化选项:
1 | -O0 、-O1 、-O2 、-O3 # 编译器的优化选项的 4 个级别,-O0 表示没有优化, -O1 为默认值,-O3 优化级别最高。 |
链接命令
通过如下命令将多个object文件生成静态库:
1 | gcc -c file1.cc file2.cc file3.cc |
通过如下一组命令生成动态库,如果动态库在编译阶段连接了某个静态库,该静态库需在编译需要指定-fPIC
参数,否则会出现recompile with -fPIC
的错误提示:
1 | gcc -fPIC -c file1.cc file2.cc |
常见编译工具如何设置gcc/g++参数
对于基于configure构建的项目,可以在命令行通过cppFLAGS
指定:
1 | ./configure --prefix=/usr/local/bin CPPFLAGS="-I/usr/local/foo/include" |
对于基于cmake构建的项目,可以通过在CMakefile.txt
中增加如下内容:
1 | # method 1 |
对于基于BCLOUD构建的,可以通过在BCLOUD
中添加如下内容指定:
1 | CXXFLAGS('-std=c++17 -O3 -g -fPIC -msse4 -DNDEBUG') |
补充其他常见BCLOUD使用命令:
1 | CPPFLAGS() # 预处理参数 |
gcc/g++命令示例
1 | gcc main.o -L../shared_lib -lcurse -o demo # just link |
对象文件理解
1 | cxxfilt |
反汇编
查看ELF文件头:
1 | readelf -d libfoo.so |
语法错误
内存问题
错误现象:
示例如下,不正确的指针使用会导致预期外的内存修改,导致不可知的问题。
1 |
|
函数调用
不失一般性,这类错误通常是由于调用时错误地混淆了函数和变量导致的。
错误现象:
1 | foo_bar.cc:100:10: error no match for call to (const Vector3d {aka const Eigen::Matrix<double, 3, 1>}) () |
错误分析:
这个报错是说对于类型const Vector3d
不存在operator()
可以调用,通常是我们错误得将变量当作函数调用所致。
错误现象:
1 | foo_bar.cc:100:10: error: invalid use of member function template<int Size> typename Eigen::DenseBase<Derived>::CostFxiedSegmentReturntype<Size>::Type Eigen::DenseBase<Derived>::head() const [with int Size = Size; Derived = Eigen::Matrix<double, 3, 1>] (did you forget the () ?) |
错误代码:
1 | Eigen::Vector3d()::Zero().head<2>.norm(); |
错误分析:
错误的将函数当做了变量调用。
Proto错误
错误现象:
程序解析proto读到的信息和proto实际存储内容不一致。
错误分析:
解析proto文件时所使用的protobuf定义和构建proto文件时的protobuf定义不兼容。
链接错误
运行时库加载失败
错误信息:
1 | ./main: error while loading shared libraries: libxxx.so: cannot open shared object file: No such file or directory |
错误分析:
该错误由运行时无法找到依赖对动态库导致,可以通过在LD_LIBRARY_PATH
中添加相应动态库的路径解决。
错误信息:
1 | /usr/bin/ld:libxxx.so: file format not recognized; treating as linker script |
错误分析:
该错误通常是由于依赖的libxxx.so
文件存在,但是因为下载不完全等原因导致的文件损坏,使得该文件无法被解析,重新下载完整的库文件可以解决该问题。