Spørgsmål:
LilyPond - hvordan man skriver en grundlæggende makefile
nath
2019-12-03 09:51:56 UTC
view on stackexchange narkive permalink

I løbet af de sidste år tænkte jeg mig selv at skrive scores ved hjælp af LilyPond og desuden gøre filhåndtering lettere ved hjælp af Bash -skripter. For nylig startede jeg et projekt lidt større end kun en eller to sider og endnu en gang stødte jeg på artiklen om Makefiles i LilyPond Documentary.

Selvom det var lidt svært at læse denne artikel for mig at forstå den egentlige teknik bag skabelonen Makefile også fordi artiklen ikke leverer det arkiv, det arbejder med.

Så jeg tager dog tid til at kompensere et eksempel på et projekt at spørge, hvordan en Makefile i dette scenarie kunne se ud. Hvordan jeg ville bygge det trin for trin, og hvordan jeg faktisk kører Makefile. ( Rediger: henviser til en make man-side jeg fik min forståelse for så vidt jeg kunne sige, at man bruger make som tolk som bash på en shell-script.sh . Kommandoen ser så simpelthen ud som make -f Makefile køres i projektets rodmappe.)


Projektet har en filstruktur som denne:

  ├── Book.ly├── Book.pdf├── globale filer│ ├── copyright.ily│ ├── Frontpage.ily│ ├── header.ily│ └── paper.ily├── input-files-voiceI│ ├── Nr_01-voiceI.ily│ ├ ── Nr_02-voiceI.ily│ └── Nr_03-voiceI.ily├── input-files-voiceII│ ├── Nr_01-voiceII.ily│ ├── Nr_02-voiceII.ily│ └── Nr_03-voiceII. ily├── README.md├── single-sides-voiceI│ ├── MIDI│ │ ├── Score-Nr_01-voiceI.midi│ │ ├── Score-Nr_02-voiceI.midi│ │ └── Score -Nr_03-voiceI.midi│ ├── PDF│ │ ├── Score-Nr_01-voiceI.pdf│ │ ├── Score-Nr_02-voiceI.pdf│ │ └── Score-Nr_03-voiceI.pdf│ ├─ ─ Score-Nr_ 01-voiceI.ly│ ├── Score-Nr_02-voiceI.ly│ └── Score-Nr_03-voiceI.ly├── single-sides-voiceI_a_II│ ├── MIDI│ │ ├── Score-I_u_II_Nr_01.midi │ │ ├── Score-I_u_II_Nr_02.midi│ │ └── Score-I_u_II_Nr_03.midi│ ├── PDF
│ │ ├── Score-I_u_II_Nr_01.pdf│ │ ├── Score-I_u_II_Nr_02.pdf│ │ └── Score-I_u_II_Nr_03.pdf│ ├── Score-I_u_II_Nr_01.ly│ ├── Score-I_u_II│ ── Score-I_u_II_Nr_03.ly└── single-sides-voiceII ├── MIDI │ ├── Score-Nr_01-voiceII.midi │ ├── Score-Nr_02-voiceII.midi │ └── Score-Nr_03-voiceII .midi ├── PDF │ ├── Score-Nr_01-voiceII.pdf │ ├── Score-Nr_02-voiceII.pdf │ └── Score-Nr_03-voiceII.pdf ├── Score-Nr_01-voiceII.ly ├ ── Score-Nr_02-voiceII.ly └── Score-Nr_03-voiceII.ly  

input-filer for begge stemmer har et format sådan:

  \ relative c {\ nøgle bas \ tid 3/4 \ nøgle c dur c4 (def |% 01 g1) \ bar "|." | % 02}  

Score -filerne har til formål at blive kompileret til output af PDF og MIDI. og se simpelthen sådan ud (på trods af at Scores for to systemer indeholder en anden Personale):

  \ version "2.18.2" # (sæt-standard-papirstørrelse "a4") # (sæt-global-personale-størrelse 22) \ inkluderer "../global-files/header.ily"\score {\ new StaffGroup = "" \ med {instrumentName = \ markup {\ bold \ enorm {\ større "1." }}} << \ new Staff = "celloI" \ med {midiInstrument = # "cello"} \ include "../input-files-voiceI/Nr_01-voiceI.ily" >> \ layout {} \ midi {}}  

Bog -delen er den del, jeg stadig er temmelig utilfreds med. Jeg foretrækker dette ret simpelt med bare at bruge Score * .ly filer som \ inkluderer , men jeg får problemer med \ inkluderer der er allerede i Score.ly -filerne, da de ikke kun indeholder \ score -blokken, der kan kompileres af dem selv.

Nå, jeg kunne bruge en \ book med at indstille et bogoutputnavn som \ bookOutputSuffix "OutputName" , men så min Book.ly ville blive en massiv fil, der tager lang tid at blive kompileret, selv for en lille ændring på et enkelt stykke.

Så lige nu har min Book.ly -fil følgende format og det eneste formål at kompilere hele bogen med to stemmer i to stabe, men med alle stykker, her 01-03:

  \ version "2.18.2" # (set-default- papirstørrelse "a4") # (sæt-global-personale-størrelse 22) \ inkluderer "./global-files/paper.ily"\book {\ include" ./global-files/Frontpage.ily "%%% % Score nummer: 1 ==================================== %%%%% \ score {\ new StaffGroup = "" \ med {instrumentName = \ markup {\ bold \ enorm {\ større "1." }}} << \ new Staff = "voiceI" \ med {midiInstrument = # "voice"} \ include "./input-files-voiceI//Nr_01-voiceI.ily" \ new Staff = "voiceII" \ med {midiInstrument = # "voice"} \ include "./input-files-voiceII//Nr_01-voiceII.ily" >> \ layout {\ printTupletBow}} %%%% Score-antal: 2 ========== ========================% %%%% \ score {\ new StaffGroup = "" \ med {instrumentName = \ markup {\ bold \ enorm { \ større "2." }}} << \ new Staff = "voiceI" \ med {midiInstrument = # "voice"} \ include "./input-files-voiceI//Nr_02-voiceI.ily" \ new Staff = "voiceII" \ med {midiInstrument = # "voice"} \ include "./input-files-voiceII//Nr_02-voiceII.ily" >> \ layout {}} %%%% Score Number: 3 ============= ======================% %%%% \ score {\ new StaffGroup = "" \ med {instrumentName = \ markup {\ bold \ enorm {\ større "3." }}} << \ new Staff = "voiceI" \ med {midiInstrument = # "voice"} \ include "./input-files-voiceI//Nr_03-voiceI.ily" \ new Staff = "voiceII" \ med {midiInstrument = # "stemme"}
\ include "./input-files-voiceII//Nr_03-voiceII.ily" >> \ layout {}}}  

Min arbejdsgang er følgende: stærk>

  1. Jeg skriver inputfilerne: input-file.ily
  2. Jeg kører en bash-script.sh kode> der opretter de kompilerbare Score.ly filer fra input-files/*.ily
  3. Jeg kører et bash-script. sh der opretter det kompilerbare Book.ly fil fra input-files/*.ily
  4. Jeg kompilerer Score. ly filer en efter en eller kør en simpel til fil i * .ly; gør lilypond "$ file"; udført loop, men i hver af de tre Score-mapper. Jeg bruger et script til at flytte PDF- og MIDI-filerne til deres tilsvarende mapper.
  5. Jeg kører blot lilypond for at kompilere Book.ly -filen.

FERDIG


Det aktuelle projekt, som dette spørgsmål stilles til, kan findes her på GitHub


Opdatering 1:

Mit system:

  Operativsystem: Debian GNU / Linux bullseye / sid Kernel: Linux 5.3.0-2 -686-pae Arkitektur: x86 GNU LilyPond: 2.18.2Min Editor - GNU Nano: 4.5 Guake Terminal: 3.6.3 GNU Make: 4.2.1  

Jeg tilføjede min shell- scripts til et separat Git-Repository


Opdatering 2:

Dette er en meget forenklet diagram over afhængigheder. Under forudsætning af, at der kun var en voice:

  ./infiles/ infile {01..03} .ily ------------- > ./Book.ly === > Book.pdf | ^ ^ ^ * --------- > Scores {01..03} .ly === | | | ===== > Score {01..03} .pdf ^ ^ === | | | ===== > Score {01..03}. Midi | | | | | ./global-files/ | | | | | header.ily ------ * | | | |
copyright.ily --------- + ------------- * | | Frontpage.ily ------------------------- * | paper.ily --------------------------- *  
Har du bash-script.sh-filerne overalt? Jeg har nogle problemer med at trække hele proceduren.
Informer også abt OS og din valgte redaktør
FYI: Jeg opdaterede mit svar for at give mere kontekst og en kort teknisk beskrivelse af mekanikken.
Dette spørgsmål blev diskuteret i [metaen] (https://music.meta.stackexchange.com/questions/3437/is-this-question-on-topic?cb=1).
To svar:
luser droog
2019-12-03 11:02:20 UTC
view on stackexchange narkive permalink

Invokation

make søger i den aktuelle mappe efter en fil med navnet Makefile eller makefile , så det er ofte enklest at navngive det et af disse to valg og derefter påberåbe sig med den enkle kommando:

 $ make 

Hvis du bruger store bogstaver 'M', så filen vil normalt blive vist øverst efter alfabetisk rækkefølge eller sorteringsrækkefølge.

Regler

make fungerer ved hjælp af regler for, hvordan man opretter et output fra et input . Formatet for en regel er målet efterfulgt af et kolon, derefter en mellemrumsafgrænset liste over afhængigheder efterfulgt af kommandoer indrykket med TAB.

 target: dependencies commands 

Målet eller afhængighederne kan være filnavne eller symboler, der svarer til andre regler.

Hvis du ikke angiver et mål på kommandolinjen, påkalder det den første regel, det møder. Så en almindelig teknik er at gøre den første regel til en "dummy" -regel, der ikke producerer en fil, men simpelthen samler alle trin eller output sammen. F.eks.

 alle: output1 

Påkaldelse af make med denne makefile vil forsøge at oprette output1 hvis det ikke eksisterer. Hvis der er en regel til oprettelse af output1 senere i makefilen, bruger den den.

For din sag foreslår jeg, at du opretter en regel på øverste niveau for at oprette Score.ly og Book.ly

 alle: Score.ly Book.ly 

Mønsterregler

For at udskifte din shell-loop kan du bruge en mønsterregel.

% .pdf:% .ly lilypond $ ^ 

Denne regel siger: For at oprette en .pdf-fil skal du køre lilypond på den tilsvarende .ly-fil .

Bemærk at kommandoen til udførelse skal start med et bogstaveligt TAB-tegn. Variablen % ^ henviser til den ovennævnte inputfil. Andre nyttige variabler er $ @ for målet og $ < for den første input, hvis der er mere end en.

Dette håndterer kun en del af din shell-loop og definerer transformationen fra en inputfil til en outputfil. For den anden opgave at generere en liste over filer, er der nogle specielle variabler tilgængelige i GNU, der gør dette.

 input = $ (notdir $ (wildcard ./*.ly))bases= $ (basenavn $ (input)) output = $ (patsubst%,%. pdf, $ (baser)) 

Efter disse definitioner kan du bruge $ (output) som en afhængighed i en regel, som:

 pdfs: $ (output) mkdir -p PDF mv * .pdf PDF mkdir -p MIDI mv *. midi MIDI 

Dette eksempel fra LilyPond-dokumenter viser, at du kan placere flere mål til venstre for tyktarmen, så du kan redegøre for begge typer filer produceret af LilyPond, som mit eksempel her gør det ikke. Igen skal hver af disse kommandoer være indrykket med et bona fide ASCII TAB-tegn.

I meget enkle tilfælde

Dig kan bruge en makefile bare til at samle et eller flere shell-scripts sammen og ignorere meget af kompleksiteten af ​​regler og afhængigheder, hvis din situation er meget enkel.

For et projekt, hvor jeg lavede en masse .abc-filer i en enkelt mappe, det hele håndteres af en enkelt regel:

  alle: for f i `ls * .abc`; \ do ../abcm2ps -O $$ {f% .abc} .ps $$ f; \ ps2pdf $$ {f% .abc} .ps; \    Færdig ; zip -r evildead.zip * .pdf  
Det fungerede ikke. Forsøger
.                
Fungerer nu. Men en semantisk indlæst startfane er så unaturlig, ikke kun for mennesker, men endog velmenende redaktører, at en stærkere advarsel kan være i orden ??
Sand. Sådan har `fabrikat` altid fungeret. Men jeg vil forsøge at markere det mere højt og oftere, når jeg udfylder svaret.
[Jeg fandt dette] (https://paste.debian.net/1119187/) i [LilyPond Docs] (http://lilypond.org/doc/v2.18/Documentation/usage/make-and-makefiles. da.html) ligner måden at håndtere begge formater ** PDF ** * og * ** MIDI **, så vidt jeg kan se ud fra min 'bash' viden, ser det også ud til at de bruger en 'if-sætning' til find ud af, om filerne findes eller ikke, og kør derefter kommandoen 'mv' på den.
I stedet for `lilypond $ ^` ville jeg bruge `lilypond $ <`. Dette giver dig mulighed for at bruge '\ include' og specificere afhængighederne i makefilen.
@Rusi Lore (tm) siger, at problemet med fanerne blev bemærket kun få uger efter, at værktøjet først blev frigivet (i 1970'erne) og ikke blev ændret, fordi der allerede var mere end et dusin brugere, der ville være blevet generet af lave om.
@luserdroog Jeg tilføjede et diagram :-)
wchargin
2019-12-04 04:20:19 UTC
view on stackexchange narkive permalink

luser droog's svar giver et godt overblik over make selv. Her er et eksempel på, hvordan man anvender det på et ægte Lilypond-projekt med følgende egenskaber:

  • Flere dele: klaver, fagot osv.
  • Flere satser.
  • Flere ønskede output: en enkelt "master" (dirigent) score, amaster score for hver bevægelse og en part score for hvert instrument.
  • Både PDF og MIDI output.
  • Almindelige definitioner (makroer) til både musik og præsentation.

For eksempel, hvis din Book.ly -fil indeholder din Nr_01-voiceI.ily -fil, som igen inkluderer din makroer.ily delte definitionsfiler, og hvis makroer.ily ændres, skal din Makefile vide, at den skal genkompilere Book.ly for at opdatere Book.pdf.

På den anden side, hvis du kun skifter en del, er det meget praktisk at kunne skrive lav dele og få Make only til at kompilere den del, der blev ændret, snarere end at spilde tid på at kompilere alle de andre. nd, hvis du bare vil lytte til et segment, skal du være i stand til at lave midi for at springe over den langsomme sætning og kun genoprette den nødvendige konsekvens.

Jeg har skrevet et shell-script til generering af en Makefile, der har alle disse egenskaber. Især krydser det automatisk \ include -grafen for dit projekt for at finde ud af, hvilke Lilypond-filer der er afhængige af, hvilke andre, og vil medføre det minimale sæt rekompileringer for en særlig ændring. Du fortæller det bare, hvilke "hovedfiler" du har, og hvilke du vil have i PDF- og / eller MIDI-form, og det vil gøre resten.

Her er scriptet: https: // github .com / MutopiaProject / MutopiaProject / blob / 918971593735f2dbf4864f289767b8d59a7d950e / ftp / MozartWA / KV488 / Mozart-KV488 / Mozart-KV488-lys / create_makefile.sh

Her er et eksempel på en kode en eksempelkode her : https://github.com/MutopiaProject/MutopiaProject/blob/918971593735f2dbf4864f289767b8d59a7d950e/ftp/MozartWA/KV488/Mozart-KV488/Mozart-KV488-lys/Makefile

er at oprette et sekundært mål for hver Lilypondfile, som jeg har kaldt dens "lydep" ("Lilypond afhængigheder") fil, sådan at filens lydep er snavset, hvis og kun hvis nogen af ​​filens transitkilder er snavset. Rent praktisk betyder dette, at hvert lydep-mål skal afhænge af dets kildefil plus alle lydep-mål, som det har direkte \ inkluderer afhængigheder. Derefter tager Make's automatiske opløsning sig af resten.

Scriptet er skræddersyet til et bestemt projekt, men du skal være i stand til at holde kerneinfrastrukturen på plads og tilpasse makefile -funktionen på bunden for at erstatte i din projektstruktur.

Jeg har skrevet dette script til GNU / Linux, og det har muligvis brug for nogle mindre justeringer til macOS / BSD (f.eks. udskiftning af readlink -f kode>), men det er generelt ret ligetil. Det kræver bash og GNU make (for sekundære mål). Jeg ser, at du er på Debian, så det skal bare fungere fint som det er.

Dette frigives alt sammen under MIT-licensen. Du er velkommen til at tage det, du finder nyttigt.

Yuhu mand, dette er et par linjer at læse igennem. Tak for svaret og for at dele dit arbejde! <3
Det er sikkert. Jeg får se, om jeg kan forklare / sammenfatte kernen i det, når jeg får en chance senere i dag.


Denne spørgsmål og svar blev automatisk oversat fra det engelske sprog.Det originale indhold er tilgængeligt på stackexchange, som vi takker for den cc by-sa 4.0-licens, den distribueres under.
Loading...