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

3

Я пытаюсь сделать, это создать скрипт 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
Андрей
источник
3
Почему бы не использовать make? Он явно разработан для удовлетворения этого требования.
Стивен Китт
Я понимаю это, но на самом деле я работаю с чужой программой и по какой-то причине они не использовали make. Проблема с make (я думаю) заключается в том, что мне нужно было бы записать каждую зависимость, и в одних общих библиотеках их более 100 (и есть целая другая группа файлов, для которых мне нужно было бы сделать то же самое).
Андрей
Вот для чего нужны шаблоны.
багамат
@Andrew То, что обычно делают люди, - это автоматически генерирует список зависимостей (обычно вы запускаете make dependили make depрегенерируете список).
Жиль

Ответы:

3

Ваш метод сценария сборки

Если вы хотите придерживаться "метода сборки 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

Создание фиктивного сценария сборки

$ 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которая выдаст команду build dependency1.o:

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

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

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

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

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

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

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

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

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

SRCS=dependency1.c dependency2.c dependency3.c

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

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

это заменит все .cс .o's. По сути, дает строку вида:

OBJS=dependency1.o dependency2.o dependency3.o

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

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

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

/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)

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

install:
    ./make_common_lib.bsh install

Обратите внимание, что есть много вещей, которые вы можете сделать с GNU make, и это хорошо задокументировано здесь GNU Make Manual .

Драв Слоан
источник
Спасибо за ответ. Я бы хотел, чтобы люди, которые изначально разрабатывали это программное обеспечение, сделали верный файл make, но они этого не сделали. У меня один вопрос: можно ли как-нибудь это сделать, не выписывая каждую зависимость? Существует более 100 отдельных файлов, которые необходимо проверить, и я не хочу выписывать зависимости для каждого из них.
Андрей
Я обновил ответ, чтобы использовать некоторые ярлыки GNU make для обработки нескольких зависимостей.
Драв Слоан