tutorial make create makefile gnu-make

create - makefile linux c



Comodines recursivos en GNU? (6)

Aquí hay un script de Python que pirateé rápidamente para resolver el problema original: mantener una copia comprimida de una biblioteca de música. La secuencia de comandos convertirá archivos .m4a (se supone que son ALAC) a formato AAC, a menos que el archivo AAC ya exista y sea más reciente que el archivo ALAC. Los archivos MP3 en la biblioteca estarán vinculados, ya que están comprimidos.

Solo tenga en cuenta que abortar el script ( ctrl-c ) dejará atrás un archivo a medio convertir.

Originalmente también quería escribir un Makefile para manejar esto, pero como no puede manejar espacios en nombres de archivos (ver la respuesta aceptada) y porque escribir un script bash me garantiza un mundo de dolor, Python sí lo es. Es bastante sencillo y breve, y por lo tanto debe ser fácil de ajustar a sus necesidades.

from __future__ import print_function import glob import os import subprocess UNCOMPRESSED_DIR = ''Music'' COMPRESSED = ''compressed_'' UNCOMPRESSED_EXTS = (''m4a'', ) # files to convert to lossy format LINK_EXTS = (''mp3'', ) # files to link instead of convert for root, dirs, files in os.walk(UNCOMPRESSED_DIR): out_root = COMPRESSED + root if not os.path.exists(out_root): os.mkdir(out_root) for file in files: file_path = os.path.join(root, file) file_root, ext = os.path.splitext(file_path) if ext[1:] in LINK_EXTS: if not os.path.exists(COMPRESSED + file_path): print(''Linking {}''.format(file_path)) link_source = os.path.relpath(file_path, out_root) os.symlink(link_source, COMPRESSED + file_path) continue if ext[1:] not in UNCOMPRESSED_EXTS: print(''Skipping {}''.format(file_path)) continue out_file_path = COMPRESSED + file_path if (os.path.exists(out_file_path) and os.path.getctime(out_file_path) > os.path.getctime(file_path)): print(''Up to date: {}''.format(file_path)) continue print(''Converting {}''.format(file_path)) subprocess.call([''ffmpeg'', ''-y'', ''-i'', file_path, ''-c:a'', ''libfdk_aac'', ''-vbr'', ''4'', out_file_path])

Por supuesto, esto se puede mejorar para realizar la codificación en paralelo. Eso se deja como un ejercicio para el lector ;-)

Ha pasado un tiempo desde que utilicé make , así que tengan paciencia conmigo ...

Tengo un directorio, flac , que contiene archivos .FLAC. Tengo un directorio correspondiente, mp3 contiene archivos MP3. Si un archivo FLAC es más nuevo que el archivo MP3 correspondiente (o el archivo MP3 correspondiente no existe), entonces quiero ejecutar una serie de comandos para convertir el archivo FLAC en un archivo MP3 y copiar las etiquetas.

The kicker: necesito buscar el directorio flac recursivamente y crear los subdirectorios correspondientes en el directorio mp3 . Los directorios y archivos pueden tener espacios en los nombres, y se nombran en UTF-8.

Y quiero usar make para conducir esto.


FWIW, he usado algo así en un Makefile :

RECURSIVE_MANIFEST = `find . -type f -print`

El ejemplo anterior buscará desde el directorio actual ( ''.'' ) Para todos los "archivos simples" ( ''-type f'' ) y establecerá la variable de variable RECURSIVE_MANIFEST en cada archivo que encuentre. A continuación, puede usar sustituciones de patrones para reducir esta lista o, alternativamente, proporcionar más argumentos en find para limitar lo que devuelve. Vea la página de manual para encontrar .


Intentaría algo en esta línea

FLAC_FILES = $(shell find flac/ -type f -name ''*.flac'') MP3_FILES = $(patsubst flac/%.flac, mp3/%.mp3, $(FLAC_FILES)) .PHONY: all all: $(MP3_FILES) mp3/%.mp3: flac/%.flac @mkdir -p "$(@D)" @echo convert "$<" to "$@"

Un par de notas rápidas para make principiantes:

  • El @ delante de los comandos evita que make imprima el comando antes de ejecutarlo realmente.
  • $(@D) es la parte del directorio del nombre del archivo de destino ( $@ )
  • Asegúrese de que las líneas con comandos de shell en ellas comiencen con una pestaña, no con espacios.

Incluso si esto debe manejar todos los caracteres UTF-8 y esas cosas, fallará en espacios en nombres de archivos o directorios, ya make utiliza espacios para separar cosas en los archivos make y no conozco una forma de evitarlo. Así que eso te deja con solo un guión de shell, me temo: - /


Mi solución se basa en la anterior, usa sed lugar de patsubst para patsubst la salida de find AND escape the spaces.

Yendo de flac / a ogg /

OGGS = $(shell find flac -type f -name "*.flac" | sed ''s/ /// /g;s/flac///ogg///;s//.flac//.ogg/'' )

Advertencias:

  1. Aún barfs si hay puntos y comas en el nombre del archivo, pero son bastante raros.
  2. El truco de $ (@ D) no funcionará (salidas de galimatías), ¡pero oggenc crea directorios para ti!

Puede definir su propia función comodín recursiva de la siguiente manera:

rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d))

El primer parámetro ( $1 ) es el nombre del directorio, y el segundo ( $2 ) es el patrón que desea emparejar.

Ejemplos

Para encontrar todos los archivos C en el directorio actual:

$(call rwildcard, , *.c)

Para encontrar todos los archivos .c y .h en src :

$(call rwildcard, src/, *.c *.h)

Source


Si está utilizando Bash 4.x, puede usar una nueva opción globbing , por ejemplo:

SHELL:=/bin/bash -O globstar list: @echo Flac: $(shell ls flac/**/*.flac) @echo MP3: $(shell ls mp3/**/*.mp3)

Este tipo de comodín recursivo puede encontrar todos los archivos de su interés ( .flac , .mp3 o lo que sea). O