Cómo compilar y ejecutar C++ en macOS: guía práctica para Intel y Apple Silicon

Programar en C++ desde un Mac no requiere instalar un entorno pesado ni recurrir necesariamente a GNU GCC. macOS dispone de Apple Clang, el compilador incluido en las herramientas de desarrollo de Apple, junto con libc++ como biblioteca estándar de C++. Con las Command Line Tools instaladas es posible escribir, compilar, depurar y ejecutar programas C++ directamente desde Terminal tanto en Mac Intel como en equipos Apple Silicon con procesadores M1, M2, M3, M4 y generaciones posteriores.

Las claves para programar C++ en macOS en 20 segundos

  • Apple utiliza Clang como compilador C y C++, acompañado de libc++ como biblioteca estándar.
  • Las Command Line Tools pueden instalarse sin descargar el entorno completo de Xcode.
  • clang++ programa.cpp -o programa basta para compilar un ejemplo sencillo.
  • Los Mac Apple Silicon generan normalmente código ARM64 de forma nativa.
  • CMake, Homebrew, VS Code, Xcode y LLDB permiten ampliar el entorno para proyectos más grandes.

Para alguien acostumbrado a Linux, la experiencia resulta bastante familiar. El cambio principal está en el toolchain: muchos desarrolladores esperan encontrar GNU GCC y descubren que el entorno de Apple gira alrededor de Clang, LLVM, los SDK de macOS y herramientas como xcrun.

Hay además algunos detalles que conviene conocer desde el principio, especialmente si el código procede de Linux, utiliza bibliotecas externas o tiene que funcionar tanto en Intel x86-64 como en Apple Silicon ARM64.

Instalar el compilador C++ en macOS

La forma más sencilla de empezar es instalar las Command Line Tools for Xcode.

Desde Terminal:

xcode-select --install

macOS mostrará el diálogo correspondiente para descargar e instalar las herramientas.

Apple ofrece este paquete precisamente para quienes necesitan trabajar desde Terminal o compilar proyectos UNIX y multiplataforma sin instalar necesariamente la aplicación completa de Xcode. Incluye el SDK de macOS, páginas de manual y los binarios principales del toolchain.

Una vez terminado el proceso puede comprobarse dónde se encuentra el entorno activo:

xcode-select -p

Si solo están instaladas las Command Line Tools, una ubicación habitual es:

/Library/Developer/CommandLineTools

También puede verificarse la versión instalada:

pkgutil --pkg-info=com.apple.pkg.CLTools_Executables

Y comprobar el compilador:

clang++ --version

En un Mac Apple Silicon la salida debería indicar un objetivo similar a:

Target: arm64-apple-darwin...

Mientras que un Mac Intel utilizará normalmente:

Target: x86_64-apple-darwin...

Esto permite comprobar rápidamente para qué arquitectura se está generando el código.

¿Clang o GCC en macOS?

Aquí aparece una confusión bastante habitual.

En muchos sistemas Linux, C++ se compila mediante:

g++

En macOS la herramienta estándar es:

clang++

Apple soporta oficialmente C++ mediante Apple Clang y libc++. Ambos forman parte de su plataforma de desarrollo.

Clang es el frontend del proyecto LLVM y soporta múltiples versiones del estándar C++. El grado exacto de compatibilidad depende de la versión instalada: C++17 dispone de soporte completo desde hace años, mientras que C++20, C++23 y las características previstas para C++26 deben comprobarse individualmente porque no todas están necesariamente disponibles en cada versión de Clang o Apple Clang.

Por eso es mejor no asumir que instalar la última versión de macOS proporciona automáticamente soporte completo para todas las características del estándar más reciente.

Para conocer el compilador disponible:

clang++ --version

Y para localizarlo:

which clang++

También puede utilizarse xcrun, que resulta especialmente útil cuando existen varios SDK o instalaciones de Xcode:

xcrun --find clang++

Para consultar el SDK activo:

xcrun --show-sdk-path

Esto ayuda a entender una diferencia importante respecto a muchos entornos Linux: en macOS, compilador, SDK y versión objetivo del sistema operativo están estrechamente relacionados.

Crear, compilar y ejecutar el primer programa C++

El primer programa puede guardarse como hello.cpp:

#include <iostream>
#include <string>

int main()
{
    std::string name;
    int age;

    std::cout << "Enter your name: ";
    std::getline(std::cin, name);

    std::cout << "Enter your age: ";
    std::cin >> age;

    std::cout << "Hello " << name
              << ", you are " << age
              << " years old!\n";

    return 0;
}

Se ha utilizado std::getline() para el nombre en lugar de:

std::cin >> name;

porque esta segunda opción se detiene en el primer espacio. Con std::getline() pueden introducirse nombres completos.

Para compilar:

clang++ hello.cpp -o hello

Si no aparecen errores, se habrá generado un ejecutable:

hello

Puede comprobarse con:

ls -lh hello

Y ejecutarlo:

./hello

El prefijo ./ es necesario porque, por motivos de seguridad y funcionamiento tradicional de los sistemas Unix, el directorio actual no suele formar parte de la variable $PATH.

Si no se especifica el nombre:

clang++ hello.cpp

el compilador genera normalmente:

a.out

que puede ejecutarse con:

./a.out

Para aprender y mantener los proyectos organizados suele ser preferible utilizar siempre -o.

Elegir C++17, C++20 o C++23

Es recomendable declarar explícitamente el estándar utilizado por el proyecto.

Por ejemplo:

clang++ -std=c++17 hello.cpp -o hello

Para C++20:

clang++ -std=c++20 hello.cpp -o hello

Y para C++23:

clang++ -std=c++23 hello.cpp -o hello

La disponibilidad de una bandera no significa necesariamente que absolutamente todas las características de ese estándar estén implementadas. LLVM mantiene una tabla detallada con el estado de compatibilidad de Clang, mientras Apple publica además información específica sobre las características soportadas en sus plataformas.

Para un proyecto nuevo que no necesite características muy recientes, C++20 puede ser una elección razonable:

clang++ -std=c++20 hello.cpp -o hello

Compilar mejor: warnings, optimización y depuración

Para aprender C++ o trabajar en un proyecto real no conviene limitarse a:

clang++ hello.cpp

Los warnings del compilador pueden detectar errores antes de ejecutar el programa.

Una configuración sencilla para desarrollo sería:

clang++ -std=c++20 -Wall -Wextra -Wpedantic hello.cpp -o hello

Estas opciones activan diferentes grupos de advertencias.

También puede añadirse:

-Werror

para convertir warnings en errores:

clang++ -std=c++20 -Wall -Wextra -Wpedantic -Werror hello.cpp -o hello

Es una política útil en algunos proyectos y sistemas de integración continua, aunque durante el desarrollo puede resultar demasiado estricta dependiendo del código y las bibliotecas utilizadas.

Compilar para depuración

Para generar información útil para un debugger:

clang++ -std=c++20 -Wall -Wextra -g hello.cpp -o hello

La opción:

-g

incluye información de depuración.

macOS incluye LLDB, el debugger del proyecto LLVM.

Puede iniciarse con:

lldb ./hello

Dentro de LLDB:

run

ejecuta el programa.

También pueden colocarse breakpoints:

breakpoint set --name main

o utilizando su forma abreviada:

b main

Después:

run

El programa se detendrá al llegar a main().

Compilar una versión optimizada

Clang dispone de diferentes niveles de optimización:

-O0
-O1
-O2
-O3
-Os

Para desarrollo suele utilizarse -O0 o una optimización moderada.

Para una versión optimizada:

clang++ -std=c++20 -O2 hello.cpp -o hello

-O3 aplica optimizaciones más agresivas:

clang++ -std=c++20 -O3 hello.cpp -o hello

Más optimización no significa automáticamente que cualquier programa vaya a ser más rápido. La decisión debe tomarse según el proyecto y, cuando el rendimiento sea importante, mediante benchmarks.

Una configuración práctica durante el desarrollo

Un comando bastante razonable sería:

clang++ -std=c++20 -Wall -Wextra -Wpedantic -g hello.cpp -o hello

Mientras que para una compilación optimizada podría utilizarse:

clang++ -std=c++20 -Wall -Wextra -Wpedantic -O2 hello.cpp -o hello

Apple Silicon cambia algunas cosas que conviene conocer

Los Mac modernos utilizan procesadores Apple Silicon basados en ARM64.

Para comprobar la arquitectura:

uname -m

En Apple Silicon:

arm64

En un Mac Intel:

x86_64

También puede analizarse un ejecutable recién compilado:

file ./hello

En Apple Silicon debería aparecer una descripción similar a:

Mach-O 64-bit executable arm64

En Intel:

Mach-O 64-bit executable x86_64

Esto se vuelve especialmente importante cuando se incorporan bibliotecas externas.

Un programa ARM64 no puede enlazar directamente con una biblioteca disponible únicamente para x86-64.

Ese es uno de los motivos por los que algunos proyectos antiguos presentan errores de compilación o linking después de migrarlos desde un Mac Intel a Apple Silicon.

Compilar explícitamente para ARM64

Puede indicarse la arquitectura:

clang++ -arch arm64 hello.cpp -o hello

Para Intel:

clang++ -arch x86_64 hello.cpp -o hello

La segunda opción solo funcionará correctamente cuando las bibliotecas y SDK necesarios estén disponibles para esa arquitectura.

macOS también permite crear Universal Binaries que contienen código para más de una arquitectura.

Conceptualmente pueden compilarse ambas versiones:

clang++ -arch arm64 hello.cpp -o hello-arm64
clang++ -arch x86_64 hello.cpp -o hello-x86_64

Y combinarse mediante:

lipo -create hello-arm64 hello-x86_64 -output hello-universal

Después:

file hello-universal

permite comprobar las arquitecturas incluidas.

Para un programa personal ejecutado únicamente en un Mac Apple Silicon normalmente no hace falta hacer nada de esto. Clang seleccionará automáticamente la arquitectura nativa.

Por qué bits/stdc++.h falla en macOS

Una de las sorpresas más frecuentes al copiar ejemplos C++ procedentes de Internet es encontrar:

#include <bits/stdc++.h>

y recibir un error parecido a:

fatal error: 'bits/stdc++.h' file not found

El problema no es C++ ni macOS.

bits/stdc++.h no forma parte del estándar C++. Es una cabecera asociada habitualmente a implementaciones de GNU libstdc++ y se utiliza mucho en programación competitiva porque incluye una gran cantidad de cabeceras de una sola vez.

Apple utiliza Clang con libc++, por lo que no debería dependerse de esa cabecera.

En su lugar hay que incluir exactamente lo que utiliza el programa:

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>

Esto tiene además una ventaja de portabilidad: el código deja de depender de una característica específica de una implementación.

Un programa que utilice:

std::vector
std::sort
std::string
std::cout

debería declarar:

#include <vector>
#include <algorithm>
#include <string>
#include <iostream>

La regla práctica es sencilla: si se pretende escribir C++ portable entre macOS, Linux y Windows, conviene utilizar cabeceras estándar.

Instalar bibliotecas C++ externas en macOS

Los programas reales suelen necesitar algo más que la biblioteca estándar.

Aquí aparece Homebrew como una opción habitual para instalar dependencias.

Por ejemplo, si un proyecto necesita Boost:

brew install boost

Para OpenSSL:

brew install openssl

Para CMake:

brew install cmake

Sin embargo, instalar una biblioteca no significa que Clang vaya a encontrarla automáticamente.

Puede ser necesario indicar rutas de cabeceras y bibliotecas:

clang++ main.cpp \
  -I/ruta/include \
  -L/ruta/lib \
  -lmi_biblioteca \
  -o programa

Las opciones principales son:

OpciónFunción
-IAñade una ruta de cabeceras
-LAñade una ruta de bibliotecas
-lIndica una biblioteca que debe enlazarse
-std=Selecciona el estándar C++
-oDefine el nombre del ejecutable
-gAñade información de depuración
-O2Activa optimizaciones
-WallActiva warnings habituales

En proyectos grandes escribir manualmente todos estos parámetros deja de ser práctico. Ahí entra CMake.

Pasar de un archivo a un proyecto con CMake

Para un único hello.cpp, Clang es suficiente.

Cuando aparecen diez, cien o miles de archivos, bibliotecas y configuraciones diferentes, interesa utilizar un sistema de build.

CMake es una de las opciones más extendidas en proyectos C++ multiplataforma.

Una estructura sencilla podría ser:

myproject/
├── CMakeLists.txt
└── src/
    └── main.cpp

El archivo CMakeLists.txt:

cmake_minimum_required(VERSION 3.20)

project(MyProject LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_executable(myapp src/main.cpp)

Después:

mkdir build
cd build
cmake ..
cmake --build .

O utilizando el enfoque moderno:

cmake -S . -B build
cmake --build build

El ejecutable aparecerá dentro del directorio de compilación.

Este modelo tiene una ventaja importante si se trabaja simultáneamente con macOS y Linux: el proyecto deja de depender de una colección de comandos manuales específicos de cada ordenador.

Clang, Xcode, VS Code o solo Terminal

No es obligatorio instalar Xcode completo para programar C++.

EntornoCuándo puede interesar
Terminal + ClangAprendizaje, scripts, pequeños proyectos
VS Code + ClangDesarrollo general y multiplataforma
XcodeSoftware especialmente integrado con plataformas Apple
CLionProyectos C++ grandes y CMake
Vim/Neovim + ClangEntornos centrados en Terminal

Las Command Line Tools son suficientes para numerosos proyectos C++.

Xcode completo empieza a ser necesario cuando se utilizan determinadas herramientas que Apple distribuye únicamente con el IDE. Por ejemplo, Apple indica que xcodebuild y otras utilidades específicas no forman parte del paquete independiente de Command Line Tools.

Errores habituales al compilar C++ en macOS

clang++: command not found

Conviene comprobar primero:

xcode-select -p

Si las herramientas no están instaladas:

xcode-select --install

'bits/stdc++.h' file not found

Hay que sustituir esa cabecera no estándar por las cabeceras C++ que realmente utilice el programa.

Undefined symbols for architecture arm64

Este error suele indicar un problema durante el enlazado.

Puede existir una biblioteca que no se está enlazando correctamente o una dependencia compilada para una arquitectura diferente.

Conviene comprobarla con:

file /ruta/a/libbiblioteca.dylib

o:

lipo -info /ruta/a/libbiblioteca.dylib

El programa compila en Linux pero no en macOS

No todo lo disponible en Linux forma parte de C++ estándar.

El programa puede depender de:

  • GNU-specific headers;
  • APIs propias de Linux;
  • llamadas al sistema;
  • bibliotecas que no están instaladas;
  • rutas de filesystem específicas;
  • o extensiones particulares de GCC.

En ese caso el problema no es necesariamente Clang. Puede ser simplemente que el código no sea portable.

library not found

Hay que comprobar dónde está instalada la biblioteca y pasar la ruta correspondiente mediante -L, además de enlazarla mediante -l.

header file not found

El equivalente para las cabeceras suele solucionarse indicando su ubicación:

clang++ main.cpp -I/ruta/include -o programa

Un pequeño entorno C++ completo en menos de cinco minutos

Para alguien que acaba de recibir un Mac y simplemente quiere empezar:

xcode-select --install

Comprobar:

clang++ --version

Crear:

nano hello.cpp

Introducir:

#include <iostream>

int main()
{
    std::cout << "Hello from C++ on macOS!\n";
    return 0;
}

Compilar:

clang++ -std=c++20 -Wall -Wextra -Wpedantic hello.cpp -o hello

Ejecutar:

./hello

Comprobar qué se ha generado:

file ./hello

Y si hay que depurarlo:

clang++ -std=c++20 -g hello.cpp -o hello
lldb ./hello

Con estos pasos ya existe un entorno C++ completamente funcional sin necesidad de abrir un IDE.

Para proyectos más grandes el siguiente paso razonable es incorporar CMake, Git, un editor con soporte para clangd y un gestor de dependencias adecuado al proyecto.

macOS no intenta reproducir exactamente el entorno GNU habitual de muchas distribuciones Linux. Su toolchain gira alrededor de Apple Clang, LLVM, libc++, LLDB y los SDK de Apple. Entender esa diferencia evita buena parte de los problemas que aparecen al trasladar código C++ entre ambos sistemas.

Preguntas frecuentes

¿Qué compilador C++ utiliza macOS?

Apple utiliza Apple Clang como compilador C++ oficial de sus herramientas de desarrollo y libc++ como implementación de la biblioteca estándar. Ambos están disponibles mediante Xcode y las Command Line Tools.

¿Es necesario instalar Xcode completo para programar C++ en Mac?

No. Para compilar programas C++ desde Terminal suele ser suficiente instalar las Command Line Tools con xcode-select --install. Xcode completo resulta útil o necesario para determinadas herramientas y proyectos específicos de las plataformas Apple.

¿Cómo se compila un archivo C++ en macOS?

Un ejemplo sencillo puede compilarse con clang++ hello.cpp -o hello y ejecutarse posteriormente con ./hello. Puede añadirse -std=c++20 o el estándar que necesite el proyecto.

¿Por qué bits/stdc++.h no funciona en macOS?

Porque no es una cabecera estándar de C++. Está asociada principalmente al entorno GNU libstdc++ y no forma parte de libc++, utilizada por Apple. Para escribir código portable deben incluirse las cabeceras estándar necesarias individualmente.

Fuentes:

  • Apple Developer Documentation, Installing the Command Line Tools for Xcode.
  • Apple Developer, C++ Language Support.
  • Apple Developer Documentation, Xcode Command-Line Tools.
  • LLVM Project, C++ Support in Clang.
Scroll al inicio