autotools:使用另一个目录中的代码进行编译
autotools: compiling with code from another directory
我有以下结构:
+Makefile.am
+-common
| +-common.c
| +-common.h
|
+-module1
| +module1.c
| +Makefile.am
|
+-module2
| +module2.c
| +Makefile.am
其中每个 moduleX 实际上由许多 C 和头文件组成,因此应该有自己的子目录。
我想用 common.c 代码编译每个 moduleX。我的意思是编译,而不仅仅是 link 使用库,因为每个模块实际上都定义了一些影响 common.c 编译的宏。
换句话说,每个模块的 Makefile 如下所示:
check_PROGRAMS = moduleX
moduleX_CFLAGS = -I$(top_srcdir)/common -DCOMMON_OPTION_X
moduleX_SOURCES = moduleX.c ../common/common.c
我写 ../common/common.c
而不是 $(top_srcdir)/common/common.c
的原因是 this bug, (also shown here)。
顶部Makefile.am声明,当然,每个模块作为子目录:
SUBDIRS = foo bar
TESTS = foo/foo bar/bar
在实际项目中,./configure && ./make distcheck
在构建 distcheck 时失败并显示 "XXX.Po file not found"。
我曾尝试以更简单的规模 (download this tar file) 重现该问题,但因 "common.h" 未找到而失败。
我想在这两种情况下,问题是我没有成功地告诉 automake 公共部分应该是每个模块的一部分(因此在构建树外时也被复制(VPATH))
实现此目标的正确方法是什么?
欢迎您指出去皮示例所需的修改,您可以使用 tar -xvf
解压(有关构建说明,请参阅内部自述文件)
谢谢!
我在多个大型、多可执行文件项目中遇到过同样的问题。
我在 Ubuntu/Linux
上使用了以下内容
可以使用 GCC 的适当参数创建依赖文件,但是,我使用 sed 完成了这部分工作。
这有一个 makefile.top 和 makefile.bot 都在顶级目录中(没有其他地方)
顶级目录中有公共文件,供所有子目录使用。
对于您的项目,您需要编辑 makefile.top 中的 'alldirectories' 宏以列出将包含每个可执行文件的源文件和头文件的子目录。
这是从顶级目录执行的,使用类似:make -f makefile.top
文件:makefile.top
SHELL = /bin/sh
SRC := $(wildcard *.c)
OBJ := $(SRC:.c=.o)
DEP := $(SRC:.c=.d)
INC := $(SRC:.c=.h)
MAKE := /usr/bin/make
CC := /usr/bin/gcc
CP := cp
MV := mv
LDFLAGS := -L/usr/local/lib -L/usr/lib -L/lib
DEBUG := -ggdb3
CCFLAGS := $(DEBUG) -Wall -W
#CPPFLAGS += =MD
LIBS := -lssl -ldl -lrt -lz -lc -lm
.PHONY: AllDirectories
# the following statement needs to be edited as
# subdirectories are added/deleted/re-named
#AllDirectories := \
# Command_Configuration \
# Communication \
# Main_Scheduler \
# Retrieve_CDS_Log \
# Retrieve_EventRecorder_Log \
# Retrieve_GPS \
# Retrieve_QES_Alarm_Log \
# Retrieve_QES_RealTime \
# Write_CDS_Log
AllDirectories := \
Main_Scheduler \
Communication \
Retrieve_GPS \
Test_Communication_Dev
.PHONY: all
#all: $(OBJ) $(AllDirectories)
# $(foreach d,$(AllDirectories), \
# ( cd $d && $(MAKE) -f makefile.top name=Tsk_$d all ); )
all: $(OBJ) $(AllDirectories)
$(foreach d,$(AllDirectories), \
( cd $d && $(MAKE) -f ../makefile.bot name=Tsk_$d all ); )
#
# create dependancy files
#
%.d: %.c
#
# ========= START $< TO $@ =========
$(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
sed 's,\($*\)\.o[ :]*,.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
# ========= END $< TO $@ =========
#
# compile the .c file into .o files using the compiler flags
#
%.o: %.c %.d
#
# ========= START $< TO $@ =========
$(CC) $(CCFLAGS) -c $< -o $@ -I.
# ========= END $< TO $@ =========
#
.PHONY: clean
#clean: $(AllDirectories)
# # ========== start clean activities ==========
# rm -f *.o
# rm -f $(name).map
# rm -f $(name)
# rm -f *.d
# $(foreach d,$(AllDirectories), \
# ( cd $d && $(MAKE) -f makefile.top clean ); )
# # ========== end clean activities ==========
clean: $(AllDirectories)
# ========== start clean activities ==========
rm -f *.o
rm -f $(name).map
rm -f $(name)
rm -f *.d
rm -f ../bin/Tsk_*
$(foreach d,$(AllDirectories), \
( cd $d && $(MAKE) -f ../makefile.bot name=Tsk_$d clean ); )
# ========== end clean activities ==========
.PHONY: install
#install: $(AllDirectories)
# # ========== start install activities ==========
# $(foreach d,$(AllDirectories), \
# ( cd $d && $(MAKE) -f makefile.mak clean ); )
# # ========== end install activities ==========
install: $(AllDirectories)
# ========== start install activities ==========
$(foreach d,$(AllDirectories), \
( cd $d && $(MAKE) -f ../makefile.bot name=Tsk_$d install ); )
# ========== end install activities ==========
# include the contents of all the .d files
# note: the .d files contain:
# <filename>.o:<filename>.c plus all the dependancies for that file
# I.E. the #include'd header files
# wrap with ifneg... so will not rebuild *.d files when goal is 'clean'
#
ifneq "$(MAKECMDGOALS)" "clean"
-include $(DEP)
endif
文件:makefile.bot
SHELL = /bin/sh
BINDIR := /home/user/bin
.PHONY: all
all : $(BINDIR)/$(name) ../makefile.mak ../makefile.bot
#
# macro of all *.c files
# (NOTE:
# (the following 'wildcard' will pick up ALL .c files
# (like FileHeader.c and FunctionHeader.c
# (which should not be part of the build
# (so be sure no unwanted .c files in directory
# (or change the extension
#
SRC := $(wildcard *.c)
OBJ := $(SRC:.c=.o)
DEP := $(SRC:.c=.d)
INC := $(SRC:.c=.h)
COMMON_OBJ := $(wildcard ../*.o)
#COMMON_SRC := $(wildcard ../*.c)
#COMMON_OBJ := $(COMMON_SRC:.c=.o)
#COMMON_DEP := $(COMMON_SRC:.c=.d)
#COMMON_INC := $(COMMON_SRC:.c=.h)
MAKE := /usr/bin/make
CC := /usr/bin/gcc
CP := cp
MV := mv
LDFLAGS := -L/usr/local/lib
DEBUG := -ggdb3
CCFLAGS := $(DEBUG) -Wall -W
#CPPFLAGS += =MD
#LIBS := -lidn -lssl -ldl -lrt -lz -lc -lm
LIBS := -lssl -ldl -lrt -lz -lc -lm
#
# link the .o files into the executable
# using the linker flags
# -- explicit rule
#
$(name): $(OBJ) $(COMMON_OBJ) ../makefile.mak ../makefile.bot
#
# ======= $(name) Link Start =========
$(CC) $(LDFLAGS) -o $@ $(OBJ) $(COMMON_OBJ) $(LIBS)
# ======= $(name) Link Done ==========
#
# note:
# using MV rather than CP results in all executables being re-made everytime
$(BINDIR)/$(name): $(name)
#
# ======= $(name) Copy Start =========
sudo $(CP) $(name) $(BINDIR)/.
# ======= $(name) Copy Done ==========
#
#
#create dependancy files -- inference rule
# list makefile.mak as dependancy so changing makfile forces rebuild
#
%.d: %.c
#
# ========= START $< TO $@ =========
$(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
sed 's,\($*\)\.o[ :]*,.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
# ========= END $< TO $@ =========
#
# compile the .c file into .o files using the compiler flags
# -- inference rule
#
%.o: %.c %.d
#
# ========= START $< TO $@ =========
$(CC) $(CCFLAGS) -c $< -o $@ -I.
# ========= END $< TO $@ =========
#
.PHONY: clean
clean:
# ========== CLEANING UP ==========
rm -f *.o
rm -f $(name).map
rm -f $(name)
rm -f *.d
# ========== DONE ==========
.PHONY: install
install: all
# include the contents of all the .d files
# note: the .d files contain:
# <filename>.o:<filename>.c plus all the dependancies for that .c file
# I.E. the #include'd header files
# wrap with ifneg... so will not rebuild *.d files when goal is 'clean'
#
ifneq "$(MAKECMDGOALS)" "clean"
-include $(DEP)
endif
在每个 moduleX
中添加一个包装文件:
$ cat <<EOF >inc_common.c
#include "common.c"
EOF
并将该文件添加到 moduleX_SOURCES
而不是 ../common/common.c
。
顺便说一句,-I
和 -D
指令应该进入 moduleX_CPPFLAGS
(而不是 moduleX_CFLAGS
)
发生了什么:
为了解决 foobar.tar
的 "common.h" not being found
问题,我已将 EXTRA_DIST = common/common.h foo/foo.h bar/bar.h
添加到顶部 Makefile.am。之后,命令 ./bootstrap && ./configure && make dist
将包含 *.h
个文件到 foobar-0.1.tar.gz.
接下来,./bootstrap && ./configure && make distcheck
失败 Makefile:204: ../common/.deps/foo-common.Po: No such file or directory
。
这是日志:
Making distclean in bar
make[2]: Entering directory `/home/user/foobar-0.1/_build/bar'
...
rm -rf ../common/.deps ./.deps
...
make[2]: Leaving directory `/home/user/foobar-0.1/_build/bar'
Making distclean in foo
make[2]: Entering directory `/home/user/foobar-0.1/_build/foo'
Makefile:204: ../common/.deps/foo-common.Po: No such file or directory
make[2]: *** No rule to make target `../common/.deps/foo-common.Po'. Stop.
make[2]: Leaving directory `/home/user/foobar-0.1/_build/foo'
make[1]: *** [distclean-recursive] Error 1
make[1]: Leaving directory `/home/user/foobar-0.1/_build'
make: *** [distcheck] Error 1
您可以看到,../common/.deps
作为栏的 make distclean
的一部分被删除。这导致 make distclean
for foo failed.
为了避免这种 automake 行为,我们必须将 ../common/.deps/foo-common.Po
和 ../common/.deps/bar-common.Po
放在 foo/.deps
和 bar/.deps
目录中。为此,我们必须将来自 common
的源放在 foo
和 bar
目录中。这可以在 Makefile
.
的构建期间完成
解决方案:
这是基于 umläute 想法的解决方案。它基于构建期间的自动源 file generation。
topdir Makefile.am:
SUBDIRS = foo bar
TESTS = foo/foo bar/bar
EXTRA_DIST = common/common.h common/common.c foo/foo.h bar/bar.h
foo/Makefile.am:
check_PROGRAMS = foo
foo_CFLAGS = -I$(top_srcdir)/common
foo_SOURCES = foo.c
nodist_foo_SOURCES = $(foo_common_SOURCES)
foo_common_SOURCES = common.c
CLEANFILES = $(foo_common_SOURCES)
$(foo_common_SOURCES):
echo "#include \"$(top_builddir)/common/$@\"" >$@
bar/Makefile.am
check_PROGRAMS = bar
bar_CFLAGS = -I$(top_srcdir)/common -DOPTION
bar_SOURCES = bar.c
nodist_bar_SOURCES = $(bar_common_SOURCES)
bar_common_SOURCES = common.c
CLEANFILES = $(bar_common_SOURCES)
$(bar_common_SOURCES):
echo "#include \"$(top_builddir)/common/$@\"" >$@
我有以下结构:
+Makefile.am
+-common
| +-common.c
| +-common.h
|
+-module1
| +module1.c
| +Makefile.am
|
+-module2
| +module2.c
| +Makefile.am
其中每个 moduleX 实际上由许多 C 和头文件组成,因此应该有自己的子目录。
我想用 common.c 代码编译每个 moduleX。我的意思是编译,而不仅仅是 link 使用库,因为每个模块实际上都定义了一些影响 common.c 编译的宏。 换句话说,每个模块的 Makefile 如下所示:
check_PROGRAMS = moduleX
moduleX_CFLAGS = -I$(top_srcdir)/common -DCOMMON_OPTION_X
moduleX_SOURCES = moduleX.c ../common/common.c
我写 ../common/common.c
而不是 $(top_srcdir)/common/common.c
的原因是 this bug, (also shown here)。
顶部Makefile.am声明,当然,每个模块作为子目录:
SUBDIRS = foo bar
TESTS = foo/foo bar/bar
在实际项目中,./configure && ./make distcheck
在构建 distcheck 时失败并显示 "XXX.Po file not found"。
我曾尝试以更简单的规模 (download this tar file) 重现该问题,但因 "common.h" 未找到而失败。
我想在这两种情况下,问题是我没有成功地告诉 automake 公共部分应该是每个模块的一部分(因此在构建树外时也被复制(VPATH))
实现此目标的正确方法是什么?
欢迎您指出去皮示例所需的修改,您可以使用 tar -xvf
解压(有关构建说明,请参阅内部自述文件)
谢谢!
我在多个大型、多可执行文件项目中遇到过同样的问题。
我在 Ubuntu/Linux
上使用了以下内容可以使用 GCC 的适当参数创建依赖文件,但是,我使用 sed 完成了这部分工作。
这有一个 makefile.top 和 makefile.bot 都在顶级目录中(没有其他地方)
顶级目录中有公共文件,供所有子目录使用。
对于您的项目,您需要编辑 makefile.top 中的 'alldirectories' 宏以列出将包含每个可执行文件的源文件和头文件的子目录。
这是从顶级目录执行的,使用类似:make -f makefile.top
文件:makefile.top
SHELL = /bin/sh
SRC := $(wildcard *.c)
OBJ := $(SRC:.c=.o)
DEP := $(SRC:.c=.d)
INC := $(SRC:.c=.h)
MAKE := /usr/bin/make
CC := /usr/bin/gcc
CP := cp
MV := mv
LDFLAGS := -L/usr/local/lib -L/usr/lib -L/lib
DEBUG := -ggdb3
CCFLAGS := $(DEBUG) -Wall -W
#CPPFLAGS += =MD
LIBS := -lssl -ldl -lrt -lz -lc -lm
.PHONY: AllDirectories
# the following statement needs to be edited as
# subdirectories are added/deleted/re-named
#AllDirectories := \
# Command_Configuration \
# Communication \
# Main_Scheduler \
# Retrieve_CDS_Log \
# Retrieve_EventRecorder_Log \
# Retrieve_GPS \
# Retrieve_QES_Alarm_Log \
# Retrieve_QES_RealTime \
# Write_CDS_Log
AllDirectories := \
Main_Scheduler \
Communication \
Retrieve_GPS \
Test_Communication_Dev
.PHONY: all
#all: $(OBJ) $(AllDirectories)
# $(foreach d,$(AllDirectories), \
# ( cd $d && $(MAKE) -f makefile.top name=Tsk_$d all ); )
all: $(OBJ) $(AllDirectories)
$(foreach d,$(AllDirectories), \
( cd $d && $(MAKE) -f ../makefile.bot name=Tsk_$d all ); )
#
# create dependancy files
#
%.d: %.c
#
# ========= START $< TO $@ =========
$(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
sed 's,\($*\)\.o[ :]*,.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
# ========= END $< TO $@ =========
#
# compile the .c file into .o files using the compiler flags
#
%.o: %.c %.d
#
# ========= START $< TO $@ =========
$(CC) $(CCFLAGS) -c $< -o $@ -I.
# ========= END $< TO $@ =========
#
.PHONY: clean
#clean: $(AllDirectories)
# # ========== start clean activities ==========
# rm -f *.o
# rm -f $(name).map
# rm -f $(name)
# rm -f *.d
# $(foreach d,$(AllDirectories), \
# ( cd $d && $(MAKE) -f makefile.top clean ); )
# # ========== end clean activities ==========
clean: $(AllDirectories)
# ========== start clean activities ==========
rm -f *.o
rm -f $(name).map
rm -f $(name)
rm -f *.d
rm -f ../bin/Tsk_*
$(foreach d,$(AllDirectories), \
( cd $d && $(MAKE) -f ../makefile.bot name=Tsk_$d clean ); )
# ========== end clean activities ==========
.PHONY: install
#install: $(AllDirectories)
# # ========== start install activities ==========
# $(foreach d,$(AllDirectories), \
# ( cd $d && $(MAKE) -f makefile.mak clean ); )
# # ========== end install activities ==========
install: $(AllDirectories)
# ========== start install activities ==========
$(foreach d,$(AllDirectories), \
( cd $d && $(MAKE) -f ../makefile.bot name=Tsk_$d install ); )
# ========== end install activities ==========
# include the contents of all the .d files
# note: the .d files contain:
# <filename>.o:<filename>.c plus all the dependancies for that file
# I.E. the #include'd header files
# wrap with ifneg... so will not rebuild *.d files when goal is 'clean'
#
ifneq "$(MAKECMDGOALS)" "clean"
-include $(DEP)
endif
文件:makefile.bot
SHELL = /bin/sh
BINDIR := /home/user/bin
.PHONY: all
all : $(BINDIR)/$(name) ../makefile.mak ../makefile.bot
#
# macro of all *.c files
# (NOTE:
# (the following 'wildcard' will pick up ALL .c files
# (like FileHeader.c and FunctionHeader.c
# (which should not be part of the build
# (so be sure no unwanted .c files in directory
# (or change the extension
#
SRC := $(wildcard *.c)
OBJ := $(SRC:.c=.o)
DEP := $(SRC:.c=.d)
INC := $(SRC:.c=.h)
COMMON_OBJ := $(wildcard ../*.o)
#COMMON_SRC := $(wildcard ../*.c)
#COMMON_OBJ := $(COMMON_SRC:.c=.o)
#COMMON_DEP := $(COMMON_SRC:.c=.d)
#COMMON_INC := $(COMMON_SRC:.c=.h)
MAKE := /usr/bin/make
CC := /usr/bin/gcc
CP := cp
MV := mv
LDFLAGS := -L/usr/local/lib
DEBUG := -ggdb3
CCFLAGS := $(DEBUG) -Wall -W
#CPPFLAGS += =MD
#LIBS := -lidn -lssl -ldl -lrt -lz -lc -lm
LIBS := -lssl -ldl -lrt -lz -lc -lm
#
# link the .o files into the executable
# using the linker flags
# -- explicit rule
#
$(name): $(OBJ) $(COMMON_OBJ) ../makefile.mak ../makefile.bot
#
# ======= $(name) Link Start =========
$(CC) $(LDFLAGS) -o $@ $(OBJ) $(COMMON_OBJ) $(LIBS)
# ======= $(name) Link Done ==========
#
# note:
# using MV rather than CP results in all executables being re-made everytime
$(BINDIR)/$(name): $(name)
#
# ======= $(name) Copy Start =========
sudo $(CP) $(name) $(BINDIR)/.
# ======= $(name) Copy Done ==========
#
#
#create dependancy files -- inference rule
# list makefile.mak as dependancy so changing makfile forces rebuild
#
%.d: %.c
#
# ========= START $< TO $@ =========
$(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
sed 's,\($*\)\.o[ :]*,.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
# ========= END $< TO $@ =========
#
# compile the .c file into .o files using the compiler flags
# -- inference rule
#
%.o: %.c %.d
#
# ========= START $< TO $@ =========
$(CC) $(CCFLAGS) -c $< -o $@ -I.
# ========= END $< TO $@ =========
#
.PHONY: clean
clean:
# ========== CLEANING UP ==========
rm -f *.o
rm -f $(name).map
rm -f $(name)
rm -f *.d
# ========== DONE ==========
.PHONY: install
install: all
# include the contents of all the .d files
# note: the .d files contain:
# <filename>.o:<filename>.c plus all the dependancies for that .c file
# I.E. the #include'd header files
# wrap with ifneg... so will not rebuild *.d files when goal is 'clean'
#
ifneq "$(MAKECMDGOALS)" "clean"
-include $(DEP)
endif
在每个 moduleX
中添加一个包装文件:
$ cat <<EOF >inc_common.c
#include "common.c"
EOF
并将该文件添加到 moduleX_SOURCES
而不是 ../common/common.c
。
顺便说一句,-I
和 -D
指令应该进入 moduleX_CPPFLAGS
(而不是 moduleX_CFLAGS
)
发生了什么:
为了解决 foobar.tar
的 "common.h" not being found
问题,我已将 EXTRA_DIST = common/common.h foo/foo.h bar/bar.h
添加到顶部 Makefile.am。之后,命令 ./bootstrap && ./configure && make dist
将包含 *.h
个文件到 foobar-0.1.tar.gz.
接下来,./bootstrap && ./configure && make distcheck
失败 Makefile:204: ../common/.deps/foo-common.Po: No such file or directory
。
这是日志:
Making distclean in bar
make[2]: Entering directory `/home/user/foobar-0.1/_build/bar'
...
rm -rf ../common/.deps ./.deps
...
make[2]: Leaving directory `/home/user/foobar-0.1/_build/bar'
Making distclean in foo
make[2]: Entering directory `/home/user/foobar-0.1/_build/foo'
Makefile:204: ../common/.deps/foo-common.Po: No such file or directory
make[2]: *** No rule to make target `../common/.deps/foo-common.Po'. Stop.
make[2]: Leaving directory `/home/user/foobar-0.1/_build/foo'
make[1]: *** [distclean-recursive] Error 1
make[1]: Leaving directory `/home/user/foobar-0.1/_build'
make: *** [distcheck] Error 1
您可以看到,../common/.deps
作为栏的 make distclean
的一部分被删除。这导致 make distclean
for foo failed.
为了避免这种 automake 行为,我们必须将 ../common/.deps/foo-common.Po
和 ../common/.deps/bar-common.Po
放在 foo/.deps
和 bar/.deps
目录中。为此,我们必须将来自 common
的源放在 foo
和 bar
目录中。这可以在 Makefile
.
解决方案: 这是基于 umläute 想法的解决方案。它基于构建期间的自动源 file generation。
topdir Makefile.am:
SUBDIRS = foo bar
TESTS = foo/foo bar/bar
EXTRA_DIST = common/common.h common/common.c foo/foo.h bar/bar.h
foo/Makefile.am:
check_PROGRAMS = foo
foo_CFLAGS = -I$(top_srcdir)/common
foo_SOURCES = foo.c
nodist_foo_SOURCES = $(foo_common_SOURCES)
foo_common_SOURCES = common.c
CLEANFILES = $(foo_common_SOURCES)
$(foo_common_SOURCES):
echo "#include \"$(top_builddir)/common/$@\"" >$@
bar/Makefile.am
check_PROGRAMS = bar
bar_CFLAGS = -I$(top_srcdir)/common -DOPTION
bar_SOURCES = bar.c
nodist_bar_SOURCES = $(bar_common_SOURCES)
bar_common_SOURCES = common.c
CLEANFILES = $(bar_common_SOURCES)
$(bar_common_SOURCES):
echo "#include \"$(top_builddir)/common/$@\"" >$@