Makefile автоматические переменные - PullRequest
0 голосов
/ 31 августа 2018

Я работаю над библиотекой (более или менее случайных) функций, которые я использую в проектах. В предыдущем воплощении каждый файл .c, .o был перечислен и скомпилирован вручную в target:

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

Это стало утомительным, неточным и мучительным, и я хотел создать более дружественный, лучший Makefile, который я мог бы использовать для любого проекта. После поиска в Google прочитал («Управление проектами с помощью 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 голосов
/ 31 августа 2018

То, что создается вашим правилом компиляции, является результатом расширения $@, которое является целью правила, то есть ... obj. Таким образом, у вас, вероятно, есть файл с именем obj, содержащий результат компиляции первого источника в $(SRC) (расширение $<). Используйте шаблонное правило вместо:

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: obj

obj: $(OBJ)

и вызвать:

make obj

Точно так же было бы лучше определить exe как фальшивое и написать правило, которое явно создает файл. Make всегда счастливее, когда мир, который он видит, состоит из рецептов создания файлов:

.PHONY: exe

exe: $(EXE)

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

Последнее замечание: вы используете make в одном из ваших рецептов (pack) через одну из ваших MK пользовательских переменных. Вы действительно должны рассмотреть замену MK на уже определенную MAKE make-переменную:

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