[itk] Számítástechnika kezdőknek

C++ programozás kezdőknek - fordítás parancssorban (Windows és Linux)

[2020. április 08.] [ christo161 ]

Ebben a részben arról lesz szó, hogy ha már van egy vagy több forrásfájlunk, akkor abból hogyan tudunk parancssort használva futtatható programot létrehozni.

linux_cli_execute.jpg

Ez a C++ programozás kezdőknek tananyag legelső részének folytatása.
Következő rész: az első program

Ennek a tananyagrésznek a tartalma:

Egyéb tudnivalók:

A parancssor egyik nagy előnye, hogy a használata általában nem sokat változik az évek során. Windowsban viszont a parancssoros fordítás előfeltételeinek telepítése, beállítása jellemzően nem parancssorban történik. Előfordulhat, hogy ennek a tananyagnak az elkészítése után fél évvel teljesen máshogy fog kinézni mondjuk a cygwin vagy a mingw telepítője. Nem ígérem, hogy amint bármi változás van, ezt a leírást módosítani fogom, de remélem, hogy programok telepítése senkinek nem okoz gondot.
És persze az is előfordulhat, hogy valaki esetleg váratlan hibaüzenetet kapjon valamelyik telepítés során, például azért, mert a számítógépén némileg eltérőek a rendszerbeállítások. Ez esetben rá kell keresni a hibaüzenetre az interneten, és ha kell, több megoldást is össze kell vetni az ott találtak közül.

Ha még nincs forrásfájlunk, és egy rövid példaprogrammal ki szeretnénk próbálni a parancssoros fordítást, akkor először nyissunk meg egy egyszerű szövegszerkesztőt (pl. jegyzettömb vagy gedit) vagy code editort (pl. Visual Studio Code vagy Notepad++), hozzunk létre egy új szöveges fájlt, amit mentsünk el mondjuk first_example_program.cpp néven (de természetesen más nevet is adhatunk neki, a lényeg, hogy a formátuma, vagy más néven kiterjesztése .cpp legyen).

Ebbe a fájlba másoljuk be a következő kódot:

#include <iostream>
int main() {
	std::cout << "Hello World!\n";
}

Természetesen mentsük is el a fájlt :)

Ezt követően tudjuk lefordítani, vagyis a futtatható programot létrehozni belőle. Ennek módja különböző operációs rendszereken némileg eltérő.

Bizonyos operációs rendszerek esetén elképzelhető, hogy alapból telepítve van C++ fordító, de jó eséllyel nekünk kell telepíteni. Több C++ fordító is létezik, talán a 3 legismertebb a g++, CLang, msvc. A tananyagban főként g++-t fogunk használni, ami a GCC része, illetve Windowson a MinGW része.
Esetleg érdemes tudni, hogy a Visual Studio msvc fordítóval dolgozik, de az msvc fordítót a Visual Studiotól függetlenül is telepíthetjük parancssoros fordításhoz, erről viszont ebben a tananyagban nem lesz szó, mint ahogy a CLang telepítéséről sem. Ha sokat foglalkozunk C++ programozással, elképzelhető, hogy később a g++ helyett más fordítóra is szükségünk lesz, de a tananyag legtöbb példaprogramja esetén tök mindegy, hogy milyen C++ fordítót használunk. Kezdőként szerintem nem érdemes egyszerre több C++ fordítót is feltelepíteni, de azért nem árt tudni, hogy nem csak a g++ létezik.

Fordítás parancssorban Windows operációs rendszereken:

A parancssorban történő fordításra Windowson több lehetőség is van. Néhány példa:

cygwin telepítése

Töltsük le a cygwin telepítőjét innen:

https://cygwin.com/install.html

Nyissuk meg a Windows beépített parancssorát.
Ezt például úgy tudjuk megtenni, hogy a billentyűzetünkön egyszerre megnyomjuk a windows gombot és az R billentyűt, majd a felugró ablakba beírjuk, hogy cmd, majd megnyomjuk a billentyűzetünkön az entert.

Lépjünk be a parancssorban abba a könyvtárba, ahova letöltöttük a cygwin telepítőjét. Ezt valami ilyesmi parancssal tehetjük meg:

cd c:\Users\felhasznalonev\Downloads\

Ha beléptünk a cygwin telepítőjét tartalmazó könyvtárba, ott futtassuk ezek közül a parancsok közül valamelyiket.

Válasszuk ezt, ha csak ki szeretnénk próbálni a  C++ forrásfájlok fordítását:

setup-x86_64.exe -P gcc-g++

Válasszuk ezt, ha a g++ fordító mellé szeretnénk telepíteni parancssoros szövegszerkesztőt (nano), fájlkezelőt (mc), debuggert/hibakeresőt (gdb), verziókezelőt (git)

setup-x86_64.exe -P gcc-g++ -P gdb -P git -P mc -P nano

Persze ennél akár több csomagot, programot is kiválaszthatunk akár parancssori paraméterként megadva, mint a fenti példákban, vagy akár a cygwin telepítőjénében kattintgatva. Az előbbire láthatunk még példát egy másik blogomon, mely a LibreOffice fejlesztéssel foglalkozik.
Jó tanács: ne telepítsünk fel mindenféle csomagot, programot, amit vélhetőleg nem is fogunk használni, mert sok helyet foglalnak, és lassítja a számítógépet, ha sok kis fájl van a háttértárolón.

cygwin_install_from_cmd.png

(Ha valamit elfelejtettünk telepíteni, később elindíthatjuk a cygwin telepítőjét, és ugyanígy telepíthetjük a hiányzó csomagokat, programokat, az újonnan elindított telepítő nem törli a már korábban telepített dolgokat.)

A cygwin telepítése innentől kezdve lényegében letudható a next, next, finish gombokra történő kattintgatással.

cygwin_install_from_cmd_5.png

A cygwin telepítőjében is kiválaszthatjuk a telepíteni kívánt csomagokat, programokat.

cygwin_install_from_cmd_8.png

cygwin_install_from_cmd_9.png

A cygwinben a Linux, és unix-szerű operációs rendszereken megszokott parancsokat és parancssori programokat használhatjuk... némi eltéréssel persze.

Fordítás cygwinben

A példaprogram kódjának beillesztése nano szövegszerkesztőben:

cygwin_nano_cpp_example.png

A példaprogram fordítása és futtatása cygwinben:

cygwin_cpp_compile_execute.png

A fordításhoz tehát a következő parancsot használhatjuk:

g++ forrasfajl.cpp -o futtathato_program_neve.exe

A parancssoros fordítás további lehetőségeiről ennek a résznek a végén, az egyéb tudnivalókban lehet olvasni.

A program futtatásánál az exe kiterjesztés elhagyható, viszont az aktuális könyvtárat ki kell írni:

./futtathato_program_neve

Annak ellenére, hogy a cygwin egy Linuxos parancsértelmezőt hivatott helyettesíteni, a fordítás eredménye, vagyis a futtatható program nem Linux bináris, mint a WSL esetében, hanem Windows bináris.

Ámdebár amit a cygwines g++-szal fordítunk, azt csak cygwinben fogjuk tudni futtatni, a cmd-ben például nem.

cygwin_cpp_compile_missing_dll.png

Ha olyan futtatható programot szeretnénk cygwinben fordítani, ami nem csak a cygwinben fut, akkor használjuk a cygwinen belül a MinGW g++ fordítóját.

Ehhez a mingw64-x86_64-gcc-core és mingw64-x86_64-gcc-g++ csomagokat telepítsük cygwinben:

cygwin_mingw_package.png

Ha az alap g++ csomagot nem telepítjük vagy töröljük, a mingw64-x86_64-gcc-g++ csomagot pedig telepítjük, akkor a g++ forrasfajl.cpp -o futtathato_program_neve.exe parancssal egy cygwintől függetlenül futtatható binárist generálunk, de ha mindkét fordító egyidejűleg telepítve van (a g++ és a mingw64-x86_64-gcc-g++), akkor használjuk a következő parancsot a cygwintől független futtatható program generálásához:

mingw32-g++ forrasfajl.cpp -o futtathato_program_neve.exe

Ezután a futtatható programot elindíthatjuk cmd-ben is.

cygwin_mingw_cpp_compile.png

Windows Subsystem for Linux telepítése

Ez a módszer legalább 16215-ös build verziójú Windows 10, vagy újabb operációs rendszeren működik.

A build verziót többféleképp is meg lehet nézni Windowsban. Egyik lehetőség, ha a Windows saját parancssorába (cmd.exe) beírjuk, hogy ver.
A cmd-t például úgy indíthatjuk el, hogy megnyomjuk egyszerre a billentyűzeten a windows gombot és az R billentyűt, majd a felugró ablakba beírjuk, hogy cmd utána pedig megnyomjuk az entert.

windows_build_version_cmd.png

Egy másik lehetőség, windows gomb + R, majd winver.

Indítsuk el a powershellt rendszergazda jogosultsággal.

windows_subsystem_for_linux_powershell.png

A powershellben futtassuk a következő parancsot:

Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux

Majd válasszuk a számítógép újraindítását.

windows_subsystem_for_linux_powershell_2.png

A Windows storeban keressünk rá valamelyik WSL által támogatott Linux disztribúcióra, például Debian vagy Ubuntu. Ebben a leírásban megtaláljuk, hogy miket használhatunk még.

windows_subsystem_for_linux_store_search.png

A választott Linux disztribúciót telepítsük fel.

windows_subsystem_for_linux_store_install.png

Majd indítsuk el.

windows_subsystem_for_linux_store_launch.png

Első indításkor adjuk meg a használni kívánt felhasználónevet és jelszót.

windows_subsystem_for_linux_adduser_passwd.png

Itt szintén a Linux és unix-szerű operációs rendszerek parancssorában megszokott parancsokat használhatjuk, de kicsit kevesebb korlátozással, mint a cygwinben. A cygwinben például nem működtek a csomagkezelők.

Telepítsük fel a fordításhoz szükséges csomagokat, programokat. Debian és Ubuntu alapú disztribúciókon például a következő parancssal:

sudo apt-get install build-essential

Más disztribúciókon előfordulhat, hogy az apt-től eltérő csomagkezelőt tudunk használni, például: yum, dnf, pacman.

windows_subsystem_for_linux_build_essential.png

Fordítás Windows Subsystem for Linuxban

A parancs, amivel fordíthatunk itt is hasonló, csak a futtatható program nevének a végére nem kell .exe kiterjesztés:

g++ forrasfajl.cpp -o futtathato_program_neve

A létrehozott indítható program viszont csak itt a WSL-ben, vagy Linux bashben futtatható, a Windows parancssorában (cmd), vagy a Windows fájlkezelőjében nem.

windows_subsystem_for_linux_cpp_example_compile.png

Előfeltételek telepítése a Windows beépített parancssorának (cmd) fordításhoz történő használatához

Természetesen a cmd-ben is csak akkor tudunk fordítani, ha előzőleg már feltelepítettünk valamilyen fordítót. Ez lehet akár egy fejlesztői környezet, például mondjuk a CodeBlocks által telepített fordító, de akár külön is telepíthetünk egyet.

A példaprogramok kipróbálásához teljesen megfelel például a MinGW, amit innen tölthetünk le:

http://www.mingw.org

Mivel nem olyan könnyű megtalálni, hogy hol kell letölteni, ezért feltöltöttem erről is néhány képernyőképet. Idővel persze lehet, hogy máshogy fog kinézni a MinGW honlapja.

mingw_download_01.png

mingw_download_02.png

A MinGW telepítője nem egészen a megszokott "next, next, finish"-szerű telepítő.

mingw_install_01.png

Nem kell mindent telepíteni, csak azt, amit használni is fogunk. Például ha nem tervezünk Adában, Fortranban, vagy Objective-C-ben programozni, akkor ezeknek a fordítóját teljesen felesleges telepíteni.

mingw_install_02.png

Next vagy finish gomb helyett elég szokatlan helyen található a telepítés lebonyolítását okozó menüpont :)

mingw_install_03.png

Ezt követően állítsuk be, hogy a parancssorban bármelyik könyvtárból elérhessük a g++ fordítót. Ehhez a rendszerbeállításokban (system settings) a path környezeti változóhoz (environment variable) hozzá adni a MinGW könyvtárán belüli bin könyvtárat.

A rendszerbeállításokat például a windows gomb + pause break billentyűkombinációval érhetjük el, vagy windows gomb + r, majd sysdm.cpl
Biztos sokan megtalálják billentyűkombinációk nélkül is, a billentyűkombinációkat csak azért szeretem, mert nem nagyon változnak a különböző Windows verziókban.

Kattintsunk a beállítások módosítása (change settings) ikonra.

windows_system_settings_01.png

Válasszuk a speciális (advanced) fült, majd kattintsunk a környezeti változók (environment variables) gombra.

windows_system_settings_02.png

Válasszuk ki a path változót majd kattintsunk a szerkesztés (edit) gombra. Ha egyedül használjuk a számítógépet, akkor mindegy, hogy a felhasználónevünkhöz tartozót, vagy az összes felhasználóhoz tartozót választjuk.

windows_system_settings_03.png

Kattintsunk a new gombra, majd írjuk be a MinGW könyvtárán belüli bin könyvtár elérési útját, majd természetesen okézzunk le mindent :)

windows_system_settings_04.png

Ha jól emlékszem, régebbi Windowsokban nem így külön sorba kellett beírni, hanem a path eddigi tartalmához hozzá kellett írni egy elválasztókaraktert (jelen esetben a pontosvessző), majd a szóban forgó könyvtár elérési útját.

Fordítás a Windows beépített parancssorában (cmd-ben)

Ezt követően elindíthatjuk a Windows parancssorát, vagy ha eddig már meg volt nyitva, újra kell indítani a változtatások érvénybelépéséhez.

Windows gomb + r, cmd

Lépjünk be abba a könyvtárba, ahol a lefordítandó cpp fájlunk található.
Itt futtassuk a következő parancsot:

g++ forrasfajl.cpp -o futtathato_program_neve.exe

windows_cmd_cpp_example_compile.png

A Windows parancssorában nem kell kiírni az aktuális könyvtár jelét az indítható fálj neve elé, vagyis nem kell ./ mint Linux/unix rendszereken, illetve az .exe kiterjesztést sem kell kiírni.

Fordítás parancssorban Linux operációs rendszereken:

Nyissunk meg egy parancssoros felületet (Ubuntuban például ctr+alt+t vagy ctr+alt+f3, mely utóbbi esetén (az Ubuntu verziójától függően) alt + f7 vagy alt + f1 billentyűkombinációval tudunk visszalépni grafikus felületre).

Linuxokon előfordulhat, hogy a c++ fordító (a g++, mely a GCC része) alapból telepítve van. Ezt a gcc -v vagy g++ -v parancsokkal tudjuk kideríteni.

gcc_not_installed.png

Debian és Ubuntu alapú Linux disztribúciókon használjuk a következő parancsot a C és C++ fordításhoz szükséges alapvető csomagok telepítéséhez.

sudo apt-get install build-essential

A build-essential csomag tartalma.

Természetesen a build-essential csomag helyett hasonlóképpen lehet telepíteni csak a g++-t.

Más Linux disztribúciókon elképzelhető, hogy az apt helyett más csomagkezelőket kell használni a telepítéshez, például yum, dnf, pacman.

apt_get_install_build_essentials.jpg

Ha a g++ fordító telepítve van, akkor valami ilyesmi kimenetet kéne látnunk a g++ -v parancs kimeneteként:

gcc_version.png

Ha a g++ fordító telepítve van, a fordításhoz lépjünk be abba a könyvtárba, ahol a lefordítandó cpp fájl található. Itt futtassuk a következő parancsot:

g++ forrasfajl.cpp -o futtathato_program_neve

A kimeneti fájlnak nem szükséges kiterjesztést adni (mint Windowsban), mivel a Linux alapú operációs rendszerek nem igénylik, hogy a fájlneveknek kiterjesztése legyen. Azért van mégis egyes fájloknak kiterjesztése Linuxon is, mivel vannak olyan alkalmazások, amik viszont igénylik a kiterjesztések használatát.

linux_gcc_cli_compile.jpg

A lefordított programot parancssorban így futtathatjuk:

./fájlnév

linux_cli_execute.jpg

Esetleg előfordulhat, hogy a lefordított fájlon nem lesz futtatási jog, és így hibaüzenetet kapunk az indítás megkísérlésekor. Erről úgy tudunk meggyőződni, hogy az ls -al parancs által megjelenített listában az adott fájlhoz tartozó első oszlop nem tartalmaz x karaktereket. Ekkor használjuk a chmod u+x ./fájlnév parancsot.

Egyéb tudnivalók

Milyen fájl az a.out?

Unix/Linux-szerű operációs rendszereken ha parancssoros fordításnál nem adjuk meg a futtatható program nevét, akkor az alapértelmezett (default) név a.out (assembly output) lesz. Ez egy futtatható fájl.

Tehát valami ilyesmi parancsnak az eredménye:

g++ forrasfajl.cpp

Windowsban a.out helyett a.exe jön létre.

Fordítás és linkelés

Előfordulhat, hogy bizonyos helyeken a futtatható program létrehozását két képésben végzik el, először elkészítik az object fájlt/fájlokat, majd az object fájlokból egy külön lépéssel hozzák létre a futtatható programot (ez utóbbit hívják linkelésnek, mivel a linker végzi el).

Parancssorban ez két külön parancsot jelent:

1. parancs
Unix/Linux-szerű operációs rendszereken:

g++ -c forrasfalj.cpp -o object_fajl_neve.o

1. parancs
Windowson:

g++ -c forrasfalj.cpp -o object_fajl_neve.obj

2. parancs

g++ object_fajl_neve.o -o futtathato_program_neve

Ügyejünk arra, hogy Linuxon .o, Windowson pedig .obj az object fájlok kiterjesztése, illetve Windowson .exe a futtatható fájlok kiterjesztése, Unix/Linux-szerű rendszereken viszont nem szükséges, hogy a futtatható fájloknak kiterjesztése legyen.

Másrészt arra is ügyeljünk, hogy ha object fájlt szeretnénk létrehozni, akkor a -c kapcsolót meg kell adnunk. Hiába írunk az -o kapcsoló után egy .o vagy .obj kiterjesztésű fájlt, ha nincs -c kapcsoló, akkor a sikeres fordítás végeredménye egy futtatható fájl lesz.

Az object fájlok nem futtatható fájlok. Például arra jók, hogy egy több forrásfájlból álló program esetén ha csak az egyik forrásfájlt módosítjuk, akkor csak abból a forrásfájlból kell újra object fájl létrehozni, a többiből nem. Vagyis ha csak egyetlen forrásfájlt módosítunk, nem kell újrafordítani azokat a fájlokat is, amiket nem is módosítottunk.

Több forrásfájlból álló programok

A tananyag elején egyelőre nem készítünk több forrásfájlból álló programokat, az ezzel kapcsolatos tudnivalókra a megfelelő tananyagrészben kitérünk.
Elöljáróban annyit el lehet mondani a témáról, hogy hasonló paranccsal fordíthatunk több fájlból álló programokat is, csak a különböző cpp fájlokat szóközzel egymástól elválasztva soroljuk fel. Az úgynevezett header fájlokat (.h, .hpp vagy .hxx kiterjesztésű fájlokat) ne soroljuk fel a bemeneti fájlok között.

A C++ nyelv különböző szabványai

C++11-es szabvány szerint érvényes kódrészletet tartalmazó forráskód esetén a fordításhoz használt parancsban a sikeres fordításhoz szerepelnie kell az std=c++11 kapcsolónak:

g++ -std=c++11 forrasfajl.cpp -o futtathato_program_neve

Hasonlóképp kell eljárnunk C++14, C++17 és C++20-as szabvány szerint érvényes forrásfájlokkal.

Gyakran használt g++ kapcsolók (angolul option)

-Wall: ne csak a fordítási hibákat (angolul error) írja ki a fordító, hanem a lényegesebb figyelmeztetéseket (angolul warning) is.

-Wextra: a fordító egyéb warningokat is írjon ki.

Fontos: a Wextra kapcsoló használata nem foglalja magában a Wall kapcsoló warningjait, ezért érdemes őket együtt használni.

Itt található egy lista, hogy a Wall és Wextra kapcsolók segítségével a fordító milyen warningokat mutat meg a kódban.
A Wall és Wextra kapcsolók együttes használata sem mutatja meg az összes lehetséges warningot. Vannak egyéb warningok is, amiket esetleg érdemes lehet debuggoláshoz használni a későbbiek során.

-g: a debug (nyomkövető) mód használatához szükséges információk elhelyezése az object fájlokban és az indítható állományban.

Néhány megjegyzés a -g kapcsolóval kapcsolatban:

  • Kerülendő a debug információkkal lefordított programot a felhasználóknak odaadni. Egyrészt mert lassabb, másrészt mert a program működése könnyebben visszafejthető.
    Persze ha mondjuk egy egyetemi beadandóról van szó, akkor jó eséllyel lényegtelen, hogy debug információkkal vagy anélkül adjuk oda a futtatható programot a tanárnak.
  • Ha már korábban fordítottuk a programunkat enélkül a kapcsoló nélkül, akkor előfordulhat, hogy törölnünk kell a korábban lefordított fájlokat ahhoz, hogy ez a beállítás érvénybe léphessen. És ez visszafele is igaz, vagyis ha már -g kapcsolóval fordítottuk a programot, de azt szeretnénk, hogy mégse kerüljenek bele a debug információk, akkor törölni kell a fordított fájlokat mielőtt -g kapcsoló nélkül elvégeznénk a fordítást.
  • Ha használjuk a -g kapcsolót, akkor ne használjunk optimalizációt (pl. -O3 kapcsoló), mert a debuggolás nem fog rendeltetésszerűen működni.

-pedantic: a fordító hibaüzenetben kiírja a kód nem szabványos részeit. Nem szabványos kódrészlet az, amit nem minden fordító tud futtathatóvá alakítani. Egy példa (VLA tömb):

int elemszam;
cin >> elemszam;
int tomb[elemszam];

A kód hordozhatósága miatt (ha esetleg más rendszeren vagy más fordítóval szeretnénk később dolgozni) javasolt a forráskódnak lehetőség szerint csak szabványos kódrészletet tartalmaznia.

-O3 (nem nulla, hanem nagy o betű): a fordító a sebességre optimalizálja a kódot.

-Os: a fordító az alacsony helyfoglalásra optimalizálja a kódot.

Ugyanazon optimalizációk más platformokon különböző eredményt fognak produkálni.

-fexceptions: kivételkezelés ( azaz try { } catch ( ) { } blokkok ) engedélyezése a forráskódban. Alapértelmezetten be van kapcsolva, viszont vannak olyan projektek, amikben ki van kapcsolva, ami gyorsít(hat)ja a programot.
Ha esetleg C++ kódban tiltani szeretnénk a kivételkezelést, akkor az -fno-exceptions kapcsolót használhatjuk.

A fordítás köztes lépéseinek eredményei:

A preprocesszálás, más néven előfeldolgozás vagy előfordítás eredményét kiíratjuk a parancssorba:

g++ -E forrasfajl.cpp

Ez általában több ezer sor, így érdemesebb inkább fájlba menteni:

g++ -E forrasfajl.cpp > fajlnev.txt

(Ha már létezik ilyen nevű fájl > jel esetén felülírja, >> jel esetén pedig az eddigi tartalmához hozzáfűzi).

gpp_e.png

Az assembly kóddá történő fordítás eredményét menjük el a fajlnev.s nevű fájlba:

g++ -S fajlnev.cpp

Teljesen más assembly kódot eredményez, ha optimalizációt is beállítunk, például:

g++ -O3 -S fajlnev.cpp

gpp_s.png

Az object fájllá történő fordítás eredményét kapjuk meg a -c kapcsolót használva, melyre kicsit fentebb láthatunk példát.

Egyéb

További kapcsolókról például itt lehet olvasni.

Következő rész: az első program

A bejegyzés trackback címe:

https://itkezdoknek.blog.hu/api/trackback/id/tr815599348

Kommentek:

A hozzászólások a vonatkozó jogszabályok  értelmében felhasználói tartalomnak minősülnek, értük a szolgáltatás technikai  üzemeltetője semmilyen felelősséget nem vállal, azokat nem ellenőrzi. Kifogás esetén forduljon a blog szerkesztőjéhez. Részletek a  Felhasználási feltételekben és az adatvédelmi tájékoztatóban.

Nincsenek hozzászólások.
süti beállítások módosítása