简体   繁体   English

具有两个可执行文件的递归makefile

[英]Recursive makefile with two executables

I have a project which contains two main functions, one is for implementation of my program and the other main function is for testing the program. 我有一个包含两个主要功能的项目,一个用于执行程序,另一个主要功能用于测试程序。 I searched the web for this but found almost nothing that was about recursive makefile with two executables. 我在网上搜索了此内容,但发现几乎没有什么与带有两个可执行文件的递归makefile有关。

Makefile 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)

In the above file, engine.c is a main function that does the implementation of my program however i have another main function as well, called test.c that does testing on my file. 在上面的文件中, engine.c是执行我的程序的主要功能,但是我还有另一个main功能,称为test.cengine.c我的文件进行测试。 What i want is, when i run the make command, it should only build the engine.c main function (by default) but if i want to test my program i should be able to run the test.c main function by specifying something like this, for instance make test . 我想要的是,当我运行make命令时,它应该仅构建engine.c main函数(默认情况下),但是如果我想测试我的程序,我应该能够通过指定以下内容来运行test.c main函数这样,例如make test


The problem is i don't have a makefile for test file. 问题是我没有测试文件的生成文件。 My directory is like this: engine.c , suggest.c , test.c and then i have another folder called levenshtein.c and that has got its own makefile. 我的目录是这样的:engine.c,Recommendation.c,test.c,然后我有另一个名为levenshtein.c的文件夹,它有自己的makefile。 Also i just want to work with only two makefiles. 我也只想使用两个makefile。 I have already written one which is in the levenshtein.c folder and the one that i have problem is this one as this folder contains two main functions.I would want a conditional compilation based on the command. 我已经写了一个在levenshtein.c文件夹中的文件夹,而我有问题的那个文件夹是这个文件夹,因为该文件夹包含两个main功能。我想要基于该命令的条件编译。

Try this; 尝试这个; Adding the new target TEST and conditionally linking in either engine.o or test.o. 添加新的目标TEST并有条件地链接到engine.o或test.o中。 This will only work if your test program doesn't require any of the functions or data in engine.o If it does you may want to conditionally compile the two main functions using something like -DTEST_PROGRAM 仅当您的测试程序不需要引擎中的任何功能或数据时,这才起作用。o如果这样做,您可能希望使用-DTEST_PROGRAM之类的条件有条件地编译两个主要功能

Since you're using other functions and data from engine.o you should add something like #if USE_TEST_PROGRAM #endif around the main(...) function inside of engine.c and define the USE_TEST_PROGRAM flag in your makefile as shown below. 由于您正在使用来自engine.o的其他函数和数据,因此应在engine.c内部的main(...)函数周围添加#if USE_TEST_PROGRAM #endif之类的内容,并在makefile中定义USE_TEST_PROGRAM标志,如下所示。 This will have the side effect of compiling engine.c twice (once into your OBJDIR for your program suggest and once in your top dir for your 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)

You don't want to use recursion for what you're doing. 您不想在执行操作时使用递归。

By the sounds of your description you want to have a single makefile, which builds one of two final targets: either test or engine . 根据您的描述,您希望有一个makefile,该文件可构建两个最终目标之一: testengine For test , it should compile and link test.c . 为了进行test ,它应该编译并链接test.c For engine , it should compile and link engine.c . 对于engine ,应编译并链接engine.c

If this is correct, you could build a makefile with two targets as so: 如果这是正确的,则可以这样构建带有两个目标的makefile:

test engine: $(PROG)

.PHONY: test engine

So each target depnds on $(PROG) . 因此,每个目标都依赖$(PROG) You then modify your makefile to have the correct list of objects to build: 然后,您修改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 $@

now when you run make test , it will add test.o to $(OBJS) , build and link ( $? will contain all .o files), otherwise it will add engine.o to $(OBJS) . 现在,当您运行make test ,它将test.o添加到$(OBJS) ,进行构建和链接( $?将包含所有.o文件),否则它将engine.o添加到$(OBJS) Make will compile all the $(OBJS) and build your target. Make将编译所有$(OBJS)并构建目标。

One other thing. 另一件事。 You have: 你有:

$(OBJDIR):
    mkdir -p $(OBJDIR)

(which is good, but not so good, you have: (这很好,但不是很好,您有:

$(PROG): $(OBJS) $(OBJDIR)

First of all, it will try to build the objects before it creates the object directory (which can cause a build failure). 首先,它将在创建对象目录之前尝试构建对象(这可能会导致构建失败)。 Also, if objdir is made ahead of time, and the compilation works, the timestamp on $(OBJDIR) is updated each time a file inside that directory changes... So it it would likely be newer than $(PROG) , causing it to be rebuilt often when it doesn't need to be. 另外,如果objdir提前完成,并且编译工作正常,则每次目录中的文件更改时, $(OBJDIR)上的时间戳都会更新...因此它可能比$(PROG)更新,从而导致不需要时经常进行重建。 The correct way to do this is: 正确的方法是:

$(OBJS): | $(OBJDIR)

notice the | 注意| , which means order-only dependency, meaning it won't rebuild $(OBJS) if $(OBJDIR) has a newer timestamp, but it will build the directory before any of the objects. ,这意味着仅顺序依赖,这意味着如果$(OBJDIR)的时间戳较新,则不会重建$(OBJS) ,但是它将在任何对象之前建立目录。

All of the above answers were very helpful but i still wasn't able to run my program. 以上所有答案都非常有帮助,但我仍然无法运行我的程序。 After getting some hints from the above answers, i was able to come up with a simplified version of makefile. 从以上答案中得到一些提示后,我能够提出一个简化版本的makefile。 The above ones are also accurate depending on the setup of your directories. 根据目录的设置,以上内容也是准确的。 This is how i did it. 这就是我做到的。

(NOTE: this may not be the best solution) (注意:这可能不是最佳解决方案)

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

I had a parent directory which contained two more folders. 我有一个父目录,其中包含另外两个文件夹。 My directory set-up looked like this: 我的目录设置如下所示:

Project/ 项目/

|_____ subdirectory that contained table.c | _____包含table.c的子目录

|_____ another subdirectory that contained my engine.c, suggest.c and test.c, and it contained levenshtein.c as well which was a separate folder. | _____另一个包含我的engine.c,suggest.c和test.c的子目录,它还包含levenshtein.c,这是一个单独的文件夹。

So for any future readers if you are reading this, take note of your directories and then try to create a makefile as it will make life less stressful. 因此,对于任何将来的读者,如果您正在阅读本文,请记下您的目录,然后尝试创建一个makefile,因为它将减少生活压力。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM