Přeskočit na hlavní obsah

Linkování

Když napíšeš program ve vyšším jazyce (např. C), překladač ho nejprve přeloží do objektových souborů (.o).
Každý objektový soubor obsahuje strojový kód, ale ještě není kompletní – mohou v něm chybět odkazy na jiné funkce nebo proměnné.

Proč rozdělujeme kód do více souborů?

Při psaní programu je praktické rozdělit kód do více souborů. Každý soubor může řešit jinou část programu – například jeden obsahuje hlavní funkci main, jiný matematické výpočty a další třeba ovládání hardwaru. Díky tomu je kód přehlednější, snadněji se udržuje a více programátorů na něm může pracovat současně.

Aby se z těchto částí stal fungující program, je potřeba je na konci spojit dohromady. Úkolem linkeru (spojovače) je tyto části poskládat dohromady a vytvořit spustitelný program.

Typy knihoven při linkování

  • Statické knihovny (.a)
    Kód se zkopíruje přímo do výsledného programu.
    Výhoda: není potřeba nic externího. Nevýhoda: větší velikost.

  • Dynamické knihovny (.so, .dll)
    Kód je načítán až při spuštění.
    Výhoda: menší velikost, sdílení knihoven. Nevýhoda: závislost na externím souboru.

Jak funguje linkování

  1. Překlad (compile)
    Zdrojový kód (např. main.c) → objektový soubor (main.o).
    V objektovém souboru mohou být:

    • definované funkce (např. main),
    • jen deklarované funkce (např. printf – víme, že existuje, ale není tam implementace).
  2. Linkování (link)
    Linker vezme všechny objektové soubory a knihovny (.o, .a, .so) a:

    • spojí je dohromady,
    • nahradí všechny odkazy správnými adresami,
    • vyhodí nevyužitý kód,
    • vytvoří výsledný spustitelný soubor (.elf, .exe).
  3. Výsledek
    Kompletní binární soubor, který se dá spustit nebo nahrát do mikrokontroléru.

Linkování v mikrokontrolérech

U MCU (bare-metal programování) linker navíc:

  • rozhoduje, kam se v paměti nahraje kód a data (flash, RAM, periferie),
  • řídí umístění přerušovacích tabulek,
  • vytváří výsledný .hex nebo .bin soubor pro nahrání do čipu.

To se určuje pomocí linker skriptů (.ld), které popisují rozložení paměti.

Příklad v C

Mějme dva zdrojové soubory:

main.c
#include <stdio.h>

void hello(void); // deklarace funkce z jiného souboru

int main(void) {
hello();
return 0;
}
hello.c
#include <stdio.h>

void hello(void) {
printf("Ahoj světe!\n");
}

1) Překlad

gcc -c main.c   # vytvoří main.o
gcc -c hello.c # vytvoří hello.o
  • main.o obsahuje volání hello, ale nezná jeho adresu.
  • hello.o obsahuje definici hello, ale ta ještě není propojená.

2) Linkování

gcc main.o hello.o -o program
  • najde symbol hello v hello.o,
  • propojí ho s voláním v main.o,
  • výsledek je spustitelný program program.

Header soubory (.h)

Když rozdělíme program do více souborů, je potřeba nějak sdílet informace mezi nimi.
Například když v jednom souboru definujeme funkci hello(), musí o ní ostatní soubory vědět – jinak překladač vyhlásí chybu.

K tomu slouží header soubory (.h):

  • Obsahují deklarace funkcí (říkají překladači, že funkce existuje někde jinde).
  • Mohou obsahovat i definice konstant, maker nebo struktur.
  • Při překladu se vkládají pomocí #include.
Příklad

hello.h

#ifndef HELLO_H
#define HELLO_H

void hello(void); // deklarace funkce

#endif

hello.c

#include <stdio.h>
#include "hello.h"

void hello(void) {
printf("Ahoj světe!\n");
}

main.c

#include "hello.h"

int main(void) {
hello(); // kompilátor ví, že funkce existuje díky deklaraci v hello.h
return 0;
}
Díky header souborům mohou různé části programu bezpečně spolupracovat