2014-10-21 89 views
2

我已经搜索并尝试了几个使用非递归makefile来完成简单项目的示例。在过去,我用了简单的单一代码库的目录,但现在我放在一起的环境多名工程师:-)简单的非递归Makefile与目标文件在单独的目录中

+--app 
| +-- obj/ 
| +-- Makefile 
| +-- first.c 
| +-- second.c 
| 
+--lib1 
| +-- obj/ 
| +-- Makefile 
| +-- foo.c 
| +-- bar.c 
| 
+--lib2 
| +-- obj/ 
| +-- Makefile 
| +-- sample.c 

没什么fancy-只是两个目录(也许第三个版本)和库代码和多个应用程序都在“应用程序”目录中。我想将.o和.d文件保存在一个单独的obj /目录中以保持清洁。

  1. 我希望能够在每个子目录(如lib1和lib2)中执行“make”来验证库。他们将分别生成libabc.a和libxyz.a。
  2. 我写了一些简单的Makefile,但我的规则不起作用,我试图理解GNU make手册,但是迷路了。

LIB1/Makefile文件:

lib_src = foo.c bar.c 
lib_obj = $(patsubst %.c,obj/%.o,$(lib_src)) 
libabc.a: $(lib_obj) 
    @echo [Archive... $(@F)] 
    @$(AR) -cr libabc.a $^ 
obj/%.c : %.c 
    $(CC) $(CFLAGS) -c -o [email protected] $< 

应用程序/ Makefile文件:

ALL_APP = first second 
% : %.c libabc.a libxyz.a 
    $(CC) $(CLFAGS) $^ -o [email protected] 
include ../lib1/Makefile 
include ../lib2/Makefile 

现在,我已经定义在每个Makefile文件(显然)对同一目标的麻烦。就像我无法在lib1/Makefile和app/Makefile中定义一个clean,因为lib1包含在那里。虽然我希望我可以在lib1中单独做一个清理,但这是有道理的。

现在,当我在“应用程序”中进行制作时,没有制定obj/foo.o的规则。我猜是因为路径都是假的。 “obj /”指的是lib1/obj /,但是随着Makefile的包含,这些都丢失了。

我在做什么错了,我可以用我真正简单的Makefiles构建项目吗?网上的大多数例子都相当复杂,因为他们试图获得更多(我相信)。

在此先感谢(对于已经讨论过很多次的话题感到抱歉)。如果我能避免它,我现在宁愿不学习automake和cmake。我希望我的项目很简单,不能保证使用这些强大的工具。

最好的问候,

+0

我不认为在您的应用程序makefile中包含库makefiles是这里的正确解决方案。这就是我要做的:为每个目录编写一个完全正常运行的独立makefile。然后为您的应用程序编写一个简单的构建脚本,为每个库调用make,最后再调用make for your app。您也可以让构建脚本将构建的库复制到您的应用程序目录中。 – 2014-10-21 22:54:57

+1

@BrandonYates这是或多或少的递归,但更多的删除了一步,因为你甚至不让make做递归构建。 – 2014-10-21 23:30:30

+0

谢谢布兰登。我认为调用make并不是一个好主意,并且包含Makefile是一种更好的方法。彼得米勒写了一篇文章解释为什么。通过独立调用每个Makefile,依赖性更难管理。 – guraaf 2014-10-21 23:32:01

回答

3

让我们先从lib1/Makefile

lib_src = foo.c bar.c 
lib_obj = $(patsubst %.c,obj/%.o,$(lib_src)) 

libabc.a: $(lib_obj) 
    @echo [Archive... $(@F)] 
    @$(AR) -cr libabc.a $^ 

obj/%.c : %.c 
    $(CC) $(CFLAGS) -c -o [email protected] $< 

我们引入变量HERE,使一对夫妇的小变化:

HERE := ../lib1 

lib_src := foo.c bar.c 
lib_obj := $(patsubst %.c,$(HERE)/obj/%.o,$(lib_src)) 

$(HERE)/libabc.a: $(lib_obj) 
    @echo [Archive... $(@F)] 
    @$(AR) -cr [email protected] $^ 

$(HERE)/obj/%.c : $(HERE)/%.c 
    $(CC) $(CFLAGS) -c -o [email protected] $< 

这个Makefile仍然会工作得如之前从lib1/内调用。为clean规则

ALL_APP = first second 
% : %.c ../lib1/libabc.a ../lib2/libxyz.a 
    $(CC) $(CLFAGS) $^ -o [email protected] 

include ../lib1/Makefile 
include ../lib2/Makefile 

现在:但是,一旦我们做出相应的改动lib2/Makefile,我们可以改变app/Makefile我们重命名lib1/Makefile =>lib1/lib1.maklib2/Makefile =>lib2/lib2.mak,谱写新的lib1/Makefile

include lib1.mak 

clean: 
    @rm -f lib*.a obj/* 

做相同的lib2/,并修改app/Makefile

... 

include ../lib1/lib1.mak 
include ../lib1/lib1.mak 

clean: 
    @rm -f $(ALL_APP) 
    @$(MAKE) -C ../lib1 clean 
    @$(MAKE) -C ../lib2 clean 

(我们可以做到这一点没有递归,但它会更复杂,并且以这种方式使用递归Make确实没有错。)

一些进一步的改进是可能的。例如,以这种方式将路径硬编码到lib1/lib1.maklib2/lib2.mak并不好,这可以修复。但这足够一天。