Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/64.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 寻找完美的Makefile画布_C_Gcc_Makefile - Fatal编程技术网

C 寻找完美的Makefile画布

C 寻找完美的Makefile画布,c,gcc,makefile,C,Gcc,Makefile,我是一名计算机工程专业的学生,我还有另一个C程序要实现。 到目前为止,我总是从以前的项目中创建一个新的Makefile,每次设置都需要时间。 是否有一个MakefileCanvas我可以使用,它是如此强大,以至于我需要提供的只是包含一个主函数的c文件的名称 我的想法是,为每个新项目创建一个文件夹,其中包含Makefile、一个bin文件夹和一个src文件夹。然后我将编辑一些变量到Makefile(包含main()函数的C文件),然后make将自动构建所有内容,同时考虑依赖关系 你知道这样的Mak

我是一名计算机工程专业的学生,我还有另一个C程序要实现。 到目前为止,我总是从以前的项目中创建一个新的Makefile,每次设置都需要时间。 是否有一个MakefileCanvas我可以使用,它是如此强大,以至于我需要提供的只是包含一个主函数的c文件的名称

我的想法是,为每个新项目创建一个文件夹,其中包含
Makefile
、一个bin文件夹和一个src文件夹。然后我将编辑一些变量到Makefile(包含
main()
函数的C文件),然后
make
将自动构建所有内容,同时考虑依赖关系

你知道这样的
Makefile
是否存在吗

[通过Alexandre C.编辑]:对于这些仅使用标准库并在标准unix操作系统上运行的项目,Automake/Autoconf是一种技巧过高的技术。
对于我们需要实现的项目,依赖关系(对于要链接的文件)总是可以从“.h”包含中推断出来,并且通常涉及的文件很少。

最接近神奇和完美的
Makefile
是使用事实上的标准来实现可移植C程序和库:

举一个例子,这是您将添加到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
函数的位置,因为链接器将在链接阶段自动找到它。如果它不存在,链接就会失败。

我也推荐autotools,你最终会学会欣赏它,它绝对值得,你可以找一本关于如何使用它的教程,或者,如果你不介意阅读一本小书,我建议读一下。但是,如果你只想要一个简单的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 $<
BIN=
OBJ=
LIB=
CFLAGS=-O2-壁-I。
LDFLAGS=
CC=gcc
LD=LD
RM=RM-f
全部::$(BIN)
$(BIN):$(OBJ)
$(CC)$(LDFLAGS)$(OBJ)$(LIB)-o$(BIN)
清洁:
$(RM)$(银行标识代码)*.o
%.o:%.c%.h
$(CC)$(CFLAGS)-c$<

程序=测试程序
CFLAGS=-c-墙
OBJECTS+=$(patsubst%.c、%.o、$(通配符./src/*.c))
OBJECTS+=$(patsubst%.c、%.o、$(通配符。/src/more sources*.c))
全部:$(对象)
gcc-o./bin/$(程序)$(对象)
%.o:%.c%.h
gcc$(CFLAGS)$<-o$@
像这样的东西就行了。很明显,我还没有测试过这个。。
您可以选择在每个文件的基础上覆盖默认编译。

您可以使用autoconf通过著名的命令
/configure
自动生成Makefile,这与大多数开源项目一样。
请参阅此链接:

您可以轻松编写自己的宏“包”来完成此操作。例如,创建此文件作为样板文件,将其命名为
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
。这种方法非常强大,而且很容易扩展。

如果您对标准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中包含它们。然而,在我看来,更好的方法是跟踪单个头文件中的所有重要依赖项,并通过后缀规则使每个文件依赖于该头文件。这并不是一个很大的麻烦,而且您仍然可以节省一些可移植性


总而言之,我的建议是避免过度担心并发症。他们很少有回报。特别是,我从来都不喜欢自动工具,而且我肯定永远也不会喜欢。UNIX就是简单。不必要地使事情复杂化是违反UNIX精神的。:)

我想出了以下解决方案:

# 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 $@;\
#作者Matthieu Sieben(http://matthieusieben.com)
#版本23/10/2012
#
#此Makefile在知识共享署名下获得许可
#Partage dans les Mêmes条件2.0比利时许可证。
#要查看此许可证的副本,请访问http://creativecommons.org/licenses/by-sa/2.0/be/.
#使用风险自负。
#
#使用Makefile.inc编写您自己的规则或覆盖此处定义的默认值。
SRCDIR=/src
BINDIR=/bin
SHELL=/bin/bash
CC=/usr/bin/gcc
自由基=
CFLAGS=-Wall-Wextra-Werror
LDFLAGS=
.PHONY:默认为“全部清除”
.后缀:.c.o
#将“所有”设为默认目标
默认值:全部
-包括Makefile.inc
-包括Makefile.d
CFLAGS+=-I$(SRCDIR)
ifeq($(调试),1)
CFLAGS+=-DDEBUG=1-ggdb
其他的
CFLAGS+=-DDEBUG=0-O2
LDFLAGS+=-O2
恩迪夫
%.o:%.c

@echo“编译`basename$@AlexBrown:没有人能为automake做一个有效的例子:-(automake对于将在常规环境下运行的学生项目来说可能有些过分了。AutoTool是为gu设计的
# 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 $@;\