ii. Verktøykjedens tekniske merknader

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.

Om Krysskompilering

[Note]

Note

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:

bygg

er maskinen der vi bygger programmer. Merk at denne maskinen refereres til som verten i andre seksjoner.

vert

er maskinen/systemet der de bygde programmene skal kjøres. Merk at denne bruken av host ikke er den samme som i andre seksjoner.

mål

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.

Implementering av Krysskompilering for LFS

[Note]

Note

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.

Andre prosedyredetaljer

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 Kapittel 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.