como um makefile pode detectar se um comando está disponível na máquina local?

11

Comecei a usar o modo organizacional para planejar minhas tarefas no sistema no estilo GTD . Colocando todos os arquivos org no diretório de uma pasta do Dropbox , eu executo o emacs para editar / gerenciar esses arquivos de três máquinas locais diferentes: Cygwin, Mac OS X e Debian. Como também uso o MobileOrg para acessar esses arquivos organizacionais no meu iPad, um checksums.datarquivo deve ser mantido atualizado quando forem feitas alterações. Isso pode ser feito executando md5sum *.org > checksums.dat.

O problema é que existem três comandos diferentes para o md5sumcomando: md5sum.exeno Cygwin, md5no Mac OS X e md5sumno Debian. A situação mais ideal é um makefile, armazenado em uma instalação do Dropbox, detecta qual comando está disponível na máquina atual e executa esse comando para executar a operação de soma de verificação md5.

Federico Magallanez
fonte
gnuautotools
Kevin
1
@ Kevin Isso parece um exagero. Não quero instalar um programa em três sistemas distintos. Em cada sistema, uma pasta Dropbox está acessível como um diretório local. Quando corro make checksumpara gerar dados de soma de verificação em uma pasta Dropbox, desejo que o makefile use um comando apropriado após detectar qual comando de soma de verificação está disponível na máquina atual.
Federico Magallanez
Se você pretende criar uma quantidade significativa de scripts e o projeto é pequeno, sugiro scons.
Faheem Mitha

Respostas:

7

Comandos possíveis para gerar uma soma de verificação

Infelizmente, não há utilitário padrão para gerar uma soma de verificação criptográfica. Há um utilitário padrão para gerar um CRC: cksum; isso pode ser suficiente para o seu objetivo de detectar alterações em um ambiente não hostil.

Eu recomendaria o uso do SHA1 em vez do MD5. Não há muitos sistemas que possuem um utilitário MD5, mas não o SHA1, e se você usar somas de verificação criptográficas, use um algoritmo sem método conhecido para encontrar colisões (assumindo que você também verifique o tamanho).

Uma ferramenta que não é padrão, mas comum e pode calcular resumos é o OpenSSL . Está disponível para Cygwin, Debian e OSX, mas infelizmente não faz parte da instalação padrão no OSX.

openssl dgst -sha1

No OSX 10.6, existe um shasumutilitário, que também está presente no Debian (faz parte do perlpacote) e acredito no Cygwin também. Este é um script Perl. A maioria dos sistemas unix possui o Perl instalado, então você pode agrupar esse script junto com o makefile se estiver preocupado com esse script não estar disponível em todos os lugares.

Selecionando o comando certo para o seu sistema

Ok, digamos que você realmente não consiga encontrar um comando que funcione em qualquer lugar.

Na concha

Use o typebuilt-in para ver se um comando está disponível.

sum=
for x in sha1sum sha1 shasum 'openssl dgst -sha1'; do
  if type "${x%% *}" >/dev/null 2>/dev/null; then sum=$x; break; fi
done
if [ -z "$sum" ]; then echo 1>&2 "Unable to find a SHA1 utility"; exit 2; fi
$sum *.org

GNU make

Você pode usar a shellfunção para executar um snippet de shell quando o makefile for carregado e armazenar a saída em uma variável.

sum := $(shell { command -v sha1sum || command -v sha1 || command -v shasum; } 2>/dev/null)
%.sum: %
        $(sum) $< >$@

Portátil (POSIX) marca

Você só pode executar comandos shell na regra, portanto, cada regra que calcula uma soma de verificação deve conter o código de pesquisa. Você pode colocar o trecho em uma variável. Lembre-se de que linhas separadas nas regras são avaliadas independentemente. Lembre-se também de que os $sinais que devem ser passados ​​para o shell precisam ser escapados $$.

determine_sum = \
        sum=; \
        for x in sha1sum sha1 shasum 'openssl dgst -sha1'; do \
          if type "$${x%% *}" >/dev/null 2>/dev/null; then sum=$$x; break; fi; \
        done; \
        if [ -z "$$sum" ]; then echo 1>&2 "Unable to find a SHA1 utility"; exit 2; fi

checksums.dat: FORCE
    $(determine_sum); \
    $$sum *.org
Gilles 'SO- parar de ser mau'
fonte
Eu tive que usar a -Popção do typecomando para obter o método "GNU make" descrito acima para funcionar corretamente, então eu acabei com sum := $(shell { type -P sha1sum || type -P sha1 || type -P shasum; } 2>/dev/null).
27515 Sean
@ Sean Obrigado pelo relatório de erros. type -Psó funciona se o seu shell for bash, não se for, por exemplo, ksh ou dash (que é o caso do Ubuntu entre outros). Você pode usar command -vpara portabilidade.
Gilles 'SO- stop be evil'
Parece que você mudou de usar typepara usar command. Os outros métodos também devem ser atualizados?
27715 Sean
@Sean Os outros métodos são bons: typeé uma maneira correta e portátil de testar a presença de um comando, o problema é que ele produz uma saída semelhante sha1sum is /usr/bin/sha1sumao nome do programa. Este foi o único local em que usei a saída typee não apenas o valor de retorno.
Gilles 'SO- stop be evil'
5

É uma espécie de hack, mas você pode testar se cada um existe e executá-los se existirem:

[ -x "`which md5 2>/dev/null`" ] && md5 newfile >>sums
[ -x "`which md5sum 2>/dev/null`" ] && md5sum newfile >>sums

Estou certo de que o cygwin reconhece comandos (incluindo md5sum) sem o .exe, mas inclua-o se for necessário.

Kevin
fonte
4
whichos valores de saída não são portáteis. Use em typevez disso (e você provavelmente deseja usar if; then; elifpara evitar problemas, pois existem vários executáveis). whiche typeprocure apenas executáveis ​​de qualquer maneira, para que seu teste com -x seja inútil.
Chris Down
mais sobre o uso de "type": cmd = $ (para cmd na barra foo md5 md5sum; digite $ cmd> / dev / null 2> & 1 && echo $ cmd && break; done); $ cmd arquivo1 arquivo2 arquivo3> md5.txt
michael
1

As ferramentas automáticas GNU (como mencionadas em um comentário) ou também o CMake são uma opção.

As ferramentas automáticas do GNU são a abordagem mais tradicional, mas (e talvez falando apenas por mim) não acho que as pessoas estejam realmente empolgadas com a perspectiva de configurar inicialmente um projeto usando-as. Bem, é uma curva de aprendizado, em qualquer caso. O CMake é o garoto mais novo do setor, e talvez menos comum (e ainda tenha uma curva de aprendizado). Ele tem sua própria sintaxe e gera makefiles para sua plataforma. O CMake possui a vantagem distinta de não ser tão un * x-centric; funciona de maneira confiável no unix, windows e mac (por exemplo, pode gerar projetos msvc, por exemplo, em vez de makefiles.)

Edit: e, claro, desde que 'makefiles' foram sugeridos, esta resposta vai junto com essa presunção. Mas talvez apenas um script python ou (gasp) um programa Java simples seja mais apropriado para esta tarefa; a linguagem de script / programação faria o mesmo entre plataformas.

Michael
fonte