Mustand: sisu ei ole veel tehniliselt ega keeleliselt täielikult kontrollitud ega toimetatud.

Peatüki vaade

Linux/Unix/macOS käsurea kiirõpik

Praegu loed peatükki Kompileerimine ja käivitamine: shell, Python, C, C++, Go, Rust, Java, mis kuulub osasse Osa V: Arendus ja töövood.

Kompileerimine ja käivitamine: shell, Python, C, C++, Go, Rust, Java

Selles peatükis võrdleme lühidalt, kuidas eri keelte programmid sünnivad ja käivituvad.

Loogika

See peatükk ei ole mõeldud nende keelte õppimiseks, vaid ühe väga praktilise vahe mõistmiseks:

  • mõni fail käivitatakse tõlgendiga otse
  • mõni fail kompileeritakse kõigepealt teise vormi
  • mõni tulemus on päris binaar
  • mõni tulemus vajab eraldi runtime'i või virtuaalmasinat

See teema seob kokku:

  • shebang'i ja käivitatavad skriptid
  • PATH-i ja käskude leidmise
  • Dockeri ja builditööriistad
  • LaTeX-i kompileerimise idee

Kiirspikker

  • sh hello.sh käivitab shelliskripti
  • python3 hello.py käivitab Pythoni faili
  • cc hello.c -o hello-c kompileerib C programmi
  • c++ hello.cpp -o hello-cpp kompileerib C++ programmi
  • go run hello.go kompileerib ja käivitab Go näite
  • go build -o hello-go hello.go ehitab Go binaari
  • cargo run ehitab ja käivitab Rusti projekti
  • javac Hello.java kompileerib Java klassi
  • java Hello käivitab Java klassi JVM-is

Kõige tavalisemad käsud

  • sh skript.sh
  • ./skript.sh
  • python3 hello.py
  • cc hello.c -o hello-c
  • c++ hello.cpp -o hello-cpp
  • go build -o hello-go hello.go
  • cargo build
  • cargo run
  • javac Hello.java
  • java Hello

Üks kiire võrdlustabel

| Keel | Lähtefail | Tüüpiline käivitus | Mis tekib | | --- | --- | --- | --- | | Shell | hello.sh | sh hello.sh või ./hello.sh | tavaliselt eraldi buildi ei teki | | Python | hello.py | python3 hello.py | lähtefail, mõnikord __pycache__ | | C | hello.c | ./hello-c pärast kompileerimist | päris binaar | | C++ | hello.cpp | ./hello-cpp pärast kompileerimist | päris binaar | | Go | hello.go | go run hello.go või ./hello-go | päris binaar | | Rust | src/main.rs | cargo run või binaar target/ all | päris binaar + target/ | | Java | Hello.java | java Hello | .class fail, käivitus JVM-is |

Shell: skript ja shebang

Shelli näide on kõige lihtsam, sest see on lihtsalt tekstifail, mida loeb shell.


cat > hello.sh <<'EOF'
#!/bin/sh
echo "Tere, maailm!"
echo "Tere, maailm!"
echo "Tere, maailm!"
EOF
chmod +x hello.sh
./hello.sh

Siin:

  • fail on tavaline tekstifail
  • chmod +x lubab selle käivitada
  • shebang #!/bin/sh ütleb, milline shell faili tõlgendab

Teine võimalus on:


sh hello.sh

Siis valid shelli käsurealt ise.

Python: tõlgendatud käivitus

Pythoni näide näeb välja samuti lihtne, aga erinevalt shellist käivitad sa tavaliselt faili Pythoni tõlgendiga.


cat > hello.py <<'EOF'
for _ in range(3):
    print("Tere, maailm!")
EOF
python3 hello.py

Siin:

  • lähtefail jääb tekstifailiks
  • python3 loeb selle sisse ja käivitab
  • tavaliselt ei teki kohe samas mõttes eraldi käivitatavat binaari

C: kompileeri binaariks

C on klassikaline näide keelest, kus lähtekood tuleb kõigepealt kompileerida.


cat > hello.c <<'EOF'
#include <stdio.h>

int main(void) {
    for (int i = 0; i < 3; i++) {
        puts("Tere, maailm!");
    }
    return 0;
}
EOF
cc hello.c -o hello-c
./hello-c

Siin:

  • hello.c on lähtefail
  • cc ... -o hello-c teeb sellest binaari
  • ./hello-c käivitab juba kompileeritud programmi

See on oluline vahe võrreldes shelli või Pythoniga: enne käivitamist tuleb ehitada eraldi käivitatav fail.

C++: sarnane C-ga, aga teise kompilaatoriga


cat > hello.cpp <<'EOF'
#include <iostream>

int main() {
    for (int i = 0; i < 3; i++) {
        std::cout << "Tere, maailm!" << std::endl;
    }
    return 0;
}
EOF
c++ hello.cpp -o hello-cpp
./hello-cpp

Loogika on sama nagu C puhul:

  • lähtekood
  • kompileerimine
  • binaar

Go: lihtne tee ühe binaarini

Go on käsureaõppe jaoks väga tänulik näide, sest buildi loogika on sirge.


cat > hello.go <<'EOF'
package main

import "fmt"

func main() {
    for i := 0; i < 3; i++ {
        fmt.Println("Tere, maailm!")
    }
}
EOF
go run hello.go
go build -o hello-go hello.go
./hello-go

Siin on kaks eri tööviisi:

  • go run kompileerib ja käivitab ühe hooga
  • go build teeb päris binaari

See teeb Go-st väga hea näite, kui tahad näha vahet "jooksuta kohe" ja "ehita fail valmis".

Rust: builditööriist on osa tavalisest töövoost

Rustis kasutatakse väga sageli tööriista cargo.


mkdir -p hello-rust
cd hello-rust
cargo init --bin .
cat > src/main.rs <<'EOF'
fn main() {
    for _ in 0..3 {
        println!("Tere, maailm!");
    }
}
EOF
cargo run
cargo build --release
./target/release/hello-rust

Siin:

  • cargo init --bin . teeb projekti karkassi
  • cargo run ehitab ja käivitab
  • cargo build --release teeb optimeerituma binaari

Rusti näide on hea, sest siin on juba näha, et mõnes keeles ei käi build ainult ühe kompilaatorikäsuga, vaid terve töövoo kaudu.

Java: kompileerimine ja eraldi runtime

Java on hea kontrast C-le ja Go-le, sest kompileerimine toimub küll enne, aga tulemus ei ole tavaliselt otse natiivne binaar.


cat > Hello.java <<'EOF'
public class Hello {
    public static void main(String[] args) {
        for (int i = 0; i < 3; i++) {
            System.out.println("Tere, maailm!");
        }
    }
}
EOF
javac Hello.java
java Hello

Siin:

  • javac teeb failist Hello.class
  • java Hello käivitab selle JVM-is

See on oluline vahe:

  • C, C++, Go ja Rust annavad sulle tavaliselt natiivse binaari
  • Java annab sulle klassifaili, mida käitab Java runtime

Millal tekib mis asi

Hea meelespea on:

  • shell: tekstifail, mida tõlgendatakse
  • Python: tekstifail, mida tõlgendatakse
  • C/C++: natiivne binaar
  • Go: natiivne binaar
  • Rust: natiivne binaar, mida haldab cargo
  • Java: baitkood, mida käitab JVM

Just see on põhjus, miks nende keelte buildi- ja käivitusloogika erineb.

Praktiline soovitus

Kui tahad mõtet kiiresti kätte saada, mine selles järjekorras:

  1. shell
  2. Python
  3. C
  4. Go
  5. Rust
  6. Java

See järjekord liigub lihtsast tõlgendamisest kuni keerukama builditööriista ja runtime'i loogikani.

Minitest

  1. Tee shelliskript, mis prindib sama rea kolm korda.
  2. Tee sama Pythonis.
  3. Kompileeri väike C programm ja käivita see.
  4. Võrdle go run ja go build käitumist.
  5. Vaata, mis fail tekib pärast javac Hello.java.
  6. Selgita ühe lausega, miks Java erineb C-st käivitamise mõttes.