как внедрить csplit в make-файл?

Как реализовать конкретно A и B в следующем make-файле. : Программисты этого проекта решили упаковать часть своего кода в «модуль» с именем chomp.adt, из которого могут быть созданы соответствующие файлы cookie.h и cookie.cpp. Шаги, необходимые для создания этой программы:

А. Запустите команду

    csplit chomp.adt "/Split Here/"

и скопируйте полученный файл xx00 в cookie.h.

Б. Запустите команду

csplit chomp.adt "/Split Here/"

и скопируйте полученный файл xx01 в cookie.cpp.

C. Скомпилируйте cookie.cpp для создания cookie.o.

D. Скомпилируйте mainProg.cpp для создания mainProg.o.

E. Свяжите файлы .o, чтобы создать исполняемую программу с именем playChomp.

Как я могу написать make-файл, который будет выполнять ВСЕ эти шаги? Я понимаю, как реализовать C-E, я думаю, это в основном A и B, где я не понимаю, как сделать из этого правило. Когда я попытался, я написал A и B как-

cookie.h: csplit chomp.adt
         cp xx00 cookie.h
cookie.cpp: csplit chomp.adt
         cp xx01 cookie.cpp

Я получил сообщение об ошибке: «Нет правила для создания целевого csplit, необходимого для cookie.cpp».


person cpc20306    schedule 09.05.2020    source источник
comment
Я улучшил расположение фрагментов кода, но не уверен, что правила cookie.h и cookie.cpp расположены так же, как вы. Как показано, они выдают сообщение об ошибке, которое вы показываете. Пожалуйста, проверьте. Обратите внимание, что обычно вы не зависите от команды, и вам нужно выполнить команду (включая контекст, в котором она должна быть разделена).   -  person Jonathan Leffler    schedule 09.05.2020
comment
Кроме того, если вы используете числа (вместо букв) для идентификации элементов в списке, вы можете получить элементы с красивым отступом. Однако вместо отступа кода всего на 4 пробела вам нужно использовать 8 пробелов внутри списка.   -  person Jonathan Leffler    schedule 09.05.2020


Ответы (1)


Простое правило makefile имеет следующий синтаксис:

<target> : <prerequisites>
        <recipe>

где цель — это создаваемый выходной файл, предпосылки — это входные файлы, используемые для построения цели, а рецепт — это процесс, с помощью которого входные файлы превращаются в выходные файлы.

Команда csplit ... является частью рецепта. Его не следует указывать в качестве обязательного условия.

Таким образом, ваше правило должно выглядеть примерно так:

cookie.h: chomp.adt
        csplit $< "/Split Here/"
        cp xx00 $@

cookie.cpp: chomp.adt
        csplit $< "/Split Here/"
        cp xx01 $@

Вы можете прочитать о $< и $@ здесь: https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html Их использование не обязательно.

Однако приведенные выше правила не идеальны, потому что вы запускаете команду csplit дважды, когда вам это не нужно. И если вы попытаетесь запустить make с включенной параллельной сборкой (make -jN), это может привести к ошибке, потому что оба будут запущены одновременно и перезапишут выходные файлы.

То, как вы можете добиться большего успеха, зависит от того, какая у вас версия GNU. Если у вас есть GNU make 4.3, вы можете использовать:

cookie.h cookie.cpp &: chomp.adt
        csplit $< "/Split Here/"
        cp xx00 cookie.h
        cp xx01 cookie.cpp

Это сгруппированная цель, о которой вы можете прочитать здесь: https://www.gnu.org/software/make/manual/html_node/Multiple-Targets.html#index-grouped-targets

Если у вас более старая версия, вы можете подшутить над тем, что цели и предварительные условия начинаются с одного и того же префикса (буква c); это будет выглядеть так:

%ookie.h %ookie.cpp : %homp.adt
        csplit $< "/Split Here/"
        cp xx00 cookie.h
        cp xx01 cookie.cpp

Это правило шаблона, о котором вы можете прочитать здесь: https://www.gnu.org/software/make/manual/html_node/Pattern-Intro.html

person MadScientist    schedule 09.05.2020
comment
Вы также можете использовать: cookie.h cookie.cpp: chomp.adt с рецептом, который вы даете. Поскольку целевые объекты оцениваются по одному в непараллельной сборке, при сборке cookie.h также строится cookie.cpp, и не нужно будет делать это снова. Параллельное строительство сталкивается с проблемами, как вы сказали. Показанное правило не зависит от того совпадения, что все имена файлов начинаются с буквы c — оно будет работать, например, с cookie.h, biscuit.cpp и datafile.adt. - person Jonathan Leffler; 09.05.2020
comment
Да, но это сломается с параллельными сборками. Поэтому я не считаю это большим улучшением по сравнению с первым примером. Избежать дополнительного csplit — это что-то, но я сомневаюсь, что время, которое это занимает, измеримо. - person MadScientist; 09.05.2020
comment
Я не делаю так много параллельных сборок, поэтому для меня это не имеет большого значения, но я заметил, что у него есть проблема с параллельными сборками. OTOH, он работает со старыми версиями make, GNU и не-GNU. Если бы не нотация без комментариев, используемая для маркера разделения, в разделении не было бы необходимости, если только mainProg.cpp не включает cookie.h. Конечно, есть умеренная вероятность того, что код в mainProg.cpp действительно включает cookie.h, но это не указано. Было бы лучше, чтобы все, что генерирует chomp.adt, также генерировало отдельные файлы cookie.h и cookie.cpp. - person Jonathan Leffler; 09.05.2020
comment
Информация о «групповых целях» интересна — спасибо за это. - person Jonathan Leffler; 09.05.2020