更新安装源
apt-get update
安装gcc和c++的开发库,安装的时候自动包含其它依赖库
apt-get install g++
调试工具
apt-get install gdb
apt-get install make
远程连接工具
apt-get install openssh-server
编辑工具
apt-get install vim
预处理,头文件include、导入库、宏
编译,检测语法等错误,将.c/.cpp等文件转化为.o或.obj
汇编
链接,.o/.so或.obj/.dll等文件转化为exe
gcc [ 选项 ] <文件名>
选项 | 含义 |
---|---|
-o file | 将经过gcc处理过的结果存为文件file,这个结果文件可能是预 处理文件、汇编文件、目标文件或者最终的可执行文件。假设 被处理的源文件为source.suffix,如果这个选项被省略了,那 么生成的可执行文件默认名称为a.out;目标文件默认名为 source.o;汇编文件默认名为source.s;生成的预处理文件则 发送到标准输出设备。 |
-c | 仅对源文件进行编译,不链接生成可执行文件。在对源文件 进行查错时,或只需产生目标文件时可以使用该选项。 |
-g[gdb] | 在可执行文件中加入调试信息,方便进行程序的调试。如果 使用中括号中的选项,表示加入gdb扩展的调试信息,方便 使用gdb来进行调试 |
-O[0、1、2、3] | 对生成的代码使用优化,中括号中的部分为优化级别,缺省 的情况为2级优化,0为不进行优化。注意,采用更高级的优 化并不一定得到效率更高的代码。 |
-Dname[=definition] | 将名为name的宏定义为definition,如果中括号中的部分缺 省,则宏被定义为1 |
-Idir | 在编译源程序时增加一个搜索头文件的额外目录——dir,即include增加一 个搜索的额外目录。 |
-Ldir | 在编译源文件时增加一个搜索库文件的额外目录——dir |
-llibrary | 在编译链接文件时增加一个额外的库,库名为liblibrary.so |
-w | 禁止所有警告 |
-Wwarning | 允许产生warning类型的警告,warning可以是:main、unused等很多取值, 最常用是-Wall,表示产生所有警告。如果warning取值为error,其含义是将 所有警告作为错误(error),即出现警告就停止编译。 |
扩展名 | 类型 | 可进行的操作方式 |
---|---|---|
.c | c语言源程序 | 预处理、编译、汇编、 链接 |
.C,.cc,.cp,.cpp,. c++,.cxx | c++语言源程序 | 预处理、编译、汇编、 链接 |
.i | 预处理后的c语言源程序 | 编译、汇编、链接 |
.ii | 预处理后的c++语言源程序 | 编译、汇编、链接 |
.s | 预处理后的汇编程序 | 汇编、链接 |
.S | 未预处理的汇编程序 | 预处理、汇编、链接 |
.h | 头文件 | 不进行任何操作 |
.o | 目标文件 | 链接 |
g++ 分步编译
#1 预处理 (Preprocessing)
g++ -E test.cpp >test.ii
#2 编译 (Compilation)
g++ -S test.ii
#3 汇编 (Assembly)
g++ -c test.s
#4 链接 (Linking)
g++ test.o -o test
#5 运行
./test
Linux下的gdb调试器,是一款GNU组织开发并发布的UNIX/Linux下的程 序调试工具。它没有图形化的友好界面,但功能强大。
命令格式 | 作用 |
---|---|
list <行号>|<函数名> | 查看指定位置的程序源代码 |
break 行号|函数名<条件表达式> | 设置断点 |
info break | 显示断点信息 |
run | 运行程序 |
print 表达式|变量 | 查看程序运行时对应表达式和变量的值 |
next | 单步恢复程序运行,但不进入函数调用 |
step | 单步恢复程序运行,且进入函数调 用 |
continue | 继续执行函数,直到函数结束或遇到新断点 |
vim test.cpp
#include
using namespace std;
#define NAME "NAME=cpp"
int main(int argc,char *argv[])
{
cout<<"test g++ makefile"<<endl;
int *c = 0;
*c = 1000;//error
cout<<NAME<<endl;
return 0;
}
按esc,输入wq保存退出
生成带调试信息的可执行文件test,文件会大一些
g++ test.cpp -o test -g
这是在调试状态下发现的错误
gdb test
run
Program received signal SIGSEGV, Segmentation fault.
0x000000000040087d in main (argc=1, argv=0x7fffffffe1c8) at test.cpp:8
8 *c = 1000;//error
随着项目代码复杂度加大,有时候我们想在运行程序之后查看程序是在哪一行dump掉的。可以查看一下coredump,默认是关闭的。
(caffe2_env) zhoujianwen@zhoujianwen-System:~$ ulimit -c
0
启动一下
(caffe2_env) zhoujianwen@zhoujianwen-System:~$ ulimit -c unlimited
再次查看coredump状态
(caffe2_env) zhoujianwen@zhoujianwen-System:~$ ulimit -c
unlimited
执行test
(caffe2_env) zhoujianwen@zhoujianwen-System:~$ ./test
test g++ makefile
段错误 (核心已转储)
报错信息存储在core文件
(caffe2_env) zhoujianwen@zhoujianwen-System:~$ ls -a | grep core
core
gdb调试core文件,输出错误信息,这样我们就能知道现场环境的程序代码是在哪里dump掉的。
(caffe2_env) zhoujianwen@zhoujianwen-System:~$ gdb test core
warning: exec file is newer than core file.
[New LWP 8480]
Core was generated by `./test'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x000000000040087d in main (argc=1, argv=0x7ffdbf9b7a58) at test.cpp:8
8 *c = 1000;//error
后面的调试当中,除了coredump会使用到,应用程序以调试状态运行过程中出现问题,也能查看coredump发现问题,特别是系统在做熔断的时候,我们生成两次coredump作比较差异发现问题。
-fPIC 编译选项 -fPIC If supported for the target machine, emit position- independent code, suitable for dynamic linking,even if branches need large displacements. 产生位置无关代码(PIC),一般创建共享库时用到。 在x86上,PIC的代码的符号引用都是通过ebx进行操作的。
-shared
示例
g++ -shared -fPIC mylib.cpp -o libmylib.so
g++ test.cpp -lmylib -L/root/cpp
#!/bin/bash
LD_LIBRARY_PATH=./;
export LD_LIBRARY_PATH
./testlib
Makefile中 -I -L -l区别
我们用gcc编译程序时,可能会用到“-I”(大写i),“-L”(大写l),“-l”(小写l)等参数,下面做个记录:
例:
gcc -o hello hello.c -I /home/hello/include -L /home/hello/lib -lworld
上面这句表示在编译hello.c时:
-I /home/hello/include表示将/home/hello/include目录作为第一个寻找头文件的目录,寻找的顺序是:/home/hello/include–>/usr/include–>/usr/local/include
-L /home/hello/lib表示将/home/hello/lib目录作为第一个寻找库文件的目录,寻找的顺序是:/home/hello/lib–>/lib–>/usr/lib–>/usr/local/lib
-lworld表示在上面的lib的路径中寻找libworld.so动态库文件(如果gcc编译选项中加入了“-static”表示寻找libworld.a静态库文件)
创建目录
mkdir code
cd code
pwd
mkdir src
mkdir lib
mkdir bin
mkdir include
mkdir doc
(caffe2_env) zhoujianwen@zhoujianwen-System:~/code$ ls
bin doc include lib src
(caffe2_env) zhoujianwen@zhoujianwen-System:~/code$ cd src
(caffe2_env) zhoujianwen@zhoujianwen-System:~/code/src$ mkdir testlib
(caffe2_env) zhoujianwen@zhoujianwen-System:~/code/src$ cd testlib
创建文件,一个头文件对应一个库文件
vim testlib.cpp
#include
#include "test_lib.h"
using namespace std;
int main(int argc,char *argv[])
{
TestLib t;
return 0;
}
vim test_lib.h
#ifndef TEST_LIB_H
#define TEST_LIB_H
class TestLib
{
public:
TestLib();
};
#endif
vim test_lib.cpp
#include "test_lib.h"
#include
using namespace std;
TestLib::TestLib()
{
std::cout<<"TestLib Create"<<std::endl;
}
生成xx.so动态链接库
(caffe2_env) zhoujianwen@zhoujianwen-System:~/code/src/testlib$ (caffe2_env) zhoujianwen@zhoujianwen-System:~/code/src/testlib$ ls
test_lib.cpp testlib.cpp test_lib.h
(caffe2_env) zhoujianwen@zhoujianwen-System:~/code/src/testlib$ g++ -fPIC -shared test_lib.cpp -o libtestlib.so
(caffe2_env) zhoujianwen@zhoujianwen-System:~/code/src/testlib$ ls
libtestlib.so test_lib.cpp testlib.cpp test_lib.h
编译testlib.cpp和-ltestlib,-ltestlib其实就是libtestlib.so文件,这是格式规范,指定共享库路径是在./
当前路径下查找,生成可执行文件testlib
注意:
-l(小写l),-L(大写l)
-ltestlib表示在上面的lib的路径中寻找libtestlib
.so动态库文件(如果gcc编译选项中加入了“-static”表示寻找libtestlib.a静态库文件)
-L ./表示将~/code/src/testlib
目录作为第一个寻找库文件的目录,寻找的顺序是:~/code/src/testlib
–>/lib–>/usr/lib–>/usr/local/lib
首先库文件名(库文件名不等于库名)的命名规则为lib+<库名>+.so,如果有一个testlib库, 那么相应的库文件为 libtestlib.so 为了在执行编译命令的时候链接指定的库,我们需要用到-L(大写l)和-l(小写l)命令.
如果在路径 ~/code/src/testlib
下面有一个库文件叫做 libtestlib.so, 我想在编译的时候链接它, 只需加上−ltestlib −L ~/code/src/testlib或−ltestlib −L ./命令即可。对于那些在/lib, /usr/lib 和 /usr/local/lib 路径下的库, 我们可以使用更加简单的命令 −l(小写l) 而无需添加库文件目录路径
(caffe2_env) zhoujianwen@zhoujianwen-System:~/code/src/testlib$ g++ testlib.cpp -ltestlib -L./ -o testlib
(caffe2_env) zhoujianwen@zhoujianwen-System:~/code/src/testlib$ ls ./
libtestlib.so testlib test_lib.cpp testlib.cpp test_lib.h
当你执行./testlib就会提示找不到动态链接库,主要是环境变量LD_LIBRARY_PATH没有指定库加载的正确路径
(caffe2_env) zhoujianwen@zhoujianwen-System:~/code/src/testlib$ ./testlib
./testlib: error while loading shared libraries: libtestlib.so: cannot open shared object file: No such file or directory
查询一下当前环境变量LD_LIBRARY_PATH的路径是/usr/local/cuda-10.0/lib64,显然不是我们刚才的测试路径~/code/src/testlib
(caffe2_env) zhoujianwen@zhoujianwen-System:~/code/src/testlib$ echo $LD_LIBRARY_PATH
/usr/local/cuda-10.0/lib64
解决共享库没法找到的问题,方法有几种,最简单是在刚才目录的当前路径下创建一个run.sh,但是export LD_LIBRARY_PATH
它只对当次run.sh执行操作有效。
vim run.sh
#!/bin/bash
LD_LIBRARY_PATH=./;
export LD_LIBRARY_PATH
./test
按下esc,wq保存退出
修改run.sh执行权限
chmod +x run.sh
(caffe2_env) zhoujianwen@zhoujianwen-System:~/code/src/testlib$ ./run.sh
TestLib Create
GNU make用来构建和管理自己的工程
Makefile 文件描述了整个工程的编译、 连接等规则
(caffe2_env) zhoujianwen@zhoujianwen-System:~/code/src$ mkdir testmake
(caffe2_env) zhoujianwen@zhoujianwen-System:~/code/src$ cd testmake/
(caffe2_env) zhoujianwen@zhoujianwen-System:~/code/src/testmake$
vim testmake.cpp
#include
using namespace std;
int main(int argc,char *argv[])
{
std::cout<<"test makefile"<<std::endl;
return 0;
}
按esc,保存退出wq
vim makefile
编辑如下内容
testmake:testmake.cpp
g++ testmake.cpp -o testmake
./testmake
(caffe2_env) zhoujianwen@zhoujianwen-System:~/code/src/testmake$ ls
makefile testmake testmake.cpp
(caffe2_env) zhoujianwen@zhoujianwen-System:~/code/src/testmake$ make
g++ testmake.cpp -o testmake
./testmake
test makefile
(caffe2_env) zhoujianwen@zhoujianwen-System:~/code/src/testmake$ ./testmake
test makefile
通过执行语句,把依赖的文件生成目标。为什么不直接使用g++ testmake.cpp -o testmake ./testmake
,而是另外新建一个testmake来管理呢?因为当项目要编译的文件数量比较多的时候,使用make可以更有效地管理和构建项目的工程代码。下面只是编译一个文件,如果有多个,或者是分开部署的呢,而且还要知道哪一部分编译出错了,这样的管理效率就不一样了。
makefile文件主要包含了5部分内容:
在上面的例子中,先让我们看看edit的规则:
edit : main.o kbd.o command.o display.o
insert.o search.o files.o utils.o
cc -o edit main.o kbd.o command.o display.o
insert.o search.o files.o utils.o
我们可以看到[.o]文件的字符串被重复了两次,如果我们的工程需要加入一个新的[.o]文件,那么我们需要在两个地方加(应该是三个地方,还有一个地方在clean 中)。当然,我们的makefile并不复杂,所以在两个地方加也不累,但如果makefile变得复杂,那么我们就有可能会忘掉一个需要加入的地方,而导致编译失败。所以,为了makefile的易维护,在 makefile中我们可以使用变量。makefile的变量也就是一个字符串,理解成C语言中的宏可能会更好。
我们在makefile 一开始就这样定义:
objects = main.o kbd.o command.o display.o
insert.o search.o files.o utils.o
于是,我们就可以很方便地在我们的makefile中以“$(objects)” 的方式来使用这个变量了,于是我们的改良版makefile就变成下面这个样子:
edit : $(objects)
cc -o edit $(objects)
include
(caffe2_env) zhoujianwen@zhoujianwen-System:~/code$ ls
bin doc include lib src
(caffe2_env) zhoujianwen@zhoujianwen-System:~/code$ cd src
(caffe2_env) zhoujianwen@zhoujianwen-System:~/code/src$ ls
testlib testmake
(caffe2_env) zhoujianwen@zhoujianwen-System:~/code/src$ cd testlib
(caffe2_env) zhoujianwen@zhoujianwen-System:~/code/src/testlib$ ls
libtestlib.so run.sh testlib test_lib.cpp testlib.cpp test_lib.h test_lib.h.gch test_lib.o testlib.o
(caffe2_env) zhoujianwen@zhoujianwen-System:~/code/src/testlib$ vim makefile
编辑makefile文件
testlib.so:test_lib.cpp test_lib.h
g++ $+ -o $@ -shared -fPIC
clean:
rm -rf *.o *.so
按esc退出编辑模式,输入wq保存退出。
make
(caffe2_env) zhoujianwen@zhoujianwen-System:~/code/src/testlib$ make
g++ test_lib.cpp test_lib.h -o testlib.so -shared -fPIC
(caffe2_env) zhoujianwen@zhoujianwen-System:~/code/src/testlib$ ls
libtestlib.so run.sh test_lib.cpp test_lib.h test_lib.o testlib.so
make clean
(caffe2_env) zhoujianwen@zhoujianwen-System:~/code/src/testlib$ make clean
rm -rf *.o *.so
(caffe2_env) zhoujianwen@zhoujianwen-System:~/code/src/testlib$ ls
makefile run.sh testlib test_lib.cpp testlib.cpp test_lib.h test_lib.h.gch
修改makefile文件内容
在rm -rf *.o *.so
前添加@可隐藏rm -rf *.o *.so
显示语句的执行
testlib.so:test_lib.cpp test_lib.h
g++ $+ -o $@ -shared -fPIC
clean:
@echo "begin clean..."
@rm -rf *.o *.so
@echo "end clean."
(caffe2_env) zhoujianwen@zhoujianwen-System:~/code/src/testlib$ (caffe2_env) zhoujianwen@zhoujianwen-System:~/code/src/testlib$ make clean
begin clean...
end clean.
添加install
testlib.so:test_lib.cpp test_lib.h
g++ $+ -o $@ -shared -fPIC
clean:
@echo "begin clean..."
@rm -rf *.o *.so
@echo "end clean."
install:
cp *.so /usr/lib
按esc退出编辑模式,输入wq保存退出。
make生成*.so文件,make install把*.so文件拷贝到/usr/lib
make
(caffe2_env) zhoujianwen@zhoujianwen-System:~/code/src/testlib$ sudo make install
[sudo] zhoujianwen 的密码:
g++ test_lib.cpp test_lib.h -o testlib.so -shared -fPIC
cp *.so /usr/lib
(caffe2_env) zhoujianwen@zhoujianwen-System:~/code/src/testlib$ ls /usr/lib | grep testlib
testlib.so
构建依赖关系
在install后面添加testlib.so
,这样在执行make install之前可以确保testlib.so文件已经生成,再把*.so拷贝到/usr/lib目录下。
testlib.so:test_lib.cpp test_lib.h
g++ $+ -o $@ -shared -fPIC
clean:
@echo "begin clean..."
@rm -rf *.o *.so
@echo "end clean."
install:testlib.so
cp *.so /usr/lib
这样执行一条命令语句就可以了
sudo make install
构建多文件项目
目录结构
~/code/src/testlib/
test_lib.h
test_lib.cpp
~/code/src/testlib/testmutimake
main.cpp include test_lib.h
person.h
person.cpp include test_lib.h
cd ..
ls
mkdir testmutimake
cd testmutimake
vim main.cpp
main.cpp
#include
#include "person.h"
#include "test_lib.h"
using namespace std;
int main(int argc,char *argv[])
{
TestLib t;
Person p;
return 0;
}
person.h
```cpp
#ifndef PERSON_H
#define PERSON_H
class Person
{
pbulic:
Person();
}
#endif
person.cpp
#include "person.h"
#include "test_lib.h"
#include
using namespace std;
Person::Person(){
TestLib t;
std::cout<<"Person Create"<<std::endl;
};
vim makefile
自动推导和手动配置,双结合的做法。
TARGET=main
OBJS = main.o person.o
CPPFLAGES=-I../testlib
LIBS = -ltestlib
$(TARGET):$(OBJS)
g++ $+ -o $@ $(LIBS) #这一步是链接
main.o:main.cpp
g++ -c $+ $(CPPFLAGS)
clean:
rm -rf $(OBJS) $(TARGET)
g++ $+ -o $@ -I../testlib -ltestlib #这一步是链接
本来-ltestlib后面是要添加-L …/testlib,不用添加是因为之前已经将testlib.so文件拷贝到/usr/lib目录下,这样就会默认搜索/usr/lib目录
编译汇编怎么做呢?是使用gcc -c指令来做自动推导的,自动推导出来就出现一个问题,就是头文件的路径没有添加。第一步我们不要让它自动推导,而是自己编写。
main.o:main.cpp
g++ -c $+ -I../testlib