TOOLCHAIN_PHILOSOPHY.md¶
La Alquimia de la Compilación Multiplataforma¶
Toolchains, Cross-Compilation y ABI Compatibility¶
🎯 PROPÓSITO DE ESTE DOCUMENTO¶
Este documento explora la filosofía y arquitectura de toolchains para compilación multiplataforma. No es una guía de instalación o configuración, sino una exploración conceptual profunda de:
- Qué ES un toolchain como organismo técnico
- Cómo funciona la cross-compilation filosóficamente
- Las diferencias fundamentales entre plataformas
- El contrato binario (ABI) y por qué importa
- Estrategias de abstracción para AudioLab
NO encontrarás aquí: - Comandos de instalación de compiladores - Configuraciones específicas de CMake - Procedimientos de setup paso a paso
SÍ encontrarás: - Anatomía completa de un toolchain - Paradigmas de compilación (native, cross, canadian) - Landscape de toolchains por plataforma - ABI compatibility profundo - Matrices de decisión para AudioLab
📖 ÍNDICE¶
CAPÍTULO 1: Anatomía de un Toolchain¶
1.1 El Ecosistema Completo 1.2 Compiler: El Transformador 1.3 Linker: El Unificador 1.4 Standard Library: El Fundamento 1.5 Utilities y SDK: El Contexto
CAPÍTULO 2: Native vs Cross Compilation¶
2.1 Paradigmas de Compilación 2.2 Native Compilation: Simplicidad 2.3 Cross Compilation: Poder y Complejidad 2.4 Canadian Cross: El Meta-Nivel 2.5 Challenges de Cross-Compilation
CAPÍTULO 3: Toolchain Landscape por Plataforma¶
3.1 Windows Ecosystem (MSVC vs MinGW) 3.2 macOS Ecosystem (Apple Clang y Universal Binaries) 3.3 Linux Ecosystem (GCC vs Clang) 3.4 Fragmentation y Estrategias de Compatibilidad
CAPÍTULO 4: ABI Compatibility - El Contrato Binario¶
4.1 API vs ABI: La Distinción Crítica 4.2 Name Mangling: El Problema de Nombres 4.3 Calling Conventions: Cómo Hablan las Funciones 4.4 Object Layout y Virtual Tables 4.5 Cross-Platform ABI Challenges
CAPÍTULO 5: AudioLab Toolchain Strategy¶
5.1 Matriz de Decisiones por Plataforma 5.2 CMake Toolchain File Concept 5.3 CI/CD Pipeline Integration 5.4 Testing Across Toolchains
CAPÍTULO 6: Sysroots y Isolation¶
6.1 El Concepto de Sysroot 6.2 Build vs Host vs Target 6.3 Dependency Management 6.4 Containerization Strategy
CAPÍTULO 7: Future-Proofing¶
7.1 Evolución de Toolchains 7.2 WebAssembly como Target 7.3 LLVM como Universal Backend 7.4 Estrategias de Longevidad
CAPÍTULO 1: Anatomía de un Toolchain¶
1.1 El Ecosistema Completo¶
Un toolchain no es una herramienta, es un ecosistema de componentes interdependientes que transforman código fuente en ejecutables.
┌─────────────────────────────────────────────────────────────┐
│ 🔧 TOOLCHAIN COMO ORGANISMO COMPLEJO │
└─────────────────────────────────────────────────────────────┘
┌─────────────────┐
│ SOURCE CODE │
│ main.cpp │
└────────┬────────┘
│
▼
┌────────────────────────────────┐
│ 🎯 TARGET SPECIFICATION │
│ │
│ "Para qué plataforma?" │
│ x86_64-pc-windows-msvc │
│ aarch64-apple-darwin │
│ x86_64-unknown-linux-gnu │
└────────────────────────────────┘
│
┌────────────────────┼────────────────────┐
│ │ │
▼ ▼ ▼
┌───────────────┐ ┌───────────────┐ ┌───────────────┐
│ 🔨 COMPILER │ │ 📚 STDLIB │ │ 🎨 SDK │
│ │ │ │ │ │
│ Transforma │ │ Implementa │ │ Headers del │
│ código → │ │ lenguaje │ │ sistema │
│ objetos │ │ estándar │ │ operativo │
└───────┬───────┘ └───────┬───────┘ └───────┬───────┘
│ │ │
│ │ │
└────────────────────┼────────────────────┘
│
▼
┌───────────────┐
│ 🔗 LINKER │
│ │
│ Combina │
│ objetos → │
│ ejecutable │
└───────┬───────┘
│
▼
┌───────────────┐
│ EXECUTABLE │
│ app.exe │
│ app.out │
└───────────────┘
Componentes del Ecosistema¶
┌─────────────────────────────────────────────────────────────┐
│ COMPONENTES DE UN TOOLCHAIN COMPLETO │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 🎯 TARGET SPECIFICATION │
│ └─ Define la plataforma objetivo │
│ │
│ Architecture: x86_64, ARM64, ARM32, RISC-V │
│ Vendor: PC, Apple, Unknown, NVIDIA │
│ OS: Windows, Darwin, Linux, None │
│ ABI: MSVC, GNU, EABI, Android │
│ │
│ Representación: "Target Triple" │
│ ┌──────────────────────────────────────────────┐ │
│ │ x86_64 - pc - windows - msvc │ │
│ │ ▲ ▲ ▲ ▲ │ │
│ │ │ │ │ │ │ │
│ │ arch vendor OS ABI │ │
│ └──────────────────────────────────────────────┘ │
│ │
│ Ejemplos: │
│ • x86_64-pc-windows-msvc (Windows 64-bit MSVC) │
│ • x86_64-w64-mingw32 (Windows MinGW) │
│ • aarch64-apple-darwin (macOS Apple Silicon) │
│ • x86_64-apple-darwin (macOS Intel) │
│ • x86_64-unknown-linux-gnu (Linux con glibc) │
│ • arm-unknown-linux-gnueabihf (Linux ARM hard float) │
│ • wasm32-unknown-unknown (WebAssembly) │
│ │
│ 2. 🔨 COMPILER │
│ └─ Transforma código fuente → código objeto │
│ │
│ Pipeline interno: │
│ Source → Tokens → AST → IR → Assembly → Object │
│ │
│ Componentes: │
│ ┌─────────────────────────────────┐ │
│ │ FRONTEND │ │
│ │ ├─ Lexer: "float x" → [TOK] │ │
│ │ ├─ Parser: TOK → AST │ │
│ │ └─ Sema: Type checking │ │
│ ├─────────────────────────────────┤ │
│ │ MIDDLE-END (Optimizer) │ │
│ │ ├─ IR generation │ │
│ │ ├─ Optimization passes │ │
│ │ └─ Target-independent opts │ │
│ ├─────────────────────────────────┤ │
│ │ BACKEND (Code Generator) │ │
│ │ ├─ Instruction selection │ │
│ │ ├─ Register allocation │ │
│ │ └─ Assembly emission │ │
│ └─────────────────────────────────┘ │
│ │
│ 3. 🔗 LINKER │
│ └─ Combina object files → ejecutable │
│ │
│ Responsabilidades: │
│ ┌─────────────────────────────────┐ │
│ │ Symbol Resolution │ │
│ │ ├─ Find definitions │ │
│ │ ├─ Match references │ │
│ │ └─ Error on undefined │ │
│ ├─────────────────────────────────┤ │
│ │ Relocation │ │
│ │ ├─ Fix absolute addresses │ │
│ │ └─ Apply relocations │ │
│ ├─────────────────────────────────┤ │
│ │ Section Merging │ │
│ │ ├─ .text → code │ │
│ │ ├─ .data → initialized data │ │
│ │ ├─ .bss → zero-init data │ │
│ │ └─ .rodata → read-only data │ │
│ ├─────────────────────────────────┤ │
│ │ Format Generation │ │
│ │ ├─ PE (Windows) │ │
│ │ ├─ Mach-O (macOS) │ │
│ │ └─ ELF (Linux) │ │
│ └─────────────────────────────────┘ │
│ │
│ 4. 📚 STANDARD LIBRARY │
│ └─ Implementación del lenguaje │
│ │
│ C++ Standard Library: │
│ ├─ libstdc++ (GCC) │
│ ├─ libc++ (LLVM/Clang) │
│ └─ MSVC STL (Microsoft) │
│ │
│ C Standard Library: │
│ ├─ glibc (Linux GNU) │
│ ├─ musl (Linux minimal) │
│ ├─ MSVCRT (Windows) │
│ └─ libSystem (macOS) │
│ │
│ Runtime Support: │
│ ├─ Exception handling │
│ ├─ RTTI (Run-Time Type Information) │
│ ├─ Thread-local storage │
│ └─ Static initialization │
│ │
│ 5. 🛠️ UTILITIES │
│ └─ Herramientas auxiliares │
│ │
│ ├─ Archiver: ar, lib.exe (create .a, .lib) │
│ ├─ Assembler: as, nasm (asm → object) │
│ ├─ Debugger: gdb, lldb, WinDbg │
│ ├─ Profiler: gprof, perf, Instruments │
│ ├─ Objdump: objdump, dumpbin (inspect) │
│ └─ Strip: strip (remove symbols) │
│ │
│ 6. 🎨 HEADERS & SDKs │
│ └─ Interface con el sistema operativo │
│ │
│ System Headers: │
│ ├─ <windows.h> (Windows API) │
│ ├─ <unistd.h> (POSIX) │
│ └─ <CoreAudio.h> (macOS frameworks) │
│ │
│ Platform SDKs: │
│ ├─ Windows SDK (kernel32, user32, etc.) │
│ ├─ macOS SDK (frameworks) │
│ └─ Linux headers (kernel headers) │
│ │
└─────────────────────────────────────────────────────────────┘
Visualización del Package¶
╔═══════════════════════════════════════════════════════════╗
║ 📦 TOOLCHAIN PACKAGE CONTENTS ║
║ ║
║ (Ejemplo: GCC 11 para x86_64-linux-gnu) ║
╚═══════════════════════════════════════════════════════════╝
/usr/
├─ bin/ 🔨 Binarios ejecutables
│ ├─ gcc C compiler
│ ├─ g++ C++ compiler
│ ├─ cpp C preprocessor
│ ├─ as Assembler
│ ├─ ld Linker
│ ├─ ar Archiver
│ ├─ ranlib Library indexer
│ ├─ objcopy Object file manipulator
│ ├─ objdump Object file viewer
│ ├─ strip Symbol stripper
│ └─ gdb Debugger
│
├─ lib/gcc/x86_64-linux-gnu/11/ 🔧 Compiler internals
│ ├─ cc1 C compiler frontend
│ ├─ cc1plus C++ compiler frontend
│ ├─ collect2 Linker wrapper
│ ├─ lto1 Link-time optimizer
│ ├─ libgcc.a Compiler support library
│ └─ plugin/ Compiler plugins
│
├─ lib/ 📚 Libraries
│ ├─ libstdc++.a C++ standard library (static)
│ ├─ libstdc++.so C++ standard library (shared)
│ ├─ libgcc_s.so GCC runtime (shared)
│ ├─ libm.a Math library
│ ├─ libc.a C standard library
│ └─ libpthread.a POSIX threads
│
├─ include/ 📋 Headers
│ ├─ c++/11/ C++ standard library headers
│ │ ├─ vector
│ │ ├─ string
│ │ ├─ algorithm
│ │ └─ ...
│ │
│ └─ x86_64-linux-gnu/ Platform-specific headers
│ ├─ sys/
│ │ ├─ types.h
│ │ └─ stat.h
│ ├─ bits/
│ └─ ...
│
└─ share/ 📖 Documentation & data
├─ man/ Man pages
├─ info/ Info documents
└─ locale/ Localization
Total size: ~500 MB (completo con debuginfo)
~150 MB (optimizado)
1.2 Compiler: El Transformador¶
El compilador es el corazón del toolchain. Transforma abstracción humana en instrucciones de máquina.
Pipeline de Compilación¶
┌─────────────────────────────────────────────────────────────┐
│ 🔬 COMPILER PIPELINE DETALLADO │
└─────────────────────────────────────────────────────────────┘
STAGE 1: PREPROCESSING
═══════════════════════════════════════════════════════════════
Input: main.cpp (con #include, #define)
Procesamiento:
├─ Expansion de #include
│ #include <vector> → paste vector header
│
├─ Expansion de macros
│ #define MAX 100 → replace MAX with 100
│
├─ Conditional compilation
│ #ifdef DEBUG → include/exclude code
│
└─ Line splicing
\ at end of line → join lines
Output: Translation unit (TU) completa
(puede ser 100K+ líneas después de headers)
STAGE 2: LEXICAL ANALYSIS (Lexer)
═══════════════════════════════════════════════════════════════
Input: float process(float* buffer, int size) { ... }
Tokenization:
┌────────────┬──────────┬─────────────────┐
│ Text │ Token │ Type │
├────────────┼──────────┼─────────────────┤
│ float │ TOK_TYPE │ Keyword │
│ process │ TOK_ID │ Identifier │
│ ( │ TOK_LPAR │ Punctuation │
│ float │ TOK_TYPE │ Keyword │
│ * │ TOK_STAR │ Operator │
│ buffer │ TOK_ID │ Identifier │
│ , │ TOK_COMMA│ Punctuation │
│ int │ TOK_TYPE │ Keyword │
│ size │ TOK_ID │ Identifier │
│ ) │ TOK_RPAR │ Punctuation │
│ { │ TOK_LBRACE│ Punctuation │
└────────────┴──────────┴─────────────────┘
Output: Token stream
STAGE 3: SYNTAX ANALYSIS (Parser)
═══════════════════════════════════════════════════════════════
Input: Token stream
Parsing:
├─ Grammar rules application
├─ Build Abstract Syntax Tree (AST)
└─ Syntax error detection
AST Example:
FunctionDecl 'process'
├─ ReturnType: float
├─ Parameters:
│ ├─ ParmVarDecl 'buffer' (float*)
│ └─ ParmVarDecl 'size' (int)
└─ Body: CompoundStmt
├─ DeclStmt: VarDecl 'result'
├─ ForStmt
│ └─ ...
└─ ReturnStmt
└─ DeclRefExpr 'result'
Output: Abstract Syntax Tree (AST)
STAGE 4: SEMANTIC ANALYSIS
═══════════════════════════════════════════════════════════════
Input: AST (untyped)
Analysis:
├─ Type checking
│ buffer[i] → is 'i' integer type? Yes ✓
│ → is 'buffer' indexable? Yes ✓
│
├─ Symbol resolution
│ 'size' → refers to parameter 'size' ✓
│
├─ Scope checking
│ Variable 'result' in scope? Yes ✓
│
├─ Const correctness
│ const float* → cannot modify *buffer ✓
│
└─ Template instantiation (if any)
std::vector<float> → generate code for float
Output: Typed AST
STAGE 5: INTERMEDIATE REPRESENTATION (IR)
═══════════════════════════════════════════════════════════════
Input: Typed AST
Transformation:
├─ Lower to platform-independent IR
├─ LLVM IR (Clang)
├─ GIMPLE (GCC)
└─ Or custom IR
Example LLVM IR:
define float @process(float* %buffer, i32 %size) {
entry:
%result = alloca float
store float 0.0, float* %result
%i = alloca i32
store i32 0, i32* %i
br label %loop
loop:
%i.val = load i32, i32* %i
%cmp = icmp slt i32 %i.val, %size
br i1 %cmp, label %body, label %end
body:
; ... loop body ...
br label %loop
end:
%ret = load float, float* %result
ret float %ret
}
Output: Intermediate Representation
STAGE 6: OPTIMIZATION
═══════════════════════════════════════════════════════════════
Input: IR (unoptimized)
Passes (examples):
├─ Dead code elimination
│ if (false) { ... } → removed
│
├─ Constant folding
│ x = 2 + 3 → x = 5
│
├─ Loop unrolling
│ for (int i = 0; i < 4; i++) {...}
│ → {...} {...} {...} {...}
│
├─ Inlining
│ float square(float x) { return x*x; }
│ y = square(3.0);
│ → y = 3.0 * 3.0;
│
├─ Vectorization
│ for (i=0; i<4; i++) a[i] = b[i] + c[i];
│ → SIMD: xmm0 = load b[0..3]
│ xmm1 = load c[0..3]
│ xmm2 = add xmm0, xmm1
│ store xmm2, a[0..3]
│
└─ Link-time optimization (LTO)
Optimize across translation units
Output: Optimized IR
STAGE 7: CODE GENERATION (Backend)
═══════════════════════════════════════════════════════════════
Input: Optimized IR
Generation:
├─ Instruction selection
│ IR ops → target machine instructions
│ add i32 %a, %b → ADD EAX, EBX
│
├─ Register allocation
│ Virtual registers → physical registers
│ %temp1 → RAX
│ %temp2 → RBX
│
├─ Instruction scheduling
│ Reorder for pipeline efficiency
│
└─ Prologue/epilogue insertion
Function call setup/teardown
Output: Assembly code
STAGE 8: ASSEMBLY
═══════════════════════════════════════════════════════════════
Input: Assembly (.s file)
Example x86_64:
process:
push rbp
mov rbp, rsp
sub rsp, 32
mov QWORD PTR [rbp-24], rdi ; buffer
mov DWORD PTR [rbp-28], esi ; size
; ... function body ...
leave
ret
Output: Object file (.o, .obj)
(machine code + metadata)
Visualización de Transformaciones¶
┌─────────────────────────────────────────────────────────────┐
│ 📊 NIVELES DE ABSTRACCIÓN EN COMPILACIÓN │
└─────────────────────────────────────────────────────────────┘
NIVEL 1: SOURCE CODE (Máxima abstracción)
───────────────────────────────────────────────────────────────
float process(float* buffer, int size) {
float sum = 0.0f;
for (int i = 0; i < size; i++) {
sum += buffer[i];
}
return sum / size;
}
Características:
✓ Humano-legible
✓ Portable (C++ estándar)
✓ Alto nivel (loops, variables)
✗ No ejecutable
│ Compiler Frontend
▼
NIVEL 2: ABSTRACT SYNTAX TREE (Estructura)
───────────────────────────────────────────────────────────────
FunctionDecl
└─ Body
├─ VarDecl 'sum' = 0.0f
├─ ForStmt
│ ├─ Init: VarDecl 'i' = 0
│ ├─ Cond: BinaryOp '<' ('i', 'size')
│ ├─ Inc: UnaryOp '++' ('i')
│ └─ Body: CompoundAssignOp '+=' ('sum', ArrayAccess)
└─ ReturnStmt
└─ BinaryOp '/' ('sum', 'size')
Características:
✓ Semántica preservada
✓ Type-checked
✗ Aún no ejecutable
│ IR Generation
▼
NIVEL 3: INTERMEDIATE REPRESENTATION (Platform-independent)
───────────────────────────────────────────────────────────────
%sum = alloca float
store float 0.0, float* %sum
%i = alloca i32
store i32 0, i32* %i
br label %loop
loop:
%i.val = load i32, i32* %i
%cmp = icmp slt i32 %i.val, %size
br i1 %cmp, label %body, label %end
body:
%idx = load i32, i32* %i
%ptr = getelementptr float, float* %buffer, i32 %idx
%val = load float, float* %ptr
%sum.val = load float, float* %sum
%new.sum = fadd float %sum.val, %val
store float %new.sum, float* %sum
%next.i = add i32 %i.val, 1
store i32 %next.i, i32* %i
br label %loop
end:
%final.sum = load float, float* %sum
%result = fdiv float %final.sum, %size
ret float %result
Características:
✓ Platform-independent
✓ Optimizable
✗ Aún no machine code
│ Code Generation
▼
NIVEL 4: ASSEMBLY (Platform-specific)
───────────────────────────────────────────────────────────────
process:
push rbp
mov rbp, rsp
xorps xmm0, xmm0 ; sum = 0.0
xor eax, eax ; i = 0
test esi, esi ; if size == 0
jle .L3 ; goto end
.L2: ; loop:
addss xmm0, DWORD PTR [rdi+rax*4] ; sum += buffer[i]
add rax, 1 ; i++
cmp eax, esi ; i < size?
jl .L2 ; goto loop
.L3: ; end:
cvtsi2ss xmm1, esi ; float(size)
divss xmm0, xmm1 ; sum / size
pop rbp
ret
Características:
✓ Target-specific (x86_64)
✓ Humano-legible (assembly)
✗ Aún no binario
│ Assembler
▼
NIVEL 5: MACHINE CODE (Mínima abstracción)
───────────────────────────────────────────────────────────────
55 48 89 e5 0f 57 c0 31 c0 85 f6 7e 0f f3 0f 58
04 87 48 83 c0 01 39 f0 7c f3 f3 0f 2a ce f3 0f
5e c1 5d c3
Características:
✓ EJECUTABLE
✓ Máxima performance
✗ No humano-legible
✗ Platform-locked
COMPARACIÓN:
───────────────────────────────────────────────────────────────
Nivel │ Abstracción │ Portabilidad │ Performance
──────────┼─────────────┼──────────────┼─────────────
Source │ ★★★★★ │ ★★★★★ │ N/A
AST │ ★★★★☆ │ ★★★★★ │ N/A
IR │ ★★★☆☆ │ ★★★★☆ │ N/A
Assembly │ ★★☆☆☆ │ ★☆☆☆☆ │ ★★★★★
Machine │ ★☆☆☆☆ │ ☆☆☆☆☆ │ ★★★★★
1.3 Linker: El Unificador¶
El linker toma múltiples fragmentos (object files) y los unifica en un ejecutable cohesivo.
El Problema que Resuelve¶
┌─────────────────────────────────────────────────────────────┐
│ 🧩 EL PROBLEMA DEL LINKER │
└─────────────────────────────────────────────────────────────┘
SITUACIÓN:
Tienes múltiples archivos .cpp compilados independientemente:
main.cpp → main.o
├─ Llama a process()
└─ Llama a init_audio()
dsp.cpp → dsp.o
├─ Define process()
└─ Llama a sqrt() (de libm)
audio.cpp → audio.o
└─ Define init_audio()
PROBLEMA:
────────────────────────────────────────────────────────────
Cuando compilas main.o:
- El compilador ve "call process"
- Pero NO sabe dónde está process()
- Genera "reference to undefined symbol process"
Cuando compilas dsp.o:
- El compilador ve "call sqrt"
- Pero sqrt está en una library externa
- Genera "reference to undefined symbol sqrt"
SOLUCIÓN: LINKER
────────────────────────────────────────────────────────────
El linker:
1. Lee todos los .o files
2. Encuentra todas las referencias (calls)
3. Encuentra todas las definiciones (functions)
4. Conecta referencias → definiciones
5. Genera ejecutable completo
Proceso de Linking¶
┌─────────────────────────────────────────────────────────────┐
│ 🔗 LINKER PIPELINE │
└─────────────────────────────────────────────────────────────┘
STAGE 1: SYMBOL COLLECTION
═══════════════════════════════════════════════════════════════
Input: main.o, dsp.o, audio.o
Linker reads symbol tables:
main.o:
┌──────────────┬──────────┬─────────┐
│ Symbol │ Type │ Status │
├──────────────┼──────────┼─────────┤
│ main │ Function │ Defined │
│ process │ Function │ Undefined│
│ init_audio │ Function │ Undefined│
└──────────────┴──────────┴─────────┘
dsp.o:
┌──────────────┬──────────┬─────────┐
│ Symbol │ Type │ Status │
├──────────────┼──────────┼─────────┤
│ process │ Function │ Defined │
│ sqrt │ Function │ Undefined│
└──────────────┴──────────┴─────────┘
audio.o:
┌──────────────┬──────────┬─────────┐
│ Symbol │ Type │ Status │
├──────────────┼──────────┼─────────┤
│ init_audio │ Function │ Defined │
└──────────────┴──────────┴─────────┘
STAGE 2: SYMBOL RESOLUTION
═══════════════════════════════════════════════════════════════
Linker matches undefined → defined:
main.o needs:
process → Found in dsp.o ✓
init_audio → Found in audio.o ✓
dsp.o needs:
sqrt → Search libraries...
→ Found in libm.a ✓
All symbols resolved ✓
If any undefined symbols remain → LINK ERROR
STAGE 3: RELOCATION
═══════════════════════════════════════════════════════════════
Problem: Object files have placeholder addresses
main.o contains:
call 0x0000 ; placeholder for process()
The linker:
1. Assigns actual addresses to symbols
process → 0x401234
2. Updates all references
call 0x401234
Relocation types:
├─ Absolute: Direct address
├─ Relative: Offset from current position (PC-relative)
└─ GOT/PLT: For shared libraries (position-independent)
STAGE 4: SECTION MERGING
═══════════════════════════════════════════════════════════════
Object files have sections:
main.o:
├─ .text (code) 100 bytes
├─ .data (init data) 50 bytes
└─ .bss (zero data) 20 bytes
dsp.o:
├─ .text 200 bytes
├─ .data 30 bytes
└─ .bss 40 bytes
audio.o:
├─ .text 150 bytes
└─ .data 10 bytes
Linker merges:
┌────────────────────────────┐
│ EXECUTABLE │
├────────────────────────────┤
│ .text (450 bytes) │
│ ├─ main.o .text │
│ ├─ dsp.o .text │
│ └─ audio.o .text │
├────────────────────────────┤
│ .data (90 bytes) │
│ ├─ main.o .data │
│ ├─ dsp.o .data │
│ └─ audio.o .data │
├────────────────────────────┤
│ .bss (60 bytes) │
│ ├─ main.o .bss │
│ └─ dsp.o .bss │
└────────────────────────────┘
STAGE 5: FORMAT GENERATION
═══════════════════════════════════════════════════════════════
Generate platform-specific executable format:
Windows: PE (Portable Executable)
┌──────────────────────────┐
│ DOS Header │
│ PE Header │
│ Section Table │
├──────────────────────────┤
│ .text section │
│ .data section │
│ .rdata section │
│ .bss section │
├──────────────────────────┤
│ Import Table │
│ Export Table │
│ Resource Directory │
└──────────────────────────┘
Linux: ELF (Executable and Linkable Format)
┌──────────────────────────┐
│ ELF Header │
│ Program Headers │
│ Section Headers │
├──────────────────────────┤
│ .text section │
│ .data section │
│ .rodata section │
│ .bss section │
├──────────────────────────┤
│ .dynsym (dynamic symbols)│
│ .dynstr (string table) │
└──────────────────────────┘
macOS: Mach-O
┌──────────────────────────┐
│ Mach Header │
│ Load Commands │
├──────────────────────────┤
│ __TEXT segment │
│ __text section │
│ __cstring section │
├──────────────────────────┤
│ __DATA segment │
│ __data section │
│ __bss section │
├──────────────────────────┤
│ Symbol Table │
│ String Table │
└──────────────────────────┘
STAGE 6: FINAL EXECUTABLE
═══════════════════════════════════════════════════════════════
Output: app.exe / app.out / app
Properties:
✓ All symbols resolved
✓ All addresses fixed
✓ Sections merged and laid out
✓ Entry point defined (main)
✓ Platform-specific format
✓ Ready to execute
Static vs Dynamic Linking¶
┌─────────────────────────────────────────────────────────────┐
│ 🔀 STATIC vs DYNAMIC LINKING │
└─────────────────────────────────────────────────────────────┘
STATIC LINKING
═══════════════════════════════════════════════════════════════
Concepto: Copy library code INTO executable
Process:
┌──────────┐ ┌──────────┐ ┌────────────────┐
│ main.o │ │ libdsp.a │ │ executable │
│ │ │ │ │ │
│ calls │ + │ contains │ → │ includes │
│ process()│ │ process()│ │ process() code │
└──────────┘ └──────────┘ └────────────────┘
Resultado:
app.exe:
┌────────────────────────────┐
│ .text │
│ ├─ main() │
│ ├─ process() [from lib] │ ← Copied from libdsp.a
│ └─ init() [from lib] │
└────────────────────────────┘
Ventajas:
✓ Self-contained (un solo archivo)
✓ No dependency hell
✓ Slightly faster (no indirection)
✓ Works without libraries installed
Desventajas:
✗ Executable size grande
✗ No shared memory (cada app tiene copia)
✗ Library updates require recompile
✗ Security patches need full rebuild
DYNAMIC LINKING
═══════════════════════════════════════════════════════════════
Concepto: Reference library, load at runtime
Process:
┌──────────┐ ┌──────────┐ ┌────────────────┐
│ main.o │ │ libdsp.so│ │ executable │
│ │ │ │ │ │
│ calls │ + │ contains │ → │ references │
│ process()│ │ process()│ │ process() │
└──────────┘ └──────────┘ └────────────────┘
│
│ Loaded at runtime
▼
┌──────────┐
│ Memory │
│ libdsp.so│
└──────────┘
Resultado:
app.exe:
┌────────────────────────────┐
│ .text │
│ └─ main() │
├────────────────────────────┤
│ Import Table │
│ ├─ process → libdsp.so │ ← Reference, not copy
│ └─ init → libdsp.so │
└────────────────────────────┘
Runtime:
┌────────────┐ ┌──────────────┐
│ app.exe │─────→│ libdsp.so │
│ calls │ │ (shared in │
│ process() │ │ memory) │
└────────────┘ └──────────────┘
│ ▲
│ │
└───────────────────┘
PLT/GOT mechanism
Ventajas:
✓ Executable size pequeño
✓ Shared memory (una copia para todas las apps)
✓ Library updates without recompile
✓ Security patches easier
Desventajas:
✗ Dependency hell (DLL hell)
✗ Library must be installed
✗ Slightly slower (indirection)
✗ Version conflicts
COMPARISON TABLE:
═══════════════════════════════════════════════════════════════
┌────────────────┬────────────┬────────────┐
│ Aspect │ Static │ Dynamic │
├────────────────┼────────────┼────────────┤
│ Exe size │ Large │ Small │
│ Memory usage │ High │ Low (shared│
│ Deployment │ Easy │ Complex │
│ Updates │ Rebuild │ Replace lib│
│ Performance │ +++ │ ++ │
│ Startup time │ Fast │ Slower │
└────────────────┴────────────┴────────────┘
AUDIOLAB STRATEGY:
═══════════════════════════════════════════════════════════════
Plugin formats (VST3, AU, AAX):
→ Dynamic linking REQUIRED
(Host loads plugin as shared library)
Standalone app:
→ Static linking preferred
(Self-contained, no dependency issues)
Dependencies (vcpkg):
→ Static linking
(Avoid version conflicts, simplify deployment)
1.4 Standard Library: El Fundamento¶
La standard library implementa el lenguaje. Sin ella, ni siquiera std::vector existe.
C++ Standard Library Implementations¶
┌─────────────────────────────────────────────────────────────┐
│ 📚 C++ STANDARD LIBRARY LANDSCAPE │
└─────────────────────────────────────────────────────────────┘
IMPLEMENTACIÓN 1: libstdc++ (GCC)
═══════════════════════════════════════════════════════════════
Origen: GNU Project
Usado por: GCC (default), compatible con Clang
Características:
├─ Mature (20+ años)
├─ Complete C++20 support (GCC 11+)
├─ Good performance
├─ GPL license (with runtime exception)
└─ Default en Linux
Headers:
/usr/include/c++/11/
├─ vector → std::vector
├─ string → std::string
├─ algorithm → std::sort, etc.
├─ memory → std::unique_ptr
└─ ...
Library files:
├─ libstdc++.a (static)
└─ libstdc++.so (shared)
IMPLEMENTACIÓN 2: libc++ (LLVM)
═══════════════════════════════════════════════════════════════
Origen: LLVM Project
Usado por: Clang (default on macOS), optional on Linux
Características:
├─ Modern design
├─ C++20 support excellent
├─ Better error messages
├─ Apache/MIT license
└─ Default en macOS
Headers:
/usr/include/c++/v1/
├─ vector
├─ string
├─ algorithm
└─ ...
Library files:
├─ libc++.a (static)
└─ libc++.dylib (shared, macOS)
libc++.so (shared, Linux)
IMPLEMENTACIÓN 3: MSVC STL (Microsoft)
═══════════════════════════════════════════════════════════════
Origen: Microsoft
Usado por: MSVC (only choice on Windows MSVC)
Características:
├─ Proprietary (but open-source now on GitHub)
├─ C++20 support complete (VS 2022)
├─ Excellent debugging (natvis)
├─ Tight integration with Visual Studio
└─ Only for Windows + MSVC
Headers:
C:\Program Files\Microsoft Visual Studio\...\include\
├─ vector
├─ string
├─ algorithm
└─ ...
Library files:
├─ (statically linked into exe typically)
└─ msvcrt.dll family (runtime)
COMPARISON:
═══════════════════════════════════════════════════════════════
┌──────────────┬──────────┬──────────┬──────────┐
│ Feature │ libstdc++│ libc++ │ MSVC STL │
├──────────────┼──────────┼──────────┼──────────┤
│ C++20 │ ✓ Good │ ✓ Great │ ✓ Great │
│ Performance │ +++ │ +++ │ +++ │
│ Diagnostics │ ++ │ +++ │ +++ │
│ License │ GPL+ex │ MIT │ Prop │
│ Platforms │ All │ All │ Windows │
│ ABI stable │ Yes* │ Yes │ Yes │
└──────────────┴──────────┴──────────┴──────────┘
* GCC 5 introduced dual ABI for std::string compatibility
C Standard Library¶
┌─────────────────────────────────────────────────────────────┐
│ 🔧 C STANDARD LIBRARY (libc) │
└─────────────────────────────────────────────────────────────┘
La C standard library es CRÍTICA:
- C++ standard library se construye sobre ella
- Proporciona funciones básicas del OS
- Malloc, printf, file I/O, threads, etc.
IMPLEMENTACIÓN 1: glibc (GNU C Library)
═══════════════════════════════════════════════════════════════
Plataforma: Linux (dominante)
Características:
├─ Feature-rich
├─ POSIX compliant
├─ Large (~2 MB)
├─ GPL license
└─ Backward compatible
Funciones:
├─ malloc, free (memory)
├─ printf, scanf (I/O)
├─ open, read, write (files)
├─ pthread_* (threads)
└─ ...
Versioning CRITICAL:
Binary compiled with glibc 2.35 WON'T RUN on system with glibc 2.31
→ Must target OLDEST glibc you support
IMPLEMENTACIÓN 2: musl libc
═══════════════════════════════════════════════════════════════
Plataforma: Linux (alternative, embedded)
Características:
├─ Minimal (~600 KB)
├─ Clean code
├─ Static linking friendly
├─ MIT license
└─ Alpine Linux uses it
Ventaja: Static linking viable
Desventaja: Menor compatibility con apps legacy
IMPLEMENTACIÓN 3: MSVCRT (Windows)
═══════════════════════════════════════════════════════════════
Plataforma: Windows
Características:
├─ Proprietary
├─ Comes with Windows
├─ Version tied to MSVC version
└─ Redistributable required for deployment
Files:
├─ msvcr140.dll (Visual Studio 2015-2022)
├─ ucrtbase.dll (Universal CRT)
└─ vcruntime140.dll
IMPLEMENTACIÓN 4: libSystem (macOS)
═══════════════════════════════════════════════════════════════
Plataforma: macOS/iOS
Características:
├─ Apple proprietary
├─ BSD-derived
├─ Integrated with OS
└─ Always available (part of OS)
CRITICAL CONCEPT: ABI COMPATIBILITY
═══════════════════════════════════════════════════════════════
Problem:
Different libc implementations have different ABIs
→ Cannot mix binaries compiled with different libc
Example:
libfoo.so compiled with glibc
app.exe compiled with musl
→ LINKER ERROR or runtime crash
Solution:
Consistent toolchain across all components
1.5 Utilities y SDK: El Contexto¶
El toolchain no es solo compilador + linker. Incluye ecosistema completo.
Utilities Críticos¶
┌─────────────────────────────────────────────────────────────┐
│ 🛠️ TOOLCHAIN UTILITIES │
└─────────────────────────────────────────────────────────────┘
1. ARCHIVER (ar, lib.exe)
═══════════════════════════════════════════════════════════════
Propósito: Crear static libraries
Función:
├─ Combina múltiples .o files en un .a/.lib
├─ Add index para fast symbol lookup
└─ Permite linking selectivo
Uso conceptual:
dsp.o + filter.o + reverb.o
↓ ar rcs libdsp.a
libdsp.a (archive of .o files)
Cuando linkeas:
Linker extrae SOLO los .o que necesitas de la archive
2. ASSEMBLER (as, nasm)
═══════════════════════════════════════════════════════════════
Propósito: Assembly → Machine code
Uso en AudioLab:
SIMD optimizations en assembly
→ .asm file → assembler → .o file
→ link con resto del proyecto
Example:
; fast_multiply.asm
movaps xmm0, [rdi]
mulps xmm0, [rsi]
movaps [rdx], xmm0
ret
$ as fast_multiply.asm -o fast_multiply.o
3. DEBUGGER (gdb, lldb, WinDbg)
═══════════════════════════════════════════════════════════════
Propósito: Runtime introspection
Capacidades:
├─ Set breakpoints
├─ Inspect variables
├─ Step through code
├─ Stack traces
└─ Core dump analysis
Requiere: Debug symbols en executable
→ Compile con -g flag
4. PROFILER (gprof, perf, Instruments)
═══════════════════════════════════════════════════════════════
Propósito: Performance analysis
Métricas:
├─ Function call counts
├─ Time spent per function
├─ Cache misses
├─ Branch mispredictions
└─ Memory allocations
5. OBJECT INSPECTOR (objdump, dumpbin, otool)
═══════════════════════════════════════════════════════════════
Propósito: Inspect binary files
Información:
├─ Symbol table
├─ Section layout
├─ Dependencies (shared libs)
├─ Disassembly
└─ Relocations
Uso:
$ objdump -t audiolab.o # Symbols
$ objdump -d audiolab.o # Disassembly
$ ldd audiolab.so # Dependencies (Linux)
$ otool -L audiolab.dylib # Dependencies (macOS)
6. STRIP
═══════════════════════════════════════════════════════════════
Propósito: Remove debug symbols
Efecto:
audiolab.exe (with symbols): 5.2 MB
audiolab.exe (stripped): 1.8 MB
Trade-off:
✓ Smaller distribution
✗ Cannot debug
✗ No meaningful stack traces
Strategy:
- Keep symbols during development
- Strip for release builds
- Maintain separate .pdb/.dSYM files
SDK y System Headers¶
┌─────────────────────────────────────────────────────────────┐
│ 🎨 PLATFORM SDKs │
└─────────────────────────────────────────────────────────────┘
SDK = Software Development Kit
= Headers + Libraries + Documentation para platform APIs
WINDOWS SDK
═══════════════════════════════════════════════════════════════
Ubicación:
C:\Program Files (x86)\Windows Kits\10\
Contenido:
├─ Include/
│ ├─ um/ (User Mode headers)
│ │ ├─ windows.h
│ │ ├─ audioclient.h (WASAPI)
│ │ └─ ...
│ ├─ shared/ (Shared headers)
│ └─ ucrt/ (Universal CRT)
│
└─ Lib/
├─ um/
│ ├─ kernel32.lib
│ ├─ user32.lib
│ └─ ...
└─ ucrt/
Para AudioLab:
#include <audioclient.h> // WASAPI para audio I/O
#pragma comment(lib, "ole32.lib")
macOS SDK
═══════════════════════════════════════════════════════════════
Ubicación:
/Applications/Xcode.app/Contents/Developer/Platforms/
MacOSX.platform/Developer/SDKs/MacOSX.sdk/
Contenido:
├─ System/Library/Frameworks/
│ ├─ CoreAudio.framework/
│ │ └─ Headers/
│ │ ├─ CoreAudio.h
│ │ ├─ AudioHardware.h
│ │ └─ ...
│ ├─ AudioUnit.framework/
│ └─ ...
│
└─ usr/
├─ include/ (POSIX headers)
└─ lib/ (System libraries)
Para AudioLab:
#include <CoreAudio/CoreAudio.h>
#include <AudioUnit/AudioUnit.h>
// Link con -framework CoreAudio -framework AudioUnit
LINUX "SDK"
═══════════════════════════════════════════════════════════════
Linux NO tiene SDK unificado, sino packages:
System headers:
/usr/include/
├─ linux/ (kernel headers)
├─ sys/ (system calls)
└─ ...
Audio APIs (install via package manager):
├─ ALSA: libasound2-dev
│ └─ /usr/include/alsa/
├─ JACK: libjack-dev
│ └─ /usr/include/jack/
└─ PulseAudio: libpulse-dev
└─ /usr/include/pulse/
Para AudioLab:
#include <alsa/asoundlib.h>
// Link con -lasound
CRITICAL: SDK Version Matching
═══════════════════════════════════════════════════════════════
Problem:
SDK version defines MINIMUM OS version
Example (macOS):
Compiled with macOS 14 SDK
→ Binary requires macOS 14+
→ Won't run on macOS 13
Solution:
Use OLDER SDK + deployment target flag
-mmacosx-version-min=11.0
→ Binary runs on macOS 11+
AudioLab strategy:
Windows: Windows 10 SDK (covers 10+11)
macOS: macOS 11 SDK (covers 11+12+13+14)
Linux: Ubuntu 20.04 headers (covers 20.04+)
CAPÍTULO 2: Native vs Cross Compilation¶
2.1 Paradigmas de Compilación¶
Hay tres formas fundamentales de compilar código. Cada una tiene su filosofía.
┌─────────────────────────────────────────────────────────────┐
│ 🎭 TRES PARADIGMAS DE COMPILACIÓN │
└─────────────────────────────────────────────────────────────┘
PARADIGMA 1: NATIVE COMPILATION
═══════════════════════════════════════════════════════════════
Compilar PARA la plataforma EN la que estás
┌──────────────────────┐
│ Developer Machine │
│ macOS (ARM64) │
│ │
│ ┌────────┐ │
│ │ Source │ │
│ │ .cpp │ │
│ └───┬────┘ │
│ │ Compile │
│ ▼ │
│ ┌────────┐ │
│ │ Binary │ │
│ │ARM64 │ │
│ │macOS │◄─────────┼─── Can execute immediately
│ └────────┘ │
│ │
└──────────────────────┘
Filosofía: Simplicidad
Metáfora: Cocinar para comer inmediatamente
PARADIGMA 2: CROSS COMPILATION
═══════════════════════════════════════════════════════════════
Compilar PARA una plataforma DIFERENTE
┌──────────────────────┐ ┌──────────────────────┐
│ Developer Machine │ │ Target Machine │
│ Linux (x86_64) │ │ Windows (x86_64) │
│ │ │ │
│ ┌────────┐ │ │ │
│ │ Source │ │ │ │
│ │ .cpp │ │ │ │
│ └───┬────┘ │ │ │
│ │ Cross-compile │ │ │
│ ▼ │ │ │
│ ┌────────┐ │ │ │
│ │ Binary │ │ │ │
│ │x86_64 │ │ │ │
│ │Windows │──────────┼─────>│ Can execute here │
│ └────────┘ │ │ │
│ │ │ │ │
│ └───────────────┼──────┼─── Cannot execute │
│ (wrong platform) │ │ on build machine │
│ │ │ │
└──────────────────────┘ └──────────────────────┘
Filosofía: Poder y flexibilidad
Metáfora: Cocinar para enviar a otra ciudad
PARADIGMA 3: CANADIAN CROSS
═══════════════════════════════════════════════════════════════
Compilar un COMPILADOR para otra plataforma
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Machine A │ │ Machine B │ │ Machine C │
│ (Build) │ │ (Host) │ │ (Target) │
│ │ │ │ │ │
│ Compile │──>│ Compiler │──>│ Programs │
│ Compiler │ │ Runs here │ │ Run here │
│ │ │ │ │ │
│ Linux │ │ Windows │ │ Embedded │
│ x86_64 │ │ x86_64 │ │ ARM │
└──────────────┘ └──────────────┘ └──────────────┘
Ejemplo real:
Build on Linux
→ Create GCC that runs on Windows
→ That GCC compiles for embedded ARM
Filosofía: Meta-nivel
Metáfora: Construir una cocina que se enviará a otra ciudad
para que allí cocinen para un tercer lugar
Tabla Comparativa¶
╔═══════════════════════════════════════════════════════════╗
║ COMPARACIÓN DE PARADIGMAS ║
╠═══════════════════════════════════════════════════════════╣
║ ║
║ ┌──────────────┬─────────┬───────────┬────────────┐ ║
║ │ Aspecto │ Native │ Cross │ Canadian │ ║
║ ├──────────────┼─────────┼───────────┼────────────┤ ║
║ │ Setup │ Trivial │ Moderate │ Complex │ ║
║ │ Testing │ Instant │ Remote │ Very remote│ ║
║ │ Debugging │ Easy │ Hard │ Very hard │ ║
║ │ CI/CD │ Per OS │ Unified │ Rare │ ║
║ │ Uso típico │ Dev │ Production│ Toolchain │ ║
║ │ │ diario │ builds │ builders │ ║
║ │ AudioLab │ ✓ Yes │ ✓ Yes │ ✗ No need │ ║
║ └──────────────┴─────────┴───────────┴────────────┘ ║
║ ║
╚═══════════════════════════════════════════════════════════╝
2.2 Native Compilation: Simplicidad¶
Native compilation es el caso base. Todo funciona "naturalmente".
┌─────────────────────────────────────────────────────────────┐
│ 🏠 NATIVE COMPILATION WORKFLOW │
└─────────────────────────────────────────────────────────────┘
SETUP (una sola vez)
═══════════════════════════════════════════════════════════════
Install toolchain para tu plataforma:
macOS:
$ xcode-select --install
✓ Apple Clang instalado
✓ SDK de macOS incluido
✓ Todo listo
Linux:
$ sudo apt install build-essential
✓ GCC instalado
✓ glibc headers incluidos
✓ Todo listo
Windows:
Install Visual Studio 2022
✓ MSVC instalado
✓ Windows SDK incluido
✓ Todo listo
DEVELOPMENT CYCLE
═══════════════════════════════════════════════════════════════
1. Edit code
$ vim compressor.cpp
2. Compile
$ g++ -c compressor.cpp -o compressor.o
✓ Uses native compiler
✓ Uses native headers
✓ Generates native object file
3. Link
$ g++ compressor.o -o compressor
✓ Uses native linker
✓ Uses native libraries
✓ Generates native executable
4. Test IMMEDIATELY
$ ./compressor
✓ Runs on same machine
✓ No transfer needed
✓ Instant feedback
5. Debug (if needed)
$ lldb ./compressor
(lldb) break compressor.cpp:42
(lldb) run
✓ Native debugger
✓ Full symbol info
✓ Easy inspection
ADVANTAGES
═══════════════════════════════════════════════════════════════
✅ Zero configuration
Toolchain "just works"
✅ Instant testing
Compile → run immediately
✅ Full debugging
Native debugger con todos los símbolos
✅ No abstraction leaks
Errores son directos
✅ Performance testing accurate
Running on target hardware
DISADVANTAGES
═══════════════════════════════════════════════════════════════
❌ Limited to one platform
macOS dev → solo macOS binaries
❌ Requires multiple machines for multi-platform
macOS dev + Windows dev + Linux dev
❌ CI/CD complexity
Separate runners para cada OS
❌ Cannot test on platforms you don't have
No macOS machine? → No macOS testing
Workflow Diagram¶
NATIVE COMPILATION FLOW
Developer's Machine (macOS ARM64)
┌───────────────────────────────────────┐
│ │
│ 📝 Write Code │
│ compressor.cpp │
│ │ │
│ ▼ │
│ 🔨 Compile (clang) │
│ compressor.o [ARM64 macOS] │
│ │ │
│ ▼ │
│ 🔗 Link │
│ compressor [ARM64 macOS executable] │
│ │ │
│ ▼ │
│ 🧪 Test │
│ $ ./compressor │
│ [Runs immediately] │
│ │ │
│ ▼ │
│ 🐛 Debug (if needed) │
│ lldb ./compressor │
│ [Full introspection] │
│ │ │
│ ▼ │
│ ✅ Works! │
│ │
└───────────────────────────────────────┘
Total time: Minutes
Complexity: Minimal
Friction: Zero
2.3 Cross Compilation: Poder y Complejidad¶
Cross compilation permite compilar para cualquier plataforma desde una máquina.
El Concepto¶
┌─────────────────────────────────────────────────────────────┐
│ 🌐 CROSS COMPILATION PHILOSOPHY │
└─────────────────────────────────────────────────────────────┘
PROBLEMA QUE RESUELVE:
- Equipo con 10 developers, todos en macOS
- Necesitan generar binaries para:
• Windows (x86_64)
• Linux (x86_64)
• macOS (x86_64 + ARM64)
• iOS (ARM64)
SIN cross-compilation:
Necesitarían:
├─ Windows machine para compilar Windows
├─ Linux machine para compilar Linux
├─ macOS Intel para compilar macOS x86_64
└─ macOS ARM para compilar macOS ARM64 + iOS
CON cross-compilation:
UN build server (Linux poderoso)
├─ Cross-compile para Windows
├─ Cross-compile para Linux (native)
├─ Cross-compile para macOS
└─ Cross-compile para iOS
CONCEPTO CORE:
┌──────────────────────────────────────────────────┐
│ BUILD MACHINE (donde compilas) │
│ ≠ │
│ TARGET MACHINE (para dónde compilas) │
└──────────────────────────────────────────────────┘
Build Machine:
- Tiene el compiler/linker
- Tiene el código fuente
- Tiene CPU/OS específicos
Target Machine:
- Es la plataforma objetivo
- Tiene CPU/OS diferentes
- Ejecutará el binary resultante
KEY INSIGHT:
El compilador NO necesita correr en la plataforma
para la que compila.
Un compilador es "solo" un programa que:
Input: Código fuente (text)
Output: Machine code (binary)
Puede generar x86_64 code mientras corre en ARM64.
Puede generar Windows PE mientras corre en Linux.
Challenges Fundamentales¶
┌─────────────────────────────────────────────────────────────┐
│ ⚠️ CROSS-COMPILATION CHALLENGES │
└─────────────────────────────────────────────────────────────┘
CHALLENGE 1: TOOLCHAIN DISCOVERY
═══════════════════════════════════════════════════════════════
Problema:
Compilador nativo: /usr/bin/gcc
Compilador cross: /usr/bin/x86_64-w64-mingw32-gcc
(nombre diferente!)
El build system necesita saber:
- Path del cross-compiler
- Path del cross-linker
- Path de utilities (ar, strip, etc.)
Solución: Toolchain file
Archivo que declara todos los paths
CHALLENGE 2: HEADERS & LIBRARIES
═══════════════════════════════════════════════════════════════
Problema:
Build machine: /usr/include/stdio.h (Linux headers)
Target (Windows): Necesita Windows headers
Si usas /usr/include → compile para Linux, not Windows!
Necesitas:
├─ Target headers (windows.h, etc.)
├─ Target libraries (kernel32.lib, etc.)
└─ NO mezclar con build headers
Solución: Sysroot
Directorio que contiene filesystem del target
/opt/windows-sysroot/
├─ include/
│ └─ windows.h
└─ lib/
└─ kernel32.lib
Compiler usa SOLO este directorio
CHALLENGE 3: FEATURE DETECTION
═══════════════════════════════════════════════════════════════
Problema:
Build systems detectan features compilando + ejecutando:
TRY_RUN(HAS_AVX2
SOURCE "int main() { /* AVX2 test */ }"
)
Pero en cross-compilation:
Compile: ✓ Works (genera binary)
Run: ✗ FAILS (wrong platform!)
Solución:
├─ Use emulator (QEMU, Wine)
├─ Pre-populate cache (manual values)
└─ Conservative assumptions
CHALLENGE 4: DEPENDENCIES
═══════════════────────────────────────────────────────────────
Problema:
Proyecto necesita libpng.
Build machine: libpng instalado PARA Linux
Target (Windows): Necesitas libpng PARA Windows
Solución:
├─ Separate dependency trees
│ build-deps/ (tools que corren durante build)
│ target-deps/ (libs que van en el binary final)
│
└─ Package manager aware de cross-compilation
(vcpkg con triplets, conan con profiles)
CHALLENGE 5: TESTING
═══════════════════════════════════════════════════════════════
Problema:
Compilaste binary para Windows.
Estás en Linux.
¿Cómo testeas?
Soluciones:
├─ Emulator
│ Wine (Windows on Linux)
│ QEMU (otras archs)
│
├─ Remote device
│ SSH al target
│ Deploy + execute
│ Collect results
│
├─ CI/CD on target
│ Build en Linux (fast)
│ Test en Windows (real hardware)
│
└─ Skip tests (risky!)
Build only, defer testing
Workflow Cross-Compilation¶
╔═══════════════════════════════════════════════════════════╗
║ 🔄 CROSS-COMPILATION WORKFLOW ║
╚═══════════════════════════════════════════════════════════╝
SETUP (una sola vez)
───────────────────────────────────────────────────────────
1. Install cross-toolchain
$ sudo apt install mingw-w64 # GCC for Windows
2. Obtain target sysroot
- Windows SDK headers/libs
- Install en /opt/win64-sysroot/
3. Create toolchain file
windows-x86_64.cmake:
set(CMAKE_SYSTEM_NAME Windows)
set(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc)
set(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++)
set(CMAKE_SYSROOT /opt/win64-sysroot)
BUILD
───────────────────────────────────────────────────────────
$ cmake -DCMAKE_TOOLCHAIN_FILE=windows-x86_64.cmake ..
$ make
CMake:
✓ Uses x86_64-w64-mingw32-gcc (not gcc)
✓ Uses /opt/win64-sysroot headers
✓ Generates Windows PE executable
Result:
audiolab.exe (Windows binary, on Linux!)
TESTING
───────────────────────────────────────────────────────────
Option A: Wine
$ wine audiolab.exe
[Runs on Linux via emulation]
Option B: Transfer to Windows
$ scp audiolab.exe user@windows-box:
$ ssh user@windows-box
windows> audiolab.exe
[Runs on real Windows]
Option C: CI/CD
Build: Linux (fast cross-compile)
Test: Windows runner (real hardware)
DIAGRAM:
───────────────────────────────────────────────────────────
Build Machine (Linux)
┌───────────────────────────────────────────┐
│ │
│ Source: compressor.cpp │
│ │ │
│ ▼ │
│ Compiler: x86_64-w64-mingw32-g++ │
│ │ │
│ Headers: /opt/win64-sysroot/include/ │
│ │ │
│ ▼ │
│ Output: compressor.exe │
│ │ [Windows PE binary] │
│ │ │
└───────────┼───────────────────────────────┘
│
│ Transfer
▼
Target Machine (Windows)
┌───────────────────────────────────────────┐
│ │
│ $ compressor.exe │
│ [Executes successfully] │
│ │
└───────────────────────────────────────────┘
2.4 Canadian Cross: El Meta-Nivel¶
Canadian cross es el nivel más abstracto: compilar un compilador.
┌─────────────────────────────────────────────────────────────┐
│ 🏭 CANADIAN CROSS COMPILATION │
└─────────────────────────────────────────────────────────────┘
CONCEPTO:
Tres máquinas en juego:
┌────────────┐
│ BUILD │ Donde compilas el compiler
└─────┬──────┘
│ Compiles
▼
┌────────────┐
│ HOST │ Donde el compiler CORRERÁ
└─────┬──────┘
│ Uses compiler to generate
▼
┌────────────┐
│ TARGET │ Para qué plataforma el compiler compilará
└────────────┘
EJEMPLO REAL:
═══════════════════════════════════════════════════════════════
Scenario: Embedded development
BUILD: Linux x86_64 (developer workstation)
HOST: Windows x86_64 (where developers work)
TARGET: ARM Cortex-M (embedded device)
Goal:
Create a GCC that:
- Runs on Windows (HOST)
- Compiles for ARM (TARGET)
- Built on Linux (BUILD)
Process:
┌────────────────────────────────────────────────────┐
│ Step 1: On Linux (BUILD) │
│ │
│ $ ./configure \ │
│ --build=x86_64-linux-gnu \ │
│ --host=x86_64-w64-mingw32 \ │
│ --target=arm-none-eabi │
│ │
│ $ make │
│ │
│ Output: arm-none-eabi-gcc.exe │
│ (Windows executable that compiles for ARM) │
└────────────────────────────────────────────────────┘
│
│ Transfer to Windows
▼
┌────────────────────────────────────────────────────┐
│ Step 2: On Windows (HOST) │
│ │
│ > arm-none-eabi-gcc.exe firmware.c -o firmware.elf│
│ │
│ Output: firmware.elf (ARM binary) │
└────────────────────────────────────────────────────┘
│
│ Flash to device
▼
┌────────────────────────────────────────────────────┐
│ Step 3: On ARM device (TARGET) │
│ │
│ [firmware.elf executes] │
└────────────────────────────────────────────────────┘
AUDIOLAB RELEVANCE:
═══════════════════════════════════════════════════════════════
❌ NOT NEEDED
Razón:
- No estamos construyendo toolchains
- Usamos toolchains existentes (MSVC, GCC, Clang)
- Solo necesitamos: Native + Cross compilation
Cuándo SÍ importa:
- Bootstrapping nuevos toolchains
- Embedded systems con custom targets
- OS development
- GCC/LLVM development
2.5 Challenges de Cross-Compilation (Profundizando)¶
Sysroot Concept¶
┌─────────────────────────────────────────────────────────────┐
│ 📁 SYSROOT: EL FILESYSTEM DEL TARGET │
└─────────────────────────────────────────────────────────────┘
CONCEPTO:
Sysroot = "System Root"
= Miniature filesystem del target platform
ESTRUCTURA:
/opt/windows-x86_64-sysroot/
├─ include/ # Headers del target
│ ├─ windows.h
│ ├─ stdio.h # MSVCRT version
│ └─ ...
├─ lib/ # Libraries del target
│ ├─ kernel32.lib
│ ├─ msvcrt.lib
│ └─ ...
└─ bin/ # (optional) Target binaries
└─ ...
USO EN COMPILACIÓN:
Compiler flag:
--sysroot=/opt/windows-x86_64-sysroot
Efecto:
#include <windows.h>
→ Busca en /opt/windows-x86_64-sysroot/include/
→ NO en /usr/include/ (build machine)
link con kernel32
→ Busca en /opt/windows-x86_64-sysroot/lib/
→ NO en /usr/lib/
CONSTRUCCIÓN DE SYSROOT:
Opción 1: Manual
- Descargar Windows SDK
- Extraer headers + libs
- Organizar en estructura sysroot
Opción 2: From running system
- SSH al target
- Copiar /usr/include, /usr/lib, etc.
- Transfer al build machine
Opción 3: Pre-built sysroots
- Toolchain vendors proveen
- Ejemplo: Debian multiarch packages
EJEMPLO PARA AUDIOLAB:
macOS → Windows cross-compilation
/Users/dev/audiolab/sysroots/windows-x64/
├─ include/
│ ├─ windows.h
│ ├─ audioclient.h # WASAPI
│ └─ ...
└─ lib/
├─ kernel32.lib
├─ ole32.lib
└─ ...
CMake toolchain file:
set(CMAKE_SYSROOT /Users/dev/audiolab/sysroots/windows-x64)
Build vs Host vs Target¶
┌─────────────────────────────────────────────────────────────┐
│ 🎯 BUILD vs HOST vs TARGET │
└─────────────────────────────────────────────────────────────┘
DEFINICIONES:
═══════════════════════════════════════════════════════════════
BUILD: Platform donde ESTÁS compilando (ahora)
HOST: Platform donde el programa CORRERÁ
TARGET: Platform para la que el programa compila (si es compiler)
CASOS:
═══════════════════════════════════════════════════════════════
CASO 1: Native compilation
──────────────────────────────────────────────────────────
BUILD = macOS ARM64
HOST = macOS ARM64
TARGET = (N/A, no estamos compilando un compiler)
BUILD == HOST → Native
CASO 2: Cross compilation
──────────────────────────────────────────────────────────
BUILD = Linux x86_64
HOST = Windows x86_64
TARGET = (N/A)
BUILD ≠ HOST → Cross
CASO 3: Canadian cross
──────────────────────────────────────────────────────────
BUILD = Linux x86_64
HOST = Windows x86_64
TARGET = ARM Cortex-M
BUILD ≠ HOST ≠ TARGET → Canadian
DEPENDENCIES:
═══════════════════════════════════════════════════════════════
Dos tipos de dependencies:
1. BUILD-TIME dependencies (corren en BUILD)
├─ Code generators (protobuf compiler)
├─ Documentation tools (doxygen)
└─ Build system tools (cmake, ninja)
Deben ser para BUILD platform
2. TARGET dependencies (van en el binary final)
├─ Libraries (libpng, zlib)
├─ Runtime (C++ stdlib)
└─ OS libraries (kernel32, pthread)
Deben ser para HOST platform
EJEMPLO AUDIOLAB:
Cross-compiling Windows plugin en macOS
BUILD: macOS (donde haces cmake + make)
HOST: Windows (donde el .dll correrá)
Dependencies:
├─ BUILD-time:
│ ├─ CMake (macOS binary)
│ ├─ Ninja (macOS binary)
│ └─ Python (macOS, para scripts)
│
└─ TARGET:
├─ JUCE (Windows headers/libs)
├─ VST3 SDK (Windows)
└─ Windows SDK (kernel32.lib, etc.)
[Continuaré con los capítulos 3-7 en la siguiente parte debido a límite de longitud...]
¿Quieres que continúe con el resto del documento (Capítulos 3-7)?