В настоящее время я пытаюсь придумать надежную структуру папок для Project-Euler
,
Моя текущая идея заключается в следующем:
--project-euler/
--resources
--primes.h
--primes.c
--factors.h
--factors.c
--...
--001_name_of_procect_one.c
--001_name_of_project_one.o
--002_name_of_project_two.c
--002_name_of_project_two.o
--...
Моя проблема с этой структурой состоит в том, что у меня есть все проекты в одной папке, и я не знаю, как писать Makefiles
для такого рода структуры.
Я мог бы создать отдельный каталог для каждого проекта, но тогда мне нужно было бы написать что-то вроде #include "../resources/primes.h"
и мне как-то не нравится такой подход.
Какую типичную структуру проекта использовать в таком случае? Как бы я мог написать Makefile
для всех небольших проектов, сохраняя их в одном каталоге?
РЕДАКТИРОВАТЬ: я использую clang
Кстати.
Если вы сохраните служебные файлы в resources
В подкаталоге вы можете создавать отдельные файлы решений в главном каталоге, которые включают необходимые заголовочные файлы вверху, например:
#include "resources/primes.h"
И включите фактический код внизу с
#include "resources/primes.c"
Таким образом, вам даже не нужно Makefile
поскольку правила по умолчанию позволят вам сделать каждую цель из соответствующего исходного файла напрямую:
make 002_name_of_project_two
make даже не создаст объектный файл, только исполняемый файл.
Я лично предпочитаю более короткие имена для файлов проекта, такие как p42.c
Makefile
все еще полезно ударить просто make
или кнопку сборки вашей IDE. Достаточно одного вкладыша:
all: p42
Но вы можете захотеть добавить некоторые зависимости, чтобы ваша цель перекомпилировалась, когда вы меняете только источники утилит. Добавьте эти строки: (с TAB в начале второй строки)
%: %.c $(wildcard resources/*)
clang $(CFLAGS) $(LFLAGS) -o $@ $<
Вы все еще должны добавить правильные параметры к вашему CFLAGS
Переменная окружения, чтобы воспользоваться способностью компилятора ловить глупые ошибки: -Wall -Wextra -Werror
за gcc
, а также -Weverything
за clang
,
Если вы используете g++
вы объявляете каталог включения с помощью:
g++ -I../resources #rest of command line
Этот расширенный комментарий о библиотеках будет филистимским ответом вопреки обычному мышлению. В ранние годы я проводил бесчисленные часы, поддерживая свою прекрасную библиотеку, но с этой идеей связаны некоторые проблемы. Такая библиотека всегда находится в стадии разработки, но когда проект подписан и доставлен, вы не осмеливаетесь изменить библиотеку, опасаясь разорвать предыдущий (ые) проект (ы), поэтому ее нужно заморозить. После этого у вас будет несколько версий вашей библиотеки. Теперь предположим, что моды требуются для старого проекта, который требует изменения библиотечной функции? Вы по-прежнему не можете использовать текущую версию, потому что вам придется заново пройти предыдущее тестирование продукта и заверения. Другое возражение заключалось в том, что некоторые из моих якобы хороших библиотечных функций никогда не были такими, какими я хотел в следующем проекте. Все это стало кошмаром обслуживания, и я отказался от него. Теперь я обнаружил, что в задаче Project Euler мне может понадобиться функция факториала. В одном случае простой unsigned
Функция будет хорошей. В другом случае мне понадобится uint64_t
быть в диапазоне. В еще одном, это будет либо unsigned
или же uint64_t
по модулю некоторая константа. Вариации бесконечны, и общий подход «одна функция подходит всем» не подходит, когда функция может нуждаться в вызове миллионы раз. Поэтому я просто использую биты копирования / вставки решения, которые мне нужны для решения других проблем.