我知道,对于许多使用公共共享库的进程,共享库中的二进制代码可以更新,而不必更新所有这些进程。只要是内部实现更改,并且不删除导出的函数或更改导出函数的参数就可以了。
我不确定如何将其与 Makefile 依赖项协调。简单的准则是,如果文件被任何命令引用,则它是一个依赖项,应作为先决条件在 Makefile 规则中列出。
链接可执行文件时,它肯定可以引用共享对象,因此依赖于该共享对象。但是,似乎并不总是因为共享对象发生了变化而需要重新链接。
所以我想知道将库列为依赖项:
all: process
# listing library.so as dependency
process: file.o library.so
gcc -o process file.o library.so
library.so: library.o
gcc -shared -o library.so library.o
library.o: library.h
与不列出它:
all: library.so process
# not listing library.so as dependency
process: file.o
gcc -o process file.o library.so
library.so: library.o
gcc -shared -o library.so library.o
file.o: library.h
library.o: library.h
假设library.h
包含从library.so
导出的所有函数的声明。
如果library.so
是process
的依赖关系,那么似乎如果我只更改函数的实现(不更改导出的函数签名),那么我不需要重新链接process
,但是make
命令会重新链接library.so
,然后反过来重新链接process
。
但是,如果library.so
不是process
的依赖项,那么make
仍然会通过all
目标重新链接library.so
以实现更改,但不会重新链接process
。如果我更改函数参数的数据类型、添加/删除函数参数或添加/删除函数,则library.h
将进行更改。这将反过来触发重新编译file.o
,进而触发重新链接process
。
使用library.h
来控制file.o
的重新编译,因此间接控制process
的重新链接仍然是不精确的,因为file.o实际上可能没有引用任何从更改 library.so 导出的函数。
我回顾了这个问题,但我找不到有关进程共享对象依赖项的任何具体信息: 生成文件依赖项,什么是依赖项?
如果您不将library.so
列为process
的依赖项,如果您修改其源之一(library.so
的源文件),则很可能以与程序process
不兼容library.so
结束,并且当您尝试执行它时,您的程序可能会崩溃。
认为您更改了库,消除了从中f()
的功能,因为您不再需要它......但是您的程序仍然process
在其main()
函数中调用它。 由于您没有修改process.o
(您没有接触它的任何源代码),因此不会对其进行编译,也不会执行新的链接命令(因为process
仅取决于process.o
)。
上次链接process
链接器在 main 中调用了f()
,并决定将其放在地址x
(对应于library.so
中存在的地址)。 但是,由于您没有说明如果library.so
发生变化,process
需要链接,因此不会链接...当你执行它时,它会在地址x
调用f()
并崩溃。
试试这个,你会发现如果你把依赖留在library.so
,那么你的程序将被链接到共享库,并会抱怨f()
不存在。 所以你应该修改process.c
并重复。
总是这样想...链接process
是否需要文件library.so
?如果是,那么您应该依赖它。 确实如此,因为您在library.so
中编写的函数是从process
调用的。 您将看到.h
文件的依赖项放在.o
目标上,而不是放在.c
文件上。 这是因为需要.c
和所有包含的.h
文件来生成.o
对象。 但是.c
文件不依赖于.h
文件...取决于编译的结果(这是.o
文件)。
第二个文件,对目标all
有假依赖。 这就是所谓的.PHONY:
目标(始终执行的目标,不需要创建文件)使用它,您可以尝试创建library.so
和process
。 如果在链接进程时存在library.so
,那么它将被包含(但不知道它是最近的 buid 还是旧的),但如果不是,当你尝试构建进程时,如果library.so
尚不存在,那么你会收到链接器的强烈抱怨,你的构建将被中止。
因此,作为结论,第二Makefile
是不正确的,您应该避免它。 在检查依赖项时make(1)
声明依赖项。
最后要注意的是,根据 Make 的实现,规则右侧的依赖项顺序可能很重要,也可能不重要。 如果您在多处理器上运行 make 并尝试执行并行构建,library.so
放在process
的左侧可能是一个坏主意(请参阅make(1)
的选项-j
)。 在并行构建中,make(1)
在满足依赖文件的所有依赖项之前不会开始构建依赖文件......但它尝试启动尽可能多的进程,以在多处理器计算机上处理这种可能性。 如果您拥有完整的内核集,构建过程会加快很多速度,但如果您不精确观察依赖项,则可能会很危险。