Makefile自动变量

时间:2018-08-31 01:08:16

标签: makefile gnu-make

我正在开发在项目中使用的(或多或少随机的)c函数的库。它的前一个版本列出了每个.c,.o文件,并在目标文件中对其进行了手动编译:

$(CC) $(SRCDIR)/somefoo.c $(CFLAGS) ... -c -o $(OBJDIR)/somefoo.o

这变得烦人,不准确和痛苦,我想创建一个可以用于任何项目的友好,更好的Makefile。谷歌搜索之后,阅读(O'Reily的“使用GNU Make管理项目”)并以为我想到了:

BIN = /usr/bin

SH  = $(BIN)/bash
CC  = $(BIN)/cc
AR  = $(BIN)/ar
RL  = $(BIN)/ranlib
RM  = $(BIN)/rm
CP  = $(BIN)/cp
RL  = $(BIN)/ranlib
TC  = $(BIN)/touch
MK  = $(BIN)/make
FND = $(BIN)/find
TAR = $(BIN)/tar
RM  = $(BIN)/rm

CFLAGS  = -Wall -Wextra -Wpedanitc -pedanitc-errors\
          -w -Waddress -Walloc-zero -Walloca -Warray-bounds\
          -Wno-deprecated -Wno-div-by-zero -Werror -Wfatal-errors\
          -Wduplicated-cond -Wduplicated-branches -Wlogical-op -Wdouble-promotion\
          -Wrestrict -Wnull-dereference -Wjump-misses-init -Wshadow\
          -Wformat=2 -Wformat -Wformat-security -pedantic --std=c99 --march=native
DEBUG   = -g -ggdb -gstabs
OPTIM   = -faggressive-loop-optimizations -fassociative-math -O3
LIBS    = -lm -lcommonC #add more here
INC     = -I/usr/include -I/usr/local/include -I$(INCDIR)
LIBPATH = -L/usr/lib -L/usr/lib64 -L/usr/local/lib -L/usr/local/lib64 -L$(LIBDIR)
MKFLAG  = -f

PACK = $(TAR) -cvs
EXTRACT = $(TAR) -xf

PREFIX = /path/to/project #root directory of the project
BINDIR = $(PREFIX)/bin #stores Makefile, shell scripts, README, LICENSE, data files...
INCIDR = $(PREFIX)/include #holds .h files for the project
SRCDIR = $(PREFIX)/src #holds source files
OBJDIR = $(PREFIX)/obj #holds generated object files
LIBDIR = $(PREFIX)/lib #holds generated or included .a files
EXEDIR = $(PREFIX)/exe #generated executable(s)
DESTDIR ?= #where the tar file will be unpacked, user defined.

SRC = $(wildcard $(SRCDIR)/*.c) #all .c source files
OBJ = $(patsubst %.c,%.o,$(wildcard *.c)) #.o files
LIB ?= $(wildcard $(LIBDIR)/*.a) #the .a
EXE = $(EXEDIR)/project #generated executable
MKE = $(BINDIR)/Makefile #Makefile, used for cleaning before packing the project
TARF ?= #tar file for project.tar, user defined

.PHONY: obj exe update test clean pack install

# up to $(EXE) updated thanks to "Renaud Pacalet"
obj: $(OBJ)
exe: $(EXE)

$(OBJ): %.o: %.c
  $(CC) $< $(CFLAGS) $(LIB) $(INC) $(LIBPATH) $(LIBS) $(OPTIM) -c -o $@

$(EXE): $(OBJ)
   $(CC) $^ $(CFLAGS) $(LIB) $(INC) $(LIBPATH) $(LIBS) $(OPTIM) -o $@

update: $(SRC)
    $(TC) $(SRC)

clean:
    $(RM) $(OBJ) $(EXE) $(LIB)

pack:
    $(MK) $(MKFLAG) $(MKE) clean && $(PACK) $(PREFIX) $(TARF)

install:
    cd $(DESTDIR) && $(TAR) $(EXTRACT) $(TARF)

我的问题是有关SRC,OBJ的声明以及要编译的目标.c-> .o SRC = ...可以正常工作,但由于某种原因未生成相应的obj文件?感谢您提供的所有信息。

更新:感谢Renaud Pacalet,我弄清楚了OBJ / SRC变量。我收到一个错误:

make: Nothing to be done for 'obj'

通常意味着目标是最新的。引起我注意的是,我的组织缺乏详细信息,因此我添加了描述每个变量引用内容的注释。我以前在大多数项目中都使用过这种组织方案,但是到目前为止,我还没有遇到任何问题。

感谢您的所有输入。

-乔丹。

-乔丹。

1 个答案:

答案 0 :(得分:0)

编译规则创建的结果是扩展$@的结果,扩展了规则的目标,即... obj。因此,您可能有一个名为obj的文件,其中包含$(SRC)中第一个源代码的编译结果(扩展$<)。使用pattern rule代替

SRC = $(wildcard $(SRCDIR)/*.c)
OBJ = $(patsubst %.c,%.o,$(SRC))

%.o: %.c
    $(CC) $< $(CFLAGS) $(LIB) $(INC) $(LIBPATH) $(LIBS) $(OPTIM) -c -o $@

static pattern rule

$(OBJ): %.o: %.c
    $(CC) $< $(CFLAGS) $(LIB) $(INC) $(LIBPATH) $(LIBS) $(OPTIM) -c -o $@

如果您想要的是用于编译所有源代码的简写形式obj,则可以定义phony target

.PHONY: obj

obj: $(OBJ)

并调用:

make obj

类似地,最好将exe定义为phony并编写一条明确创建文件的规则。当创建世界的食谱由创建文件的食谱组成时,Make总是会更快乐:

.PHONY: exe

exe: $(EXE)

$(EXE): $(OBJ)
    $(CC) $^ $(CFLAGS) $(LIB) $(INC) $(LIBPATH) $(LIBS) $(OPTIM) -o $@

最后一个注意事项:您可以通过make自定义变量之一在食谱之一(pack)中使用MK。您应该真正考虑用已经定义的MAKE make变量替换MK

pack:
    $(MAKE) $(MKFLAG) $(MKE) clean && $(PACK) $(PREFIX) $(TARF)