Vai al contenuto

Compilare C++

Pubblicato:

C++ è un linguaggio compilato, il che significa che il codice che scrivi viene tradotto in codice macchina prima di essere eseguito. Sebbene la compilazione di un piccolo programma sia solitamente abbastanza indolore, le cose possono complicarsi quando il progetto cresce.

Librerie statiche e dinamiche

Quando compili un programma, puoi linkarlo a librerie. Ci sono due tipi di librerie: statiche e dinamiche.

Librerie statiche

Una libreria statica è un file che contiene del codice precompilato che può essere linkato a un programma durante la compilazione. Il codice viene copiato nel programma e il tutto viene meso insieme in un singolo file eseguibile. Per creare una libreria statica, puoi usare il comando ar. Questo genererà un archivio di file oggetto.

# Crea una libreria statica
ar rcs libmylib.a file1.o file2.o

Per elencare le librerie linkate staticamente ad un binario, puoi usare il comando nm.

nm -D binary

Librerie dinamiche

Una libreria dinamica è un file che contiene codice compilato che può essere linkato a un programma a runtime. Il codice non appare nel binario, ma questo è a conoscenza dell’interfaccia della libreria e può invocarne le funzioni esposte.

Per creare una libreria dinamica, puoi usare il comando gcc con l’opzione -shared.

# Crea una libreria dinamica
gcc -shared -o libmylib.so file1.o file2.o

Per controllare quali librerie il binario andrà a cercare durante la sua esecuzione, puoi usare il comando ldd.

# Controlla quali librerie sono linkate ad un binario
ldd binary

Su Windows, un’alternativa è usare l’utilità mingw-ldd, che può essere installata tramite pip. Dopo, basta eseguire il comando

mingw-ldd.exe binary --dll-lookup-dirs $env:GUROBI_HOME\bin 'C:\Program Files (x86)\Windows Kits\10\Redist\ucrt\DLLs\x64

dove --dll-lookup-dirs indica le cartelle in cui il software deve cercare le dll.
Altrimenti, la soluzione nativa, se Visual Studio è installato, è usare dumpbin da un prompt dei comandi per sviluppatori:

dumpbin /DEPENDENTS binary.exe

Metadati nei file Elf

RPATH

rpath indica il percorso di ricerca a runtime. È hard-coded nel file eseguibile o libreria. I loader di linking dinamico usano l’rpath per trovare le altre librerie richieste.

# Leggi l'rpath di una libreria
readelf -d bazel-bin/dlinear/libdlinear.so | grep 'R.*PATH'

SONAME

soname indica il nome della libreria condivisa. Viene solitamente considerato da altri binari per linkare la versione corretta della libreria condivisa a runtime.

# Leggi il SONAME
objdump -p libdlinear.so | grep SONAME

NEEDED

Quando un binario è linkato a delle librerie condivise, esse vengono contrassegnate come NEEDED nel binario per garantire che vengano caricate a runtime. Il campo NEEDED viene solitamente preso dal SONAME della libreria condivisa. Se il SONAME non è presente, il campo NEEDED sarà il percorso del file.

# Leggi il NEEDED
objdump -p libdlinear.so | grep NEEDED

Flag di compilazione

gcc

Flag generiche

Flag del preprocessore

Flag del linker

Flag di warning

Flag di ottimizzazione

Flag di debugging

Flag di sicurezza

Flag di dipendenza

MSVC

Flag generiche

Aggiungi intestazioni di sistema

Debugging

GDB

MSVC

Il debugger utilizzato da Visual Studio Code è abbastanza buono per la maggior parte delle attività di debugging. Tuttavia, se hai bisogno di funzionalità più avanzate (ad es. un problema nel linking di una libreria esterna), puoi utilizzare il debugger di Visual Studio. Per farlo, apri il Developer Command Prompt per Visual Studio (View > Terminal) ed esegui il seguente comando:

devenv /DebugExe <path_to_executable>

Si aprirà una nuova istanza di Visual Studio e potrai eseguire il debug dell’eseguibile come faresti in Visual Studio Code.