linux编程快速入门学习笔记

ubuntu开发环境安装gcc/make/gdb

更新安装源
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

使用gcc/g++编译程序详解

gcc(g++)

预处理,头文件include、导入库、宏
编译,检测语法等错误,将.c/.cpp等文件转化为.o或.obj
汇编
链接,.o/.so或.obj/.dll等文件转化为exe

gcc [ 选项 ] <文件名>

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),即出现警告就停止编译。

gcc文件扩展名规范

扩展名 类型 可进行的操作方式
.c c语言源程序 预处理、编译、汇编、 链接
.C,.cc,.cp,.cpp,. c++,.cxx c++语言源程序 预处理、编译、汇编、 链接
.i 预处理后的c语言源程序 编译、汇编、链接
.ii 预处理后的c++语言源程序 编译、汇编、链接
.s 预处理后的汇编程序 汇编、链接
.S 未预处理的汇编程序 预处理、汇编、链接
.h 头文件 不进行任何操作
.o 目标文件 链接

g++ 分步编译

gdb调试工具使用和coredump

#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

gdb调试器

gdb概述

Linux下的gdb调试器,是一款GNU组织开发并发布的UNIX/Linux下的程 序调试工具。它没有图形化的友好界面,但功能强大。

gdb指令参数

命令格式 作用
list <行号>|<函数名> 查看指定位置的程序源代码
break 行号|函数名<条件表达式> 设置断点
info break 显示断点信息
run 运行程序
print 表达式|变量 查看程序运行时对应表达式和变量的值
next 单步恢复程序运行,但不进入函数调用
step 单步恢复程序运行,且进入函数调 用
continue 继续执行函数,直到函数结束或遇到新断点

coredump

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作比较差异发现问题。

gcc编译动态链接库

-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

makefile

GNU make用来构建和管理自己的工程
Makefile 文件描述了整个工程的编译、 连接等规则

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

按esc,保存退出wq,在保存之前确保tab格式输入正确。
在这里插入图片描述

(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中常见预定义变量

linux编程快速入门学习笔记_第1张图片

makefile变量的使用

linux编程快速入门学习笔记_第2张图片

make和makefile

makefile文件主要包含了5部分内容:

  1. 显式规则。说明了如何生成一个或多个目标文件。由makefile文件的创作者指出,包括要生成的文件、文件的依赖文件、生成的命令。
  2. 隐式规则。由于make有自动推导的功能,所以隐式的规则可以比较粗糙地简略书写makefile文件,这是由make所支持的。
  3. 变量定义。在makefile文件中要定义一系列的变量,变量一般都是字符串, 这与C语言中的宏有些类似。当makefile文件执行时,其中的变量都会扩展到相应的引用位置上。
  4. 文件指示。其包括3个部分,一个是在一个makefile文件中引用另一个 makefile文件;另一个是指根据某些情况指定makefile文件中的有效部分; 还有就是定义一个多行的命令。
  5. 注释。makefile文件中只有行注释,其注释用“#”字符。如果要在 makefile文件中使用“#”字符,可以用反斜框进行转义,如:“#”。

makefile变量使用和规则分析

在上面的例子中,先让我们看看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

你可能感兴趣的:(操作系统,#,C++)