使用Make构建C / C ++项目的“标准库”

时间:2011-04-20 05:31:16

标签: c++ c makefile

有时我需要我的项目使用普通的makefile,虽然它是一种不推荐用于任何用途的过时的构建技术,但是因为make几乎在任何地方都可用,它有时是有意义的。

但是我希望我的Makefile看起来像

Include "../buildexec.mk"

TARG = my_exec

CPPFILES = file1.cpp \
           file2.cpp \

并且所有通用(和可怕)依赖关系跟踪代码都在buildexec.mk中。

是否有这样的“制作图书馆”?

在Go中,您可以包含一个标准的Makefile,并且您的Makefile看起来像this一样漂亮:

include $(GOROOT)/src/Make.inc

TARG=irc
GOFILES=irc.go irc_struct.go irc_callback.go

include $(GOROOT)/src/Make.pkg 

C ++有类似的东西吗?

澄清:我知道tup,cmake和scons /我知道waf和bjam等等但是我希望我的deps这么小/以便编译完全没问题。我特别要求Make支持,而不是Make替代。

5 个答案:

答案 0 :(得分:1)

我建议使用automake生成makefile。 Cmake还生成makefile,同时还能够为多个IDE生成项目文件。

问题是没有人make。最基本的语法总是相同的,但是任何稍微复杂的东西(你需要这些包括)都不兼容,即使在 GNU make BSD make 之间也是如此(不是试图提到 nmake )。但是,Automake可以处理几个版本的make,并提供自动依赖规则(只有一些编译器支持它们)。

答案 1 :(得分:0)

您可能希望查看CMakePremake

对于大型C / C ++项目,您往往会有其他要求,例如特定于平台的API或需要自定义的库。

答案 2 :(得分:0)

这将满足您的要求(至少在GNUMake中)。

makelib.mk:

$(TARG): $(CPPFILES:.cc=.o)
    $(CC) $^ -o $@

%.o : %.cc
    $(CC) -MD -o $@ $<                                               
    @cp $*.d $*.P; \                                                        
      sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \            
          -e '/^$$/ d' -e 's/$$/ :/' < $*.d >> $*.P; \                 
      rm -f $*.d                                                       

-include $(CPPFILES:.cc=.P)

生成文件:

CPPFILES = foo.cc bar.cc
TARG = someTarget
include makelib.mk      # Note lower-case "i"

CPPFILES = baz.cc quartz.cc quince.cc
TARG = anotherTarget
include makelib.mk

...

但建议:不要诅咒你的工具。您可以使用它来学习如何使用它们或切换到您更喜欢的能量。

答案 3 :(得分:0)

有一个googlecode项目完全符合我的要求:

http://code.google.com/p/nonrec-make/

答案 4 :(得分:0)

我不知道。 make确实存在很多问题,但它仍然是最常用的工具,一旦你让它正常运行,你应该专注于你的开发。

在那之前,你必须编写makefile。但是,不是寻找一个'make library',一个非常简单的解决方案(如果你实际上是在Make语言中启动的),经常被忽视太明显,就是实现你自己的。创建一个make脚本,其中包含一组默认模式规则和变量,用于与项目makefile进行通信,并且只需在每个项目的makefile中包含此脚本。这并不难,也许有点耗费时间,但它往往得到很好的回报,特别是如果你有很多小项目需要管理。

我使用这样的设计。我有一些精心设计的GNU make脚本,它们提供了一个几乎无足轻重的机制来创建相当复杂的构建系统:自动依赖生成,处理不同的语言,生成语言解析器,不同的构建配置(调试或发布),构建日志生成,等等。并且脚本并不繁琐:当前版本只包含大约250行makefile代码,不包括注释。

我将为您提供此类系统的旧版本示例,仅处理C源代码,其中包含一些功能。它应该处理二进制文件和库(静态和动态)的编译。它还应该通过DEPS变量帮助您跟踪项目间的依赖关系。

请致电$(ROOT)/project.mk

# Remove the default suffix rules.
.SUFFIXES:

# Turn on the delete-on-error feature.
.DELETE_ON_ERROR:

# Set up additional command variables.
STRIP ?= strip

# Set up a global search path to locate prerequisites.
VPATH := $(VPATH) $(shell find -type d)

# Locate all source files from the default locations in the project tree.
SRC := $(SRC) $(shell find src -name '*.c')

# Set up the default dependency files.
DEP := $(DEP) $(addprefix dep/,$(addsuffix .d,$(basename $(notdir $(filter %.c,$(SRC))))))

# Set up the default object files.
OBJ := $(OBJ) $(addprefix obj/,$(addsuffix .o,$(basename $(notdir $(filter %.c,$(SRC))))))

# Set up a set of default flags for all commands used.
STRIPFLAGS ?= -p
CPPFLAGS ?= -DNDEBUG
CFLAGS ?= -Wall -Wextra -Werror -pedantic -O3 -march=native -fomit-frame-pointer -ffast-math
LDFLAGS ?= --as-needed -O1
ARFLAGS ?= -scr

# Set up the default include and library search paths.
override INCLUDES := \
    $(addprefix $(ROOT)/,$(addsuffix /include,$(DEPS))) \
    $(INCLUDES)
override LIBRARIES := \
    $(addprefix $(ROOT)/,$(addsuffix /lib,$(DEPS))) \
    $(LIBRARIES) lib

# The default rule to build every target in the project.
.PHONY: all
all: deps $(DEP) $(OBJ) $(BIN) $(LIB)

# Phony rule to recursively build the library dependencies.
.PHONY: deps
deps:
    @for dep in $(DEPS); do cd $(ROOT)/lib/$$dep && $(MAKE); done

# Secondary expansion is used to properly locate prerequisites.
.SECONDEXPANSION:

# Rule for dependency file generation.
%.d: $$(notdir $$*).c
    $(CC) -M $(CPPFLAGS) $(CFLAGS) -iquote include $(addprefix -I ,$(INCLUDES)) $< -MM -MG -MP -MT '$@ $(filter %/$(notdir $*).o,$(OBJ))' > $@

# Rule for compiling object files.
%.o: $$(notdir $$*).c
    $(CC) -c $(CPPFLAGS) $(CFLAGS) -iquote include $(addprefix -I ,$(INCLUDES)) $< -o $@

# Rule for linking binaries.
%: $$(notdir $$*).c
    $(CC) $(CPPFLAGS) $(CFLAGS) $(addprefix -Xlinker ,$(LDFLAGS)) -iquote include $(addprefix -I ,$(INCLUDES)) $(addprefix -L ,$(LIBRARIES)) $(filter-out $<,$^) -o $@ $(addprefix -l,$(LDLIBS))
    $(STRIP) $(STRIPFLAGS) $@

# Rule for linking shared libraries.
%.so: $$(notdir $$*).c
    $(CC) $(CPPFLAGS) $(CFLAGS) $(addprefix -Xlinker ,$(LDFLAGS)) -iquote include $(addprefix -I ,$(INCLUDES)) $(addprefix -L ,$(LIBRARIES)) $(filter-out $<,$^) -o $@ -fpic -shared -Wl,-h,$(notdir $@) $(addprefix -l,$(LDLIBS))
    $(STRIP) $(STRIPFLAGS) $@

# Rule for generating static libraries.
%.a:
    $(AR) $(ARFLAGS) $@ $?

# Include all dependency files and remake them if necessary.
ifneq ($(MAKECMDGOALS),clean)
    include $(DEP)
endif

# Phony rule to clean the entire build tree.
.PHONY: clean
clean:
    @for dep in $(DEPS); do cd $(ROOT)/lib/$$dep && $(MAKE) clean; done
    $(RM) $(DEP) $(OBJ) $(BIN) $(LIB) $(CLEAN)

ROOT包含项目目录的路径(例如,存储库的工作副本),通常作为环境变量导出。您还需要在项目中添加几个目录(bindepobjsrc

使用此系统的Makefile示例可能是:

DEPS := mylib

BIN := bin/test
LIB := lib/libtest.a

include $(ROOT)/project.mk

bin/test: $(OBJ)
lib/libtest.a: obj/test1.o obj/test2.o

也就是说,您只需编写有关项目的最低要求,然后让构建系统完成剩下的工作。您始终可以显式指定给定变量的值(例如SRCCFLAGS),但如果不这样做,则会得到合理的默认值。

以上内容是根据我的需求量身定制的,但应该很容易适应你的需求,同时保持事情就像你提到的例子一样简单。