如何为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)
规则是有问题的,因为:
- 这是一种不分青红皂白的做法,使每个对象的所有来源的先决条件,
- 它经常使用错误的源代码 (正如您在
file1.o
和file2.o
发现的file2.o
) - 它会尝试构build可执行文件,而不是停止在对象上
- 目标名称(
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树中使用一些可维护性/多项目支持,请看下面的内容 –