时间
Access:文件最近被访问的时间,
Modify: 最近一次修改文件内容的时间
Change:最近一次修改文件属性的时间
Change time
修改文件内容的时候,有可能也会修改文件的属性
比如: 可能会更改文件的大小属性
我们会发现操作下来, 文件时间貌似没有变化:
在较新的Linux内核中,Accsee中不会被立即刷新更新,而是有一定的时间间隔进行刷新
makefile更新的机制
makefile and gcc 会根据时间问题,来判定源文件和可执行文件次序谁更新,为就以谁为主
如gcc test.c -o test
如果test的modify时间比test.c的modify时间新,说明就已经更新了,反之,如果test.c的时间比test的时间新,说明makefile需要更新
对于这种伪目标的,他总是被执行,因为他不关心时间
touch会更新文件的时间,我们重新make也可以
静态库和动态库
查看可执行程序依赖库
ldd 【可执行文件】
第二个是c标准库,我们查看了一下,发现是软链接,
我们发现这个文件也是有inode
linux当中,一般库分为两种: 动态库和静态库(库也是一个文件)
在Linux中,如果是库文件:库文件一般是以.so作为后缀的,如果是静态库,一般是以.a为后缀的
- 库文件的命名:
::libXXX.so- or libYYY.a-- 库的真正名字
去掉包含lib前缀,去掉包含a-,so-的后缀
如/lib64/libc.so.1真实名字就是c
/lib64/libc-2.17.so真实名字就是c-2.17
c++标准库
也可以使用file查看连接库的情况
动态库只有一个,删除的话,其他文件都无法使用了
如何制作库
库本身就是一个二进制文件,
一套完整的库:
- 库文件本身
- 头文件.h(文本,会说明库中暴露出来的方法的基本使用!)
我们在C/C++ 中,为什么在写代码的时候,有时候.h里面放上声明,在.c里面放上定义,为什么要这么设计
因为我们要制作库!
- 方便使用 2. 私密,比较安全,用库对头文件进行封装保护,
我们在other目录下面写一个add.cpp add.h这两个,一个声明,一个定义- 如果我们想要使用的话,要加上这个库的路径
- 编译的时候
添加上特定的路径中的定义,才能使用
如果没有库,我们想要编译要怎么编译呢
mytest:%.o
gcc -o $@ $^
%.o:%.c
gcc -c $<
,o是我们汇编之后生成的
所以%.o 依赖所有的%.c
$<就是把上面的所有东西展开,一个一个的进行编译
1 obj=mytest.o add.o sub.o
2
3 mytest:$(obj)
4 gcc -o $@ $^
5 %.o:%.c
6 gcc -c $<
7
8 %.o:./other/%.c
9 gcc -c $<
先形成3个.o文件,最后在链接形成可执行
如果我们想把自己的代码给别人用
- 提供源代码+头文件
- 只提供.o文件也可以链接,所以库的思想:就是把所有的.o打包就是库了
打包成一个库
- 所有的源代码要先被编译成为.0文件(可重定向文件)
- 制作动静态库的本质就是将所有.0打包好,使用ar 或者gcc来打包
- 交付: inlcude + .a or .so文件
ar (类比tar)
-rc(replace and creat)
libmymath.a:sub.o add.o
ar -rc $@ $^ //把所有的.o文件都打包成一个静态库
%.o:%.c
gcc -c $< //把所有的.c都展开成.o文件
查看静态库中的内容
我们可以查看c标准静态库中的内容都是.o
这样我们就把我们自己的源文件都隐藏起来
别人想要用我们的库,就还需要一些头文件,因为二进制根本看不懂
所以我们可以发布一个output
PHONY:output
output:
mkdir output
cp -rf *.h output
cp libmymath.a output
头文件和库文件都在
使用自己的库
#include"add.h"
#include"sub.h"
int main()
{
int x=10;
int y=2;
int y1=add(x,y);
printf("y1=%d" ,y1);
return 0;
}
$ gcc demo.c -I./output -L./output -lmymath
这样编译才可以
-I 指明,我们要使用知名头文件搜索路径
-L 指明:我们要指明库文件的搜索路径
-l 指明:我们要链接那一个库
我们之前写的代码,也用了库,为什么就没有指明选项呢??
之前的库,在系统的默认路径下,/lib64,/user/lib,/user/include等
编译器是能够识别这些路径的,
换一句话说我们如果想不添加这些选项,我是不是可以把对应的库和头文件,拷贝到默认的路径之下
没有问题的,这也就是一般软件的安装过程
我们给别人交付的其实就是一个库文件+ 一套头文件
形成动态库
libmymath.so:add.o sub.o
gcc -shared -o $@ $^
%.o:%.c
gcc -fPIC -c $<
.PHONY:clean
clean:
rm -f libmymath.so
.PHONY:lib
lib:
mkdir lib
cp *.h lib
cp libmymath.so lib
编译使用的方法和静态库一样的
我们在加载的时候,还要进一步高树系统,我们的库在哪里,因为动态库我们编译的时候需要,不编译的时候就不需要,不像静态库是一次性直接拷贝进去,在编译的时候就不需要去考虑库在哪里
编译
$ gcc x.c -o x -I./lib -L./lib -lmymath
导入环境变量
export LD_LIBRARY_PATH=/home/xvzewen/githubgovern/Linuxstudy/link/friend/lib
执行
./x
为什么我们之前写所有的代码都没有报错呢??
默认情况下我们都是动态的,因为我们一定有动态库!,因为我们linux很多都是用c语言写的