C makefile先决条件是否应列出共享对象?

C makefile先决条件是否应列出共享对象?,c,gcc,makefile,C,Gcc,Makefile,我知道,对于使用公共共享库的许多进程,可以更新共享库中的二进制代码,而不必更新所有这些进程。只要是内部实现更改,并且不删除导出函数或更改导出函数的参数,就可以了 但我不确定如何将其与Makefile依赖项相协调。简单的指导原则是,如果文件被任何命令引用,那么它是一个依赖项,应该在Makefile规则中作为先决条件列出 链接可执行文件时,它肯定可以引用共享对象,因此依赖于该共享对象。但是,似乎并不总是因为共享对象发生了更改就需要重新链接 所以我想知道如何将库列为依赖项: all: process

我知道,对于使用公共共享库的许多进程,可以更新共享库中的二进制代码,而不必更新所有这些进程。只要是内部实现更改,并且不删除导出函数或更改导出函数的参数,就可以了

但我不确定如何将其与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
不是
过程的依赖项,则
make
仍将通过
all
目标重新链接
library.so
,而不是重新链接
过程。如果更改函数参数的数据类型、添加/删除函数参数或添加/删除函数,则
library.h
将发生更改。这将依次触发重新编译
文件.o
,并依次触发重新链接
进程

但是,使用
library.h
来控制
文件.o的重新编译,从而间接控制
进程的重新链接仍然是不精确的,因为file.o可能实际上没有引用库中导出的任何函数。因此,更改了

我回顾了这个问题,但找不到关于流程的共享对象依赖关系的任何具体信息:
如果不将
库列为
进程的依赖项,那么如果修改它的一个源(库的源文件,所以
),很可能会以一个不兼容的
库结束。因此
与程序
进程
,当你试图执行它时,你的程序可能会崩溃

假设您更改了库,从库中删除了函数
f()
,因为您不再需要它了。。。但是您的程序
process
仍然在其
main()函数中调用它。由于您没有修改
process.o
(您没有接触它的任何源代码),因此不会编译它,也不会执行新的链接命令(因为
process
仅依赖于
process.o

上次链接
process
时,链接器在main中调用了
f()
,并决定将其放在地址
x
(对应于
库中存在的地址。因此
)。但由于您没有说明,如果
库发生变化,则需要链接
过程
。因此
将不会被链接。。。当您执行它时,它将调用地址
x
处的
f()
,并崩溃

尝试此操作,您将看到如果您将依赖项保留在
库上,那么您的程序将链接到共享库,并将抱怨
f()
不存在。因此,您应该修改
process.c
并重复

总是这样想。。。是文件
库。因此需要链接
过程
?如果是的话,那么你应该依靠它。是的,因为您在
库中编写的函数,所以
是从
进程
调用的。您将看到对
.h
文件的依赖关系放在
.o
目标上,而不是放在
.c
文件上。这是因为构建
.o
对象需要
.c
和所有包含的
.h
文件。但是
.c
文件不依赖于
.h
文件。。。这取决于编译的结果(这是
.o
文件)

第二个文件对目标
all
具有伪依赖性。这就是所谓的
.PHONY:
目标(一个总是执行的目标,不需要创建文件),您可以用它创建
库。因此
过程
。如果链接进程时出现
library.so
,则将包含该进程(但不知道它是最近生成的还是旧的),但如果它不是,则当您尝试构建进程时,如果
library.so
尚不存在,则链接器会强烈抱怨,您的构建将被中止

因此,作为结论,第二个
Makefile
是不正确的,您应该避免它。将依赖项声明为
make(1)
检查它们

最后一点需要注意的是,根据Make的实现,规则右侧部分中的依赖项顺序可能重要,也可能不重要。如果您在多处理器上运行make并尝试进行并行构建(请参阅
make(1)
)的选项
-j
),那么将
放在
进程的左侧可能是个坏主意。在并行生成中,
make(1)
在满足依赖文件的所有依赖项之前不会启动依赖文件的生成。。。但它试图启动尽可能多的进程,以便在多处理器机器上处理这种可能性。如果您有一整套内核,构建过程会加快很多,但是如果您不精确地观察依赖关系,则可能会很危险。

通常,您会