Denne delen forklarer noen av begrunnelsen og de tekniske detaljene bak den overordnede byggemetoden. Det er ikke nødvendig å umiddelbart forstå alt i denne delen. Det meste av denne informasjonen vil være klarere etter å ha utført en faktisk konstruksjon. Denne delen kan refereres til når som helst under prosessen.
Det overordnede målet for Kapittel 5 og Kapittel 6 er å produsere et midlertidig område som inneholder et kjent sett med verktøy som kan isoleres fra vertssystemet. Ved bruk av chroot kommandoene, kompilasjonene i de resterende kapitlene vil være isolert inne i det miljøet, og sikre en ren, problemfri bygging av det nye LFS systemet. Byggeprosessen er designet for å minimere risikoen for nye lesere og gi den mest pedagogiske verdien samtidig.
Byggeprosessen baserer seg på krysskompilering. Krysskompilering brukes normalt for å bygge en kompilator og dens verktøykjede for en annen maskin enn den som brukes til byggingen. Dette er strengt tatt ikke nødvendig for LFS, siden maskinen der det nye systemet skal kjøre er den samme som den brukt til byggingen. Men krysskompilering har den store fordelen at alt som er krysskompilert ikke avhenger av vertsmiljøet.
LFS boken er ikke, og inneholder ikke en generell veiledning til å bygge en kryss (eller lokal) verktøykjede. Ikke bruk kommandoen i boken for en kryssverktøykjede som skal brukes til andre formål enn å bygge LFS, med mindre du virkelig forstår hva du gjør.
Krysskompilering involverer noen begreper som fortjener en seksjon for seg selv. Selv om denne delen kan utelates i en første lesning, å komme tilbake til det senere vil være gunstig for din fulle forståelse av prosessen.
La oss først definere noen begreper som brukes i denne sammenhengen.
er maskinen der vi bygger programmer. Merk at denne maskinen er også referert til som “verten”.
er maskinen/systemet der de bygde programmene skal kjøres. Merk at denne bruken av “verten” ikke er den samme som i andre seksjoner.
brukes kun for kompilatorer. Det er maskinen kompilatoren produserer kode for. Det kan være forskjellig fra både bygg og vertent.
Som et eksempel, la oss forestille oss følgende scenario (noen ganger referert til som “Canadian Cross”). vi har en kompilator bare på en treg maskin, la oss kalle det maskin A, og kompilatoren ccA. Vi kan også ha en rask maskin (B), men uten kompilator, og vi ønsker å produsere kode for en annen treg maskin (C). Å bygge en kompilator for maskin C, ville vi ha tre trinn:
Stadie | Bygg | Vert | Mål | Handling |
---|---|---|---|---|
1 | A | A | B | bygg krysskompilator cc1 med ccA på maskin A |
2 | A | B | C | bygg krysskompilator cc2 med cc1 på maskin A |
3 | B | C | C | bygg kompilator ccC med cc2 på maskin B |
Deretter kan alle de andre programmene som trengs av maskin C kompileres ved å bruke cc2 på den raske maskinen B. Merk at med mindre B kan kjøre programmer produsert for C, er det ingen måte å teste de bygde programmene før maskinen C selv kjører. For eksempel, for å teste ccC, vil vi kanskje legge til en fjerde trinn:
Stadie | Bygg | Vert | Mål | Handling |
---|---|---|---|---|
4 | C | C | C | bygge om og teste ccC ved å bruke seg selv på maskin C |
I eksemplet ovenfor er bare cc1 og cc2 krysskompilatorer, det vil si de produserer kode for en annen maskin enn de de kjører på. De andre kompilatorene ccA og ccC produserer kode for maskinen de kjører på. Slike kompilatorer kalles lokale kompilatorer.
Alle de krysskompilerte pakkene i denne boken bruker en autoconf basert byggesystem. Det autoconf baserte byggesystemet godtar systemtyper i formen cpu-vendor-kernel-os, referert til som systemtripletten. Siden leverandørfeltet ofte er irrelevant, autoconf lar deg utelate det.
En klok leser kan lure på hvorfor en “triplett” refererer
til et firekomponents navn. Kjernefeltet og os-feltet begynte som
et enkelt “system” felt. Et slikt trefeltsskjema er
fortsatt gyldig i dag for noen systemer, for eksempel,
x86_64-unknown-freebsd
. Men to
systemer kan dele samme kjerne og fortsatt være for forskjellige
for å bruke den samme tripletten for å beskrive dem. For eksempel
Android kjørende på en mobiltelefon er helt forskjellig fra
Ubuntu som kjører på en ARM64 server, selv om de begge kjører på
samme type CPU (ARM64) og bruker samme kjerne (Linux).
Uten et emuleringslag kan du ikke kjøre en kjørbar fil for en
server på en mobiltelefon eller omvendt. Så “system” feltet har
blitt delt inn i kjerne- og os-felt, for å angi disse systemene
entydig. I vårt eksempel, Android systemet er angitt aarch64-unknown-linux-android
, og Ubuntu
systemet er angitt aarch64-unknown-linux-gnu
.
Ordet “triplett” forblir innebygd i leksikonet. En
enkel måte å bestemme din systemtriplett er å kjøre config.guess skript som følger
med kilden for mange pakker. Pakk ut binutils sine kilder, kjør
skriptet ./config.guess
, og merk
utdaten. For eksempel, for en 32-bits Intel-prosessor utdataen
vil være i686-pc-linux-gnu. På et 64-bit system
blir det x86_64-pc-linux-gnu. På de fleste
Linux systemer den enklere gcc
-dumpmachine kommando vil gi deg lignende
informasjon.
Vær også oppmerksom på navnet på plattformens dynamiske lenker,
ofte referert til som den dynamiske lasteren (ikke å forveksle
med standard lenker ld som er en del av binutils).
Den dynamiske lenkeren levert av Glibc finner og laster de delte
bibliotekene som trengs av et program, forbereder programmet for
kjøring, og deretter kjører det. Navnet på dynamisk lenker for en
32-bits Intel-maskin er ld-linux.so.2
; og er ld-linux-x86-64.so.2
for 64-bits systemer. En
sikker måte å bestemme navnet på den dynamiske lenkeren på er å
inspisere en tilfeldig binær fra vertssystemet ved å kjøre:
readelf -l <navn på binær>
| grep interpreter
og legg merke til utdataen.
Den autoritative referansen som dekker alle plattformer er i
a Glibc wiki
page.
For å forfalske en krysskompilering i LFS, navnet på
vertstripletten justeres litt ved å endre "vendor" feltet i
LFS_TGT
variabel så det står "lfs". Vi
bruker også --with-sysroot
alternativet når du bygger krysslenkeren og krysskompilatoren for å
fortelle dem hvor de skal finne de nødvendige vertsfilene. Dette
sikrer at ingen av de andre programmene bygget i Kapittel 6
kan lenke til biblioteker på byggemaskinen. Kun to trinn er
obligatoriske, og ett til for tester:
Stadie | Bygg | Vert | Mål | Handling |
---|---|---|---|---|
1 | pc | pc | lfs | Bygg krysskompilator cc1 ved å bruke cc-pc på pc |
2 | pc | lfs | lfs | Bygg kompilator cc-lfs ved å bruke cc1 på pc |
3 | lfs | lfs | lfs | Bygge om og teste cc-lfs ved å bruke seg selv på lfs |
I tabellen ovenfor, “på pc” betyr at kommandoene kjøres på en maskin som bruker den allerede installerte distribusjonen. “på lfs” betyr at kommandoene kjøres i et chroot-miljø.
Dette er ennå ikke slutten på historien. C-språket er ikke bare en kompilator; den definerer også et standardbibliotek. I denne boken er det GNU C-biblioteket, kalt glibc, som brukes (det finnes et alternativ, "musl"). Dette biblioteket må kompileres for LFS-maskinen; det vil si å bruke krysskompilatoren cc1. Men kompilatoren selv bruker et internt bibliotek som gir komplekse subrutiner for funksjoner som ikke er tilgjengelige i assembler-instruksjonssettet. Dette interne biblioteket heter libgcc, og det må være koblet til glibc for at biblioteket skal være fullt funksjonelt. Videre standardbiblioteket for C++ (libstdc++) må også være koblet til glibc. Løsningen på dette kylling og egg problemet er først å bygge en nedgradert cc1-basert libgcc, mangler noen funksjoner som tråder og unntakshåndtering, og da å bygge glibc ved å bruke denne nedgraderte kompilatoren (glibc selv er ikke nedgradert), og også for å bygge libstdc++. Dette siste biblioteket vil mangle noe av funksjonaliteten til libgcc.
Resultatet av det foregående avsnittet er at cc1 ikke er i stand til å bygge et fullt funksjonell libstdc++ med den nedgraderte libgcc, men cc1 er den eneste kompilatoren som er tilgjengelig for å bygge C/C++-bibliotekene under fase 2. Det er to grunner til at vi ikke umiddelbart bruker kompilator bygget i trinn 2, cc-lfs, for å bygge disse bibliotekene.
Generelt sett kan ikke cc-lfs kjøre på pc (vertssystemet). Selv om triplettene for pc og lfs er kompatible med hverandre, en kjørbar fil for lfs må avhenge av glibc-2.40; vertsdistroen kan bruke en annen implementering av libc (for eksempel musl), eller en tidligere utgivelse av glibc (for eksempel, glibc-2.13).
Selv om cc-lfs kan kjøre på pc, vil det å bruke det på pc skape en risiko for å koble til pc-bibliotekene, siden cc-lfs er en lokal kompilator.
Så når vi bygger gcc trinn 2, instruerer vi byggesystemet til å gjenoppbygge libgcc og libstdc++ med cc1, men vi kobler libstdc++ til den nye gjenoppbygde libgcc i stedet for den gamle, nedgraderte konstruksjonen. Dette gjør den ombygde libstdc++ fullt funksjonell.
I Kapittel 8 (eller “stage 3”), alle pakkene som trengs for LFS systemet er bygget. Selv om en pakke allerede er installert i LFS systemet i et tidligere kapittel, bygger vi fortsatt pakken på nytt. Hovedårsaken til å gjenoppbygge disse pakkene er å gjøre dem stabile: hvis vi installerer en LFS pakke på nytt på et fullført LFS system, det reinstallerte innholdet i pakken skal være det samme som innholdet i den samme pakken når den først installeres i Kapittel 8. De midlertidige pakkene installert i Kapittel 6 eller Kapittel 7 kan ikke tilfredsstille dette kravet, fordi noen av dem er bygget uten valgfrie avhengigheter, og autoconf kan ikke utføre noen funksjonsinnsjekker Kapittel 6 på grunn av krysskompilering, forårsaker at de midlertidige pakkene mangler valgfrie funksjoner, eller bruker suboptimale koderutiner. I tillegg en mindre grunn til gjenoppbygging av pakkene er å kjøre testpakkene.
Krysskompilatoren vil bli installert i en separat $LFS/tools
mappe, siden den ikke vil være en del
av det endelige systemet.
Binutils installeres først fordi configure kjøringer av både GCC og Glibc utfører forskjellige funksjonstester på assembleren og lenker for å bestemme hvilke programvarefunksjoner som skal aktiveres eller deaktiveres. Dette er viktigere enn man kanskje først er klar over. En feilkonfigurert GCC eller Glibc kan resultere i en subtilt ødelagt verktøykjede, hvor virkningen av et slikt brudd ikke vises før mot slutten av konstruksjonen av hele distribusjonen. En feil i testserien vil vanligvis fremheve denne feilen før det utføres for mye tilleggsarbeid.
Binutils installerer sin assembler og lenker på to steder,
$LFS/tools/bin
og $LFS/tools/$LFS_TGT/bin
. Verktøyene i en
plassering er hardlenket til den andre. En viktig fasett av
lenkeren er bibliotekets søkerekkefølge. Detaljert informasjon kan
fås fra ld ved å gi
den --verbose
flagget. For
eksempel, $LFS_TGT-ld --verbose |
grep SEARCH vil illustrere gjeldende søkestier og
rekkefølgen deres. (Merk at dette eksempelet kan kjøres som vist
kun mens du er logget på som bruker lfs
. Hvis du kommer tilbake til denne siden
senere, bytt ut $LFS_TGT-ld med ld).
Den neste pakken som er installert er GCC. Et eksempel på hva som kan bli sett under kjøringen av configure er:
checking what assembler to use... /mnt/lfs/tools/i686-lfs-linux-gnu/bin/as
checking what linker to use... /mnt/lfs/tools/i686-lfs-linux-gnu/bin/ld
Dette er viktig av grunnene nevnt ovenfor. Det viser også at GCCs konfigureringsskript ikke søker i STI (PATH) mapper for å finne hvilke verktøy det skal bruke. Imidlertid under selve kjøringen av gcc er ikke de samme søkestiene nødvendigvis brukt. For å finne ut hvilke standardlenker gcc vil bruke, kjør: $LFS_TGT-gcc -print-prog-name=ld. (En gang til, fjern $LFS_TGT- prefikset hvis du kommer tilbake til dette seinere.)
Detaljert informasjon kan fås fra gcc med å gi alternativet
-v
på kommandolinjen under
kompilering av et program. For eksempel, $LFS_TGT-gcc -v example.c
(eller
uten $LFS_TGT- hvis
du kommer tilbake senere) vises detaljert informasjon om
forprosessoren, kompileringen og sammenstillings stadier, inkludert
gcc sine søkestier
for inkluderte deklarasjoner og deres rekkefølge.
Neste, desinfiserte Linux API deklarasjoner (headers). Disse tillater standard C-bibliotek (Glibc) å bruke funksjoner som Linux kjernen vil gi.
Neste kommer glibc. Det viktigste hensynet for å bygge glibc er
kompilatoren, binære verktøy og kjernedeklarasjoner. Kompilatoren
og binære verktøy er generelt ikke et problem siden glibc vil
alltid bruke kompilatoren som er relatert til --host
parameteret sendt til
konfigureringsskriptet; f.eks. i vårt tilfelle vil kompilatoren
være $LFS_TGT-gcc og
readelf verktøyet vil
være $LFS_TGT-readelf. Kjerne
deklarasjonene kan være litt mer komplisert. Derfor tar vi ingen
risiko og bruker den tilgjengelige konfigurasjonsbryteren for å
fremtvinge riktig valg. Etter kjøring av configure, sjekk innholdet i
config.make
filen i build
mappen for alle viktige detaljer. Disse
elementene fremhever et viktig aspekt ved glibc pakken—en er veldig
selvforsynt med tanke på byggemaskineriet og er generelt ikke
avhengig av standardinnstillinger for verktøykjeder.
Som nevnt ovenfor, blir standard C++-biblioteket kompilert som
neste, etterfulgt i Kapittel 6
av andre programmer som må krysskompileres for å bryte sirkulære
avhengigheter på byggetidspunktet. Installasjonstrinnet for alle
disse pakkene bruker DESTDIR
variabel
for å tvinge installasjonen inn i LFS filsystemet.
Ved slutten av Kapittel 6
den lokale lfs kompilatoren er installert. Første binutils-pass2
blir bygget, med den samme DESTDIR
mappen som de andre programmene, deretter konstrueres den andre
passeringen av GCC, og utelater libstdc++ og andre ikke-viktige
biblioteker. På grunn av en merkelig logikk i GCC
konfigureringsskript, CC_FOR_TARGET
ender opp som cc når
verten er den samme som målet, men er forskjellig fra
byggesystemet. Det er derfor CC_FOR_TARGET=$LFS_TGT-gcc
er erklært
eksplisitt som et av konfigurasjonsalternativene.
Når du kommer inn i chroot-miljøet i Kapittel 7, de midlertidige installasjonene av programmer som trengs for riktig betjening av verktøykjeden utføres. Fra dette tidspunktet og fremover er kjerneverktøykjeden selvstendig og selvhostet. I Kapittel 8, endelige versjoner av alle pakker som trengs for et fullt funksjonelt system bygges, testes og installert.