c++ module standards abi

Módulos C++ y el C++ ABI



module standards (3)

Los encabezados precompilados (PCH) son archivos especiales que ciertos compiladores pueden generar para un archivo .cpp. Lo que son es exactamente eso: código fuente precompilado. Son código fuente que se ha alimentado a través del compilador y se ha incorporado en un formato dependiente del compilador.

Los PCH se utilizan comúnmente para acelerar la compilación. Pones encabezados de uso común en el PCH, luego solo incluye el PCH. Cuando hace un #include en el PCH, su compilador no hace el trabajo habitual de #include. En su lugar, carga estos símbolos precompilados directamente en el compilador. No se ejecuta un preprocesador de C ++. No se ejecuta un compilador de C ++. No # incluyendo un millón de archivos diferentes. Se carga un archivo y los símbolos aparecen completamente formados directamente en el área de trabajo de su compilador.

Menciono todo eso porque los módulos son PCHs en su forma perfecta . Los PCH son básicamente un hack gigante construido sobre un sistema que no permite módulos reales. El propósito de los módulos es, en última instancia, poder tomar un archivo, generar un archivo de módulo específico del compilador que contenga símbolos, y luego otro archivo carga ese módulo según sea necesario. Los símbolos están precompilados, así que de nuevo, no hay necesidad de #incluir un montón de cosas, ejecutar un compilador, etc. Tu código dice, import thing.foo , y aparece.

Mire cualquiera de los encabezados de biblioteca estándar derivados de STL. Tome <map> por ejemplo. Es probable que este archivo sea gigantesco o tenga muchas #inclusiones de otros archivos que hagan que el archivo resultante sea gigantesco. Eso es un montón de análisis de C ++ que tiene que suceder. Debe ocurrir para cada archivo .cpp que tenga #include <map> en él. Cada vez que compilas un archivo fuente, el compilador tiene que recompilar lo mismo. Terminado. Y más. Y otra vez.

¿Cambia <map> entre compilaciones? No, pero tu compilador no puede saber eso. Así que hay que seguir compilándolo. Cada vez que toca un archivo .cpp, debe compilar todos los encabezados que este archivo .cpp incluya. Aunque no hayas tocado esos encabezados o archivos de origen que afectan a esos encabezados.

Los archivos PCH eran una forma de solucionar este problema. Pero son limitados, porque son solo un hack. Solo puede incluir uno por archivo .cpp, ya que debe ser lo primero que incluyan los archivos .cpp. Y como solo hay un PCH, si haces algo que cambia el PCH (como agregarle un nuevo encabezado), tienes que volver a compilar todo en ese PCH.

Los módulos esencialmente no tienen nada que ver con el ABI de compilador cruzado (aunque tener uno de esos sería bueno, y los módulos harían un poco más fácil de definir uno). Su propósito fundamental es acelerar los tiempos de compilación.

He estado leyendo sobre la propuesta de los módulos de C ++ ( último borrador ) pero no entiendo bien qué problema (s) pretende resolver.

¿Su propósito es permitir que un compilador construido por un compilador sea utilizado por cualquier otro compilador (en el mismo sistema operativo / arquitectura, por supuesto)? Es decir, ¿la propuesta equivale a estandarizar el ABI de C ++?

De no ser así, ¿se está considerando otra propuesta que estandarice el ABI de C ++ y permita que los compiladores interactúen?


Los módulos en C ++ tienen que ser principalmente mejores que las soluciones actuales, es decir, cuando una biblioteca consta de un archivo * .so y un archivo * .h con API. Tienen que resolver los problemas que están hoy en día con #includes, es decir:

  • requiere macroguards (macros que impiden que las definiciones se proporcionen varias veces)
  • están estrictamente basados ​​en texto (para que puedan ser engañados y, en condiciones normales, se reinterpretan, lo que también brinda la oportunidad de verse de manera diferente en las diferentes unidades de compilación que se unirán a continuación)
  • no distinga entre bibliotecas dependientes que solo se usan de manera instrumental y derivadas de (especialmente si el encabezado proporciona plantillas de función en línea)

A pesar de lo que dice Xeo, los módulos no existen en Java o C #. De hecho, en estos idiomas, "cargar módulos" se basa en eso "ok, aquí tiene CLASSPATH y busque a través de él para encontrar los módulos que pueden proporcionar símbolos que el archivo de origen realmente usa". La declaración de "importación" en Java no es "solicitud de módulo" en absoluto, lo mismo que "usar" en C ++ ("import ns.ns2. *" En Java es lo mismo que "usar el espacio de nombres ns :: ns2" en C ++) . No creo que esa solución pueda usarse en C ++. La aproximación más cercana que puedo imaginar son los paquetes en Vala o los módulos en Tcl (los de la versión 8.5).

Me imagino que los módulos C ++ no pueden ser multiplataforma ni cargados dinámicamente (requiere un cargador de módulos dinámico C ++ dedicado; no es imposible, pero hoy en día es difícil de definir). Definitivamente, dependerán de la plataforma y también deberán ser configurables cuando se soliciten. Pero prácticamente solo se requiere un C ++ ABI estable dentro del rango de un sistema, tal como lo es ahora con C ++ ABI.


Los módulos son lo que ofrecen Java, C # y muchos otros lenguajes modernos. Reducen enormemente el tiempo de compilación simplemente porque el código que se encuentra en el encabezado de hoy no tiene que analizarse una y otra vez, cada vez que se incluye. Cuando diga #include <vector> , el contenido de <vector> se copiará en el archivo actual. #include realmente no es nada más que copiar y pegar.

En el mundo de los módulos, simplemente dices import std.vector; por ejemplo, y el compilador carga la tabla de consulta / símbolo de ese módulo. El archivo del módulo tiene un formato que facilita el análisis y uso del compilador. También se analiza una sola vez , cuando se compila el módulo. Después de eso, solo se consulta el archivo del módulo generado por el compilador por la información que se necesita.

Debido a que los archivos de módulo son generados por compilador, estarán bastante ligados a la representación interna del código C ++ (AST) del compilador y, como tal, probablemente no serán portátiles (al igual que los archivos .o / .so / .a , por el nombre mangling etc.).