C makefile先决条件是否应列出共享对象?
我知道,对于使用公共共享库的许多进程,可以更新共享库中的二进制代码,而不必更新所有这些进程。只要是内部实现更改,并且不删除导出函数或更改导出函数的参数,就可以了 但我不确定如何将其与Makefile依赖项相协调。简单的指导原则是,如果文件被任何命令引用,那么它是一个依赖项,应该在Makefile规则中作为先决条件列出 链接可执行文件时,它肯定可以引用共享对象,因此依赖于该共享对象。但是,似乎并不总是因为共享对象发生了更改就需要重新链接 所以我想知道如何将库列为依赖项:C makefile先决条件是否应列出共享对象?,c,gcc,makefile,C,Gcc,Makefile,我知道,对于使用公共共享库的许多进程,可以更新共享库中的二进制代码,而不必更新所有这些进程。只要是内部实现更改,并且不删除导出函数或更改导出函数的参数,就可以了 但我不确定如何将其与Makefile依赖项相协调。简单的指导原则是,如果文件被任何命令引用,那么它是一个依赖项,应该在Makefile规则中作为先决条件列出 链接可执行文件时,它肯定可以引用共享对象,因此依赖于该共享对象。但是,似乎并不总是因为共享对象发生了更改就需要重新链接 所以我想知道如何将库列为依赖项: all: process
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)
在满足依赖文件的所有依赖项之前不会启动依赖文件的生成。。。但它试图启动尽可能多的进程,以便在多处理器机器上处理这种可能性。如果您有一整套内核,构建过程会加快很多,但是如果您不精确地观察依赖关系,则可能会很危险。通常,您会