Развитие Make-файла из плоской структуры каталогов в структуру подкаталогов - PullRequest
0 голосов
/ 14 февраля 2019

ПОСМОТРЕТЬ ОБНОВЛЕНИЯ НИЖЕ


Исследование завершено: Мне трудно научиться превращать Make-файлы из одной ситуации в другую.Существует множество вопросов и ответов, но немногие из них на самом деле показывают, как Makefile может развиваться по мере изменения вашего проекта.Кажется, все они также используют различные техники и идиомы Makefiles, поэтому перевод с одного вопроса на другой может быть сложным, когда вы впервые изучаете Makefiles, как и я.

Проблема: Моя проблема в том, что у меня есть проект, который начинался как плоская структура каталогов, но затем мигрировал в структуру с подкаталогами.Что я не могу сделать, так это взять с собой мой Makefile для поездки.

Сначала я покажу, что я создал, что работает, а затем я покажу, как я хочу, чтобы он развивался и как это не работало.

Плоская структура каталогов, рабочий Makefile

У меня есть каталог проекта, в котором есть все мои C-файлы и один заголовочный файл плюс мой Makefile:

project
  Makefile
  c8_asm.c
  c8_dasm.c
  c8_terp.c
  chip8.h

Вот мой Makefile (который прекрасно работает):

CC = gcc

CFLAGS += -c -Wall -std=c99
CFLAGS += -D_POSIX_C_SOURCE=200809L

LDLIBS += -lm

# Targets

all: c8_dasm c8_asm c8_terp

c8_dasm: c8_dasm.o
    $(CC) $(LDLIBS) c8_dasm.o -o $@

c8_asm: c8_asm.o
    $(CC) $(LDLIBS) c8_asm.o -o $@

c8_terp: c8_terp.o
    $(CC) $(LDLIBS) c8_terp.o -o $@

# Using implicit rules for updating an '.o' file from a correspondingly
# named '.c' file.

c8_dasm.o: chip8.h
c8_asm.o: chip8.h
c8_terp.o: chip8.h

.PHONY: clean
clean:
    rm c8_dasm c8_asm c8_terp c8_dasm.o c8_asm.o c8_terp.o

Я получаю все мои .o файлы и мои исполняемые файлы создаются в каталоге проекта.

Развитие проекта

Но я хотел, чтобы мои исходные файлы (все .c и .h) были в каталоге src.Я хотел встроить в каталог obj и сделать так, чтобы исполняемые файлы помещались в каталог bin.Поэтому мой проект будет выглядеть следующим образом:

project
  src
    c8_asm.c
    c8_dasm.c
    c8_terp.c
    chip8.h
  Makefile

Структура подкаталога, Makefile НЕ работает

Чтобы учесть вышеизложенное, я изменил свой Makefile соответствующим образом:

CC = gcc

CFLAGS += -c -Wall -std=c99
CFLAGS += -D_POSIX_C_SOURCE=200809L

LDLIBS += -lm

SRC_DIR = src
OBJ_DIR = obj
BIN_DIR = bin

SOURCES := $(wildcard $(SRC_DIR)/*.c)
OBJECTS := $(SOURCES:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)

MKDIR_P ?= mkdir -p

# Targets

all: $(BIN_DIR)/c8_dasm $(BIN_DIR)/c8_asm $(BIN_DIR)/c8_terp

$(BIN_DIR)/c8_dasm: $(OBJ_DIR)/c8_dasm.o
    $(CC) $(LDLIBS) $(OBJ_DIR)/c8_dasm.o -o $@

$(BIN_DIR)/c8_asm: $(OBJ_DIR)/c8_asm.o
    $(CC) $(LDLIBS) $(OBJ_DIR)/c8_asm.o -o $@

$(BIN_DIR)/c8_terp: $(OBJ_DIR)/c8_terp.o
    $(MKDIR_P) $(dir $@)
    $(CC) $(LDLIBS) $(OBJ_DIR)/c8_terp.o -o $@

$(OBJECTS): $(OBJ_DIR)/%.o : $(SRC_DIR)/%.c
    $(MKDIR_P) $(dir $@)
    $(CC) $< -o $(OBJ_DIR)/$@

# Using implicit rules for updating an '.o' file from a correspondingly
# named '.c' file.

$(OBJ_DIR)/c8_dasm.o: $(SRC_DIR)/chip8.h
$(OBJ_DIR)/c8_asm.o: $(SRC_DIR)/chip8.h
$(OBJ_DIR)/c8_terp.o: $(SRC_DIR)/chip8.h

.PHONY: clean
clean:
    rm -r $(BUILD_DIR)
    rm $(OBJECTS)

После запуска этого я получаю следующее:

mkdir -p obj/obj/
gcc src/c8_dasm.c -o obj/c8_dasm.o
gcc -lm obj/c8_dasm.o -o bin/c8_dasm
ld: can't link with a main executable file 'obj/c8_dasm.o' for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [bin/c8_dasm] Error 1

Я хотел остановиться здесь и получить некоторую помощь, потому что я боюсь, что делаю этот Makefile сложнее, чем нужно, и яЯ пытаюсь избежать вредных привычек.

Я надеюсь услышать мнения о том, что я не правильно концептуализирую здесь.

ПЕРВОЕ ОБНОВЛЕНИЕ

Мне удалось взять это понемногу и заставить его работать в основном.Вот что я закончил:

CC = gcc

CFLAGS += -c -Wall -std=c99
CFLAGS += -D_POSIX_C_SOURCE=200809L

LDLIBS += -lm

# Directories.

SRC_DIR = src
BIN_DIR = bin

$(shell mkdir -p $(BIN_DIR))

# Patterns for files.

SOURCES := $(wildcard $(SRC_DIR)/*.c)
OBJECTS := $(SOURCES:$(SRC_DIR)/%.c=$(SRC_DIR)/%.o)

EXECUTABLES := c8_dasm c8_asm c8_terp

# Targets

all: $(EXECUTABLES)

c8_dasm: $(SRC_DIR)/c8_dasm.o
    $(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$@
    @echo "C8 Disassembler Built"

c8_asm: $(SRC_DIR)/c8_asm.o
    $(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$@
    @echo "C8 Assembler Built"

c8_terp: $(SRC_DIR)/c8_terp.o
    $(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$@
    @echo "C8 Interpreter Built"

# Using implicit rules for updating an '.o' file from a correspondingly
# named '.c' file.

c8_dasm.o: $(SRC_DIR)/chip8.h
c8_asm.o: $(SRC_DIR)/chip8.h
c8_terp.o: $(SRC_DIR)/chip8.h

.PHONY: clean
clean:
    rm $(OBJECTS)
    rm -r $(BIN_DIR)

Конечно, поскольку я нахожу с Make, это приводит к другим неясным проблемам.Например, сделав это:

make
make clean

работает нормально.Это означает, что все файлы сгенерированы, и файлы очищены, включая каталог bin.

Однако, если я сделаю это:

make c8_dasm
make clean

Это прекрасно работает.Но очистка не удаляет каталог bin (хотя она и удаляет объектные файлы).Это происходит независимо от того, какой отдельный исполняемый файл я пытаюсь создать.

Никакие поиски не помогают мне выяснить, почему это так.

ВТОРОЕ ОБНОВЛЕНИЕ

Я обнаружил, что проблема также была решена.Просто потребовалось использовать "-f" для операторов rm в чистой цели.

ТРЕТЬЕ ОБНОВЛЕНИЕ

Чтобы заставить работать часть каталога объектных файлов, я попытался (из этого: путь include и make-файл каталога src ) для создания моего Makefile следующим образом:

CC = gcc

CFLAGS += -c -Wall -std=c99
CFLAGS += -D_POSIX_C_SOURCE=200809L

LDLIBS += -lm

SRC_DIR = src
OBJ_DIR = obj
BIN_DIR = bin

$(shell mkdir -p $(BIN_DIR))
$(shell mkdir -p $(OBJ_DIR))

SOURCES := $(wildcard $(SRC_DIR)/*.c)
OBJECTS := $(SOURCES:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)

EXECUTABLES := c8_dasm c8_asm c8_terp

all: $(EXECUTABLES)

c8_dasm: $(SRC_DIR)/c8_dasm.o
    $(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$@
    @echo "C8 Disassembler Built"

c8_asm: $(SRC_DIR)/c8_asm.o
    $(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$@
    @echo "C8 Assembler Built"

c8_terp: $(SRC_DIR)/c8_terp.o
    $(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$@
    @echo "C8 Interpreter Built"

$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
    $(CC) $(CFLAGS) -c $< -o $(BIN_DIR)/$@

.PHONY: clean
clean:
    rm -rf $(BIN_DIR)
    rm -f $(OBJECTS)

Мне удалось сжать три исходные строки, используя chip8.h, в одну цель, но яне знаю, правильно ли это.Это компилирует по крайней мере.Я также изменил строку OBJECTS, чтобы отразить новую созданную мной OBJ_DIR.

Однако, это не помещает объектные файлы в правильное место.Он по-прежнему помещает их в каталог src, а не в каталог obj.

Ответы [ 3 ]

0 голосов
/ 14 февраля 2019

Stackoverflow жалуется на слишком много комментариев, поэтому я сделаю еще один «ответ».После нашего возврата к моему первоначальному комментарию ваш последний комментарий верен.Это то, что я хотел, чтобы вы увидели.

Поймите, что вы не можете использовать Make, чтобы делать именно то, что вы хотите.

Так вот, действительно, ответ: Вы не можетесоздайте несколько исполняемых файлов И только с некоторыми объектными файлами, применяемыми к каждому И при использовании структуры каталогов. Make никоим образом не способен справиться с этим.

Сейчас вы пытаетесь использовать Makeтаким образом, это не было предназначено, поэтому вы сталкиваетесь с таким количеством проблем.Если вы продолжаете играть, вы столкнетесь с серией ошибок, которые говорят «дублирующий символ», потому что вы будете компилировать каждый из ваших файлов несколько раз для каждого исполняемого файла, при условии, что вы будете следовать большинству советов, которые найдете.

Проверьте это Как я могу создать Makefile для проектов C с подкаталогами SRC, OBJ и BIN? , чтобы понять, что я имею в виду.Это работает, потому что все объектные файлы используются для создания одного исполняемого файла.Но, как вы заявили, это не будет иметь место для вас.И это то, что Мак не может справиться.Вот почему вы не нашли ответа на этот вопрос.

И хотя ваш файл chip8.h теперь не будет вызывать проблем с точки зрения возможности компиляции, ваш Makefile с этим третьим обновлением не распознает, когдаСам файл chip8.h изменился.Вам нужно изменить файл .c, чтобы принудительно перекомпилировать, чтобы изменения в вашем .h были распознаны.Таким образом, вы должны придерживаться второго обновления или использовать что-то другое, кроме Make.

0 голосов
/ 15 февраля 2019

Полагаю, я понял это.Ниже мой Makefile.Кажется, делать то, что я хочу.Он выполняет следующие действия:

  • Компилирует все объектные файлы в каталог obj.
  • Компилирует и создает ссылки, так что исполняемые файлы создаются в каталоге bin.
  • Распознает, если какие-либо файлы .c изменены, и соответственно перекомпилирует.
  • Распознает, если файл .h изменяется, и перекомпилирует все файлы C, ссылающиеся на него.

Это кажетсячтобы удовлетворить все критерии, но я не могу сказать, нарисовал ли я себя в каком-то углу, который я пока не вижу.

CC = gcc

CFLAGS += -c -Wall -std=c99
CFLAGS += -D_POSIX_C_SOURCE=200809L

LDLIBS += -lm

SRC_DIR = src
OBJ_DIR = obj
BIN_DIR = bin

$(shell mkdir -p $(BIN_DIR))
$(shell mkdir -p $(OBJ_DIR))

SOURCES := $(wildcard $(SRC_DIR)/*.c)
OBJECTS := $(SOURCES:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)

EXECUTABLES := c8_dasm c8_asm c8_terp

all: $(EXECUTABLES)

c8_dasm: $(OBJ_DIR)/c8_dasm.o
    $(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$@
    @echo "C8 Disassembler Built"

c8_asm: $(OBJ_DIR)/c8_asm.o
    $(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$@
    @echo "C8 Assembler Built"

c8_terp: $(OBJ_DIR)/c8_terp.o
   $(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$@
   @echo "C8 Interpreter Built"

$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c $(SRC_DIR)/chip8.h
    $(CC) $(CFLAGS) -c $< -o $@

.PHONY: clean
clean:
    rm -rf $(BIN_DIR)
    rm -rf $(OBJ_DIR)
0 голосов
/ 14 февраля 2019

Вот почему имеет смысл не делать ничего сложного с Makefiles.Просто введите фактические имена каталогов в ваших командах.Никогда не полагайтесь на подстановочные знаки.

Люди, использующие C и C ++ и использующие Makefiles, тратят слишком много времени на то, чтобы заставить их работать, а не просто на деле.Вот почему вы видите так много вопросов, которые видите, и почему ответы так сильно различаются.

В вашем конкретном случае ваши цели не всегда должны содержать каталог, и это является частью проблемы.Сгенерированные правила не имеют фактической цели в вашем файле из-за каталогов, которые вы добавляете ко всему.Вы должны думать о том, что генерируется каждой целью: значение, результат.Так что, если c8_dasm получает выходные данные, это ваша цель.Каталог не имеет к этому никакого отношения.Поэтому вам нужно удалить все подстановки каталогов там, где они не нужны.

Но прежде чем сделать это, спросите себя: если ваше первое решение работало, зачем его менять?Лучше даже не делать каталоги, когда вы используете Make.Просто поместите все в тот же каталог, с которого вы начали.Вы даже можете видеть, что это делает ваш Makefile намного чище.

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