Skip to content

Instantly share code, notes, and snippets.

@davinci-tech
Last active April 17, 2022 21:12
Show Gist options
  • Save davinci-tech/fe72f3fd4691f372647f1e51dcf8727a to your computer and use it in GitHub Desktop.
Save davinci-tech/fe72f3fd4691f372647f1e51dcf8727a to your computer and use it in GitHub Desktop.

Procesul de construire la LFS

Note

Acest document a fost scris în română, folosind ca referință LFS 11.1 (This document was written in romanian, using as a reference the LFS book, version 11.1). De asemenea, ce am scris aici reprezintă părerea mea personală (Also, what I wrote here is just my personal opinion). Oricine vrea să mă corecteze e bine venit (Suggestions are welcome)

Introducere

LFS (Linux From Scratch) este o carte (foarte bună cartea, o puteți citi aici) care constă în instrucțiuni pas-cu-pas în urma cărora veți sfârși prin a avea propria voastră distribuție Linux, perfect funcțională și bootabilă. Cartea face o treabă excelentă explicând procesul de construire a sitemului final, dar eu unul nu am putut să înțeleg anumite aspecte. Așa că am apelat la bunul meu prieten StackOverflow și, după multe ore chinuitoare, am înțeles în sfârșit cum se construiește LFS și m-am gândit că ar trebui să scriu asta undeva... poate într-un gist, cine știe?

Cross-compiling

Pentru a construi LFS, autorul a apelat la tehnica cross-compilării (de la ediția a 10a în sus). A făcut această decizie deoarece o caracteristică interesantă a programelor făcute în urma cross-compilării este că acestea sunt independente față de sistemul unde au fost construite.

Să luăm în considerare următorul scenariu: să spunem că avem o mașină numită PC, și alta numită LFSM (LFS Machine). Mașina LFSM nu are nimic pe ea, dar noi vrem să-i instalăm LFS. Pe de altă parte, PC are toate instrumentele necesare pentru un development enviroment, inclusiv un compiler (ccPC-PC), dar problema cu acest compiler este că e un compiler nativ (adică rulează pe PC și face executabile doar pentru PC), el nu poate produce executabile pentru LFSM. Noi vrem să avem un compiler nativ pentru LFSM (ccLFSM-LFSM), nu pentru PC, deoarece odată ce-l vom avea pe ccLFSM-LFSM vom putea construi și mai multe programe cu care să ne populăm LFS-ul (poate un window manager???). Așa că întrebarea este: Cum ajungem să-l pe construim ccLFSM-LFSM pornind de la ccPC-PC?

Înainte de a răspunde, trebuie să introducem câteva denumiri:

  • build system: sistemul pe care este construit cross-compiler-ul
  • host system: sistemul pe care va rula cross-compiler-ul
  • target system: sistemul pentru care cross-compiler-ul va produce cod

Spre exemplu, dacă avem un cross-compiler a cărui build system este mașina B, host system este mașina H, iar target system este mașina T, asta înseamnă că acest cross-compiler rulează pe mașina H, a fost construit pe mașina B și produce programe specifice mașinii T.

Acum că am scăpat de asta, hai să răspundem la întrebarea inițială: Cum ajungem să-l pe construim ccLFSM-LFSM pornind de la ccPC-PC?

Răspunsul, ingenios chiar, este că vom folosi ccPC-PC pentru a construi un nou compiler ccPC-LFSM, care va rula pe PC, dar va produce cod pentru LFSM. După aceea, vom folosi ccPC-LFSM pentru a construi compiler-ul ccLFSM-LFSM.

Simplu, nu? Poate chiar simplu... Vedeți voi, când construim LFS-ul nu avem de-a construit numai compilere, avem de construit și programe care depind de acele compilere, dar care sunt necesare pentru a construi exact acele compilere...

Intrăm în mirobolanta lume (în ghilimele) a circular-dependency-urilor.

Circular dependencies

Cele mai frumoase chestii din lume (*ironie*). Se petrec atunci când proiectul A depinde de proiectul B, dar proiectul B depinde de proiectul A. Un bun exemplu este limbajul de programare C. Vedeți voi, C nu este numai un limbaj de programare, el conține de asemenea un compiler (gcc) și o librărie standard (aici, glibc). Pentru ca gcc să ruleze, are nevoie de glibc (asta pentru că gcc are o librărie internă - libgcc, care trebuie linkată cu glibc pentru a fi complet funcțională), iar glibc trebuie să fie construit cu gcc. Mai mult, librăria pentru c++ (libstdc++), depinde de glibc! Așa că... ce putem face?

Sistemul nostru îl are pe ccPC-PC, care este complet funcțional și are un glibc complet funcțional. Noi vrem să-l construim pe ccPC-LFSM și pe glibc pentru LFSM. Ce vom face, este că mai întâi vom construi un temporar binutils care va rula pe LFSM. Temporarul binutils este necesar construirii unui ccPC-LFSM temporar și degradat (degradat deoarece libgcc-ul lui nu va fi linkat cu glibc, că glibc încă nu există). Spunem că ambele programe sunt temporare pentru că avem nevoie de ele numai pentru a rezolva circular-dependency-urile. Odată rezolvate, le vom șterge. Temporarul binutils conține linker-ul și assembler-ul necesare pentru temporarul ccPC-LFSM (temporarul ccPC-LFSM trebuie să știe ce linkere și assemblere are la dispoziție). Temporarul ccPC-LFSM va depinde the PC pentru a rula, dar va putea produce executabile pentru LFSM, independente de PC. Cu toate acestea, temporarul ccPC-LFSM nu este complet funcțional, căci îi lipsește glibc. Așa că următoarea etapă este să compilăm Kernel API Header-urile (glibc nu e nimic altceva decât un wrapper în jurul acestor header-uri) și să construim glibc. Observați că am spus "glibc" și nu "temporarul glibc", asta pentru că, prin natura sa, glibc-ul odată compilat va fi complet funcțional. Acum poate fi linkat cu temporarul ccPC-LFSM pentru a-l face să meargă. Următorul pas este construirea unui degradat libstdc++ folosindu-ne de temporarul și funcționalul ccPC-LFSM (degradat deoarece temporarul ccPC-LFSM are cu un libgcc degradat). Îl vom folosi apoi pe temporarul ccPC-LFSM pentru a compila o nouă versiune a lui binutils. Așa cum am spus adineaori, temporarul ccPC-LFSM poate produce cod care să ruleze pe LFSM, cod care va fi total independent de PC. De aceea construim o nouă versiune a binutils, pentru a fi complet independentă de PC (noul binutils va merge pe LFSM, complet izolat de PC, cel vechi mergea numai pe PC). După aceea vom folosi noul binutils și temporarul ccPC-LFSM pentru a construi un complet funcțional, fully-featured ccLFSM-LFSM. Tot ce va trebui să mai facem va fi să recompilăm libstdc++ pentru a-i adăuga și lui toate celălalte caracteristici care înainte îi lipseau din cauza libgcc-ului degradat. Dar cum singurul compiler care-l poate compila în așa fel încât să ruleze pe LFSM este un compiler nativ (ccLFSM-LFSM ; ccPC-LFSM este un compiler degradat, așa că nu-l putem folosi), înseamnă că va trebui să construim librăria doar în momentul în care vom ajunge să codăm pe LFSM (adică în chroot enviroment). Până atunci, trebuie să ne pregătim.

Chroot setup

Așa cum am spus înainte, atunci când vom ajunge să folosim LFSM va trebui să construim libstdc++ și toate celălalte programe ce depind de libstdc++. Cu toate astea, haideți să facem un inventar al lucrurilor pe care le avem în momentul de față care pot rula pe LFSM: *cricket sounds* și cam atâta... Nu avem prea multe...

Așa că trebuie să construim câteva. Înainte de a intra în LFSM va trebui să folosim ccPC-LFSM ca să compilăm niște programe ce ne vor face viața mai ușoară, mai exact: m4, ncurses, bash, coreutils, diffutils, file, findutils, gawk, grep, gzip, make, patch, sed, tar și xz. Acum că le-am compilat, vom construi noul binutils (folosind temporarul ccPC-LFSM) și compiler-ul ccLFSM-LFSM (folosind noul binutils și temporarul ccPC-LFSM). După ce am terminat cu astea două suntem gata să intrăm in chroot.

Chroot

A sosit acel moment în care revendicăm permisiunile, creăm foldere-le, montăm virtual file system-urile și introducem:

chroot "$LFS" /usr/bin/env -i   \
    HOME=/root                  \
    TERM="$TERM"                \
    PS1='(lfs chroot) \u:\w\$ ' \
    PATH=/usr/bin:/usr/sbin     \
    /bin/bash --login

Boom! Am intrat în lfs-chroot. Felicitări! Acum, hai să continuăm.

De notat este faptul că tot ce construim noi în chroot (adică LFSM) garantat nu depinde de PC. Știind asta, putem să ne asigurăm că toate programele care rulează pe LFSM vor rula pe LFSM. Vedeți voi, noi avem câteva instrumente (precum m4, tar, make...) care au fost compilate folosind ccPC-LFSM și nu ccLFSM-LFSM. Asta înseamnă că s-ar putea să depindă de librăriile de pe PC, librării ce siguranță nu se găsesc pe LFSM. Pentru a ne asigura că nu o să se întâmple acest dezastru, toate instrumentele de până acum (da, toate! ; adică gcc, glibc, m4, tar, make...) vor trebui să fie recompilate folosind ccLFSM-LFSM (mai puțin libstdc++, că el a fost deja construit cu ccLFSM-LFSM). Acesta este mai mult un sanity-check. Adevărul este că dacă am făcut o treabă bună cu ccPC-LFSM, ele ar trebui să fie independente față de PC și nu ar trebui să întâmpinăm niciun fel de erori la compilarea cu ccLFSM-LFSM. Totuși, în cazul în care apar erori, e posibil ca ceea ce am făcut noi cu ccPC-LFSM să nu fie tocmai corect ("trebuia să urmez instrucțiunile din carte...").

Lăsând asta de-o parte, primul lucru pe care îl construim este libstdc++. După aceea, construim gettext, bison, util-linux, perl, python și texinfo. Cartea spune că fac parte din temporary system, dar de fapt sunt niște versiuni mai degradate ale programelor finale, necesare rezolvării circular dependency-urilor.

The end

Odată ce am terminat și cu temporary system-ul, vine capitolul 8 în care recompilăm vechile instrumente și le compilăm pe cele noi. Apoi capitolul 9, în care edităm /etc-ul și în final capitolul 10, în care facem LFS-ul bootabil. După aceea... Beyond LFS =)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment