本文谢绝转载,原文来自http://990487026.blog.51cto.com


<大纲>

linux开发基础
	od -tc 查看文件所有字符
	显示硬件信息:
		lshw
	apt-get操作:
		软件包搜索:apt-cache search vim
		显示软件包信息 apt-cache show vim
	进程:
		who
		ps
		ps aux
	作业号:
		ctrl + z 丢到后台,停止运行
		fg 1	调到前台,开始运行
		bg 2	调到后台,开始运行
		kill
	环境变量:
		env
		PATH
		finger 用户信息
安装vsftpd
	安装
	登陆
	下载
	上传
VIM
	命令模式
	vim分屏操作
	调整屏幕尺寸
	vim 进制切换
gcc
	gcc -I指定头文件的位置
	gcc -DDEBUG 定义宏参数
	nm 查看符号表
	objdump反汇编
	ldd 查看程序依赖哪些库
	共享库简介
	静态库实例
	共享库实例
gdb
	gdb演示
	
Makefile
	阶段1
	阶段2
	阶段3
	阶段4	


查看文件所有字符

2016-08-01_14:58:52chunli@http://990487026.blog.51cto.com~/linux_c$ od -tc main.c 
0000000   #   i   n   c   l   u   d   e       <   s   t   d   i   o   .
0000020   h   >  \n  \n   i   n   t       m   a   i   n   (   v   o   i
0000040   d   )  \n   {  \n  \t   p   r   i   n   t   f   (   "   %   d
0000060   \   n   "   ,   a   d   d   (   2   ,   4   )   )   ;  \n  \t
0000100   p   r   i   n   t   f   (   "   %   d   \   n   "   ,   d   i
0000120   v   (   8   ,   3   )   )   ;  \n  \t   r   e   t   u   r   n
0000140       0   ;  \n   }  \n  \n
0000147



apt-get操作


软件包搜索:$ apt-cache search vim

软件包信息:$ apt-cache show vim


解压到指定的文件路径:$ tar xf linux-4.6.tar.gz -C haha/


踢人下线

chunli@http://990487026.blog.51cto.com~$ ps
   PID TTY          TIME CMD
  3585 pts/0    00:00:00 bash
  3899 pts/0    00:00:00 ps
chunli@http://990487026.blog.51cto.com~$ who
chunli   pts/0        2016-07-27 02:19 (10.11.12.1)
chunli   pts/1        2016-07-27 02:47 (10.11.12.1)
chunli@http://990487026.blog.51cto.com~$


列出所有进程:

chunli@http://990487026.blog.51cto.com~$ ps aux
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root          1  0.0  0.4  33656  4076 ?        Ss   Jul26   0:02 /sbin/init
root          2  0.0  0.0      0     0 ?        S    Jul26   0:00 [kthreadd]
root          3  0.0  0.0      0     0 ?        S    Jul26   0:00 [ksoftirqd/0]
root          5  0.0  0.0      0     0 ?        S<   Jul26   0:00 [kworker/0:0H]
root          7  0.0  0.0      0     0 ?        S    Jul26   0:04 [rcu_sched]
root          8  0.0  0.0      0     0 ?        S    Jul26   0:00 [rcu_bh]



作业号:

ctrl + z 丢到后台,停止运行

fg 1调到前台,开始运行

bg 2调到后台,开始运行

kill


kill;

chunli@http://990487026.blog.51cto.com~$ kill -l
 1) SIGHUP	 2) SIGINT	 3) SIGQUIT	 4) SIGILL	 5) SIGTRAP
 6) SIGABRT	 7) SIGBUS	 8) SIGFPE	 9) SIGKILL	10) SIGUSR1
11) SIGSEGV	12) SIGUSR2	13) SIGPIPE	14) SIGALRM	15) SIGTERM
16) SIGSTKFLT	17) SIGCHLD	18) SIGCONT	19) SIGSTOP	20) SIGTSTP
21) SIGTTIN	22) SIGTTOU	23) SIGURG	24) SIGXCPU	25) SIGXFSZ
26) SIGVTALRM	27) SIGPROF	28) SIGWINCH	29) SIGIO	30) SIGPWR
31) SIGSYS	34) SIGRTMIN	35) SIGRTMIN+1	36) SIGRTMIN+2	37) SIGRTMIN+3
38) SIGRTMIN+4	39) SIGRTMIN+5	40) SIGRTMIN+6	41) SIGRTMIN+7	42) SIGRTMIN+8
43) SIGRTMIN+9	44) SIGRTMIN+10	45) SIGRTMIN+11	46) SIGRTMIN+12	47) SIGRTMIN+13
48) SIGRTMIN+14	49) SIGRTMIN+15	50) SIGRTMAX-14	51) SIGRTMAX-13	52) SIGRTMAX-12
53) SIGRTMAX-11	54) SIGRTMAX-10	55) SIGRTMAX-9	56) SIGRTMAX-8	57) SIGRTMAX-7
58) SIGRTMAX-6	59) SIGRTMAX-5	60) SIGRTMAX-4	61) SIGRTMAX-3	62) SIGRTMAX-2
63) SIGRTMAX-1	64) SIGRTMAX	
chunli@http://990487026.blog.51cto.com~$



环境变量:

chunli@http://990487026.blog.51cto.com~$ env
XDG_SESSION_ID=2
TERM=xterm
SHELL=/bin/bash
SSH_CLIENT=10.11.12.1 8045 22
OLDPWD=/dev
SSH_TTY=/dev/pts/0
USER=chunli
LD_LIBRARY_PATH=:.
MAIL=/var/mail/chunli
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
PWD=/home/chunli
LANG=en_US.UTF-8
SHLVL=1
HOME=/home/chunli
LANGUAGE=en_US:en
LOGNAME=chunli
SSH_CONNECTION=10.11.12.1 8045 10.11.12.4 22
XDG_RUNTIME_DIR=/run/user/1000
_=/usr/bin/env
chunli@http://990487026.blog.51cto.com~$



添加用户:

chunli@http://990487026.blog.51cto.com~$ sudo useradd -s /bin/bash -g chunli -d /home/xioaming -m xiaoming


finger 用户信息

chunli@http://990487026.blog.51cto.com~$ finger chunli
Login: chunli         			Name: chunli
Directory: /home/chunli             	Shell: /bin/bash
On since Wed Jul 27 02:24 (CST) on tty1    7 hours 56 minutes idle
On since Wed Jul 27 02:19 (CST) on pts/0 from 10.11.12.1
   7 seconds idle
On since Wed Jul 27 02:47 (CST) on pts/1 from 10.11.12.1
   7 hours 34 minutes idle
No mail.
No Plan.
chunli@http://990487026.blog.51cto.com~$



安装vsftpd:

ubuntu14.04

chunli@ubuntu:~$ sudo apt-get install vsftpd
chunli@ubuntu:~$ echo $?

chunli@ubuntu:~$ sudo mkdir /home/ftp
chunli@ubuntu:~$ sudo chmod 777 /home/ftp/

chunli@ubuntu:~$ vim /etc/vsftpd.conf 
listen=YES
anonymous_enable=NO
local_enable=YES
write_enable=YES
local_umask=022
dirmessage_enable=YES
use_localtime=YES
xferlog_enable=YES
connect_from_port_20=YES
xferlog_std_format=YES
secure_chroot_dir=/var/run/vsftpd/empty
pam_service_name=vsftpd
rsa_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
rsa_private_key_file=/etc/ssl/private/ssl-cert-snakeoil.key

chunli@ubuntu:~$ sudo service vsftpd restart
chunli@ubuntu:~$ netstat -tnlp
tcp        0      0 0.0.0.0:21              0.0.0.0:*               LISTEN      -               

登陆:chunli@ubuntu:~$ ftp 10.11.12.4
Name (10.11.12.4:chunli): chunli

ftp> ls 
drwxrwxr-x    2 1000     1000         4096 Jul 29 13:32 c++

使用二进制传输
ftp> bin
200 Switching to Binary mode.

文件下载:
ftp> ls
-rw-rw-r--    1 1000     1000            5 Jul 29 13:47 hello.txt
ftp> get hello.txt

文件上传:
ftp> put 123 
ftp> ls -l
rw-r--r--    1 1000     1000            0 Jul 29 14:23 123
-rw-rw-r--    1 1000     1000           60 Jul 29 14:22 ll

quit,exit,bye结束


ftp缺点:不可以下载一个目录




VIM

命令模式:
M: 光标移动到中间行
L: 光标移动到屏幕最后一行行首
G: 移动到指定行,行号 -G
w: 向后一次移动一个字
b: 向前一次移动一个字
{: 按段移动,上移
}: 按段移动,下移
Ctr-d: 向下翻半屏
Ctr-u: 向上翻半屏
Ctr-f: 向下翻一屏
Ctr-b: 向上翻一屏
gg: 光标移动文件开头
G: 光标移动到文件末尾
gg=G:所有代码缩进

删除命令:
x: 删除光标后一个字符,相当于 Del
X: 删除光标前一个字符,相当于 Backspace
dd: 删除光标所在行,n dd 删除指定的行数 D: 删除光标后本行所有内容,包含光标所在字符
d0: 删除光标前本行所有内容,不包含光标所在字符
dw: 删除光标开始位置的字,包含光标所在字符

撤销命令:
u: 一步一步撤销
U: 一次性撤销当前行所作的所有操作
Ctr-r: 反撤销

重复命令:
.: 重复上一次操作的命令


文本行移动:
>>: 文本行右移
<<: 文本行左移

复制粘贴:
yy: 复制当前行,n yy 复制 n 行
p: 在光标所在位置向下新开辟一行,粘贴

可视模式:
v: 按字符移动,选中文本
V: 按行移动,选中文本可视模式可以配合 d, y, >>, << 实现对文本块的删除,复制,左右移动

替换操作:
r: 替换当前字符
R: 替换当前行光标后的字符

查找命令:
/: str查找
n: 下一个
N:上一个

vim分屏操作
分屏操作:
sp: 上下分屏,后可跟文件名
vsp: 左右分屏,后可跟文件名
Ctr+w+w: 在多个窗口切换

启动分屏:
1.使用大写O参数进行垂直分屏
$ vim -On file1 file2 ...
2.使用小写o参数进行水平分屏
$ vim -on file1 file2 ...
注: n是数字,表示分屏的数量,n要大于等于文件个数

关闭分屏
1.关闭当前窗口
ctrl+w c

2.关闭当前窗口,如果只剩最后一个,则退出vim
ctrl+w q

编辑中分屏
1.上下分割当前打开的文件
ctrl+w s

2.上下分割,并打开一个新的文件
:sp filename

3.左右分割当前打开的文件
ctrl+w v

4.左右分割,并打开一个新的文件
:vsp filename

分屏编辑中光标的移动
vi中的光标键是h,j,k,l,要在各个屏之间切换,只需要先按一下ctrl+w
ctrl+w k 把光标移动到上边的屏
ctrl+w j 把光标移动到下边的屏
ctrl+w l 把光标移动到右边的屏
ctrl+w h 把光标移动到左边的屏
ctrl+w w 把光标移动到下一个的屏

移动分屏
1.向上移动 ctrl+w K
2.向下移动 ctrl+w J
3.向右移动 ctrl+w L
4.向左移动 ctrl+w H

屏幕尺寸
1.增加高度 ctrl+w +
2.减少高度 ctrl+w -
3.所有屏的高度一致 ctrl+w =
4.左加宽度 ctrl+w >
5.右加宽度 ctrl+w <
6.右增加n宽 (如:n=30) ctrl+w n < [实用]

光标fopen 按3 shift + k:查看函数的定义 ,相当于man 3 fopen

vim 进制
:%!xxd 以16进制编辑
:%!xxd -r 回到正常模式编辑

vim ide
ctag




查看gcc版本

chunli@ubuntu:~$ gcc -v
gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04.3) 
chunli@ubuntu:~$ 
有些项目的开发需要指定版本的编译器




gcc -I指定头文件的位置:

chunli@ubuntu:~$ gcc -I/tmp/  main.c 
chunli@ubuntu:~$ cat main.c 
#include <stdio.h>
#include "test.h"

int main(void)
{
	return 0;
}
chunli@ubuntu:~$ ll /tmp/
total 4
-rw-rw-r-- 1 chunli chunli 2 Jul 30 15:29 test.h
chunli@ubuntu:~$ gcc -I/tmp/  main.c 
chunli@ubuntu:~$



gcc -DDEBUG 定义宏参数

chunli@ubuntu:~$ cat main.c 
#include <stdio.h>
int main(void)
{
	#ifdef DEBUG
		printf("hello \n");
	#endif

	return 0;
}

chunli@ubuntu:~$ gcc -DDEBUG main.c 
chunli@ubuntu:~$ ./a.out 
hello 
chunli@ubuntu:~$


-E参数:预编译

chunli@ubuntu:~$ gcc -DDEBUG  -E main.c -o main.i
chunli@ubuntu:~$ cat main.i



nm 查看符号表

chunli@ubuntu:~$ nm a.out 
0000000000601040 B __bss_start
0000000000601040 b completed.6973
0000000000601030 D __data_start
0000000000601030 W data_start
0000000000400470 t deregister_tm_clones
00000000004004e0 t __do_global_dtors_aux
0000000000600e18 t __do_global_dtors_aux_fini_array_entry
0000000000601038 D __dso_handle
0000000000600e28 d _DYNAMIC
0000000000601040 D _edata
0000000000601048 B _end
00000000004005c4 T _fini
0000000000400500 t frame_dummy
0000000000600e10 t __frame_dummy_init_array_entry
0000000000400700 r __FRAME_END__
0000000000601000 d _GLOBAL_OFFSET_TABLE_
                 w __gmon_start__
00000000004003e0 T _init
0000000000600e18 t __init_array_end
0000000000600e10 t __init_array_start
00000000004005d0 R _IO_stdin_used
                 w _ITM_deregisterTMCloneTable
                 w _ITM_registerTMCloneTable
0000000000600e20 d __JCR_END__
0000000000600e20 d __JCR_LIST__
                 w _Jv_RegisterClasses
00000000004005c0 T __libc_csu_fini
0000000000400550 T __libc_csu_init
                 U __libc_start_main@@GLIBC_2.2.5
000000000040052d T main
                 U puts@@GLIBC_2.2.5
00000000004004a0 t register_tm_clones
0000000000400440 T _start
0000000000601040 D __TMC_END__
chunli@ubuntu:~$


objdump反汇编

chunli@ubuntu:~$ objdump -dSsx a.out 

a.out:     file format elf64-x86-64
a.out
architecture: i386:x86-64, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x0000000000400440

Program Header:
    PHDR off    0x0000000000000040 vaddr 0x0000000000400040 paddr 0x0000000000400040 align 2**3
         filesz 0x00000000000001f8 memsz 0x00000000000001f8 flags r-x
  INTERP off    0x0000000000000238 vaddr 0x0000000000400238 paddr 0x0000000000400238 align 2**0
         filesz 0x000000000000001c memsz 0x000000000000001c flags r--
    LOAD off    0x0000000000000000 vaddr 0x0000000000400000 paddr 0x0000000000400000 align 2**21
         filesz 0x0000000000000704 memsz 0x0000000000000704 flags r-x
    LOAD off    0x0000000000000e10 vaddr 0x0000000000600e10 paddr 0x0000000000600e10 align 2**21
         filesz 0x0000000000000230 memsz 0x0000000000000238 flags rw-
 DYNAMIC off    0x0000000000000e28 vaddr 0x0000000000600e28 paddr 0x0000000000600e28 align 2**3
         filesz 0x00000000000001d0 memsz 0x00000000000001d0 flags rw-
    NOTE off    0x0000000000000254 vaddr 0x00000



ldd 查看程序依赖哪些库

chunli@ubuntu:~$ cat main.c 
#include <stdio.h>
int main(void)
{
	printf("hello \n");
	return 0;
}

chunli@ubuntu:~$ gcc  main.c && ./a.out 
hello 
chunli@ubuntu:~$ ldd ./a.out 
	linux-vdso.so.1 =>  (0x00007ffc93dad000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6c61011000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f6c613d6000)
chunli@ubuntu:~$





面试题,编写一个静态库并调用

chunli@linux-dev:~$ cat add.c 
int add(int a,int b)
{
	return a+b;
}
chunli@linux-dev:~$ cat main.c 
#include <stdio.h>
int main()
{
	printf("%d\n",add(4,5));
	return 0;
}
chunli@linux-dev:~$ gcc -c add.c 
chunli@linux-dev:~$ ar crs libadd.a add.o 
chunli@linux-dev:~$ gcc main.c -L. -ladd
chunli@linux-dev:~$ ./a.out 
9
chunli@linux-dev:~$




共享库简介:

chunli@ubuntu:~$ cat add.c 
int add(int a,int b)
{
	return a+b;
}

chunli@ubuntu:~$ gcc -fPIC -c add.c 
chunli@ubuntu:~$ ls -l
-rw-rw-r-- 1 chunli chunli       38 Jul 30 16:51 add.c
-rw-rw-r-- 1 chunli chunli     1232 Jul 30 16:51 add.o

后面可以接多个o文件
chunli@ubuntu:~$ gcc -shared -Wl,-soname,libmyadd.so.1 -o libmyadd.so.1.10 add.o 
chunli@ubuntu:~$ ll
-rw-rw-r-- 1 chunli chunli       38 Jul 30 16:51 add.c
-rw-rw-r-- 1 chunli chunli     1232 Jul 30 16:51 add.o
-rwxrwxr-x 1 chunli chunli     7853 Jul 30 16:56 libmyadd.so.1.10*

写个主函数,来调用
chunli@ubuntu:~$ cat main.c 
#include <stdio.h>

int main(void)
{
	printf("%d\n",add(2,4));
	return 0;
}

chunli@ubuntu:~$ gcc  main.c libmyadd.so.1.10
运行时出错 
chunli@ubuntu:~$ ./a.out 
./a.out: error while loading shared libraries: libmyadd.so.1: cannot open shared object file: No such file or directory
chunli@ubuntu:~$ 

查看程序的依赖:可以看到not found
chunli@ubuntu:~$ ldd ./a.out 
	linux-vdso.so.1 =>  (0x00007ffe9c99c000)
	libmyadd.so.1 => not found
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9c35e4c000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f9c36211000)
chunli@ubuntu:~$ 



【问题解决】修改ld.so.conf
追加一行动态库的路径
libmyadd.so.1.10 在 /home/chunli目录下
chunli@ubuntu:~$ cat /etc/ld.so.conf
include /etc/ld.so.conf.d/*.conf
/home/chunli



更新 ldconfig -v
chunli@ubuntu:~$ sudo ldconfig -v
生成了soname,指向realname
chunli@ubuntu:~$ ll
lrwxrwxrwx 1 root   root         16 Jul 30 17:22 libmyadd.so.1 -> libmyadd.so.1.10*
-rwxrwxr-x 1 chunli chunli     7853 Jul 30 17:00 libmyadd.so.1.10*


再次执行
chunli@ubuntu:~$ ./a.out 
6

linkname的制作,都指向realname 
chunli@ubuntu:~$ ln -s libmyadd.so.1.10 libadd.so
chunli@ubuntu:~$ ll
lrwxrwxrwx 1 chunli chunli       16 Jul 30 18:23 libadd.so -> libmyadd.so.1.10*
lrwxrwxrwx 1 root   root         16 Jul 30 17:22 libmyadd.so.1 -> libmyadd.so.1.10*
-rwxrwxr-x 1 chunli chunli     7853 Jul 30 17:00 libmyadd.so.1.10*




静态库实例

源文件:

2016-08-01_14:06:13 chunli@http://990487026.blog.51cto.com~/linux_c$ cat src/add.c 
int add(int a,int b)
{
	return a+b;
}

2016-08-01_14:06:22 chunli@http://990487026.blog.51cto.com~/linux_c$ cat src/div.c 
int div(int a,int b)
{
	if(b == 0)
	{
		return -1;
	}
	return a/b;
}

2016-08-01_14:06:25 chunli@http://990487026.blog.51cto.com~/linux_c$ cat main.c 
#include <stdio.h>

int main(void)
{
	printf("%d\n",add(2,4));
	printf("%d\n",div(8,3));
	return 0;
}



2016-08-01_14:04:57 chunli@http://990487026.blog.51cto.com~/linux_c$ tree
.
├── lib
├── main.c
└── src
    ├── add.c
    └── div.c

 src是源代码
 lib是编译好的库
 main.c是测试程序


编译库文件,与位置无关
2016-08-01_14:07:31 chunli@http://990487026.blog.51cto.com~/linux_c$ cd src/
2016-08-01_14:07:33 chunli@http://990487026.blog.51cto.com~/linux_c/src$ gcc -c -fPIC *.c
2016-08-01_14:07:47 chunli@http://990487026.blog.51cto.com~/linux_c/src$ ls
add.c  add.o  div.c  div.o

做一个静态库:
2016-08-01_14:07:50 chunli@http://990487026.blog.51cto.com~/linux_c/src$ ar rcs libmycal.a *.o
2016-08-01_14:11:03 chunli@http://990487026.blog.51cto.com~/linux_c/src$ ls
add.c  add.o  div.c  div.o  libmycal.a

nm查看一下静态库里面有什么,只是把2个.o文件归档到一起
2016-08-01_14:11:38 chunli@http://990487026.blog.51cto.com~/linux_c/src$ nm libmycal.a 
add.o:
0000000000000000 T add
div.o:
0000000000000000 T div

开始main的测试程序
2016-08-01_14:14:04chunli@http://990487026.blog.51cto.com~/linux_c/src$ cd ..
2016-08-01_14:14:40 chunli@http://990487026.blog.51cto.com~/linux_c$ mv src/libmycal.a  lib/
2016-08-01_14:15:23 chunli@http://990487026.blog.51cto.com~/linux_c$ tree
.
├── lib
│   └── libmycal.a
├── main.c
└── src
    ├── add.c
    ├── add.o
    ├── div.c
    └── div.o

静态库已经编译到程序之中,可以直接运行
优点:复制到任意linux,都可以运行
缺点:文件过大
编译运行:
2016-08-01_14:15:44 chunli@http://990487026.blog.51cto.com~/linux_c$ gcc main.c  lib/libmycal.a 
2016-08-01_14:15:52 chunli@http://990487026.blog.51cto.com~/linux_c$ ./a.out 
6
2

2016-08-01_14:21:44chunli@http://990487026.blog.51cto.com~/linux_c$ ll ./a.out 
-rwxrwxr-x 1 chunli chunli 8.5K Aug  1 14:15 ./a.out*

2016-08-01_14:21:57chunli@http://990487026.blog.51cto.com~/linux_c$ size ./a.out 
   text	   data	    bss	    dec	    hex	filename
   1438	    560	      8	   2006	    7d6	./a.out

查看程序的依赖
2016-08-01_14:22:00chunli@http://990487026.blog.51cto.com~/linux_c$ ldd ./a.out 
	linux-vdso.so.1 =>  (0x00007ffd9439b000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd610550000)
	/lib64/ld-linux-x86-64.so.2 (0x00007fd610915000)



共享库实例

文件目录:
2016-08-01_14:30:43chunli@http://990487026.blog.51cto.com~/linux_c$ tree
.
├── lib
├── main.c
└── src
    ├── add.c
    └── div.c

2016-08-01_14:06:13 chunli@http://990487026.blog.51cto.com~/linux_c$ cat src/add.c 
int add(int a,int b)
{
	return a+b;
}

2016-08-01_14:06:22 chunli@http://990487026.blog.51cto.com~/linux_c$ cat src/div.c 
int div(int a,int b)
{
	if(b == 0)
	{
		return -1;
	}
	return a/b;
}

2016-08-01_14:06:25 chunli@http://990487026.blog.51cto.com~/linux_c$ cat main.c 
#include <stdio.h>

int main(void)
{
	printf("%d\n",add(2,4));
	printf("%d\n",div(8,3));
	return 0;
}


编译与位置不相关
2016-08-01_14:34:11chunli@http://990487026.blog.51cto.com~/linux_c$ cd src/
2016-08-01_14:35:17chunli@http://990487026.blog.51cto.com~/linux_c/src$ gcc -c -fPIC *.c
2016-08-01_14:35:41chunli@http://990487026.blog.51cto.com~/linux_c/src$ ls
add.c  add.o  div.c  div.o

搞一个共享库
2016-08-01_14:38:47chunli@http://990487026.blog.51cto.com~/linux_c/src$ gcc -shared -Wl,-soname,libmycal.so.1 -o libmycal.so.1.10 *.o
2016-08-01_14:38:49chunli@http://990487026.blog.51cto.com~/linux_c/src$ ls
add.c  add.o  div.c  div.o  libmycal.so.1.10

2016-08-01_14:38:50chunli@http://990487026.blog.51cto.com~/linux_c/src$ mv libmycal.so.1.10 ../lib/
2016-08-01_14:40:39chunli@http://990487026.blog.51cto.com~/linux_c/src$ cd ..
2016-08-01_14:40:44chunli@http://990487026.blog.51cto.com~/linux_c$ tree
.
├── lib
│   └── libmycal.so.1.10
├── main.c
└── src
    ├── add.c
    ├── add.o
    ├── div.c
    └── div.o


编译通过,运行报错
2016-08-01_14:43:21chunli@http://990487026.blog.51cto.com~/linux_c$ gcc -o app main.c lib/libmycal.so.1.10 
2016-08-01_14:43:33chunli@http://990487026.blog.51cto.com~/linux_c$ ls
app  lib  main.c  src
2016-08-01_14:43:35chunli@http://990487026.blog.51cto.com~/linux_c$ ./app 
./app: error while loading shared libraries: libmycal.so.1: cannot open shared object file: No such file or directory
2016-08-01_14:43:38chunli@http://990487026.blog.51cto.com~/linux_c$ 

查看依赖:libmycal.so.1 => not found
2016-08-01_14:43:38chunli@http://990487026.blog.51cto.com~/linux_c$ ldd ./app 
	linux-vdso.so.1 =>  (0x00007fffba765000)
	libmycal.so.1 => not found
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f19daf92000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f19db357000)

解决方案:把库的路径搞到/etc/ld.so.conf里面
2016-08-01_14:46:59chunli@http://990487026.blog.51cto.com~/linux_c$ cat /etc/ld.so.conf
include /etc/ld.so.conf.d/*.conf
/home/chunli/linux_c/lib

更新:根据realname自动生成soname
2016-08-01_14:47:59chunli@http://990487026.blog.51cto.com~/linux_c$ sudo ldconfig -v
看看变化:
2016-08-01_14:48:15chunli@http://990487026.blog.51cto.com~/linux_c$ tree
.
├── app
├── lib
│   ├── libmycal.so.1 -> libmycal.so.1.10
│   └── libmycal.so.1.10
├── main.c
└── src
    ├── add.c
    ├── add.o
    ├── div.c
    └── div.o

如果更新失败,重新更新
删除/etc/ld.so.cache 

再查一下,找到了吧   
2016-08-01_14:48:55chunli@http://990487026.blog.51cto.com~/linux_c$ ldd ./app 
	linux-vdso.so.1 =>  (0x00007ffccd709000)
	libmycal.so.1 => /home/chunli/linux_c/lib/libmycal.so.1 (0x00007ff302499000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff3020d4000)
	/lib64/ld-linux-x86-64.so.2 (0x00007ff30269b000)

运行:OK
2016-08-01_14:48:56chunli@http://990487026.blog.51cto.com~/linux_c$ ./app 
6
2

手动生成linkname
2016-08-01_14:55:44chunli@http://990487026.blog.51cto.com~/linux_c/lib$ tree
.
├── libmycal.so -> libmycal.so.1.10
├── libmycal.so.1 -> libmycal.so.1.10
└── libmycal.so.1.10





gdb

gdb调试工具

程序中除了一目了然的Bug之外都需要一定的调试手段来分析到底错在哪。到目前为止

我们的调试手段只有一种:根据程序执行时的出错现象假设错误原因,然后在代码中适当的

位置插入printf,执行程序并分析打印结果,如果结果和预期的一样,就基本上证明了自己

假设的错误原因,就可以动手修正Bug了,如果结果和预期的不一样,就根据结果做进一步

的假设和分析。本章我们介绍一种非常强大的调试工具gdb,可以完全操控程序的运行,使

得程序就像你手里的玩具一样,叫它走就走,叫它停就停,并且随时可以查看程序中所有的

内部状态,比如各变量的值、传给函数的参数、当前执行的语句位置等。掌握了gdb的用法

以后,调试的手段就更加丰富了。但要注意,即使调试的手段非常丰富了,其基本思想仍然

是“分析现象->假设错误原因->产生新的现象去验证假设”这样一个循环,根据现象如何假

设错误原因,以及如何设计新的现象去验证假设,这都需要非常严密的分析和思考,如果因

为手里有了强大的工具就滥用,而忽视了严谨的思维,往往会治标不治本地修正Bug,导致

一个错误现象消失了但Bug仍然存在,甚至是把程序越改越错。本章通过几个初学者易犯的

错误实例来讲解如何使用gdb调试程序,在每个实例后面总结一部分常用的gdb命令。

gcc -g main.c -o main

wKioL1equezRmWzZAAG2eYEb0yc807.png




gdb set命令的使用

wKioL1equgSyCw9WAADD6da65i0306.png



gdb演示:

chunli@ubuntu:~/linux_c$ gdb app
//run	全速运行
(gdb) run
//start 开始运行跑到主函数处
(gdb) start
Temporary breakpoint 1 at 0x4009ce: file main.c, line 189.
Starting program: /home/chunli/linux_c/app 
Temporary breakpoint 1, main () at main.c:189

//加入断点
(gdb) break 189
Breakpoint 2 at 0x4009ce: file main.c, line 189.

//跑到断点处
(gdb) continue

//list显示上下文
(gdb) list
37	
38		//方法2【递归】
39		if(ls)      //只要地址不为NULL
40		{
41			//先序递归
42			printf("地址 %p,本节点的值 %d \n",ls,ls->data);
43			traverse(ls->next);
44	
45		}
46	}
//按回车,继续执行上一条命令
(gdb) 
47	
48	struct list *insert_list(struct list *ls,int n,int data)  //在指定位置插入元素,(首节点,在第几个节点插入,这个节点的data值)
49	{  
50		struct list *p = ls;
51		while(p && n--)
52		{
53			p = p->next;
54		}
55		if(!p) return NULL;//n指向了一个无效的位置
56		else
//next 逐过程执行
(gdb) next

//where 显示我在哪个位置
(gdb) list
184	
185	int main()
186	{
187		//链表操作,入门
188		{
189			struct list *first  = create_list();   //创建一个节点,为首节点
190			struct list *second = create_list();    //再创建一个节点
191			struct list *thrid  = create_list();   //再创建一个节点
192			first  ->next = second;          //第一个指向第二个
193			second ->next = thrid;            //第二个指向第三
(gdb) where
(gdb) where
#0  main () at main.c:189

//break加入断点
(gdb) break 192
Breakpoint 4 at 0x4009f8: file main.c, line 192.
(gdb) break 193
Breakpoint 5 at 0x400a04: file main.c, line 193.

//continue执行到第一个断点处
(gdb) continue
Continuing.

Breakpoint 4, main () at main.c:192
192			first  ->next = second;          //第一个指向第二个
(gdb) 

//next逐过程执行
(gdb) next
(gdb) 
200			free(thrid);
//step进入函数内部
(gdb) step
__GI___libc_free (mem=0x603050) at malloc.c:2935
2935	malloc.c: 没有那个文件或目录.


查看断点信息
(gdb) info breakpoints
Num     Type           Disp Enb Address            What
2       breakpoint     keep y   0x00000000004009ce in main at main.c:189
	breakpoint already hit 1 time
4       breakpoint     keep y   0x00000000004009f8 in main at main.c:192
	breakpoint already hit 1 time
5       breakpoint     keep y   0x0000000000400a04 in main at main.c:193
	breakpoint already hit 1 time
	
显示有3处断点	
//删除Num为2的断点
(gdb) delete breakpoints 2
	
//printf的打印变量信息功能
(gdb) where
#0  main () at main.c:192
(gdb) list
187		//链表操作,入门
188		{
189			struct list *first  = create_list();   //创建一个节点,为首节点
190			struct list *second = create_list();    //再创建一个节点
191			struct list *thrid  = create_list();   //再创建一个节点
192			first  ->next = second;          //第一个指向第二个
193			second ->next = thrid;            //第二个指向第三
194			first  ->data = 1    ;       //为节点设置数值
195			second ->data = 2;
196			thrid  ->data = 3;
(gdb) print second
$1 = (struct list *) 0x603030
(gdb) print &second
$2 = (struct list **) 0x7fffffffe4d0
(gdb) print first
$3 = (struct list *) 0x603010
(gdb) print &first
$4 = (struct list **) 0x7fffffffe4c8
(gdb) 

//显示结构体信息
//显示指针的值信息
(gdb) print first
$5 = (struct list *) 0x603010
(gdb) print *first
$6 = {data = 0, next = 0x0}
(gdb) print &first
$7 = (struct list **) 0x7fffffffe4c8
(gdb) 


list 简写 l
continue简写c
break 简写 b

查看当前栈帧(反映出函数调用关系)
(gdb) bt
#0  0x0000000000400622 in traverse (ls=0x2c30353033303678) at main.c:42
#1  0x000000000040064a in traverse (ls=0x603050) at main.c:43
#2  0x000000000040064a in traverse (ls=0x603030) at main.c:43
#3  0x000000000040064a in traverse (ls=0x603010) at main.c:43
#4  0x0000000000400a46 in main () at main.c:202



Makefile

wKioL1eqvGPQKs4GAAN3iifqP3U224.jpg



有以下文件

chunli@ubuntu:~/linux_c$ ll
总用量 24K
-rw-rw-r-- 1 chunli chunli  40 8月  10 10:14 add.c
-rw-rw-r-- 1 chunli chunli  39 8月  10 10:16 dive.c
-rw-rw-r-- 1 chunli chunli 163 8月  10 10:23 main.c
-rw-rw-r-- 1 chunli chunli  38 8月  10 10:16 mul.c
-rw-rw-r-- 1 chunli chunli 134 8月  10 10:22 myfun.h
-rw-rw-r-- 1 chunli chunli  40 8月  10 10:15 sub.c

文件内容:
chunli@ubuntu:~/linux_c$ cat add.c 
int add(int a,int b)
{
	return a + b;
}
chunli@ubuntu:~/linux_c$ cat dive.c 
int dive(int a,int b)
{
	return a*b;
}
chunli@ubuntu:~/linux_c$ cat main.c 
#include <stdio.h>
#include "myfun.h"

int main(void)
{
	printf("%d\n",add(3,5));
	printf("%d\n",sub(3,5));
	printf("%d\n",dive(3,5));
	printf("%d\n",mul(3,5));
}
chunli@ubuntu:~/linux_c$ cat mul.c 
int mul(int a,int b)
{
	return a/b;
}
chunli@ubuntu:~/linux_c$ cat myfun.h 
#ifndef _MYFUN_H_
#define _MYFUN_H_
int add(int a,int b);
int sub(int a,int b);
int dive(int a,int b);
int mul(int a,int b);

#endif

chunli@ubuntu:~/linux_c$ cat sub.c 
int sub(int a,int b)
{
	return a - b;
}
chunli@ubuntu:~/linux_c$


编译方法1:最原始的方法

chunli@ubuntu:~/linux_c$ ./a.out 
8
-2
15
0
chunli@ubuntu:~/linux_c$





编译方法2:

chunli@ubuntu:~/linux_c$ cat Makefile 
#阶段1
app:add.c sub.c dive.c mul.c main.c
	gcc add.c  sub.c dive.c mul.c  main.c -o app
chunli@ubuntu:~/linux_c$ make
gcc add.c  sub.c dive.c mul.c  main.c -o app
chunli@ubuntu:~/linux_c$ ./app 
8
-2
15
0
chunli@ubuntu:~/linux_c$ 

------------------------------------------------------
编译方法3;

Makefile,冒号左边是目标,右边是依赖,tab右边是执行
chunli@ubuntu:~/linux_c$ cat Makefile 
#阶段2

app:add.o sub.o dive.o mul.o main.o
	gcc add.o sub.o dive.o mul.o main.o -o app
add.o:add.c
	gcc -c add.c
sub.o:sub.c
	gcc -c sub.c
dive.o:dive.c
	gcc -c dive.c
mul.o:mul.c
	gcc -c mul.c
main.o:main.c
	gcc -c main.c
clean:#如果目标不依赖任何条件,则执行对应命令
	rm *.o
	rm app
chunli@ubuntu:~/linux_c$ make clean
rm *.o
rm app
chunli@ubuntu:~/linux_c$ make
gcc -c add.c
gcc -c sub.c
gcc -c dive.c
gcc -c mul.c
gcc -c main.c
gcc add.o sub.o dive.o mul.o main.o -o app
chunli@ubuntu:~/linux_c$ ./app 
8
-2
15
0
chunli@ubuntu:~/linux_c$


make clean的尴尬,

如果目录下有一个叫clean的文件,make clean的命令就不能正常使用

chunli@ubuntu:~/linux_c$ ll
总用量 60K
-rw-rw-r-- 1 chunli chunli   40 8月  10 10:14 add.c
-rw-rw-r-- 1 chunli chunli 1.3K 8月  10 10:42 add.o
-rwxrwxr-x 1 chunli chunli 8.7K 8月  10 10:42 app*
-rw-rw-r-- 1 chunli chunli   39 8月  10 10:16 dive.c
-rw-rw-r-- 1 chunli chunli 1.3K 8月  10 10:42 dive.o
-rw-rw-r-- 1 chunli chunli  163 8月  10 10:23 main.c
-rw-rw-r-- 1 chunli chunli 2.0K 8月  10 10:42 main.o
-rw-rw-r-- 1 chunli chunli  307 8月  10 10:42 Makefile
-rw-rw-r-- 1 chunli chunli   38 8月  10 10:16 mul.c
-rw-rw-r-- 1 chunli chunli 1.3K 8月  10 10:42 mul.o
-rw-rw-r-- 1 chunli chunli  134 8月  10 10:22 myfun.h
-rw-rw-r-- 1 chunli chunli   40 8月  10 10:15 sub.c
-rw-rw-r-- 1 chunli chunli 1.3K 8月  10 10:42 sub.o
chunli@ubuntu:~/linux_c$ touch clean
chunli@ubuntu:~/linux_c$ make clean
make: 'clean' is up to date.
chunli@ubuntu:~/linux_c$



解决办法:

加入.PHONY:clean就好了

chunli@ubuntu:~/linux_c$ ll
总用量 60K
-rw-rw-r-- 1 chunli chunli   40 8月  10 10:14 add.c
-rw-rw-r-- 1 chunli chunli 1.3K 8月  10 10:42 add.o
-rwxrwxr-x 1 chunli chunli 8.7K 8月  10 10:42 app*
-rw-rw-r-- 1 chunli chunli    0 8月  10 10:44 clean
-rw-rw-r-- 1 chunli chunli   39 8月  10 10:16 dive.c
-rw-rw-r-- 1 chunli chunli 1.3K 8月  10 10:42 dive.o
-rw-rw-r-- 1 chunli chunli  163 8月  10 10:23 main.c
-rw-rw-r-- 1 chunli chunli 2.0K 8月  10 10:42 main.o
-rw-rw-r-- 1 chunli chunli  320 8月  10 10:46 Makefile
-rw-rw-r-- 1 chunli chunli   38 8月  10 10:16 mul.c
-rw-rw-r-- 1 chunli chunli 1.3K 8月  10 10:42 mul.o
-rw-rw-r-- 1 chunli chunli  134 8月  10 10:22 myfun.h
-rw-rw-r-- 1 chunli chunli   40 8月  10 10:15 sub.c
-rw-rw-r-- 1 chunli chunli 1.3K 8月  10 10:42 sub.o
chunli@ubuntu:~/linux_c$ cat Makefile 
#阶段2

app:add.o sub.o dive.o mul.o main.o
	gcc add.o sub.o dive.o mul.o main.o -o app
add.o:add.c
	gcc -c add.c
sub.o:sub.c
	gcc -c sub.c
dive.o:dive.c
	gcc -c dive.c
mul.o:mul.c
	gcc -c mul.c
main.o:main.c
	gcc -c main.c
.PHONY:clean
clean:#如果目标不依赖任何条件,则执行对应命令
	rm -f *.o
	rm -f app
chunli@ubuntu:~/linux_c$ make clean
rm *.o
rm app
chunli@ubuntu:~/linux_c$


-可以忽略当rm出错时,makefile继续执行下一步

chunli@ubuntu:~/linux_c$ cat Makefile 
#阶段2

app:add.o sub.o dive.o mul.o main.o
	gcc add.o sub.o dive.o mul.o main.o -o app
add.o:add.c
	gcc -c add.c
sub.o:sub.c
	gcc -c sub.c
dive.o:dive.c
	gcc -c dive.c
mul.o:mul.c
	gcc -c mul.c
main.o:main.c
	gcc -c main.c
.PHONY:clean
clean:#如果目标不依赖任何条件,则执行对应命令
	-rm -f *.o
	-rm -f app
chunli@ubuntu:~/linux_c$


@不显示语法的执行

chunli@ubuntu:~/linux_c$ cat Makefile 
test:
	echo "Hello"

chunli@ubuntu:~/linux_c$ make test
echo "Hello"
Hello
chunli@ubuntu:~/linux_c$ 


加了@符号,就隐藏起来了
chunli@ubuntu:~/linux_c$ 
chunli@ubuntu:~/linux_c$ cat Makefile 
test:
	@echo "Hello"
chunli@ubuntu:~/linux_c$ make test
Hello
chunli@ubuntu:~/linux_c$


方法4 通用的makefile

chunli@ubuntu:~/linux_c$ cat Makefile 
#阶段3
#设置变量obj
obj=add.o sub.o mul.o dive.o main.o
#引用obj这个变量
add:$(obj)
	gcc $(obj) -o app
.PHONY:clean
clean:
	-rm -f *.o
	-rm -f app
chunli@ubuntu:~/linux_c$ make 
cc    -c -o add.o add.c
cc    -c -o sub.o sub.c
cc    -c -o mul.o mul.c
cc    -c -o dive.o dive.c
cc    -c -o main.o main.c
gcc add.o sub.o mul.o dive.o main.o -o app
chunli@ubuntu:~/linux_c$ ./app 
8
-2
15
0
chunli@ubuntu:~/linux_c$




方法4 通用的makefile,自建内联语法

chunli@ubuntu:~/linux_c$ 
chunli@ubuntu:~/linux_c$ ll
总用量 28K
-rw-r--r-- 1 root   root     0 8月  10 11:05 abc
-rw-rw-r-- 1 chunli chunli  40 8月  10 10:14 add.c
-rw-rw-r-- 1 chunli chunli   0 8月  10 10:44 clean
-rw-rw-r-- 1 chunli chunli  39 8月  10 10:16 dive.c
-rw-rw-r-- 1 chunli chunli 163 8月  10 10:23 main.c
-rw-rw-r-- 1 chunli chunli 342 8月  10 11:17 Makefile
-rw-rw-r-- 1 chunli chunli  38 8月  10 10:16 mul.c
-rw-rw-r-- 1 chunli chunli 134 8月  10 10:22 myfun.h
-rw-rw-r-- 1 chunli chunli  40 8月  10 10:15 sub.c
chunli@ubuntu:~/linux_c$ cat Makefile 
#阶段3
#设置变量obj
obj=add.o sub.o mul.o dive.o main.o
#引用obj这个变量
add:$(obj)
	gcc $(obj) -o app

#手动内建语法规则
# $@代表目标 $^代表所有依赖项 $<代表依赖中的第一个
%.o:%c#o文件依赖c文件
	gcc -c  $< -o $@ #理解:如果遇到add.o依赖add.c


.PHONY:clean
clean:
	-rm -f *.o
	-rm -f app
chunli@ubuntu:~/linux_c$ make 
cc    -c -o add.o add.c
cc    -c -o sub.o sub.c
cc    -c -o mul.o mul.c
cc    -c -o dive.o dive.c
cc    -c -o main.o main.c
gcc add.o sub.o mul.o dive.o main.o -o app
chunli@ubuntu:~/linux_c$ ./app 
8
-2
15
0
chunli@ubuntu:~/linux_c$


Makefile的 wildcard查找功能


列出目录所有的C文件

chunli@ubuntu:~/linux_c$ cat Makefile 
src = $(wildcard *.c)
test:
	@echo $(src)

	chunli@ubuntu:~/linux_c$ make test
mul.c dive.c main.c add.c sub.c
chunli@ubuntu:~/linux_c$


Makefile patsubst字符串替换

#查找目录下所有的C文件
src = $(wildcard *.c)
#把变量src的.c文件替换成.o文件,保存到obj
obj = $(patsubst %.c,%.o,$(src))
test:
	@echo $(src)
	@echo $(obj)

chunli@ubuntu:~/linux_c$ make test
mul.c dive.c main.c add.c sub.c
mul.o dive.o main.o add.o sub.o
chunli@ubuntu:~/linux_c$


wildcard patsubst 通用makefile

chunli@ubuntu:~/linux_c$ cat Makefile 
#阶段3,通用makefile

#查找目录下所有的C文件
src = $(wildcard *.c)

#把变量src的.c文件替换成.o文件,保存到obj
obj = $(patsubst %.c,%.o,$(src))

#编译出目标程序
target = app
$(target):$(obj)
	gcc $^ -o $@

#自建内联语法
%.o:%.c		#$@代表目标 $^代表所有依赖项 $<代表依赖中的第一个
	gcc -c $< -o $@

test:
	@echo $(src)
	@echo $(obj)
.PHONY:clean
clean:
	-rm -f *.o
	-rm -f app
chunli@ubuntu:~/linux_c$ make
gcc -c mul.c -o mul.o
gcc -c dive.c -o dive.o
gcc -c main.c -o main.o
gcc -c add.c -o add.o
gcc -c sub.c -o sub.o
gcc mul.o dive.o main.o add.o sub.o -o app
chunli@ubuntu:~/linux_c$ ./app 
8
-2
15
0
chunli@ubuntu:~/linux_c$


阶段4 灵活的通用Makefile文件

chunli@ubuntu:~/linux_c$ tree
.
├── add.c
├── dive.c
├── include
│   └── myfun.h
├── main.c
├── Makefile
├── mul.c
└── sub.c

1 directory, 7 files
chunli@ubuntu:~/linux_c$ cat Makefile 
#阶段4,通用makefile

CPPFLAGS = -Iinclude #比如我的头文件都在include目录内
CFLAGS = -g -Wall -O2 
LDFLAGS = 	#link,没有可以不写
CC  = gcc	#arm-linux-gcc

#查找目录下所有的C文件
src = $(wildcard *.c)

#把变量src的.c文件替换成.o文件,保存到obj
obj = $(patsubst %.c,%.o,$(src))

#编译出目标程序
target = app
$(target):$(obj)
	$(CC) $^  $(LDFLAGS) -o $@

#自建内联语法
%.o:%.c		#$@代表目标 $^代表所有依赖项 $<代表依赖中的第一个
	$(CC) -c $< $(CFLAGS) $(CPPFLAGS) -o $@  

test:
	@echo $(src)
	@echo $(obj)
.PHONY:clean
clean:
	-rm -f *.o
	-rm -f app
chunli@ubuntu:~/linux_c$ make
gcc	 -c mul.c -g -Wall -O2  -Iinclude  -o mul.o  
gcc	 -c dive.c -g -Wall -O2  -Iinclude  -o dive.o  
gcc	 -c main.c -g -Wall -O2  -Iinclude  -o main.o  
gcc	 -c add.c -g -Wall -O2  -Iinclude  -o add.o  
gcc	 -c sub.c -g -Wall -O2  -Iinclude  -o sub.o  
gcc	 mul.o dive.o main.o add.o sub.o   -o app
chunli@ubuntu:~/linux_c$ ./app 
8
-2
15
0
chunli@ubuntu:~/linux_c$