Execução de scripts de compilação somente se o arquivo de origem for mais recente que o programa compilado

3

Não tenho certeza se esta pergunta pertence aqui ou a algum outro site, mas imaginei que iria começar por aqui e algum moderador útil me chutaria se houvesse um local melhor.

O que eu estou tentando fazer é criar um script bash que irá executar outro script bash para compilar alguns programas apenas se a fonte tiver mudado. O que eu tenho até agora é uma maneira de obter os timestamps para cada arquivo em segundos desde a época 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")

e um script de instalação

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

Eu quero descobrir como criar um estado if tal que (em semi-pseudocódigo)

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

Meu melhor palpite até agora é usar read , mas não sei como eu poderia indexar as duas variáveis ao mesmo tempo.

Se houver uma maneira realmente fácil de fazer isso, peço desculpas por ser muito novo no bash scripting, mas até o momento nenhuma das minhas pesquisas do Google realmente retornou algo útil.

Mais algumas informações:

As variáveis de registro de data e hora estão em um formato como

1432326068 1432326069 1432326069 1432326069 1432326069 1432326069 1432326069 1432326069 1432326069 1432326069 1432326069 1432326069 1432326068 1432326069 1432326069
    
por Andrew 04.08.2015 / 17:45

1 resposta

3

Seu método de criação de scripts

Se você quiser manter o "método de compilação bash", provavelmente será melhor "tocar" em um arquivo ( touch lastbuild ) quando o script de compilação for executado e concluir a compilação. Além disso, o script de construção poderia procurar pelo arquivo gerado pelo touch (se ele não existir, suponha que uma compilação é necessária) ou, se existir, use find para ver se existem arquivos mais recentes:

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

e, em seguida, construa se essa saída for 1 ou mais linhas (pode ser verificada com algo como wc -l ).

Usando o Make

Isso é melhor gerenciado por algo como um Makefile (usado especificamente para esse tipo de verificação de dependência).

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

Criando um script "build" fictício:

$ cat make_common_lib.bsh 
#! /bin/sh

echo "Build $1"

Agora podemos executar o make:

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

Você também pode substituir o ./make_common_lib.bsh build pelo comando que o ./make_common_lib.bsh build emitirá para criar dependency1.o etc:

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

Makefiles também permitem a substituição de símbolos, então você pode declarar o complier e o compilador sinalizar antes no Makefile:

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

e, em seguida, faça referências a eles em suas regras:

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

Observe que a linha que é recuada após uma declaração de dependência deve começar com uma tabulação e não com espaços.

Encurtando a lista de regras de dependência

O OP perguntou se é possível fazer maneiras mais curtas de declarar todas as dependências. É possível com alguns truques usando o make do GNU (note que nem todos eles funcionarão com o make vanilla).

Você pode fazer uma substituição variável. Dada a declaração:

SRCS=dependency1.c dependency2.c dependency3.c

Você pode então criar uma regra de objetos usando a substituição de variáveis:

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

isso substituirá todos os .c com .o . Com efeito, dando uma linha do formulário:

OBJS=dependency1.o dependency2.o dependency3.o

Você pode, além disso, reduzir o "comando de compilação" usando as variáveis especiais $< e $@ :

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

$< representa o pré-requisito no GNU make language (ou dependência como eu o chamei) e $@ o destino, e assim ele acabará lançando:

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

Colocando tudo isso junto, com opções de vinculação e um comando para vincular e compilar o executável $(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

Note que há muitas coisas que você pode fazer com o GNU make, e está bem documentado aqui GNU Make Manual .

    
por 04.08.2015 / 18:18