自动从静态库中删除文件
Automatically remove files from static library
我想知道是否可以设置 makefile 规则以便自动删除库中不再存在的目标文件而无需进行干净的构建。我的 makefile 设置是这样的。
SRC_FILES = a.c b.c c.c
libtest.a : $(SRC_FILES:.c=.o)
ar -rcs $@ $?
%.o : %.c
gcc -o $@ -c $<
现在假设我从 SRC_FILES
中删除 c.c
,我希望下一个 运行 从存档中删除相应的目标文件。有没有什么方法可以做到这一点而不必 运行 一个干净的构建?先删除存档然后重建它不起作用,因为当库比其所有依赖项更新时永远不会调用该规则。如果没有任何实际更改,我也不想重建库,因此将其设为 .PHONY 也不起作用。
您无法执行任何自动或内置操作。 make
只是不太擅长注意到这种事情。您可以做的最简单的事情 "solve" 这个问题是保留一个 FORCE
d 目标,其中包含存档中表示的源文件列表,将该文件作为 [=14= 的先决条件] 并将文件内容与存档内容和 rebuild/add/delete/etc 进行比较。 to/from 适当的图书馆。
libtest.lst: FORCE $(SRC_FILES:.c=.o)
printf '%s\n' $(filter-out $<,$^) > $@
libtest.a: libtest.lst $(SRC_FILES:.c=.o)
ar t $@ > $@.contents
if diff -q $@.contents libtest.lst; then \
ar ....; \
fi
rm $@.contents
或者,如果您不关心避免重建,请忘记 listing/diffing/etc。只需重新运行 ar
命令来构建存档。
作为一项额外的改进,您可以将差异逻辑添加到 libtest.lst
配方中,这样它只会在文件发生变化时更新 libtest.lst
文件(以避免 make
认为它需要运行 libtest.a
规则(当库内容未更改时)。像这样。
libtest.lst: FORCE $(SRC_FILES:.c=.o)
printf '%s\n' $(filter-out $<,$^) | sort > $@.tmp
cmp -s $@ $@.tmp || mv $@.tmp $@
rm -f $@.tmp
libtest.a: libtest.lst $(SRC_FILES:.c=.o)
ar -rcs $@ $(filter-out $<,$?)
虽然这是一个老问题,但Etan已经给出了答案。我尝试像 Etan 一样解决它,但使用“更多制造”和“更少 bash”:
LibSources = $(wildcard *.c)
LibObjects = $(patsubst %.c,%.o,$(LibSources))
Lib := libtest.a
LibContent = $(if $(wildcard $(Lib)),$(shell ar t $(Lib) | grep -v "^__"),)
LibRemoves = $(filter-out $(LibObjects),$(LibContent))
SrcRemoves = $(patsubst %.o,%.c,$(LibRemoves))
ArDelete = $(if $(LibRemoves),ar d $(Lib) $(LibRemoves),)
.PHONY: all clean
all: $(Lib)
clean:
$(RM) $(Lib)
$(Lib)(%.o) : %.o
ar cr $@ $^
$(SrcRemoves) :
$(ArDelete)
$(Lib) : $(Lib)($(LibObjects)) $(SrcRemoves)
ranlib $(Lib)
请注意,这使用隐式规则来创建目标文件。
BSD ar 为全局符号 table 创建类似 __.SYMDEF
的成员。 -grep -v
用于过滤掉该成员。
更多细节
LibSources = $(wildcard *.c)
将在您的情况下扩展为 a.c b.c c.c 或您拥有的任何扩展名为 .c
的文件。
LibObjects = $(patsubst %.c,%.o,$(LibSources))
给出库中应该的目标文件列表。例如。 a.o
, b.o
, c.o
.
LibContent = $(if $(wildcard $(Lib)),$(shell ar t $(Lib) | grep -v "^__"),)
如果库已经存在,这会给出一个归档对象文件的列表。需要过滤掉索引的条目 __.SYMDEF SORTED
。
LibRemoves = $(filter-out $(LibObjects),$(LibContent))
这给出了区别,即要删除的目标文件列表。并且
SrcRemoves = $(patsubst %.o,%.c,$(LibRemoves))
因此扩展到已删除的源文件列表。
ArDelete = $(if $(LibRemoves),ar d $(Lib) $(LibRemoves),)
如果不需要删除任何内容,它将扩展为一个空字符串,否则为命令 ar d libtest.a ...objects-to-delete...
库的先决条件是:所有对象都是存档的成员,如果源文件被删除,对象也会被删除。如果库被修改,索引会更新:
$(Lib) : $(Lib)($(LibObjects)) $(SrcRemoves)
ranlib $(Lib)
GNU make 支持 archive members 的规则。如果目标文件不是存档的成员,则会添加:
$(Lib)(%.o) : %.o
ar cr $@ $^
如果源文件被删除(或重命名),则存档中相应的目标文件也会被删除
$(SrcRemoves) :
$(ArDelete)
另一种可靠的方法是使所有目标文件、存档、共享库和可执行文件都依赖于构建它们的 Makefile
。在食谱中,您 $(filter-out Makefile,$^)
从编译器、ar 和链接器命令行中过滤掉 Makefile
。最适合 non-recursive makefiles.
这样,每当您更改 Makefile
时,它都会自动重建并重新链接。一种理想的方法是仅在编译器选项更改时重建。这是可能的,但需要一些额外的努力,这可能不值得(ninja
自动执行,但由于 ninja
构建文件通常由更高级别的构建系统生成,例如 CMake
, 这个功能几乎毫无意义)。
此外,如果您不分发 .a
文件,您可能喜欢使用带有 T
ar
选项的 thin 存档以避免将目标文件不必要地复制到存档中。
GNU ar
can optionally create a thin archive, which contains a symbol index and references to the original copies of the member files of the archive. This is useful for building libraries for use within a local build tree, where the relocatable objects are expected to remain available, and copying the contents of each object would only waste time and space.
我想知道是否可以设置 makefile 规则以便自动删除库中不再存在的目标文件而无需进行干净的构建。我的 makefile 设置是这样的。
SRC_FILES = a.c b.c c.c
libtest.a : $(SRC_FILES:.c=.o)
ar -rcs $@ $?
%.o : %.c
gcc -o $@ -c $<
现在假设我从 SRC_FILES
中删除 c.c
,我希望下一个 运行 从存档中删除相应的目标文件。有没有什么方法可以做到这一点而不必 运行 一个干净的构建?先删除存档然后重建它不起作用,因为当库比其所有依赖项更新时永远不会调用该规则。如果没有任何实际更改,我也不想重建库,因此将其设为 .PHONY 也不起作用。
您无法执行任何自动或内置操作。 make
只是不太擅长注意到这种事情。您可以做的最简单的事情 "solve" 这个问题是保留一个 FORCE
d 目标,其中包含存档中表示的源文件列表,将该文件作为 [=14= 的先决条件] 并将文件内容与存档内容和 rebuild/add/delete/etc 进行比较。 to/from 适当的图书馆。
libtest.lst: FORCE $(SRC_FILES:.c=.o)
printf '%s\n' $(filter-out $<,$^) > $@
libtest.a: libtest.lst $(SRC_FILES:.c=.o)
ar t $@ > $@.contents
if diff -q $@.contents libtest.lst; then \
ar ....; \
fi
rm $@.contents
或者,如果您不关心避免重建,请忘记 listing/diffing/etc。只需重新运行 ar
命令来构建存档。
作为一项额外的改进,您可以将差异逻辑添加到 libtest.lst
配方中,这样它只会在文件发生变化时更新 libtest.lst
文件(以避免 make
认为它需要运行 libtest.a
规则(当库内容未更改时)。像这样。
libtest.lst: FORCE $(SRC_FILES:.c=.o)
printf '%s\n' $(filter-out $<,$^) | sort > $@.tmp
cmp -s $@ $@.tmp || mv $@.tmp $@
rm -f $@.tmp
libtest.a: libtest.lst $(SRC_FILES:.c=.o)
ar -rcs $@ $(filter-out $<,$?)
虽然这是一个老问题,但Etan已经给出了答案。我尝试像 Etan 一样解决它,但使用“更多制造”和“更少 bash”:
LibSources = $(wildcard *.c)
LibObjects = $(patsubst %.c,%.o,$(LibSources))
Lib := libtest.a
LibContent = $(if $(wildcard $(Lib)),$(shell ar t $(Lib) | grep -v "^__"),)
LibRemoves = $(filter-out $(LibObjects),$(LibContent))
SrcRemoves = $(patsubst %.o,%.c,$(LibRemoves))
ArDelete = $(if $(LibRemoves),ar d $(Lib) $(LibRemoves),)
.PHONY: all clean
all: $(Lib)
clean:
$(RM) $(Lib)
$(Lib)(%.o) : %.o
ar cr $@ $^
$(SrcRemoves) :
$(ArDelete)
$(Lib) : $(Lib)($(LibObjects)) $(SrcRemoves)
ranlib $(Lib)
请注意,这使用隐式规则来创建目标文件。
BSD ar 为全局符号 table 创建类似 __.SYMDEF
的成员。 -grep -v
用于过滤掉该成员。
更多细节
LibSources = $(wildcard *.c)
将在您的情况下扩展为 a.c b.c c.c 或您拥有的任何扩展名为 .c
的文件。
LibObjects = $(patsubst %.c,%.o,$(LibSources))
给出库中应该的目标文件列表。例如。 a.o
, b.o
, c.o
.
LibContent = $(if $(wildcard $(Lib)),$(shell ar t $(Lib) | grep -v "^__"),)
如果库已经存在,这会给出一个归档对象文件的列表。需要过滤掉索引的条目 __.SYMDEF SORTED
。
LibRemoves = $(filter-out $(LibObjects),$(LibContent))
这给出了区别,即要删除的目标文件列表。并且
SrcRemoves = $(patsubst %.o,%.c,$(LibRemoves))
因此扩展到已删除的源文件列表。
ArDelete = $(if $(LibRemoves),ar d $(Lib) $(LibRemoves),)
如果不需要删除任何内容,它将扩展为一个空字符串,否则为命令 ar d libtest.a ...objects-to-delete...
库的先决条件是:所有对象都是存档的成员,如果源文件被删除,对象也会被删除。如果库被修改,索引会更新:
$(Lib) : $(Lib)($(LibObjects)) $(SrcRemoves)
ranlib $(Lib)
GNU make 支持 archive members 的规则。如果目标文件不是存档的成员,则会添加:
$(Lib)(%.o) : %.o
ar cr $@ $^
如果源文件被删除(或重命名),则存档中相应的目标文件也会被删除
$(SrcRemoves) :
$(ArDelete)
另一种可靠的方法是使所有目标文件、存档、共享库和可执行文件都依赖于构建它们的 Makefile
。在食谱中,您 $(filter-out Makefile,$^)
从编译器、ar 和链接器命令行中过滤掉 Makefile
。最适合 non-recursive makefiles.
这样,每当您更改 Makefile
时,它都会自动重建并重新链接。一种理想的方法是仅在编译器选项更改时重建。这是可能的,但需要一些额外的努力,这可能不值得(ninja
自动执行,但由于 ninja
构建文件通常由更高级别的构建系统生成,例如 CMake
, 这个功能几乎毫无意义)。
此外,如果您不分发 .a
文件,您可能喜欢使用带有 T
ar
选项的 thin 存档以避免将目标文件不必要地复制到存档中。
GNU
ar
can optionally create a thin archive, which contains a symbol index and references to the original copies of the member files of the archive. This is useful for building libraries for use within a local build tree, where the relocatable objects are expected to remain available, and copying the contents of each object would only waste time and space.