Запуск сценариев компиляции только в том случае, если исходный файл более поздний, чем скомпилированная программа

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

То, что я пытаюсь сделать, это создать сценарий bash, который будет запускать другой скрипт bash для компиляции некоторых программ только в том случае, если источник был изменен. То, что я до сих пор, это способ получить временные метки для каждого файла за считанные секунды с эпохи J2000:

#get a list of the source timestamps sourceTimes=$(stat -f "%Sm" -t "%s" *.f) #get a list of the program timestamps exeTimes=$(stat -f "%Sm" -t "%s") 

и скрипт установки

 ./make_common_lib.bsh build ./make_common_lib.bsh install 

Я хочу выяснить, как создать состояние if таким образом, чтобы (в полу-псевдокоде)

 if [any of $sourceTimes>$exeTimes]; then #run make_common_lib.bsh script else #Do nothing fi 

До сих пор я догадываюсь как-то использовать read но я не уверен, как я мог одновременно индексировать обе переменные.

Если есть очень простой способ сделать это, я приношу свои извинения за то, что я очень новичок в разработке сценариев bash, но до сих пор ни один из моих поисковых запросов Google действительно не возвращал ничего полезного.

Дополнительная информация:

Переменные временной метки находятся в формате, таком как

 1432326068 1432326069 1432326069 1432326069 1432326069 1432326069 1432326069 1432326069 1432326069 1432326069 1432326069 1432326069 1432326068 1432326069 1432326069 

Метод сборки скрипта

Если вы хотите сохранить «метод сборки bash», то вам, вероятно, лучше всего «прикоснуться» к файлу ( touch lastbuild ), когда скрипт сборки будет запущен и завершит сборку. Кроме того, скрипт сборки мог бы искать файл, сгенерированный прикосновением (если он не существует, предполагается, что требуется сборка), или если он существует, используйте find чтобы узнать, существуют ли более новые файлы:

 find . -name "*.[ch]" -newer lastbuild 

а затем постройте, если этот вывод – 1 или более строк (может быть проверен с помощью чего-то вроде wc -l ).

Использование Make вместо

Это лучше всего управляется чем-то вроде Makefile (специально используется для проверки такого рода зависимостей).

 default: all all: dependency1.o dependency2.o dependency1.o: dependency1.c ./make_common_lib.bsh build dependency2.o: dependency2.c ./make_common_lib.bsh build install: ./make_common_lib.bsh install 

Создание фиктивного скрипта «build»:

 $ cat make_common_lib.bsh #! /bin/sh echo "Build $1" 

Теперь мы можем запустить make:

 $ make ./make_common_lib.bsh build Build build ./make_common_lib.bsh build Build build 

Вы также можете заменить ./make_common_lib.bsh build командой, которую ./make_common_lib.bsh build создаст для сборки dependency1.o т. Д .:

 dependency1.o: dependency1.c gcc -c dependency1.c 

Makefiles также допускают замену символов, поэтому вы можете объявить флаги компилятора и компилятора ранее в Makefile:

 CC=/usr/bin/gcc CFLAGS=-O2 -Wall 

а затем сделайте ссылки на них в своих правилах:

 dependency1.o: dependency1.c $(CC) $(CFLAGS) -c dependency1.c 

Обратите внимание, что строка с отступом после объявления зависимости должна начинаться с вкладок, а не пробелов.

Сокращение списка правил зависимостей

ОП спросил, возможно ли более короткие способы объявления всех зависимостей. Это возможно с помощью нескольких трюков с использованием GNU make (обратите внимание, что не все это будет работать с ванильным маркером).

Вы можете сделать замену переменных. Учитывая заявление:

 SRCS=dependency1.c dependency2.c dependency3.c 

Затем вы можете создать правило объектов с помощью замены переменных:

 OBJS=$(SRCS:.c=.o) 

это заменит все .c на .o . Фактически, давая строку вида:

 OBJS=dependency1.o dependency2.o dependency3.o 

Затем вы можете дополнительно сократить «команду компиляции» с помощью специальных переменных $< и $@ :

 .co: $(CC) $(CFLAGS) -c $< -o $@ 

$< представляет собой предварительное условие в GNU make parlance (или зависимости, как я его называл) и $@ target, и поэтому он будет выдавать:

 /usr/bin/gcc -Wall -O2 -c dependency1.c -o dependency1.o /usr/bin/gcc -Wall -O2 -c dependency2.c -o dependency2.o . . . 

Объединяя все это вместе со ссылками и командой для связывания и компиляции исполняемого файла $(TARGET) :

 # Globals CC=/usr/bin/gcc CFLAGS=-Wall -O2 LDFLAGS=-L/usr/local/lib LIBS=-ldependencylib # declare all the sources SRCS=dependency1.c dependency2.c # declare the objects files using variable substitution (find .c and replace with .o) OBJS=$(SRCS:.c=.o) # Target executable name: TARGET=myexefile default: all all: $(TARGET) @echo Target has been built $(TARGET): $(OBJS) $(CC) $(CFLAGS) -o $(TARGET) $(OBJS) $(LDFLAGS) $(LIBS) .co: $(CC) $(CFLAGS) -c $< -o $@ install: ./make_common_lib.bsh install 

Обратите внимание, что с GNU make можно многое сделать, и это хорошо описано в GNU Make Manual .