Algoritmos y Estructuras de Datos Herramientas Lenguaje de programación
!Prog C/C++ Rust
Linux Matemáticas
Mates Discretas
Programación Orientada a Objetos Sistemas Operativos

Instalación y compilación

[date: 30-07-2021 00:00] [last modification: 19-07-2023 13:48]
[words: 1082] [reading time: 6min] [size: 26975 bytes]

Guía de como instalar un compilador de C/C++. También se aportan algunas directrices de compilación de librerías así como su importación.

Nota
El proceso de compilación para C y C++ es prácticamente idéntico.

Instalación

Se debe instalar el determinado compilador para la plataforma. Si estás desarrollando en Windows, lo más común es instalar un editor especializado en C/C++ que ya tenga incorporado el compilador. La opción más popular y recomendada de Microsoft es Visual Studio. Alternativamente puedes usar MinGW, que emula el comportamiento de un compilador de Linux.

Si instalas MinGW debes añadirlo a la variable PATH (se instala por defecto en C:/MinGW y se debe de añadir su carpeta bin -> C:/MinGW/bin).

En Linux existen dos compiladores populares, gcc (GNU C Compiler) y clang (C Language). Este último es más reciente y pretende ser totalemente compatible con gcc, utilizando como backend LLVM.

El compilador de C y C++ de GCC y MinGW es gcc y g++ respectivamente; y el de clang es clang y clang++.

Para los siguientes ejemplos se usará gccy g++ (aunque las opciones y parámetros sean prácticamente las mismas) dado que también es compatible con clang.

Compilación básica

1gcc main.c   -o compilado.exe
2g++ main.cpp -o compilado.exe

Se le pasan los nombres de los archivos de código fuente (main.cpp o main.c) y para especificar el nombre del ejecutable con el parámetro -o (compilado.exe).

También se puede generalizar y especificar un patrón como *.cpp o src/*.cpp.

Versión de C++

Para especificar qué versión estamos usando se usa -std y (en el momento de escribir esto) hay las siguientes opciones:

Includes

Podemos usar cabeceras (de extensión .h o .hpp) añadiéndolas en el código simplemente:

1#include <cabecera.h>
2#include "cabecera.h"
3
4#include <cabecera.hpp>
5#include "cabecera.hpp"

Y si tenemos la librería dentro de un paquete o subpaquete, no hay nada más que hacer que especificar en dónde se encuentra:

1#include "paquete/cabecera.h"
2// Y variantes

Sin embargo, esto no es muy óptimo si la estructura del proyecto es un poco más complicada. Por ese motivo, se le puede indicar al compilador en qué directorios buscar.

1gcc -Ipaquete main.c   -o compilado.exe
2g++ -Ipaquete main.cpp -o compilado.exe

Por tanto, se puede simplemente especificar:

1#include "cabecera.h"
2// Y variantes

Errores y Warnings

Se recomiendan los siguientes argumentos para configurar los warnings y errores que genera el compilador:

Debug y Release

Por ahora, para la configuración debug compila con información de depuración usa la opción -g o -ggdb si usas GDB.

Y para release usa -O2 -DNDEBUG.

Código objeto

Cuando se trabaja con proyectos grandes, los tiempos de compilación se pueden volver bastante elevados. Por eso mismo, se compila cada archivo de código fuente a su propio binario (código objeto) y este solo se recompilará si se le hace algún cambio. De esta forma, se ahorra tener que recompilar siempre los mismos archivos que no cambiaron y que ya estaban compilados de iteraciones anteriores.

Esto se consigue con la opción -c, que compila y ensambla pero no llama al linker:

1gcc -c <src>.c
2g++ -c <src>.cpp

Por defecto, el nombre del archivo de salida será de <src>.o.

Estos archivos se pueden enviar directamente al compilador como si fuese código fuente normal, por ejemplo:

1gcc main.o suma.o resta.o -o mates.exe
2g++ main.o suma.o resta.o -o mates.exe

Crear una librería estática

Una librería estática es simplemente un archivo .zip que contiene el código objeto ya precompilado. Este se añade al ejecutable final directamente, por tanto, este será independiente del archivo de la librería: hacen un programa más manejable, un solo archivo.

Primero debemos compilar a código objeto y luego usar la herramienta ar para crear dicho .zip.

1gcc -c <source>.c
2g++ -c <source>.cpp
3ar sr lib<libraryname>.[lib|a] <sources>.o

Los argumentos de ar son:

Crear una librería dinámica

Se enlazan al iniciar el programa o de forma dinámica, mediante código, haciendo que el .exe sea más pequeño. Además, se pueden actualizar sin tener que recompilar y usar para programas diferentes.

Compilar librería:

1gcc -shared <sources>.c   -o <libraryname>.[dll|so]
2g++ -shared <sources>.cpp -o <libraryname>.[dll|so]

Usar librerías estáticas

Simplemente se puede listar el archivo de la librería como si fuese más código fuente o código objeto:

1gcc <sources> <libpath>/<library> -o <exe>
2g++ <sources> <libpath>/<library> -o <exe>

Nótese que el orden es importante, lo siguiente dará un error:

1gcc <librarypath>/<library> <sources> -o <exe> # ERROR
2g++ <librarypath>/<library> <sources> -o <exe> # ERROR

Alternativamente se pueden usar los argumentos -L y -l:

1gcc <sources> -L<librarypath> -l<libraryname> -o <exe>
2g++ <sources> -L<librarypath> -l<libraryname> -o <exe>

Con estos parámetros el nombre de la librería es importante, porque si se le da el argumento -l<xxx>, el compilador buscará en los directorios especificados un archivo de nombre lib<xxx>.a o lib<xxx>.so.

Y nótese que esto tampoco funciona:

1gcc -L<librarypath> -l<libraryname> <sources> -o <exe> # ERROR
2g++ -L<librarypath> -l<libraryname> <sources> -o <exe> # ERROR

Se puede forzar usar una librería estática (a veces se confunden por las dinámicas) con la opción -static.

Usar librerías dinámicas

Aparte de poder abrirlas en tiempo de ejecución mediante código (gracias a dlopen()), podemos añadirlas en tiempo de compilación. Esto resulta muy similar al uso de librerías estáticas:

 1gcc <sources> -L<librarypath> -l<library> -o <exe>
 2g++ <sources> -L<librarypath> -l<library> -o <exe>
 3
 4gcc <sources> <librarypath>/<library> -o <exe>
 5g++ <sources> <librarypath>/<library> -o <exe>
 6
 7# Recuerda que estos no funcionan:
 8gcc -L<librarypath> -l<library> <sources> -o <exe>
 9g++ -L<librarypath> -l<library> <sources> -o <exe>
10gcc <librarypath>/<library> <sources> -o <exe>
11g++ <librarypath>/<library> <sources> -o <exe>

Pero esto aún puede dar algunos problemas. Esto se debe a que la librería dinámica debe estar presente en el momento de ejecución, pero no hemos especificado donde. Eso se haría de la siguiente forma:

1gcc <sources> -Wl,-rpath,<runtime-library-path> -L<librarypath> -l<library> -o <exe>
2gcc <sources> -Wl,-rpath,<runtime-library-path> <librarypath>/<library> -o <exe>
3
4g++ <sources> -Wl,-rpath,<runtime-library-path> -L<librarypath> -l<library> -o <exe>
5g++ <sources> -Wl,-rpath,<runtime-library-path> <librarypath>/<library> -o <exe>

Explicación:

Anterior: Introducción Volver a C/C++ Siguiente: Sintaxis básica