[学习笔记]达内纪录片day19 大型项目的构建

    选择打赏方式

一、 大型应用项目的构建

一个大型项目,通常需要需要一个团队协同开发,多人不可能写一份代码,而是要模块化开发,每个人开发一个模块,分别实现一些功能,最后组装起来。

C语言提供了头文件的方式进行模块化开发。


多个源文件是如何链接生成可执行文件的   链接的时候做了什么?
nm 二进制文件     查看二进制文件中符号 

nm结果含义

nm 将找到的符号值使用十六进制缺省表示,并在函数前添加其类型,类型主要有:


Value Descripition Note
A The symbol's value is absolute, and will not be changed by further linking. 符号绝对,链接过程不会改变
B/b The symbol is in the uninitialized data section (known as BSS). 非初始化符号
C The symbol is common. 公有符号,链接时会被同名符号覆盖
D/d The symbol is in the initialized data section. 初始化符号
G/g The symbol is in an initialized data section for small objects. 初始化符号,面向小数据访问优化
I The symbol is an indirect reference to another symbol. 其它符号的间接引用
N The symbol is a debugging symbol. 调试符号
P The symbols is in a stack unwind section. 栈区符号(清空)
R/r The symbol is in a read only data section. 符号只读
S/s The symbol is in an uninitialized data section for small objects. 非初始化符号,面向小数据访问优化
T/t The symbol is in the text (code) section. 代码区符号
U The symbol is undefined. 未定义或在外部定义的符号
u The symbol is a unique global symbol. 全局唯一,GNU保留符
V/v The symbol is a weak object. 弱定义符(详见C++强弱符号定义)
W/w The symbol is a weak symbol that has not been specifically tagged as a weak object symbol. emm...绕口令符号
- The symbol is a stabs symbol in an a.out object file. stabs格式符号
? The symbol type is unknown, or object file format specific. NM也不认识的符号


 file  文件名  查看文件的类型
可重定位的目标文件 
可执行的二进制文件


二、静态库文件的制作和使用

静态库是一些.o目标文件的集合,一般以.a形式结尾。静态库在程序链接阶段使用,链接器将程序要用到的函数从库中提取出来,并整合到程序中,程序运行不再使用静态库了。由于每个程序要用到函数都从库提取并整合在一起,所以可执行文件夹会比较大。

静态库的好处是使用方便,对于企业来说也可以隐藏项目的核心代码,非核心员工调用即可完成工作,虽然可以逆向,但是真正会完整逆出来的人,自己写也是完全ok的。


生成方法:

gcc -c 源文件1.c 源文件2.c ...源文件n

ar -r lib库文件名.a 目标文件1.o 目标文件2.o ...目标文件n

使用方法
在main中引入相应的头文件,直接使用静态库中的函数即可。

编译方法

gcc main.c -L路径 -l库文件名

三、动态库的制作和使用
动态库本身文件比较大,包含了目标文件中所有的函数,但是动态库并不会被真正编译到可执行文件,而是完全独立于可执行文件,在运行时被加载进来,也可以由程序员动态的加载和卸载。

-fPIC 作用于编译阶段,告诉编译器产生与位置无关代码(Position-Independent Code),则产生的代码中,没有绝对地址,全部使用相对地址,故而代码可以被加载器加载到内存的任意位置,都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。
PIC使.so文件的代码段变为真正意义上的共享 

如果不加-fPIC,则加载.so文件的代码段时,代码段引用的数据对象需要重定位, 重定位会修改代码段的内容,这就造成每个使用这个.so文件代码段的进程在内核里都会生成这个.so文件代码段的copy.每个copy都不一样,取决于 这个.so文件代码段和数据段内存映射的位置.


生成方法
gcc -c 源文件1.c 源文件2.c ...源文件n

gcc -shared -fPIC -o ib库文件名.so 目标文件1.o 目标文件2.o ...目标文件n

   -shared:表示要创建共享库;

   -fpci或-fPCI:表示创建产生独立目标代码,具体应用取决于平台;

使用方法
在main中引入相应的头文件,直接使用静态库中的函数,或者由调用程序动态加载后使用。
编译方法
gcc main.c -L路径 -l库文件名
运行时需要
sudo cp 库文件名.so /usr/lib
export LD_LIBRARY_PATH=库文件目录

四、环境变量
所有的应用级进程构成了一棵树  进程树
如何查看计算本上的进程树呢?
pstree(1)
进程的关系   父子关系  兄弟关系


每个进程都有自己的环境变量列表。
进程执行期间通过环境变量访问计算机的资源。
环境变量表是进程的属性之一
每个进程都拥有一张独立的环境变量表,其中保存着专属于该进程的所有环境变量

bash 进程的环境变量
查看bash进程的环境变量列表
env(1)


环境变量的组织形式 name=value 
注意:=的两边绝对不允许出现空格


取出环境变量的值

$name


echo 字符串   将字符串输出到显示器
grep  字符串 filename   在filename文件中查找含有字符串的行,将这些行提取出来。

env|grep 字符串 (| 管道)

给环境变量设置初值
name=value   如果环境变量name存在,改变环境变量的值。
                    如果环境变量name不存在,创建一个自定义变量


bash进程有环境变量和自定义变量
环境变量是可以被子进程继承的
自定义变量是进程私有的,不能被子进程继承


自定义变量转环境变量
export 变量名


使用set命令显示所有本地定义的Shell变量


使用unset命令来清除环境变量

unset 变量名


使用readonly命令设置只读变量

readonly 变量名


环境变量表数据结构
环境变量表是一个以空指针结尾的字符指针数组,其中每个指针指向一个格式为“变量名=变量值”的字符串,该指针数组的起始地址保存在全局变量environ中。

TIM截图20190728005808.png

通过环境变量表指针environ访问所有环境变量

演示源码:

#include <stdio.h>
int main(){
	extern char** environ;
	char **pp;
	for(pp=environ;pp && *pp;++pp)
		printf("%s\n",*pp);
	return 0;
}


运行结果:

TIM截图20190728012116.png


通过main函数的第三个参数访问环境变量

main函数的第三个参数就是环境变量表的起始地址

演示源码:

#include <stdio.h>
int main(int argc,char* argv[],char* envp[]){
	char** pp;
	for(pp=envp;pp && *pp;++pp)
		printf("%s\n",*pp);
	return 0;
}


运行结果同上


调用任何操作环境变量的函数都需要包含标准库头文件
#include <stdlib.h>


获取环境变量

根据环境变量的名称获取该变量的值
char*getenv(const char* name)

参数:

-name:环境变量名

返回值:成功返回与参数匹配的环境变量的值,失败返回NULL


设置环境变量

增加新的环境变量或修改已有环境变量的值
int putenv(char* string)

参数:

-string:指向形如“变量名=变量值”的字符串,若变量名不存在就增加该环境变量,否则就修改该环境变量的值

返回值:成功返回0,失败返回非0


设置环境变量方式2

int setenv(const char* name,const char *value,int overwrite)

参数:
-name:环境变量名,若该变量名不存在就增加该环境变量,否则由overwrite参数决定是否修改该环境变量的值
-value:环境变量值
-overwrite:当name参数所表示的环境变量已存在时,若此参数非0则将该环境变量的值修改为value,否则该环境变量的值保持不变

返回值:成功返回0,失败返回-1


删除环境变量

根据环境变量的名称删除环境变量

int unsetenv(const char* name)

参数:

-name:环境变量名

返回值:成功返回0,失败返回-1

清空环境变量表
清除所有的环境变量
int clearenv(void)

返回值:成功返回0,失败返回非0
说明:该函数在清除掉所有环境变量后,把用于表示环境变量表首地址的全局变量environ设置成空指针

演示源码:

#include <stdio.h>
#include <stdlib.h>
int main(){
	printf("PATH=%s\n",getenv("PATH"));
	putenv("TEST=100");
	printf("TEST=%s\n",getenv("TEST"));
	int ret=setenv("TEST","200",1);
	printf("修改是否成功:%d,TEST=%s\n",ret,getenv("TEST"));
	ret=setenv("TEST","300",0);
	printf("修改是否成功:%d,TEST=%s\n",ret,getenv("TEST"));
	unsetenv("TEST");
	printf("TEST=%s\n",getenv("TEST"));
	clearenv();
	extern char** environ;
	printf("%p\n",environ);
	return 0;
}


运行结果:

TIM截图20190728023844.png


补充:bash脚本设置

vi .bashrc    //打开bashrc脚本文件

写入如下内容

PS1=‘\W\$’    //命令提示符 root为# 普通为$

PATH=$PATH:.    //相当于取出PATH的值后加上:.,不能把之前的覆盖掉


PS1设置参考资料:https://www.cnblogs.com/feiyun126/p/6125608.html


THE END!

版权声明:若无特殊注明,本文皆为《 8964CN 》原创,转载请保留文章出处。
本文链接:[学习笔记]达内纪录片day19 大型项目的构建 http://www.8964cn.net/?post=80
正文到此结束

热门推荐

发表吐槽

你肿么看?

你还可以输入 250 / 250 个字

嘻嘻 大笑 可怜 吃惊 害羞 调皮 鄙视 示爱 大哭 开心 偷笑 嘘 奸笑 委屈 抱抱 愤怒 思考 日了狗 胜利 不高兴 阴险 乖 酷 滑稽

评论信息框

吃奶的力气提交吐槽中...


既然没有吐槽,那就赶紧抢沙发吧!