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 i de resterende kapitlene vil være 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å prosessen med 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 refereres til som “verten” i andre seksjoner.
er maskinen/systemet der de bygde programmene skal kjøres. Merk at denne bruken av “host” 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 build og host.
Som et eksempel, la oss forestille oss følgende scenario (noen ganger referert til som “Canadian Cross”): vi kan ha 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.
Nesten alle byggesystemer bruker navn i formen
cpu-vendor-kernel-os referert til som maskintripletten. En klok
leseren kan lure på hvorfor en “triplett”
refererer til et firekomponents navn. Årsaken er historie: i
utgangspunktet var tre komponentnavn nok å angi en maskin
entydig, men nye maskiner og systemer dukket opp, som viste seg
utilstrekkelig. Ordet “triplett” hang igjen. En enkel måte å
finne din maskintriplett på er å kjøre config.guess skript som følger
med kilden for mange pakker. Pakk ut binutils kilder og kjør
skriptet: ./config.guess
og merk deg
utdataen. 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.
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 <name of binary>
| grep interpreter
og legger merke til utdataen.
Den autoritative referansen som dekker alle plattformer er i
shlib-versions
filen i roten til
Glibc kildetreet.
For å forfalske en krysskompilering i LFS, navnet på
vertstripletten justeres litt ved å endre "vendor" feltet i
LFS_TGT
variabelen. 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ø.
Nå er det mer om krysskompilering: C-språket er ikke bare en kompilator, men definerer også et standardbibliotek. I denne boken blir GNU C-biblioteket, kalt glibc, brukt. Dette biblioteket må kompileres for lfs-maskinen, det vil si ved å bruke krysskompilatoren cc1. Men kompilatoren selv bruker interne bibliotekimplementeringskomplekse instruksjoner som ikke tilgjengelige i assembleranvisningssettet. Dette interne biblioteket heter libgcc, og må være koblet til glibc biblioteket for å være fullt funksjonelt! Videre må standardbiblioteket for C++ (libstdc++) også kobles til glibc. Løsningen på dette kylling og egg problemet er først å bygge en degradert cc1 basert libgcc, som mangler noen funksjoner som tråder og unntakshåndtering, bygge glibc ved å bruke denne degraderte kompilatoren (glibc selv er ikke degradert), og bygg deretter libstdc++. Men dette siste biblioteket vil mangle samme funksjonalitet som libgcc.
Dette er ikke slutten på historien: konklusjonen av det foregående avsnittet er at cc1 ikke er i stand til å bygge en fullt funksjonell libstdc++, men dette er den eneste kompilatoren som er tilgjengelig for å bygge C/C++ bibliotekene under trinn 2! Selvfølgelig, kompilatoren bygget under trinn 2, cc-lfs, ville være i stand til å bygge disse bibliotekene, men (1) byggesystemet til GCC vet ikke at det er brukbart på pc, og (2) å bruke det på pc vil være en fare for å koble til pc-bibliotekene, siden cc-lfs er en lokal kompilator. Så vi må bygge libstdc++ senere, i chroot.
Krysskompilatoren vil bli installert i en separat $LFS/tools
mappe, siden det 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. Det viser hvilken filer som er lenket av
ld ved å kompilere et
dummyprogram og gi --verbose
parameteren til lenkeren.
For eksempel, $LFS_TGT-gcc dummy.c
-Wl,--verbose 2>&1 | grep succeeded vil vise
alle filene som ble åpnet under koblingen.
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 PATH mapper for å finne hvilke verktøy det skal bruke. Imidlertid under selve kjøringen av gcc, er det 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.
Detaljert informasjon kan fås fra gcc med å gi alternativet
-v
på kommandolinjen under
kompilering av et dummy-program. For eksempel, gcc -v dummy.c Vil vise detaljert
informasjon om forprosessorenkompileringen og sammenstillings
stadier, inkludert gcc sine inkluderte søkestier og
deres rekkefølge.
Neste installert er desinfiserte Linux API deklarasjoner (headers). Disse tillater standard C-bibliotek (Glibc) å bruke funksjoner som Linux kjernen vil gi.
Den neste pakken som blir installert er Glibc. Det viktigste hensyn
for å bygge Glibc er kompilatoren, binære verktøy og
kjernedeklarasjoner. Kompilatoren 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 kompilatoren vil
være $LFS_TGT-gcc. De
binære verktøyene og kjerne deklarasjoner kan være litt mer
kompliserte. Derfor tar vi ingen risiko og bruker de tilgjengelige
konfigurasjonsbryterne for å fremtvinge de riktige valgene. Etter
kjøring av configure,
sjekk innholdet i config.make
filen i
build
mappen for alle viktige
detaljer. Legg merke til bruken av CC="$LFS_TGT-gcc"
(med $LFS_TGT
utvidet) for å kontrollere hvilke binære
verktøy som brukes og bruken av -nostdinc
og -isystem
flaggfor å kontrollere
kompilatorens inkluderte søkeveier. Disse elementene fremhever et
viktig aspekt ved Glibc pakken—den 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 alle programmene som må bygges selv. Installasjonstrinnet for
alle disse pakkene bruker DESTDIR
variabelen for å få programmene til å lande i LFS filsystemet.
Ved slutten av Kapittel 6
den lokale lfs kompilatoren er installert. Første binutils-pass2
blir bygget, med det samme DESTDIR
installasjon 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 satt
eksplisitt inn i konfigureringsalternativene.
Når du kommer inn i chroot-miljøet i Chapter 7, den første oppgaven er å installere libstdc++. Deretter utføres midlertidige installasjoner av programmer som trengs for riktig betjening av verktøykjeden. Fra dette tidspunktet og fremover er kjerneverktøykjeden selvstendig og selvbetjent. I Chapter 8, bygges, testes og installeres de endelige versjonene av alle pakker som trengs for et fullt funksjonelt system.