<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Build System on kenji.blog</title><link>http://kenji.blog/es/tags/build-system/</link><description>Recent content in Build System on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>es</language><copyright>kenjinote</copyright><lastBuildDate>Sat, 12 Sep 2026 09:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/es/tags/build-system/index.xml" rel="self" type="application/rss+xml"/><item><title>Guía para construir un entorno de compilación de C++ multiplataforma usando CMake</title><link>http://kenji.blog/es/p/cmake-cross-platform-build-environment-guide/</link><pubDate>Sat, 12 Sep 2026 09:00:00 +0900</pubDate><guid>http://kenji.blog/es/p/cmake-cross-platform-build-environment-guide/</guid><description>&lt;img src="http://kenji.blog/p/cmake-cross-platform-build-environment-guide/img/eyecatch.jpg" alt="Featured image of post Guía para construir un entorno de compilación de C++ multiplataforma usando CMake" />&lt;p>En el desarrollo de software con C++, la elección y construcción de un &amp;ldquo;sistema de compilación&amp;rdquo; ha sido un dolor de cabeza para muchos desarrolladores durante años. Dado que C++ no tiene un gestor de paquetes o sistema de compilación estándar oficial, era necesario utilizar diferentes compiladores y herramientas de compilación (MSVC, GCC, Clang, Make, Ninja, etc.) dependiendo de la plataforma (Windows, Linux, macOS).&lt;/p>
&lt;p>Sin embargo, en la actualidad, &lt;strong>CMake&lt;/strong> se ha establecido como el estándar de facto de la industria, y al usar CMake correctamente, ahora es posible construir elegantemente un entorno de compilación multiplataforma desde un único &lt;code>CMakeLists.txt&lt;/code>.&lt;/p>
&lt;p>En este artículo, explicaremos de forma exhaustiva y detallada los pasos para construir un entorno de compilación de C++ multiplataforma utilizando CMake moderno, desde lo básico hasta técnicas avanzadas.&lt;/p>
&lt;h2 id="1-qué-es-cmake-el-concepto-de-metasistema-de-compilación">1. ¿Qué es CMake? (El concepto de metasistema de compilación)
&lt;/h2>&lt;p>CMake no es una herramienta que compila código fuente directamente por sí misma. CMake es un &amp;ldquo;sistema que genera sistemas de compilación&amp;rdquo;, es decir, un &lt;strong>metasistema de compilación (Meta-Build System)&lt;/strong>.&lt;/p>
&lt;p>La función principal de CMake es leer un archivo de configuración abstracto (&lt;code>CMakeLists.txt&lt;/code>) que no depende de la plataforma o el compilador, y generar automáticamente los scripts de compilación nativos óptimos para cada entorno (por ejemplo, &lt;code>Makefile&lt;/code> para Linux, el archivo de proyecto &lt;code>.sln&lt;/code> de Visual Studio para Windows, o el rápido &lt;code>build.ninja&lt;/code>).&lt;/p>
&lt;p>El siguiente diagrama muestra el proceso de generación de CMake.&lt;/p>
&lt;div class="mermaid">graph TD
A["CMakeLists.txt (Definición abstracta de compilación)"] --> B["CMake (Configurar y Generar)"]
B --> C["Makefiles de Unix"]
B --> D["Archivos de compilación Ninja"]
B --> E["Soluciones de Visual Studio"]
B --> F["Proyectos de Xcode"]
C --> G["Herramienta de compilación nativa (make, ninja, MSBuild, xcodebuild)"]
D --> G
E --> G
F --> G
G --> H["Ejecutable / Biblioteca compartida / Biblioteca estática"]&lt;/div>
&lt;p>De esta manera, al usar CMake como intermediario, los desarrolladores pueden gestionar proyectos C++ sin tener que preocuparse por las diferencias menores en los comandos de cada sistema operativo.&lt;/p>
&lt;h2 id="2-conceptos-básicos-de-cmake-moderno-de-variables-a-objetivos-targets">2. Conceptos básicos de CMake moderno: De variables a objetivos (targets)
&lt;/h2>&lt;p>La notación de CMake 3.0 en adelante se llama &amp;ldquo;CMake moderno&amp;rdquo;, y su filosofía de diseño es fundamentalmente diferente de la anterior (CMake heredado). En CMake heredado, el enfoque principal era sobrescribir variables globales por directorio (por ejemplo, usando &lt;code>include_directories()&lt;/code> y &lt;code>link_libraries()&lt;/code>), pero esto a menudo causaba efectos secundarios graves donde las configuraciones se propagaban accidentalmente a otros módulos.&lt;/p>
&lt;p>En CMake moderno, todo se trata como &lt;strong>objetivos (Targets)&lt;/strong> y &lt;strong>propiedades (Properties)&lt;/strong>. Es similar a la relación entre clases y variables miembro en la programación orientada a objetos.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Objetivo (Target)&lt;/strong>: Archivos ejecutables (Executable) y bibliotecas (Library).&lt;/li>
&lt;li>&lt;strong>Propiedad (Property)&lt;/strong>: Archivos fuente, directorios de inclusión, opciones de compilación, otras bibliotecas a enlazar, etc., necesarios para compilar ese objetivo.&lt;/li>
&lt;/ul>
&lt;p>Al encapsular (confinar) la configuración solo en objetivos específicos, es posible crear definiciones de compilación seguras que no fallen ni siquiera en proyectos a gran escala.&lt;/p>
&lt;h3 id="el-cmakeliststxt-mínimo">El &lt;code>CMakeLists.txt&lt;/code> mínimo
&lt;/h3>&lt;p>Primero, echemos un vistazo al &lt;code>CMakeLists.txt&lt;/code> más básico.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cmake" data-lang="cmake">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Especifica la versión mínima requerida de CMake
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">cmake_minimum_required&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">VERSION&lt;/span> &lt;span class="s">3.20&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Especifica el nombre del proyecto y el lenguaje utilizado
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">project&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">MyAwesomeApp&lt;/span> &lt;span class="s">VERSION&lt;/span> &lt;span class="s">1.0.0&lt;/span> &lt;span class="s">LANGUAGES&lt;/span> &lt;span class="s">CXX&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Requiere el estándar de C++ (C++20)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">set&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">CMAKE_CXX_STANDARD&lt;/span> &lt;span class="s">20&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">set&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">CMAKE_CXX_STANDARD_REQUIRED&lt;/span> &lt;span class="s">ON&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">set&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">CMAKE_CXX_EXTENSIONS&lt;/span> &lt;span class="s">OFF&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="c"># Desactiva las extensiones específicas del compilador
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Definición del objetivo ejecutable
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">add_executable&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">MyAwesomeApp&lt;/span> &lt;span class="s">main.cpp&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Con estas pocas líneas, se completa la configuración de compilación de un archivo ejecutable portátil que requiere C++20 y desactiva las extensiones del compilador.&lt;/p>
&lt;h2 id="3-dependencias-y-alcance-public--private--interface">3. Dependencias y alcance: PUBLIC / PRIVATE / INTERFACE
&lt;/h2>&lt;p>El concepto más importante y difícil para dominar CMake moderno es el de los tres modificadores de acceso (alcances): &lt;strong>&lt;code>PUBLIC&lt;/code>, &lt;code>PRIVATE&lt;/code> e &lt;code>INTERFACE&lt;/code>&lt;/strong>, que se utilizan en comandos como &lt;code>target_include_directories&lt;/code> y &lt;code>target_link_libraries&lt;/code>.&lt;/p>
&lt;p>Estos controlan si las propiedades de un objetivo (rutas de inclusión o bibliotecas dependientes) son &amp;ldquo;necesarias para su propia compilación&amp;rdquo; y si deben &amp;ldquo;propagarse a otros objetivos que dependen de él&amp;rdquo;.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>&lt;code>PRIVATE&lt;/code>&lt;/strong>: Necesario solo para la propia compilación del objetivo. &lt;strong>No&lt;/strong> se propaga a los objetivos dependientes.&lt;/li>
&lt;li>&lt;strong>&lt;code>INTERFACE&lt;/code>&lt;/strong>: No es necesario para la propia compilación del objetivo, pero &lt;strong>sí&lt;/strong> se propaga para compilar los objetivos dependientes (utilizado en bibliotecas solo de encabezado, etc.).&lt;/li>
&lt;li>&lt;strong>&lt;code>PUBLIC&lt;/code>&lt;/strong>: Necesario para la propia compilación del objetivo, y también se &lt;strong>propaga&lt;/strong> a los objetivos dependientes (&lt;code>PRIVATE&lt;/code> + &lt;code>INTERFACE&lt;/code>).&lt;/li>
&lt;/ol>
&lt;p>Visualicemos la propagación de dependencias (propagación de requisitos de uso) con el siguiente diagrama.&lt;/p>
&lt;div class="mermaid">graph TD
subgraph "Bibliotecas"
MathLib["MathLib (Biblioteca estática)"]
NetworkLib["NetworkLib (Biblioteca compartida)"]
HeaderLib["HeaderLib (Solo encabezado)"]
end
subgraph "Aplicación"
App["Aplicación principal"]
end
App -- "target_link_libraries(App PRIVATE MathLib)" --> MathLib
App -- "target_link_libraries(App PUBLIC NetworkLib)" --> NetworkLib
NetworkLib -- "target_link_libraries(NetworkLib INTERFACE HeaderLib)" --> HeaderLib
note1["App depende de la implementación de MathLib, pero no la expone externamente"]
note2["NetworkLib expone la interfaz de HeaderLib"]&lt;/div>
&lt;h3 id="ejemplo-específico-del-uso-del-alcance">Ejemplo específico del uso del alcance
&lt;/h3>&lt;p>Supongamos que una biblioteca &lt;code>MyLib&lt;/code> usa &lt;code>nlohmann/json&lt;/code> como implementación interna y no incluye &lt;code>nlohmann/json&lt;/code> en su archivo de encabezado público &lt;code>MyLib.hpp&lt;/code>. En este caso, el usuario de &lt;code>MyLib&lt;/code> (la aplicación) no necesita conocer la existencia de la biblioteca JSON.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cmake" data-lang="cmake">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Definición de la biblioteca
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">add_library&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">MyLib&lt;/span> &lt;span class="s">src/MyLib.cpp&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Especificación de los directorios de inclusión del propio proyecto
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># El directorio include es necesario para los usuarios de MyLib, por lo que es PUBLIC
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c"># El directorio src solo se usa en la implementación de MyLib, por lo que es PRIVATE
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">target_include_directories&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">MyLib&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">PUBLIC&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">$&amp;lt;&lt;/span>&lt;span class="nv">BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">$&amp;lt;&lt;/span>&lt;span class="nv">INSTALL_INTERFACE:include&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">PRIVATE&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">${&lt;/span>&lt;span class="nv">CMAKE_CURRENT_SOURCE_DIR&lt;/span>&lt;span class="o">}&lt;/span>&lt;span class="s">/src&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># La biblioteca json se usa solo en la implementación interna, por lo que se enlaza como PRIVATE
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">target_link_libraries&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">MyLib&lt;/span> &lt;span class="s">PRIVATE&lt;/span> &lt;span class="s">nlohmann_json::nlohmann_json&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Por el contrario, si escribe &lt;code>#include &amp;lt;nlohmann/json.hpp&amp;gt;&lt;/code> dentro de &lt;code>MyLib.hpp&lt;/code>, el usuario de &lt;code>MyLib&lt;/code> también debe conocer la ruta del encabezado de JSON o se producirá un error de compilación, por lo que debe enlazarse como &lt;code>PUBLIC&lt;/code>. Al establecer este alcance adecuadamente, puede acortar el tiempo de compilación y evitar la fuga de dependencias innecesarias.&lt;/p>
&lt;h2 id="4-compilación-fuera-de-la-fuente-out-of-source-build">4. Compilación fuera de la fuente (Out-of-source Build)
&lt;/h2>&lt;p>Una mejor práctica que siempre se debe seguir al usar CMake es la &lt;strong>compilación fuera de la fuente&lt;/strong>.
Este es un método en el que los artefactos de compilación (archivos objeto y archivos ejecutables) no se generan en absoluto en el directorio donde se encuentra el código fuente (árbol de fuentes), sino que se separan en un directorio dedicado diferente (generalmente &lt;code>build/&lt;/code>) para la compilación.&lt;/p>
&lt;div class="mermaid">graph TD
Root["Raíz del proyecto (Repositorio de Git)"]
Root --> Src["src/"]
Root --> Inc["include/"]
Root --> CMake["CMakeLists.txt"]
Root -. "Crear dir build" .-> Build["build/ (Fuera de la fuente)"]
Build --> Obj["CMakeFiles/ (Archivos objeto, cachés)"]
Build --> Bin["Binarios (MyApp.exe)"]
Build --> Gen["Makefile generado / build.ninja"]&lt;/div>
&lt;p>Con esta configuración, si desea restablecer el entorno de compilación, solo necesita eliminar el directorio &lt;code>build&lt;/code> por completo, y dado que el árbol de fuentes no se contamina, la gestión con Git también es más fácil (solo necesita agregar &lt;code>build/&lt;/code> al &lt;code>.gitignore&lt;/code>).&lt;/p>
&lt;h3 id="pasos-para-ejecutar-la-compilación">Pasos para ejecutar la compilación
&lt;/h3>&lt;p>En CMake moderno, puede ejecutar la compilación con comandos comunes que no dependen del sistema operativo o la herramienta de compilación.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 1. Configuración y generación (creando el directorio de compilación y configurando)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cmake -S . -B build
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 2. Compilación real (compilación y enlace)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cmake --build build --config Release
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># (Opcional) Usar la opción -j para compilación multihilo&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">cmake --build build --config Release -j &lt;span class="m">8&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Aquí, &lt;code>cmake -S . -B build&lt;/code> significa &amp;ldquo;establecer el directorio actual (&lt;code>.&lt;/code>) como directorio fuente y &lt;code>build&lt;/code> como directorio de compilación&amp;rdquo;.&lt;/p>
&lt;h2 id="5-cómo-integrar-bibliotecas-de-terceros">5. Cómo integrar bibliotecas de terceros
&lt;/h2>&lt;p>En el desarrollo de C++, la integración de bibliotecas externas (bibliotecas de terceros) siempre ha sido un gran obstáculo. Sin embargo, hoy en día, los siguientes 3 enfoques son principalmente el estándar.&lt;/p>
&lt;h3 id="51-find_package-búsqueda-de-bibliotecas-instaladas-en-el-sistema">5.1. find_package (Búsqueda de bibliotecas instaladas en el sistema)
&lt;/h3>&lt;p>Este es el método más tradicional para encontrar y enlazar bibliotecas que ya están instaladas en el sistema (por ejemplo, OpenSSL, Zlib, etc.).&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cmake" data-lang="cmake">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">find_package&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">ZLIB&lt;/span> &lt;span class="s">REQUIRED&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">if&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">ZLIB_FOUND&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span> &lt;span class="nb">target_link_libraries&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">MyAwesomeApp&lt;/span> &lt;span class="s">PRIVATE&lt;/span> &lt;span class="s">ZLIB::ZLIB&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">endif&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="52-fetchcontent-descarga-desde-el-código-fuente-e-integración">5.2. FetchContent (Descarga desde el código fuente e integración)
&lt;/h3>&lt;p>Este es un módulo introducido en CMake 3.11 y mejorado desde la versión 3.14. Durante la compilación, descarga el código fuente directamente desde un repositorio de Git externo o URL, y lo compila junto como parte del proyecto. Dado que las dependencias se pueden administrar de forma centralizada, la reproducibilidad multiplataforma es extremadamente alta.&lt;/p>
&lt;p>El siguiente es un ejemplo de cómo integrar GoogleTest usando FetchContent.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cmake" data-lang="cmake">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">include&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">FetchContent&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">FetchContent_Declare&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">googletest&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">GIT_REPOSITORY&lt;/span> &lt;span class="s">https://github.com/google/googletest.git&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">GIT_TAG&lt;/span> &lt;span class="s">v1.14.0&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Integrar la biblioteca en el proyecto
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">FetchContent_MakeAvailable&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">googletest&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Creación y enlace de archivo ejecutable para pruebas
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">add_executable&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">MyTests&lt;/span> &lt;span class="s">test/main.cpp&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">target_link_libraries&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">MyTests&lt;/span> &lt;span class="s">PRIVATE&lt;/span> &lt;span class="s">gtest_main&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="53-integración-con-vcpkg">5.3. Integración con vcpkg
&lt;/h3>&lt;p>Al usar el gestor de paquetes para C++ &lt;strong>vcpkg&lt;/strong>, liderado por Microsoft, puede integrar fácilmente miles de bibliotecas. vcpkg está diseñado para integrarse perfectamente con CMake.&lt;/p>
&lt;p>Simplemente especificando el archivo de cadena de herramientas de vcpkg al ejecutar CMake, &lt;code>find_package&lt;/code> buscará automáticamente las bibliotecas dentro de vcpkg.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">cmake -S . -B build -DCMAKE_TOOLCHAIN_FILE&lt;span class="o">=&lt;/span>/path/to/vcpkg/scripts/buildsystems/vcpkg.cmake
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Además, al colocar &lt;code>vcpkg.json&lt;/code> (modo de manifiesto) en la raíz del proyecto, puede automatizar completamente el control de versiones de las bibliotecas necesarias.&lt;/p>
&lt;h2 id="6-banderas-del-compilador-multiplataforma">6. Banderas del compilador multiplataforma
&lt;/h2>&lt;p>Para que la compilación se complete en cualquiera de los entornos Windows (MSVC), Linux (GCC/Clang) y macOS (Apple Clang), es necesario establecer adecuadamente las banderas específicas del compilador.&lt;/p>
&lt;p>Al usar las &lt;strong>expresiones de generador (Generator Expressions)&lt;/strong> de CMake, puede describir declarativamente bifurcaciones condicionales como &amp;ldquo;si el compilador es MSVC, esta bandera, de lo contrario, aquella bandera&amp;rdquo;. Las expresiones de generador utilizan la sintaxis &lt;code>$&amp;lt;...&amp;gt;&lt;/code> y se evalúan durante la generación del sistema de compilación (fase Generate).&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cmake" data-lang="cmake">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Ejemplo de habilitación del nivel máximo de advertencias en todas las plataformas
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">target_compile_options&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">MyAwesomeApp&lt;/span> &lt;span class="s">PRIVATE&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># En el caso de MSVC
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span> &lt;span class="o">$&amp;lt;&lt;/span>&lt;span class="nv">$&amp;lt;CXX_COMPILER_ID:MSVC&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="s">:/W4&lt;/span> &lt;span class="s">/WX&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c"># En el caso de GCC o Clang
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span> &lt;span class="o">$&amp;lt;&lt;/span>&lt;span class="nv">$&amp;lt;OR:$&amp;lt;CXX_COMPILER_ID:GNU&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="s">,&lt;/span>&lt;span class="o">$&amp;lt;&lt;/span>&lt;span class="nv">CXX_COMPILER_ID:Clang&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="s">,&lt;/span>&lt;span class="o">$&amp;lt;&lt;/span>&lt;span class="nv">CXX_COMPILER_ID:AppleClang&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="s">&amp;gt;:-Wall&lt;/span> &lt;span class="s">-Wextra&lt;/span> &lt;span class="s">-Wpedantic&lt;/span> &lt;span class="s">-Werror&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>El uso de este método evita que &lt;code>CMakeLists.txt&lt;/code> se vuelva difícil de leer debido al uso frecuente de bifurcaciones condicionales como &lt;code>if(MSVC)&lt;/code>, y permite una configuración flexible para cada objetivo.&lt;/p>
&lt;h2 id="7-construcción-del-entorno-de-pruebas-ctest">7. Construcción del entorno de pruebas (CTest)
&lt;/h2>&lt;p>En el aseguramiento de la calidad en un entorno multiplataforma, la introducción de pruebas automáticas es indispensable. CMake incluye un ejecutor de pruebas llamado &lt;strong>CTest&lt;/strong> de serie.&lt;/p>
&lt;p>Los pasos para integrar GoogleTest, que se introdujo anteriormente con &lt;code>FetchContent&lt;/code>, con CTest son los siguientes:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;span class="lnt">9
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cmake" data-lang="cmake">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Habilitar la funcionalidad de pruebas (escribir solo una vez en el CMakeLists.txt de la raíz)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">enable_testing&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">add_executable&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">MyMathTests&lt;/span> &lt;span class="s">test/math_test.cpp&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">target_link_libraries&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">MyMathTests&lt;/span> &lt;span class="s">PRIVATE&lt;/span> &lt;span class="s">gtest_main&lt;/span> &lt;span class="s">MyLib&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Registrar como prueba en CTest
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">include&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">GoogleTest&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">gtest_discover_tests&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">MyMathTests&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Después de la compilación, simplemente ejecute el comando &lt;code>ctest&lt;/code> dentro del directorio de compilación para ejecutar todas las pruebas y reportar los resultados.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cd&lt;/span> build
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">ctest --output-on-failure -C Release
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="8-teoría-y-modelo-matemático-de-los-sistemas-de-compilación">8. Teoría y modelo matemático de los sistemas de compilación
&lt;/h2>&lt;p>Aquí, cambiando un poco la perspectiva, consideremos la eficiencia de los sistemas de compilación y la compilación en paralelo en proyectos a gran escala utilizando un modelo matemático.&lt;/p>
&lt;p>La reducción del tiempo de compilación (tiempo de compilación) es un desafío eterno en el desarrollo de C++. Al dividir el código fuente y compilar en paralelo, se puede reducir el tiempo de compilación. Esta mejora de velocidad (Speedup) debida a la paralelización se modela mediante la &lt;strong>Ley de Amdahl (Amdahl&amp;rsquo;s Law)&lt;/strong>.&lt;/p>
&lt;p>Si la proporción de la parte de un programa que se puede paralelizar es $P$, la proporción de la parte que debe ejecutarse secuencialmente (no paralelizable) es $1-P$, y el número de procesadores utilizados es $N$, entonces la tasa de mejora de velocidad máxima teórica general $S(N)$ se expresa con la siguiente fórmula:&lt;/p>
$$ S(N) = \frac{1}{(1 - P) + \frac{P}{N}} $$
&lt;p>En el proceso de compilación de C++, la &amp;ldquo;compilación de cada archivo &lt;code>.cpp&lt;/code> a &lt;code>.o&lt;/code> u &lt;code>.obj&lt;/code>&amp;rdquo; es independiente y paralelizable (la parte de $P$), pero el &amp;ldquo;proceso de enlace final (Linker)&amp;rdquo; se realiza básicamente de forma secuencial (la parte de $1-P$).&lt;/p>
&lt;p>Por lo tanto, no importa cuántos núcleos de CPU ($N \to \infty$) se proporcionen, mientras exista el cuello de botella del tiempo de enlace, la tasa de mejora de velocidad máxima se acercará asintóticamente a la siguiente fórmula:&lt;/p>
$$ \lim_{N \to \infty} S(N) = \frac{1}{1 - P} $$
&lt;p>Lo que esta fórmula sugiere es que &amp;ldquo;simplemente aumentar los núcleos de la CPU tiene un límite en la reducción del tiempo de compilación&amp;rdquo;. Al utilizar adecuadamente &lt;code>PRIVATE&lt;/code> e &lt;code>INTERFACE&lt;/code> en CMake moderno y minimizar las dependencias de los archivos de encabezado (utilizando declaraciones anticipadas, etc.), aumentar la proporción de $P$ y reducir los objetivos de recompilación durante la compilación incremental se convierte en la estrategia de aceleración de compilación más efectiva en la práctica.&lt;/p>
&lt;p>Además, para reducir el tiempo de enlace, es importante cambiar de bibliotecas estáticas (Static Library) a bibliotecas compartidas / DLL (Shared Library), e incorporar enlazadores rápidos como LLD / Mold.&lt;/p>
&lt;p>En CMake, puede especificar fácilmente el enlazador de la siguiente manera:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cmake" data-lang="cmake">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Configurar para usar el enlazador lld en el entorno Clang/GCC
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">if&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">UNIX&lt;/span> &lt;span class="s">AND&lt;/span> &lt;span class="s">NOT&lt;/span> &lt;span class="s">APPLE&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span> &lt;span class="nb">target_link_options&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">MyAwesomeApp&lt;/span> &lt;span class="s">PRIVATE&lt;/span> &lt;span class="s2">&amp;#34;-fuse-ld=lld&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">endif&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="9-ejemplo-práctico-de-una-estructura-de-directorios-compleja">9. Ejemplo práctico de una estructura de directorios compleja
&lt;/h2>&lt;p>En el desarrollo real de aplicaciones, la estructura de directorios es una combinación de múltiples módulos. Por último, mostraremos la estructura de directorios ideal para un proyecto de mediana escala y la relación entre los &lt;code>CMakeLists.txt&lt;/code> padre e hijo.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">ProjectRoot/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── CMakeLists.txt (Root: Definición de todo el proyecto)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── vcpkg.json (Definición de bibliotecas dependientes)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── external/ (Módulos externos)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── include/ (Encabezados públicos)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── myapp/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── src/ (Código fuente y definiciones de compilación internas)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── CMakeLists.txt
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── main.cpp
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── math/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ├── CMakeLists.txt
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ├── Vector3.hpp
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └── Vector3.cpp
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── network/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── CMakeLists.txt
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── NetworkManager.cpp
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└── tests/ (Código de prueba)
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── CMakeLists.txt
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> └── math_test.cpp
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>El &lt;code>CMakeLists.txt&lt;/code> raíz solo realiza configuraciones de entorno y definiciones de opciones globales, y agrega subdirectorios con &lt;code>add_subdirectory()&lt;/code>.&lt;/p>
&lt;p>&lt;strong>&lt;code>CMakeLists.txt&lt;/code> raíz&lt;/strong>:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cmake" data-lang="cmake">&lt;span class="line">&lt;span class="cl">&lt;span class="nb">cmake_minimum_required&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">VERSION&lt;/span> &lt;span class="s">3.20&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">project&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">ComplexApp&lt;/span> &lt;span class="s">LANGUAGES&lt;/span> &lt;span class="s">CXX&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Configuración global
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">set&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">CMAKE_CXX_STANDARD&lt;/span> &lt;span class="s">20&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">set&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">CMAKE_CXX_STANDARD_REQUIRED&lt;/span> &lt;span class="s">ON&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Habilitar pruebas
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">enable_testing&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Agregar subdirectorios
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">add_subdirectory&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">src&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">add_subdirectory&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">tests&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;strong>&lt;code>src/CMakeLists.txt&lt;/code>&lt;/strong>:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cmake" data-lang="cmake">&lt;span class="line">&lt;span class="cl">&lt;span class="c"># Agregar cada módulo
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">add_subdirectory&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">math&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="nb">add_subdirectory&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">network&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Archivo ejecutable final
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">add_executable&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">ComplexApp&lt;/span> &lt;span class="s">main.cpp&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">&lt;/span>&lt;span class="c"># Enlace de módulos
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c">&lt;/span>&lt;span class="nb">target_link_libraries&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">ComplexApp&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">PRIVATE&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">MathLib&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">NetworkLib&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>&lt;span class="err">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Al dividir el &lt;code>CMakeLists.txt&lt;/code> por directorio y definir dependencias entre objetivos de esta manera, aumenta la reutilización de los módulos y también mejora el paralelismo de la compilación. Esta es la verdadera esencia del &amp;ldquo;entorno de compilación modularizado&amp;rdquo; defendido por CMake moderno.&lt;/p>
&lt;h2 id="10-resumen">10. Resumen
&lt;/h2>&lt;p>Hemos explicado los pasos para construir un entorno de compilación de C++ multiplataforma utilizando CMake.
Repasemos los puntos clave.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Comprensión del metasistema de compilación&lt;/strong>: CMake es una herramienta que genera scripts de compilación.&lt;/li>
&lt;li>&lt;strong>Implementación de CMake moderno&lt;/strong>: No usar variables, y encapsular la configuración en una forma &lt;strong>orientada a objetivos&lt;/strong> con comandos como &lt;code>add_executable&lt;/code>, &lt;code>target_link_libraries&lt;/code> y &lt;code>target_include_directories&lt;/code>.&lt;/li>
&lt;li>&lt;strong>Configuración adecuada del alcance&lt;/strong>: Usar correctamente &lt;code>PUBLIC&lt;/code>, &lt;code>PRIVATE&lt;/code> e &lt;code>INTERFACE&lt;/code> para controlar la propagación de dependencias.&lt;/li>
&lt;li>&lt;strong>Compilación estricta fuera de la fuente&lt;/strong>: Compilar dentro del directorio &lt;code>build/&lt;/code> y no ensuciar el árbol de fuentes.&lt;/li>
&lt;li>&lt;strong>Integración con terceros&lt;/strong>: Utilizar &lt;code>FetchContent&lt;/code> y &lt;code>vcpkg&lt;/code> para automatizar la resolución de bibliotecas dependientes.&lt;/li>
&lt;li>&lt;strong>Uso de expresiones de generador&lt;/strong>: Absorber inteligentemente las diferencias en las banderas de cada compilador.&lt;/li>
&lt;li>&lt;strong>Enfoque matemático&lt;/strong>: Ser consciente de la Ley de Amdahl, reducir las dependencias y aumentar la eficiencia de la compilación en paralelo.&lt;/li>
&lt;/ol>
&lt;p>CMake puede parecer difícil al principio, pero una vez que comprenda los conceptos de objetivos y propiedades, podrá mantener un entorno de compilación ordenado, sin importar cuán complejo y grande sea su proyecto C++. Esperamos que utilice este artículo como referencia y construya su entorno de desarrollo en C++ con la sintaxis más reciente de CMake moderno.&lt;/p></description></item></channel></rss>