我有一个包含两个主要功能的项目,一个用于实现我的程序,另一个主要功能用于测试程序。我在网上搜索了这个,但发现几乎没有关于带有两个可执行文件的递归makefile。
生成文件
CC = clang
CFLAGS = -g -Wall
PROG = suggest
OBJDIR = objects
OBJS = $(OBJDIR)/suggest.o $(OBJDIR)/engine.o $(OBJDIR)/table.o $(OBJDIR)/levenshtein.o
# ... link them
$(PROG): $(OBJS) $(OBJDIR)
$(CC) $(CFLAGS) $(OBJS) -o $(PROG)
$(OBJDIR)/table.o:
$(MAKE) -C table.c
cp ../file1/table.c/table.o $(OBJDIR)
$(OBJDIR)/levenshtein.o:
$(MAKE) -C levenshtein.c
cp levenshtein.c/levenshtein.o $(OBJDIR)
# build them all...
$(OBJDIR)/%.o: %.c $(OBJDIR)
$(CC) $(CFLAGS) -c -o $@ $<
$(OBJDIR):
mkdir -p $(OBJDIR)
clean:
rm -rf $(OBJDIR) $(PROG)
在上面的文件中,engine.c
是执行我的程序的主要功能,但我还有另一个main
函数,名为test.c
,对我的文件进行测试。
我想要的是,当我运行make
命令时,它应该只构建engine.c
main
函数(默认情况下),但如果我想测试我的程序,我应该能够运行通过指定类似内容的test.c
main
函数,例如make test
。
问题是我没有测试文件的makefile。我的目录是这样的:engine.c,suggest.c,test.c然后我有另一个名为levenshtein.c的文件夹,它有自己的makefile。另外,我只想使用两个makefile。我已经写了一个在levenshtein.c文件夹中的文件,我有问题的是这个文件夹,因为这个文件夹包含两个main
函数。我想要一个基于命令的条件编译。
答案 0 :(得分:1)
试试这个;在engine.o或test.o中添加新目标TEST并有条件地链接。这只有在您的测试程序不需要engine.o中的任何函数或数据时才有效。如果是,您可能需要使用-DTEST_PROGRAM
等条件有条件地编译两个主函数由于你正在使用engine.o中的其他函数和数据,你应该在engine.c中的main(...)函数周围添加类似#if USE_TEST_PROGRAM #endif的东西,并在你的makefile中定义USE_TEST_PROGRAM标志,如图所示下面。这将产生两次编译engine.c的副作用(一次进入你的程序建议的OBJDIR,一次进入你的测试程序的顶级目录)。
CC = clang
CFLAGS = -g -Wall
PROG = suggest
TEST = test
OBJDIR = objects
OBJS = $(OBJDIR)/suggest.o $(OBJDIR)/table.o $(OBJDIR)/levenshtein.o
# ... link them
$(PROG): $(OBJS) $(OBJDIR)
$(CC) $(CFLAGS) $(OBJS) $(OBJDIR)/engine.o -o $(PROG)
$(TEST): $(OBJS) $(OBJDIR)
$(CC) $(CFLAGS) -DUSE_TEST_PROGRAM=1 engine.c $(OBJS) $(OBJDIR)/test.o -o $(PROG)
$(OBJDIR)/table.o:
$(MAKE) -C table.c
cp ../file1/table.c/table.o $(OBJDIR)
$(OBJDIR)/levenshtein.o:
$(MAKE) -C levenshtein.c
cp levenshtein.c/levenshtein.o $(OBJDIR)
# build them all...
$(OBJDIR)/%.o: %.c $(OBJDIR)
$(CC) $(CFLAGS) -c -o $@ $<
$(OBJDIR):
mkdir -p $(OBJDIR)
clean:
rm -rf $(OBJDIR) $(PROG)
答案 1 :(得分:1)
您不想对正在进行的操作使用递归。
根据您的描述的声音,您希望拥有一个makefile,它构建两个最终目标之一:test
或engine
。对于test
,它应该编译并链接test.c
。对于engine
,它应该编译并链接engine.c
。
如果这是正确的,你可以构建一个包含两个目标的makefile:
test engine: $(PROG)
.PHONY: test engine
因此每个目标都会在$(PROG)
上展开。然后修改makefile以获得要构建的正确对象列表:
OBJS := ....
ifneq ($(filter test,$(MAKECMDGOALS)),)
#test was a command goal, add test.o to the targets:
OBJS+=$(OBJDIR)/test.o
else ifneq ($(filter engine,$(MAKECMDGOALS)),)
#engine was a command goal, add test.o to the targets:
OBJS+=$(OBJDIR)/engine.o
else
#neither were command goals. set default:
OBJS+=$(OBJDIR)/engine.o
fi
$(PROG): $(OBJS)
@$(CC) $(CFLAGS) $? -o $@
现在当你运行make test
时,它会将test.o添加到$(OBJS)
,构建和链接($?
将包含所有.o文件),否则它将添加{{1}到engine.o
。 Make将编译所有$(OBJS)并构建你的目标。
另一件事。你有:
$(OBJS)
(这很好,但不太好,你有:
$(OBJDIR):
mkdir -p $(OBJDIR)
首先,它会在创建对象目录之前尝试构建对象(这可能导致构建失败)。此外,如果提前$(PROG): $(OBJS) $(OBJDIR)
并且编译工作,那么每次该目录中的文件发生更改时,objdir
上的时间戳都会更新...所以它可能比{{更新... 1}},导致它在不需要的时候经常重建。正确的方法是:
$(OBJDIR)
注意$(PROG)
,这意味着只有顺序依赖,这意味着如果$(OBJS): | $(OBJDIR)
有一个更新的时间戳,它将不会重建|
,但它会在任何一个之前构建目录对象。
答案 2 :(得分:0)
以上所有答案都非常有用,但我仍然无法运行我的程序。从上面的答案得到一些提示后,我能够提出一个简化版的makefile。根据您的目录设置,上述内容也是准确的。这就是我做到的。
(注意:这可能不是最佳解决方案)
TEST = test.c engine.c levenshtein.c/levenshtein.c ../subdir1/table.c
PROG = suggest.c engine.c levenshtein.c/levenshtein.c ../subdir1/table.c
OBJ_TEST = $(TEST:.c=.o)
OBJ_PROG = $(PROG:.c=.o)
CC = clang
CFLAGS = -g -Wall
test: $(OBJ_TEST)
$(CC) $(OBJ_TEST) -o $@
suggest: $(OBJ_PROG)
$(CC) $(OBJ_PROG) -o $@
.SUFFIXES: .c .o
.c.o:
$(CC) $< $(CFLAGS) -c -o $@
clean:
rm -rf *.o
我有一个父目录,其中包含两个以上的文件夹。我的目录设置如下所示:
项目/
包含table.c的| _____子目录
| _____另一个包含我的engine.c,suggest.c和test.c的子目录,它还包含levenshtein.c,它是一个单独的文件夹。
因此,对于任何未来的读者,如果您正在阅读本文,请记下您的目录,然后尝试创建一个makefile,因为它会减少生活压力。