我正在开发在项目中使用的(或多或少随机的)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'
通常意味着目标是最新的。引起我注意的是,我的组织缺乏详细信息,因此我添加了描述每个变量引用内容的注释。我以前在大多数项目中都使用过这种组织方案,但是到目前为止,我还没有遇到任何问题。
感谢您的所有输入。
-乔丹。
-乔丹。
答案 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 $@
$(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)