Блин, наконец-то! Знаешь, сколько я перелопатил, чтобы узнать, как грамотно по разным директориям разносить файлы? На удивление только у тебя нашёл толковое объяснение. Все статьи пишут одно и то же, но как будто бы в отрыве от реальности и только для учебных проектов. Спасибо огромное и +100500 в карму! =)
Этого в планах нет. Была задача сформировать такой makefile, чтобы потом про него забыть и никогда не вспоминать, но чтобы при копировании в папку с новым проектом все .c файлы компилировались и собирались в исполняемый файл. Может эта тема и заинетесует, но многообразие утилит для сборки и тестирования пока что только огорчает, так как попытки собрать проект из исходников напоминют ситуацию, когда ты заказал табурет, и мастер уже забивает последний гвоздь и вдруг говорит: "для двух последних ударов нужен молоток Х". Отвечаешь: "у меня такого нет, но есть Y и он вполне способен решить эту задачу". А мастер в ответ выдергивает гвоздь, разламывает всю табуретку и уходит. Стоит тебе через время найти этот X, как мастер заявлает, что тот уже старый и нужен "X 5.0", и вообще, половина досок уже "deprecated"
А если у меня в src лежат несколько папок, и все файлы в этих папках надо скомпилировать, но так-же есть и файлы которые не в папках, как можно это сделать?
TARGET = MyProject CC = gcc PREF_SRC = ./src/ PREF_OBJ = ./obj/ SRC = $(shell find . -name "*.c") OBJ = $(patsubst $(PREF_SRC)%.c, $(PREF_OBJ)%.o, $(SRC)) $(TARGET) : $(OBJ) $(CC) $(OBJ) -o $(TARGET) $(PREF_OBJ)%.o : $(PREF_SRC)%.c mkdir -p $(dir $@) $(CC) -c $< -o $@ clean : rm $(TARGET) $(OBJ) Разница в том, что в переменой SRC список всех файлов, оканчивающихся на ".c", в том числе и в подкатологах внутри src. Команда shell позволяет выполнить команду оболочки и получить результат в виде строки. Далее заменяем префикс "./src/" на "./obj/", а так же расширение ".c" на ".o" с помощью команды patsubst во всех найденных именах файлов исходников. Таким образом, структура папок внутри "./obj/" предполагается такой же, как и в "./src/", но компилятор не будет создавать недостающие папки автоматически по относительному пути файла в "./obj/". Чтобы решить эту проблему, в правило компиляции отдельного исходника добавлена команда mkdir -p $(dir $@). Здесь $@ - это имя файла-цели, то есть файла ".o". dir позволяет выделить из этого имени имя католога, а ключ -p блокирует ошибку, если католог уже существует.
Ещё раз спасибо! А как решать проблему отслеживания изменений заголовочных файлов? И ещё вопрос: ведь в каталоге src исходник могут быть размещены по подкаталогам произвольной структуры. Как этот момент учесть?
Для компилятора обычно указывают место хранения дополнительных заголовочных файлов. Делается это опцией -I Но здесь это не требуется, поскольку заголовочный там же, где исходник. Поэтому, к стати, заголовочный указан не в угловых скобках, а в ковычках
Хороший гайд. Но не все вопросы решены. Что делать, если в проекте есть код на нескольких языках? А ещё проект состоит из десятка других проектов, и вообще не ясно, что где лежит. У кого-то cmake прикручен, у кого-то makefile, а некоторые вообще sln. И ещё некоторые любят писать #include , а кто-то просто пишет #include , кто-то #include "C:\васян\sdl. h" , и плевать они хотели на то, что это один файл. Кому-то так удобнее, кому-то так. А тебе все это читать и переписывать не надо, тебе бы только скомпилировать. Под виндой кто-то уже для всего этого цирка сделал sln, и это работает. А makefile нет. Конкретно в моём случае это ещё и статическая библиотека name.lib, которую надо бы пересобрать для линукса в name.a. Если будет настолько обширный гайд, то тема уже будет освещена полностью
Да, есть над чем подумать. Для заголовочных файлов можно добавить место поиска с помощью опции -I. Makefile очень часто бывает результатом работы скрипта "configure" в случае Linux. Поэтому имеет смысл этот скрипт разобрать. Ещё подкинули вопрос насчет изменения содержимого .h файлов - мол, нужно добавить зависимость. Тут гайд скорее ситуационный: мне нужно было решить конкретную задачу - вот решил до определенной степени и поделился)
Возможно. Но gcc компонует исполняемый файл из набора модулей (.o), поэтому они присутствуют в зависимостях. Получение файлов (.o) - это тоже набор целей Makefile-а, для достижения которых нужны соответствующие исходники (.c). А вот какие заголовочные файлы использовать для компиляции исходников, указано в самих исходниках
@@daniilgavr5811и не должно перекомпилироваться, т.к. вы не изменили реализации функций, т.е. осталось всё по-прежнему. А вот если изменить, например, сигнатуру какой-нибудь ф-ии в .h - это повлечёт изменение и в .c, тогда потребуется перекомпиляция.
Зачем городить огород с мейкфайлом, если можно зависимости прописать в include в исходниах => тогда чтобы собрать проект, нужно скомпилировать 1 файл c main(), а все остальные подтянутся автоматически?
@@vitlevanskiy зависит от IDE. Visual studio сама умеет находить .c файлы по имени h файла в правильной папке и повторно не компилирует если нет изменений.
@@tripledistillation1755 , прошу прощения. Например для создания библиотеки, мы используем .h, и если изменить этот хедер файл, то нужно будет пересобирать все .c файлы, зависимые от него. Спасибо за видео!
Если вместо " $(PREF_OBJ)%.o: $(PREF_SRC)%.c " использовать " $(OBJ): $(SRC) ", то Make может неправильно сопоставить имена исходников и объектных файлов. Таким образом, при компиляции main.c объектный код может быть отправлен в my_lib.obj, например.
@@tripledistillation1755 я попытался подставить готовые списки. Мэйк безошибочно перебирает список зависимостей по порядку, но почему-то подставляет в каждой команде только первое значение из списка целей (адресовал через $^). При подстановке корня то же правило работает чётко. Видимо, только так.
@@MECHANISMUS у меня тоже самое, только верно перебирает список целей и в каждой команде подставляет первый аргумент из зависимостей. Как решить понятия не имею. Метод из видео выдает ошибку, что нет правила для сборки объектников, хотя указано все точно так же.
Makefile в целом достаточно бесполезен. Всё равно многие тулзы не создают файлов для зависимостей, поэтому можно просто sh-скрипт писать, и компилировать просто всё заново. Для малых проектов в винде это windres, крупные проекты так вообще свои тулзы имеют, как тот же firefox.
В том, что в make есть механизм " : " А это удобно в случае сборки проекта. Можно относительно просто выстроить дерево зависимостей. Такая задача наверняка решаема в bash, но, может быть, с большими усилиями. Но это то, как я себе представляю ситуацию. А вообще, make - это утилита, то есть средство, а не цель. Средства могут быть разными, зацикливаться на них не следует
Если есть желание поддержать канал: yoomoney.ru/fundraise/16KBTQF4G72.241120
Блин, наконец-то! Знаешь, сколько я перелопатил, чтобы узнать, как грамотно по разным директориям разносить файлы? На удивление только у тебя нашёл толковое объяснение. Все статьи пишут одно и то же, но как будто бы в отрыве от реальности и только для учебных проектов. Спасибо огромное и +100500 в карму! =)
Приятная подача материала с хорошей методической проработкой. Молодец!
Thanks a lot bro... U searched many things but only ur content was in high quality . Lucky me that I know Russian)))
Отличная подача материала. Спасибо !
Здравствуйте, огромный вам спасибо за ценный урок!
Пожалуйста
Спасибо добрый человек!
Господи, почему же я не нашёл это видео раньше, автору гигантское спасибо!!!
Как же круто ты всё разложил по полочкам!!!! Спасибо!!
Голос офигенный, тебе бы озвучивать какие нить жизненные происходящие событие в мире)))))))
спасибо большое, спустя столько попыток разобраться, мне наконец-то стало понятно
Смотрю пока только первые 5 минут и уже хочу сказать респект автору без воды и всякой чуши, пока все по делу, и что самое главное понятно и доступно 👍
Спасибо за единственный нормальный туториал на ютюбе
Всё доходчиво чтобы понимали такие как я =) Отлично. Спасибо.
Большое спасибо за видео. Весьма полезно и интересно!
Божественный контент!
Лучшее видео, благодарю
Офигенно и понятно,спасибо, человече
Отличный туториал. Спасибо!!!
Спасибо! Очень хорошее объяснение!
очень классно и доходчиво, спасибо ))
Спасибо большое приятель.
отличное видео большое спасибо
Nicely done!
Спасибо, супер объяснение
Круто!
Спасибо большое дружище !
Круто! Спасибо, очень помогли! Кстати голос похож на shimoroshow
а я все думаю, что слишком знакомый голос)
Отличное видео!
Вапщее агонь! :)
Огромное спасибо то что нужно было!)
Cпасибо!
крутяк чел!
супер, спасибо большое, а планируется ли видео про cmake или юнит тесты?
Этого в планах нет. Была задача сформировать такой makefile, чтобы потом про него забыть и никогда не вспоминать, но чтобы при копировании в папку с новым проектом все .c файлы компилировались и собирались в исполняемый файл.
Может эта тема и заинетесует, но многообразие утилит для сборки и тестирования пока что только огорчает, так как попытки собрать проект из исходников напоминют ситуацию, когда ты заказал табурет, и мастер уже забивает последний гвоздь и вдруг говорит: "для двух последних ударов нужен молоток Х". Отвечаешь: "у меня такого нет, но есть Y и он вполне способен решить эту задачу". А мастер в ответ выдергивает гвоздь, разламывает всю табуретку и уходит. Стоит тебе через время найти этот X, как мастер заявлает, что тот уже старый и нужен "X 5.0", и вообще, половина досок уже "deprecated"
Спасибо
А если у меня в src лежат несколько папок, и все файлы в этих папках надо скомпилировать, но так-же есть и файлы которые не в папках, как можно это сделать?
TARGET = MyProject
CC = gcc
PREF_SRC = ./src/
PREF_OBJ = ./obj/
SRC = $(shell find . -name "*.c")
OBJ = $(patsubst $(PREF_SRC)%.c, $(PREF_OBJ)%.o, $(SRC))
$(TARGET) : $(OBJ)
$(CC) $(OBJ) -o $(TARGET)
$(PREF_OBJ)%.o : $(PREF_SRC)%.c
mkdir -p $(dir $@)
$(CC) -c $< -o $@
clean :
rm $(TARGET) $(OBJ)
Разница в том, что в переменой SRC список всех файлов, оканчивающихся на ".c", в том числе и в подкатологах внутри src. Команда shell позволяет выполнить команду оболочки и получить результат в виде строки. Далее заменяем префикс "./src/" на "./obj/", а так же расширение ".c" на ".o" с помощью команды patsubst во всех найденных именах файлов исходников. Таким образом, структура папок внутри "./obj/" предполагается такой же, как и в "./src/", но компилятор не будет создавать недостающие папки автоматически по относительному пути файла в "./obj/". Чтобы решить эту проблему, в правило компиляции отдельного исходника добавлена команда mkdir -p $(dir $@). Здесь $@ - это имя файла-цели, то есть файла ".o". dir позволяет выделить из этого имени имя католога, а ключ -p блокирует ошибку, если католог уже существует.
Ещё раз спасибо! А как решать проблему отслеживания изменений заголовочных файлов? И ещё вопрос: ведь в каталоге src исходник могут быть размещены по подкаталогам произвольной структуры. Как этот момент учесть?
Пожалуйста. Про заголовочные файлы - приведите пример. А про подкаталоги уже был вопрос ранее, я на него ответил. Там есть пример
@@tripledistillation1755 например, в Вашем примере не указаны зависимости от my_lib.h
Для компилятора обычно указывают место хранения дополнительных заголовочных файлов. Делается это опцией -I
Но здесь это не требуется, поскольку заголовочный там же, где исходник. Поэтому, к стати, заголовочный указан не в угловых скобках, а в ковычках
Не понимаю в чём глобальная разница от bash скриптов
Хороший гайд. Но не все вопросы решены. Что делать, если в проекте есть код на нескольких языках? А ещё проект состоит из десятка других проектов, и вообще не ясно, что где лежит. У кого-то cmake прикручен, у кого-то makefile, а некоторые вообще sln. И ещё некоторые любят писать #include , а кто-то просто пишет #include , кто-то #include "C:\васян\sdl. h" , и плевать они хотели на то, что это один файл. Кому-то так удобнее, кому-то так. А тебе все это читать и переписывать не надо, тебе бы только скомпилировать. Под виндой кто-то уже для всего этого цирка сделал sln, и это работает. А makefile нет. Конкретно в моём случае это ещё и статическая библиотека name.lib, которую надо бы пересобрать для линукса в name.a. Если будет настолько обширный гайд, то тема уже будет освещена полностью
Да, есть над чем подумать. Для заголовочных файлов можно добавить место поиска с помощью опции -I. Makefile очень часто бывает результатом работы скрипта "configure" в случае Linux. Поэтому имеет смысл этот скрипт разобрать. Ещё подкинули вопрос насчет изменения содержимого .h файлов - мол, нужно добавить зависимость. Тут гайд скорее ситуационный: мне нужно было решить конкретную задачу - вот решил до определенной степени и поделился)
Кажется, стоило бы .h тоже добавить в зависимости
Возможно. Но gcc компонует исполняемый файл из набора модулей (.o), поэтому они присутствуют в зависимостях. Получение файлов (.o) - это тоже набор целей Makefile-а, для достижения которых нужны соответствующие исходники (.c). А вот какие заголовочные файлы использовать для компиляции исходников, указано в самих исходниках
@@tripledistillation1755 Да, но вот если в проекте поменять .h, но не менять ничего другого - модули не перекомпилируются
@@daniilgavr5811и не должно перекомпилироваться, т.к. вы не изменили реализации функций, т.е. осталось всё по-прежнему. А вот если изменить, например, сигнатуру какой-нибудь ф-ии в .h - это повлечёт изменение и в .c, тогда потребуется перекомпиляция.
Браво
САЛАМАЛЕЙКУМ МИФИСТЫ
Кажется, что после распределения файлов (.с и .о) по папкам необходимо слегка модифицировать clean цель.
Предлагайте свой вариант, будет интересно
Оказывается Make не такой сложный, хотя это всё можно и в простом скрипте описать )
Зачем городить огород с мейкфайлом, если можно зависимости прописать в include в исходниах => тогда чтобы собрать проект, нужно скомпилировать 1 файл c main(), а все остальные подтянутся автоматически?
Тогда огородом будет main(), из за каждого там изменения все инклюды компилируй по 100 раз. Может откомпилировать их и больше не трогать никогда?
@@vitlevanskiy зависит от IDE. Visual studio сама умеет находить .c файлы по имени h файла в правильной папке и повторно не компилирует если нет изменений.
Можно ли с вами связаться? Мне нужно кое что спросить.
Можно. Если вопрос касается материала или чего-то смежного, то задавайте его здесь
спасибо ничего не работает
@You Tube если не получается забить гвоздь молотком, это еще не значит, что молоток плохой)))
А если используется header файл?
Приведите конкретный пример
@@tripledistillation1755 , прошу прощения. Например для создания библиотеки, мы используем .h, и если изменить этот хедер файл, то нужно будет пересобирать все .c файлы, зависимые от него. Спасибо за видео!
Верно. Спасибо за комментарий
А если у меня один cpp и один h файл?
Можно поместить их в "src", а в Makefile-е заменить все вхождения ".c" на ".cpp"
делайте, пожалуйста, крупнее: на телефоне не разглядеть
Тут видео в принципе не рассчитано на такой способ просмотра, но подумаю
Вы из стс? На голос из галилео похож
Если бы)
ох уж эти гайды, когда все лежит в одной папке
$(PREF_OBJ)%.c: $(PREF_SRC)%.o тут уже лишнее. Переменные SRC и OBJ уже содержат префы. То есть $(OBJ): $(SRC). Для этого ж они и создавались.
Если вместо " $(PREF_OBJ)%.o: $(PREF_SRC)%.c " использовать " $(OBJ): $(SRC) ", то Make может неправильно сопоставить имена исходников и объектных файлов. Таким образом, при компиляции main.c объектный код может быть отправлен в my_lib.obj, например.
@@tripledistillation1755 я попытался подставить готовые списки. Мэйк безошибочно перебирает список зависимостей по порядку, но почему-то подставляет в каждой команде только первое значение из списка целей (адресовал через $^). При подстановке корня то же правило работает чётко. Видимо, только так.
@@MECHANISMUS да, я столкнулся с такой же проблемой, пытаясь проверить предложенный Вами вариант. Спасибо за обратную связь и рассмотренный случай
@@MECHANISMUS у меня тоже самое, только верно перебирает список целей и в каждой команде подставляет первый аргумент из зависимостей. Как решить понятия не имею. Метод из видео выдает ошибку, что нет правила для сборки объектников, хотя указано все точно так же.
ЛИЧНО РУКУ ПОЖАЛ БЫ!!!!!!!!!!!!!!!!!
Makefile в целом достаточно бесполезен. Всё равно многие тулзы не создают файлов для зависимостей, поэтому можно просто sh-скрипт писать, и компилировать просто всё заново. Для малых проектов в винде это windres, крупные проекты так вообще свои тулзы имеют, как тот же firefox.
А разработчики make-а в курсе?)
А почему бы не написать баш скрипт? В чем разница? Зачем мне именно make?
В том, что в make есть механизм
" :
"
А это удобно в случае сборки проекта. Можно относительно просто выстроить дерево зависимостей. Такая задача наверняка решаема в bash, но, может быть, с большими усилиями. Но это то, как я себе представляю ситуацию. А вообще, make - это утилита, то есть средство, а не цель. Средства могут быть разными, зацикливаться на них не следует
@@tripledistillation1755 да, досмотрел видос до конца, немного поюзал, удобнее, чем могло бы быть с башем)
Круто! Спасибо!