Makefile для компиляции всех файлов .c без необходимости их указания - PullRequest
0 голосов
/ 04 ноября 2018

Я пытаюсь создать Makefile, который вызывает компиляцию всех файлов .c без необходимости добавлять имена файлов в каждой строке внутри Makefile. Я думаю, что это довольно похоже на makefiles - компилировать все файлы c одновременно . Вот что я хочу сделать:

1 - Убедитесь, что все .c файлы из /src имеют соответствующие .o файлы из /obj. Если файл .o не существует, создайте его из файла .c;

2 - Скомпилируйте main.exe из всех .o и поместите его в /bin.

Мой Makefile:

BIN     = ./bin
OBJ     = ./obj
INCLUDE = ./include
SRC     = ./src

all:
    gcc -c "$(SRC)/Distances.c" -o "$(OBJ)/Distances.o"
    gcc -c "$(SRC)/HandleArrays.c" -o "$(OBJ)/HandleArrays.o"
    gcc -c "$(SRC)/HandleFiles.c" -o "$(OBJ)/HandleFiles.o"
    gcc -c "$(SRC)/Classifier.c" -o "$(OBJ)/Classifier.o"
    gcc -c main.c -o "$(OBJ)/main.o"
    gcc -o $(BIN)/main.exe $(OBJ)/*.o -lm

run:
    $(BIN)/main.exe

clean:
    del /F /Q "$(OBJ)" ".o"
    del /F /Q "$(BIN)" ".exe"

Полагаю, мне нужно использовать что-то вроде $(SRC)/*.c, но я не смог этого сделать.

Теперь, о make clean, я не знаю, как заставить его работать кроссплатформенно. Я использую del в Windows.

Ответы [ 2 ]

0 голосов
/ 04 ноября 2018

Примечание: этот ответ предполагает, что вы используете GNU make . Если это не так, вероятно, есть несколько вещей для адаптации. Я не буду отвечать на ваш последний вопрос о кросс-платформенной переносимости. Во-первых, потому что это сложный вопрос, во-вторых, потому что у меня нет коробки с Windows, и я не могу выполнять никаких тестов с этой ОС. Но если вы знаете переносимый способ обнаружения ОС, посмотрите на последнюю заметку. Между тем, следующее должно работать под Windows.

Самый простой и стандартный способ использования GNU make в вашем случае, вероятно, выглядит примерно так:

MKDIR   := md
RMDIR   := rd /S /Q
CC      := gcc
BIN     := ./bin
OBJ     := ./obj
INCLUDE := ./include
SRC     := ./src
SRCS    := $(wildcard $(SRC)/*.c)
OBJS    := $(patsubst $(SRC)/%.c,$(OBJ)/%.o,$(SRCS))
EXE     := $(BIN)/main.exe
CFLAGS  := -I$(INCLUDE)
LDLIBS  := -lm

.PHONY: all run clean

all: $(EXE)

$(EXE): $(OBJS) | $(BIN)
    $(CC) $(LDFLAGS) $^ -o $@ $(LDLIBS)

$(OBJ)/%.o: $(SRC)/%.c | $(OBJ)
    $(CC) $(CFLAGS) -c $< -o $@

$(BIN) $(OBJ):
    $(MKDIR) $@

run: $(EXE)
    $<

clean:
    $(RMDIR) $(OBJ) $(BIN)

Пояснения:

  1. Функция wildcard make используется для обнаружения списка исходных файлов на языке C.
  2. Функция patsubst make используется для преобразования имен файлов исходного кода C. в имена файлов объектов.
  3. Специальная цель .PHONY сообщает make, что все ее предпосылки phony : они не являются реальными файлами и должны учитываться make, даже если файл с таким именем уже существует случайно.
  4. $(OBJ)/%.o: $(SRC)/%.c | $(OBJ) - это шаблонное правило , универсальное правило, которое работает для всех ваших похожих правил построения объектов. В этом рассказывается make, как создать каждый объектный файл ./obj/xxx.o, скомпилировав соответствующий исходный файл ./src/xxx.c C.
  5. Часть ... | $(OBJ) правила шаблона говорит make, что $(OBJ) является обязательным условием только для заказа . Make соберет его, если он еще не существует. В противном случае он не будет учитывать время последнего изменения, чтобы решить, должна ли цель быть восстановлена ​​или нет. Каталоги почти всегда указываются как предварительное условие только для заказа, поскольку время их последнего изменения не имеет значения. Здесь он используется, чтобы сказать make, что каталог $(OBJ) должен быть собран до того, как может быть создан любой объектный файл. То же самое для $(BIN) в правиле $(EXE): $(OBJS) | $(BIN).
  6. $@, $< и $^ - 3 из автоматических переменных make . В рецептах правила они расширяются соответственно как цель, первая регулярная предпосылка и все регулярные (не только для заказа) предпосылки правила.
  7. CC, CFLAGS и LDLIBS являются стандартными делают неявные переменные соответственно используемыми для определения компилятора C, параметров компилятора C и параметров компоновщика -lxxx.
  8. Назначение переменной := предпочтительнее , в данном конкретном случае , чем назначение = по соображениям производительности. См. документацию GNU make для подробного объяснения.

Примечание: поскольку у вас есть каталог include, я предполагаю, что у вас также есть пользовательские заголовочные файлы. Они должны быть перечислены в качестве предварительных условий соответствующих объектных файлов, чтобы make знал, что объектный файл должен быть перестроен, если заголовочные файлы зависят от изменений. Вы можете сделать это, добавив правила без рецепта в любом месте после правила шаблона:

$(OBJ)/Distances.o: $(INCLUDE)/foo.h $(INCLUDE)/bar.h

Если заголовочный файл включен во все исходные файлы C вашего проекта, просто добавьте:

$(OBJS): $(INCLUDE)/common.h

И если для заголовочных файлов существует своего рода шаблон (например, если каждый $(SRC)/xxx.c включает $(INCLUDE)/xxx.h), вы также можете добавить правило шаблона, чтобы объявить этот тип зависимости:

$(OBJ)/%.o: $(INCLUDE)/%.h

Примечание: если вы знаете способ установки переменной make (например, OS) для имени текущей ОС, вы, вероятно, можете изменить то, что предшествует, чтобы сделать ее переносимой, используя GNU make conditionals. Например, вы можете заменить две первые строки на:

OS := $(shell <the-command-that-returns-the-current-OS-name>)

ifeq ($(OS),Windows)
MKDIR   := md
RMDIR   := rd /S /Q
else ifeq ($(OS),GNU/Linux)
MKDIR   := mkdir -p
RMDIR   := rm -rf
else ifeq  ($(OS),pokemon)
MKDIR   := bulbasaur
RMDIR   := charmander
endif
0 голосов
/ 04 ноября 2018

% шаблонное правило может помочь % .O:% с

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...