我是计算机工程专业的学生,我还有另一个C程序要实施。 到目前为止,我总是从以前的项目中创建一个新的Makefile,这需要花时间进行设置。 是否有一个我可以使用的Makefile画布是如此强大,我需要提供的是包含main函数的c文件的名称?
我的想法是,对于每个新项目,我创建一个包含Makefile
,bin文件夹和src文件夹的文件夹。然后我会将一些变量编辑到Makefile(包含main()
函数的C文件),然后make
会自动构建所有内容,并考虑依赖项。
你知道这样的Makefile
是否存在吗?
[通过Alexandre C.编辑]:Automake / Autoconf对于仅使用标准库并在标准unix操作系统上运行的这类项目来说是过度的。 对于我们需要实现的项目,依赖项(对于要链接的文件)总是可以从“.h”包含中推断出来,并且通常涉及的文件非常少。
答案 0 :(得分:3)
最接近神奇且完美Makefile
的是使用便携式C程序和库的事实标准:Automake。
作为一个从this page解除的例子,这是你要添加到Makefile.am的例子:
bin_PROGRAMS = zardoz
zardoz_SOURCES = main.c head.c float.c vortex9.c gun.c
zardoz_LDADD = $(LIBOBJS)
我们在此处添加的make目标的等价物称为zardoz
。源代码在zardoz_SOURCES
下指定,任何需要链接的其他库都在zardoz_LDADD
下指定。您无需指定main
函数所在的位置,因为链接器将在链接阶段自动找到它。如果它不存在,链接就会失败。
答案 1 :(得分:1)
PROGRAM = test-program
CFLAGS = -c -Wall
OBJECTS += $(patsubst %.c, %.o, $(wildcard ./src/*.c))
OBJECTS += $(patsubst %.c, %.o, $(wildcard ./src/more-sources*.c))
all: $(OBJECTS)
gcc -o ./bin/$(PROGRAM) $(OBJECTS)
%.o: %.c %.h
gcc $(CFLAGS) $< -o $@
这样的事情可以解决问题。我显然没有测试过这个.. 您可以选择基于每个文件覆盖默认编译。
答案 2 :(得分:1)
您可以轻松编写自己的宏“包”来执行此操作。例如,创建此文件作为样板文件,将其命名为program.mk
并将其放在树中的中心位置:
lang.c.objs = $(patsubst %.c,%.o,$(1))
lang.c.link = $(CC) $(CFLAGS) $(LDFLAGS) -o $(1) $(2)
lang.c++.objs = $(patsubst %.cpp,%.o,$(1))
lang.c++.link = $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $(1) $(2)
define make-program
program.$(1).lang ?= c
program.$(1).objects ?= $$(call lang.$$(program.$(1).lang).objs,$$(program.$(1).sources))
$$(program.$(1).name): $$(program.$(1).objects) $$(program.$(1).extra-deps)
$$(call lang.$$(program.$(1).lang).link,$$@,$$^ $$(program.$(1).ldlibs))
CLEANABLE += $$(program.$(1).name)
ALL_PROGRAMS += $$(program.$(1).name)
endef
# If the user didn't specify a list of programs, build them all
ifndef PROGRAMS
PROGRAMS = $(foreach p,$(filter program.%.name,$(.VARIABLES)),\
$(patsubst program.%.name,%,$(p)))
endif
# Generate the rule to build each program
$(foreach p,$(PROGRAMS),$(eval $(call make-program,$(p))))
.PHONY: all clean
all: $(ALL_PROGRAMS)
clean: ; rm -f $(CLEANABLE)
.DEFAULT_GOAL := all
现在,在您要构建程序的每个目录中,您的makefile可以是:
program.p.name = Program
program.p.sources = Program1.c Program2.c
include path/to/program.mk
类似的library.mk
可用于库。这种方法非常强大且非常容易扩展。
答案 3 :(得分:0)
我也推荐autotools,你会学会最终欣赏它,这绝对值得,你可以找一个关于如何使用它的教程,或者,如果你不介意读一本小书,我建议你阅读autobook但是,如果您只想要一个简单的Makefile模板,我会使用它:
BIN = <binary name>
OBJ = <object files *.o>
LIB = <libraries>
CFLAGS = -O2 -Wall -I.
LDFLAGS = <ld flags>
CC = gcc
LD = ld
RM = rm -f
all:: $(BIN)
$(BIN): $(OBJ)
$(CC) $(LDFLAGS) $(OBJ) $(LIB) -o $(BIN)
clean:
$(RM) $(BIN) *.o
%.o: %.c %.h
$(CC) $(CFLAGS) -c $<
答案 4 :(得分:0)
你可以使用autoconf通过着名的命令./configure
自动生成一个Makefile,这是最开源的项目。
请参阅此链接:configure file template to generate makefile
答案 5 :(得分:0)
如果您对标准UNIX环境感兴趣,为什么不简单地坚持使用POSIX make
提供的内容?
# Lean and mean.
.POSIX:
CFLAGS = -DNDEBUG -O
LDFLAGS = -s
TARGETS = abc def
all: $(TARGETS)
clean:
rm -f $(TARGETS)
# Some dependencies.
abc: def.h
# Some special rules.
def: def.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ def.c -l m
对于大多数小型项目,您不需要比默认项目更精细的任何内容;可能你应该专注于项目本身,而不是浪费时间编写复杂的makefile逻辑。
POSIX make
的一个限制是没有模式规则,后缀规则无法处理目录;因此,在不同目录中传播源文件要么对每个文件都需要一个规则,要么递归制作。就个人而言,对于小型项目,我并不打算将源文件移到别处。坚持POSIX make
还将提供跨其他POSIX兼容构建系统的可移植性(例如,BSD make
)。
关于自动依赖关系计算,请阅读gcc -M
。它生成包含依赖性规则的makefile。然后,您可以在makefile中include
。但是,在我看来,更好的想法是在单个头文件中跟踪所有重要的依赖项,并通过后缀规则使每个文件依赖于此标头。这不是什么麻烦,你仍然可以节省一些便携性。
总结一下,我的建议是避免过多担心并发症。他们很少还清。特别是,我从来不喜欢autotools
,我肯定永远不会。 UNIX就是简单性。不必要地使事情复杂化是违背UNIX精神的。 :)
答案 6 :(得分:0)
我提出了以下解决方案:
# Author Matthieu Sieben (http://matthieusieben.com)
# Version 23/10/2012
#
# This Makefile is licensed under the Creative Commons Attribution
# Partage dans les Mêmes Conditions 2.0 Belgique License.
# To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/2.0/be/.
# Use at your own risk.
#
# Use Makefile.inc to write you own rules or to overwrite the default values defined here.
SRCDIR = ./src
BINDIR = ./bin
SHELL = /bin/bash
CC = /usr/bin/gcc
LIBS =
CFLAGS = -Wall -Wextra -Werror
LDFLAGS =
.PHONY: default all clean distclean
.SUFFIXES: .c .o
# make "all" the default target
default: all
-include Makefile.inc
-include Makefile.d
CFLAGS += -I$(SRCDIR)
ifeq ($(DEBUG), 1)
CFLAGS += -DDEBUG=1 -ggdb
else
CFLAGS += -DDEBUG=0 -O2
LDFLAGS += -O2
endif
%.o: %.c
@echo " Compiling `basename $<`";
@$(CC) $(CFLAGS) -o $@ -c $<;
clean:
@echo "Cleaning compiled files";
@find $(SRCDIR) -name "*.o" -exec rm {} \;
@[ -e Makefile.d ] && rm Makefile.d;
distclean: clean
@echo "Removing executables";
@find $(BINDIR) -type f -exec rm {} \;
Makefile.d: $(shell find $(SRCDIR) -type f -name "*.c")
@echo "Building dependencies";
@for file in `find $(SRCDIR) -name "*.c" -print`; do\
$(CC) $(CFLAGS) -MM -MT $${file/%.c/.o} $$file | tr -d "\n\\" >> Makefile.d.tmp;\
echo -e "\n" >> Makefile.d.tmp;\
done;\
for file in `find $(SRCDIR) -name "*.c" -exec grep -Hs "main(" {} \; | cut -f1 -d':'`; do\
execname=`basename $$file .c`;\
objs="$${file/%.c/.o}";\
for header in `$(CC) $(CFLAGS) -MM $$file | tr " " "\n" | grep ".h$$" | sort | uniq | tr "\n" " "`; do\
if [ -f $${header/%.h/.c} ]; then\
objs+=" $${header/%.h/.o}";\
fi;\
for obj in `grep "^$${header/%.h/.o}" Makefile.d.tmp | tr " " "\n" | grep ".h$$" | tr "\n" " "`; do\
if [ -f $${obj/%.h/.c} ]; then\
objs+=" $${obj/%.h/.o}";\
fi;\
done;\
done;\
objs=`echo -n "$$objs" | tr " " "\n" | sort | uniq | tr "\n" " "`;\
echo "all: $$execname" >> Makefile.d.tmp;\
echo "$$execname: $(BINDIR)/$$execname" >> Makefile.d.tmp;\
echo "$(BINDIR)/$$execname: $$objs" >> Makefile.d.tmp;\
echo " @echo \"Linking $$execname\";" >> Makefile.d.tmp;\
echo " @\$$(CC) \$$(LDFLAGS) -o \$$@ $$objs \$$(LIBS);" >> Makefile.d.tmp;\
echo >> Makefile.d.tmp;\
done;\
mv Makefile.d.tmp $@;\
它不是很强大,所以请随意提供改进。下面是它的工作原理。
这里的想法是,对于$(SRCDIR)
中的每个.c文件,查找包含主函数(grep "main(" src/*.c
)的文件。然后,为每个本地include #include "myfile.h"
添加myfile.o
到该可执行文件的对象列表中,然后在Makefile.d中写上面的行
修改强> 这个新版本的脚本支持bin文件链接的依赖关系。