如何为SRC,OBJ和BIN子目录的C项目创buildMakefile?

几个月前,我提出了以下用于学校作业的通用Makefile

 # ------------------------------------------------ # Generic Makefile # # Author: yanick.rochon@gmail.com # Date : 2010-11-05 # # Changelog : # 0.01 - first version # ------------------------------------------------ # project name (generate executable with this name) TARGET = projectname CC = gcc -std=c99 -c # compiling flags here CFLAGS = -Wall -I. LINKER = gcc -o # linking flags here LFLAGS = -Wall SOURCES := $(wildcard *.c) INCLUDES := $(wildcard *.h) OBJECTS := $(SOURCES:.c=*.o) rm = rm -f $(TARGET): obj @$(LINKER) $(TARGET) $(LFLAGS) $(OBJECTS) @echo "Linking complete!" obj: $(SOURCES) $(INCLUDES) @$(CC) $(CFLAGS) $(SOURCES) @echo "Compilation complete!" clean: @$(rm) $(TARGET) $(OBJECTS) @echo "Cleanup complete!" 

这将基本上编译每个.c.h文件生成.o文件和可执行项目名称都在同一个文件夹中。

现在,我想推这一点。 我如何编写一个Makefile来编译一个具有以下目录结构的C项目?

  ./ ./Makefile ./src/*.c;*.h ./obj/*.o ./bin/<executable> 

换句话说,我想要一个Makefile,将./src/ C源代码编译为./obj/ ,然后将所有内容链接到./obj/中创build可执行文件。

我试过阅读不同的Makefiles,但是我不能让它们为上面的项目结构工作。 相反,该项目无法编译各种错误。 当然,我可以使用全面的IDE(Monodevelop,Anjuta等),但是我真的宁愿坚持使用gEdit和好的terminal。

有没有一个能够给我一个工作解决scheme的专家,或者清楚的知道如何做到这一点? 谢谢!

** 更新(v4) **

最终的解决scheme :

 # ------------------------------------------------ # Generic Makefile # # Author: yanick.rochon@gmail.com # Date : 2011-08-10 # # Changelog : # 2010-11-05 - first version # 2011-08-10 - added structure : sources, objects, binaries # thanks to http://stackoverflow.com/users/128940/beta # 2017-04-24 - changed order of linker params # ------------------------------------------------ # project name (generate executable with this name) TARGET = projectname CC = gcc # compiling flags here CFLAGS = -std=c99 -Wall -I. LINKER = gcc # linking flags here LFLAGS = -Wall -I. -lm # change these to proper directories where each file should be SRCDIR = src OBJDIR = obj BINDIR = bin SOURCES := $(wildcard $(SRCDIR)/*.c) INCLUDES := $(wildcard $(SRCDIR)/*.h) OBJECTS := $(SOURCES:$(SRCDIR)/%.c=$(OBJDIR)/%.o) rm = rm -f $(BINDIR)/$(TARGET): $(OBJECTS) @$(LINKER) $(OBJECTS) $(LFLAGS) -o $@ @echo "Linking complete!" $(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.c @$(CC) $(CFLAGS) -c $< -o $@ @echo "Compiled "$<" successfully!" .PHONY: clean clean: @$(rm) $(OBJECTS) @echo "Cleanup complete!" .PHONY: remove remove: clean @$(rm) $(BINDIR)/$(TARGET) @echo "Executable removed!" 

首先,你的$(OBJECTS)规则是有问题的,因为:

  1. 这是一种不分青红皂白的做法,使每个对象的所有来源的先决条件,
  2. 它经常使用错误的源代码 (正如您在file1.ofile2.o发现的file2.o
  3. 它会尝试构build可执行文件,而不是停止在对象上
  4. 目标名称( foo.o )不是规则实际产生的( obj/foo.o )。

我build议如下:

 OBJECTS := $(SOURCES:$(SRCDIR)/%.c=$(OBJDIR)/%.o) $(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.c $(CC) $(CFLAGS) -c $< -o $@ @echo "Compiled "$<" successfully!" 

$(TARGET)规则具有相同的问题,即目标名称实际上不描述规则构build的内容。 因此,如果你多次inputmake ,Make每次都会重build目标,即使没有理由。 一个小小的变化修复了:

 $(BINDIR)/$(TARGET): $(OBJECTS) $(LINKER) $@ $(LFLAGS) $(OBJECTS) @echo "Linking complete!" 

一旦这一切顺利,你可能会考虑更复杂的依赖处理; 如果您修改其中一个头文件,这个makefile将不知道必须重build哪些对象/可执行文件。 但是,这可以等待另一天。

编辑:
对不起,我省略了上面的$(OBJECTS)规则的一部分; 我纠正了它。 (我希望我可以在代码示例中使用“罢工”。)

您可以将-I标志添加到编译器标志(CFLAGS)以指示编译器应该在哪里查找源文件,并使用-o标志来指示二进制文件应保留在哪里:

 CFLAGS = -Wall -I./src TARGETPATH = ./bin $(TARGET): obj @$(LINKER) $(TARGETPATH)/$(TARGET) $(LFLAGS) $(OBJECTS) @echo "Linking complete!" 

为了将目标文件放入obj目录,在编译时使用-o选项。 另外,看看$@$< 自动variables 。

例如,考虑这个简单的Makefile

 CFLAGS= -g -Wall -O3 OBJDIR= ./obj SRCS=$(wildcard *.c) OBJS=$(SRCS:.c=.o ) all:$(OBJS) %.o: %.c $(CC) $(CFLAGS) -c $< -o $(OBJDIR)/$@ 

更新>

通过查看你的makefile,我意识到你正在使用-o标志。 好。 继续使用它,但添加一个目标目录variables,以指示输出文件应写入的位置。

如果你的学习目标是要学习,那么我现在已经停止写makefile了,否则你会有一个好的makefile生成器。 如果你想在构build树中使用一些可维护性/多项目支持,请看下面的内容 –

https://github.com/dmoulding/boilermake我发现这很不错;..!