Ninja: mezclar rutas absolutas de archivo depfile con rutas relativas manifiestas rompe reconstrucciones

Creado en 24 feb. 2017  ·  70Comentarios  ·  Fuente: ninja-build/ninja

El manual ninja advierte contra tal mezcla, pero se ha convertido en una seria limitación.

El problema es que la gente quiere que sus sistemas de compilación invoquen al compilador con una ruta absoluta al archivo fuente. Esto produce una mejor salida para que los IDE coincidan con los mensajes de error y vuelvan a consultar los archivos originales. También puede afectar las rutas registradas en la información de depuración. Sin embargo, esto entra en conflicto con la preferencia de ninja por las rutas relativas en el manifiesto de compilación.

Aquí hay una secuencia de comandos que demuestra el problema: ninja-bug.bash.txt

Comentario más útil

Realmente no creo que la solución deba ser "solucionar esto en todas las demás herramientas".

1924 demuestra una solución funcional completa con pruebas, basada en el enfoque ninja_workdir . Un generador que use esto puede resolver todos los problemas anteriores.

Todos 70 comentarios

CC: @nico @chaoren

En CMake, hay una discusión relevante en el número 16675 , número 13894 y MR 520 .

Como solución alternativa, puede establecer el directorio de salida del objeto explícitamente, incluso "." o "..", pero la ruta absoluta también funciona.
ninjatst.bash.txt

@zlolik IIUC sugiere colocar rutas absolutas en los nodos gráficos del manifiesto de compilación ( build.ninja ). Ciertamente, eso funciona (y es lo que hace CMake en compilaciones fuera de la fuente), pero mi punto aquí es que Ninja desaconseja el uso de rutas absolutas y, sin embargo, los IDE las requieren en la salida.

También es hipotéticamente posible que un compilador dado -c foo.c pueda generar una ruta absoluta en el archivo de dep de todos modos. Si eso sucede, Ninja no reconocerá la dependencia debido al mismo problema informado aquí.

Arreglar esto requerirá que Ninja pueda reconocer cuándo una ruta relativa y una ruta absoluta son el mismo archivo y tienen solo un nodo gráfico internamente en lugar de dos. Hacer esto solo para el procesamiento de archivos dep puede ser suficiente, ya que es razonable pedir a los generadores de build.ninja que nombren las rutas de manera consistente dentro del manifiesto de compilación.

@bradking En primer lugar, estoy de acuerdo con usted en que tenemos un problema con ninja y solo sugiero una solución.
Creo que hay 3 problemas relacionados:

  1. Lógica con ruta absoluta/relativa de entrada, más detalles en #1152.
  2. Lógica para forzar la ruta de salida absoluta/relativa. El problema con los compiladores: la única forma de decirle al compilador que desea tener una ruta absoluta en la salida es usar una ruta absoluta en la línea de comando. No es un problema ninja sino nuestro.
  3. Lógica para analizar la ruta absoluta/relativa del archivo depfile. Este problema.

Yo uso 2 soluciones:

  1. Use los prefijos $p y $o en la ruta del generador build.ninja para resolver los primeros 2 problemas. En mi caso $p y $o no son absolutos sino relativos del directorio actual donde se ejecutó el generador build.ninja .
  2. Use algún script para convertir el archivo dep en una ruta compatible con ninja. Algunos compiladores incluso necesitan una llamada separada para generar un archivo dep. Pero no hay un problema de ruta absoluta while.

Como referencia, comencé un hilo en la lista de correo ninja-build con una solución propuesta.

Otro problema relacionado con la información de depuración y cobertura: el uso de comandos con rutas relativas crea también archivos de información de depuración con rutas relativas. El problema es que los archivos de depuración generalmente se colocan junto a los archivos de objetos, no los archivos de origen, por lo que las rutas relativas allí hacen referencia a archivos que no existen.

¿Algún avance en esto? No ha habido ninguna respuesta en el hilo de la lista de correo...

Hola a todos,

También es hipotéticamente posible que un compilador dado -c foo.c pueda generar una ruta absoluta en el archivo de dep de todos modos.

Los archivos de dependencia de IAR v8 solo contienen rutas absolutas.

Nos encontramos con este problema al hacer compilaciones fuera de la fuente con CMake/Ninja/IAR: los archivos generados que terminan en el directorio binario de CMake son relativos en el manifiesto de Ninja, la salida de deps por IAR es absoluta.

Para mí, esto es claramente un problema de Ninja: no debería tener dos nodos para el mismo archivo, pase lo que pase.

He leído la sugerencia de @bradking , pero realmente no entiendo la parte sobre los enlaces simbólicos y por qué no se puede usar getcwd() . ¿Te importaría elaborar?

Realmente no entiendo la parte sobre los enlaces simbólicos y por qué no se puede usar getcwd()

@sebknzl el problema es que las rutas absolutas escritas en build.ninja por el generador pueden contener enlaces simbólicos que intencionalmente no se resuelven por una razón u otra. getcwd() generalmente devuelve una ruta con enlaces simbólicos resueltos. Si Ninja interpretara una ruta relativa en el manifiesto de compilación o un archivo de dep relativo a getcwd() entonces la ruta absoluta que construye puede no coincidir con la que usó el generador de manifiesto de compilación y todavía terminaríamos con dos nodos.

El ninja_workdir que propongo en el hilo que vinculó básicamente le dice a Ninja qué usó el generador como base para las rutas relativas. En la práctica realpath(ninja_workdir) == realpath(getcwd()) siempre debería ser verdadero, pero eso no significa ninja_workdir == getcwd() . Otra alternativa sería que Ninja realpath todo antes de crear nodos, pero eso significaría que $in no se expandiría a lo que pretendía el generador.

@jhasse , consulte este problema y mi propuesta para solucionarlo.

¿Por qué no generar un _build.ninja_ con rutas absolutas controladas por un CMAKE_NINJA_GENERATOR_OPTION_ ?

es decir, así, que funciona:

Claus-MBP:build clausklein$ cat build.ninja 

# project dir
p = /Users/clausklein/Downloads
# object dir
o = /Users/clausklein/Downloads/.ninjatst.build

rule cp
  command = cp $in $out

rule cc
  depfile = $out.d
  deps = gcc
  command = cc -I$o -c $in -o $out -MD -MT $out -MF $out.d

# All absolute paths works
build all: phony $o/foo.o

# All absolute paths works
build $o/foo.h: cp $p/foo.h.in
  IN = $p/foo.h.in

# All absolute paths works
build $o/foo.o: cc $p/foo.c || $o/foo.h
  IN = "$p/foo.c"

default all

Claus-MBP:build clausklein$ 

generado con ninjatst.bash.txt

@ClausKlein intentamos enseñarle a CMake a usar rutas absolutas. Vea las discusiones que vinculé en https://github.com/ninja-build/ninja/issues/1251#issuecomment -282322776. Prefiero no agregar una opción que diga "hacer las cosas de una manera diferente que solucione algunos casos y rompa otros".

Realmente necesitamos la función Ninja en la propuesta que vinculé en https://github.com/ninja-build/ninja/issues/1251#issuecomment -487618865 para arreglar esto correctamente.

Está bien

Entonces, esta solución para el sistema mesonbuild también estaría disponible ;-)

Am 12.03.2020 um 12:56 schrieb Brad King [email protected] :

@ClausKlein https://github.com/ClausKlein intentamos enseñar a CMake a usar rutas absolutas. Vea las discusiones que vinculé en #1251 (comentario) https://github.com/ninja-build/ninja/issues/1251#issuecomment-282322776 . Prefiero no agregar una opción que diga "hacer las cosas de una manera diferente que solucione algunos casos y rompa otros".

Realmente necesitamos la función Ninja en la propuesta que vinculé en #1251 (comentario) https://github.com/ninja-build/ninja/issues/1251#issuecomment-487618865 para arreglar esto correctamente.


Estás recibiendo esto porque te mencionaron.
Responda a este correo electrónico directamente, véalo en GitHub https://github.com/ninja-build/ninja/issues/1251#issuecomment-598146822 , o cancele la suscripción https://github.com/notifications/unsubscribe-auth/AAN7QWWEDHMDA45DQVPLOUDRHDEVDANCNFSM4DBNL6GA .

Digamos que Ninja usaría ninja_workdir para hacer coincidir la información del archivo de profundidad y tenemos la situación en la que ninja_workdir != getcwd() debido a un enlace simbólico. ¿Qué pasa si el compilador ahora imprime rutas absolutas usando getcwd() ?

El compilador no debe usar getcwd() para nada a menos que esas cosas se hayan pasado como rutas relativas, en cuyo caso es probable que el generador del sistema de compilación deba asumir la responsabilidad.

O podemos considerar intentar normalizar wrt tanto ninja_workdir como getcwd() .

Bueno, el compilador tampoco debería devolver una ruta absoluta en el archivo dep cuando se le dan rutas relativas;)

@ClausKlein intentamos enseñarle a CMake a usar rutas absolutas. Vea las discusiones que vinculé en # 1251 (comentario). Prefiero no agregar una opción que diga "hacer las cosas de una manera diferente que solucione algunos casos y rompa otros".

¿Qué se rompió exactamente cuando usó rutas absolutas como lo sugirió @ClausKlein?

Si el compilador recibe rutas absolutas, el archivo dep que genera tiene rutas absolutas, y esas no se reconcilian con las rutas relativas a los encabezados en el manifiesto de compilación, por ejemplo, para los encabezados generados. Vea el enlace ninja-bug.bash.txt en mi primera publicación en la parte superior de este número. Muestra un ejemplo paso a paso de lo que sucede y se expresa únicamente en términos de Ninja y no de CMake.

Lo he leído, pero ¿por qué no usar https://github.com/ninja-build/ninja/issues/1251#issuecomment -284533599? ¿Simplemente porque Ninja "desaconseja" los caminos absolutos? Si es así, ¿se trata de un cambio de documentación?

Los archivos build.ninja son mucho más pequeños sin repetir rutas absolutas en todas partes, y eso los hace más rápidos. También se ven mejor, son más fáciles de depurar y son más apropiados para completar con pestañas los nombres de destino de compilación en los shells. En mi opinión, es una buena recomendación que haga Ninja. Ninja solo necesita un poco más de información para conciliar este caso, y eso es lo que propongo.

Las rutas relativas de @bradking pueden no siempre ser cortas:

build jsoncpp@sha/src_lib_json_json_reader.cpp.o: cpp_COMPILER ../../../../../Users/clausklein/Workspace/cpp/jsoncpp/src/lib_json/json_reader.cpp
 DEPFILE = jsoncpp@sha/src_lib_json_json_reader.cpp.o.d
 ARGS = -Ijsoncpp<strong i="7">@sha</strong> -I. -I../../../../../Users/clausklein/Workspace/cpp/jsoncpp -I../../../../../Users/clausklein/Workspace/cpp/jsoncpp/include -I../../../../../Users/clausklein/Workspace/cpp/jsoncpp/dir1 -I../../../../../Users/clausklein/Workspace/cpp/jsoncpp/dir2 -fdiagnostics-color=always -pipe -Wall -Winvalid-pch -Wnon-virtual-dtor -std=c++17 -O3

¡mi ejemplo https://github.com/ninja-build/ninja/issues/1251#issuecomment -597877775 se ve mejor!

Los generadores de CMake tienen una regla sobre no usar secuencias ../ que salen del árbol de compilación. En compilaciones completamente fuera de la fuente, usamos rutas absolutas al árbol de origen y rutas relativas dentro del árbol de compilación. Estos últimos nunca comienzan en ../ porque están bajo el árbol de compilación.

Lo sé, se generó con _mesonbuild_ . ;-)

Pero entonces, ¿por qué no negar la generación en el árbol fuente?

Podemos debatir los méritos de los caminos relativos versus absolutos para siempre. Ninja no debe ser obstinado al respecto. El problema aquí es reconciliar los casos en los que ambos se usan dentro de una sola compilación. El generador del sistema de compilación no siempre puede controlar lo que las herramientas harán con las rutas. Ninja debería admitir rutas combinadas absolutas/relativas al mismo archivo y puede hacerlo con un enfoque simple que describí en mi propuesta. Para el caso de uso motivador, los cambios se aíslan en el análisis de archivos profundos.

Ninja debería admitir rutas mixtas absolutas/relativas al mismo archivo

¡Estoy de acuerdo!

Gracias por todas las explicaciones, estoy empezando a entender.

¿Qué pasaría si Ninja (al encontrar una ruta absoluta en el archivo dep) hiciera una ruta real tanto de cwd como de la ruta que encontró? Luego, eliminaría el cwd con ruta real de la ruta del archivo de ruta real para obtener la ruta relativa para que coincida con el encabezado generado. Funcionaría eso?

getcwd() siempre es una ruta real, por lo que ese paso no es necesario. Si Ninja fuera a realpath() la ruta absoluta proporcionada por el archivo depfile y verifique si hay un prefijo cwd que podría funcionar. Sin embargo, realpath() es una llamada al sistema posiblemente costosa, mientras que mi propuesta ninja_workdir puede conciliar rutas puramente en la memoria a través del procesamiento de cadenas.

También se debe permitir la mezcla en la otra dirección: una ruta absoluta en el manifiesto de compilación pero una ruta relativa en el archivo de configuración. No creo que Ninja deba tener que realpath() cada ruta absoluta mientras analiza build.ninja . Eso probablemente sería lento.

Podríamos usar el resultado para determinar el directorio de trabajo. P.ej:

getcwd(): /var/xyz/build
entrada de archivo profundo: /home/foo/build/bar.h
ruta real (entrada del archivo de profundidad): /var/xyz/build/bar.h
ruta real relativa: bar.h
elimine eso de la entrada del archivo dep: /home/foo/build -> ninja_workdir

De esta manera, solo necesitamos llamar a realpath una vez.

No creo que derivar ninja_workdir automáticamente sea posible en general. ¿Cómo sabemos cuántos componentes lógicos de la ruta lógica original que contiene el enlace simbólico corresponden al directorio de trabajo? Es posible que podamos hacerlo tomando un componente a la vez hasta que su ruta real coincida con el cwd, pero eso parece complicado y propenso a errores. Se siente arriesgado confiar en el primer enlace simbólico que se ve así. También tendríamos que ejecutar realpath() en cada ruta absoluta que encontremos hasta que una se resuelva de esta manera.

El generador del sistema de compilación sabe exactamente qué ruta lógica al directorio de trabajo usó al generar rutas absolutas en declaraciones de compilación y líneas de comando en build.ninja . Por lo tanto, es la fuente de información más confiable para la ruta workdir. Solo necesitamos una forma de comunicar esta información a Ninja, de ahí mi propuesta de enlace ninja_workdir .

No estoy seguro de entender, lo siento. ¿Puede dar un ejemplo donde mi lógica de detección no funcionaría?

Podría romperse si el generador del sistema de compilación coloca un enlace simbólico dentro del árbol de compilación (apuntando a otra parte del árbol de compilación o afuera por completo):

getcwd(): /var/xyz/build
entrada de archivo profundo: /home/foo/build/subdir-link/bar.h
ruta real (entrada del archivo de profundidad): /var/xyz/build/subdir-real/bar.h
ruta real relativa: subdir-real/bar.h
elimine eso de la entrada del archivo dep: ???

CMake no hace esto, pero en general un generador de sistemas de compilación podría hacerlo.

Incluso si estamos dispuestos a decir que no es compatible, la detección aún podría enfrentar:

getcwd(): /var/xyz/build
1000 entradas de archivo profundo: /home/foo/ext-lib/bar{1,2,...}.h
1000 ruta real (entradas de archivo profundo): /var/xyz/ext-lib/bar{1,2,...}.h
1000 rutas reales relativas: ninguna bajo cwd

Ahora imagine que aparece en 1000 archivos de fuente y nunca hay un éxito. Eso es 1 millón de llamadas a realpath() sin ninguna coincidencia para esta heurística. Y eso se repite cada vez que se reconstruye una fuente y se vuelve a analizar su archivo profundo.

enlace simbólico dentro del árbol de compilación -> sí, realmente no podemos admitir eso, dará como resultado todo tipo de otros problemas de todos modos (sin ruta real en todo el lugar).

El segundo ejemplo suena bastante artificial. Normalmente, los archivos dep comienzan con las dependencias locales, no con los encabezados del sistema.

Si realmente resulta ser un problema de rendimiento, ¿podríamos almacenar en caché el directorio de trabajo en .ninja_deps ?

En una compilación fuera de la fuente, muy pocas entradas del archivo dep apuntarán al árbol de compilación. Esto será muy común:

getcwd(): /var/xyz/build
1000 entradas de archivo profundo: /home/foo/project-source/bar{1,2,...}.h
1000 ruta real (entradas de archivo dep): /var/xyz/project-source/bar{1,2,...}.h
1000 rutas reales relativas: ninguna bajo cwd

Ninja tendrá que llamar a realpath() en todos esos por si acaso, o mantener algún tipo de tabla de resultados para evitar las llamadas al sistema reales. No puede saber de antemano cuándo encontrará una ruta de enlace simbólico que se resuelva en el cwd, y ni siquiera sabe si encontrará uno.

Dado que actualmente no funciona mezclar rutas absolutas y reales en el archivo dep, no veo cómo eso sería "muy común".

Los archivos dep del formulario en mi ejemplo ya son muy comunes incluso cuando no se usan enlaces simbólicos o rutas mixtas. Los tengo en la mayoría de mis árboles de construcción. Ninja no puede saber de antemano si se necesita la heurística, por lo que tendrá que bloquear las llamadas al sistema realpath() por si acaso.

Tal vez entendí mal tu ejemplo. ¿Quiere decir un archivo dep con 3000 entradas o fueron esos 3 ejemplos separados para archivos dep con 1000 entradas cada uno?

Me refiero a 1000 entradas de depfile repartidas en cualquier número de depfiles. Podría ser uno. Podrían ser muchos. Podría haber 10000 entradas en un proyecto. Sus rutas pueden apuntar a cualquier parte del sistema de archivos y pueden o no apuntar al árbol de compilación.

¿Puedes dar un ejemplo CMakeLists.txt que resulte en tal combinación de rutas (no tiene que ser 1000, solo una de cada una)?

Es difícil mostrarlo en un archivo CMakeLists.txt porque CMake actualmente se encarga de evitar mezclar rutas en la mayoría de los casos. Sin embargo, hay problemas en el rastreador de problemas de CMake que no se pueden solucionar sin que Ninja solucione esto primero. Consulte, por ejemplo, el problema 13894 de CMake . Los usuarios quieren poder dar rutas absolutas al compilador incluso para las fuentes (y tal vez incluir directorios) en el árbol de compilación, o al realizar compilaciones en la fuente. Esto funciona bien con el generador de archivos Make de CMake. Si hacemos eso con Ninja, los archivos dep regresan con rutas absolutas y no coinciden con las rutas relativas en build.ninja . Tal vez podríamos cambiar a rutas absolutas para todo, pero como se discutió anteriormente aquí, no deberíamos tener que hacer eso.

Tal vez pueda probar esto para las pruebas https://github.com/ClausKlein/build-performance/commit/8013836486e3a459474eb374f6c3da5e20983443

El problema que se muestra aquí se basa en https://github.com/ninja-build/ninja/issues/1251#issue -210080507
Genera tanto target como quieras. es decir, 2 subduers cada uno con 2 archivos fuente:

PWD=/Users/clausklein/Workspace/build-performance/build

rule cp
  command = cp $in $out

rule cc
  depfile = $out.d
  deps = gcc
  command = gcc -c -I$PWD $IN -o $out $FLAGS -MMD -MT $out -MF $out.d

rule link
  command = gcc -o $out $in $LINK_PATH $LINK_LIBRARIES

build foo: phony foo.h
build foo.h: cp foo.h.in

build bin/main0.o: cc /Users/clausklein/Workspace/build-performance/build/subdir0/main.c || foo.h
  IN = /Users/clausklein/Workspace/build-performance/build/subdir0/main.c
build /Users/clausklein/Workspace/build-performance/build/subdir0/file0.o: cc /Users/clausklein/Workspace/build-performance/build/subdir0/file0.c || foo.h
  IN = /Users/clausklein/Workspace/build-performance/build/subdir0/file0.c

build bin/main1.o: cc /Users/clausklein/Workspace/build-performance/build/subdir1/main.c || foo.h
  IN = /Users/clausklein/Workspace/build-performance/build/subdir1/main.c
build /Users/clausklein/Workspace/build-performance/build/subdir1/file0.o: cc /Users/clausklein/Workspace/build-performance/build/subdir1/file0.c || foo.h
  IN = /Users/clausklein/Workspace/build-performance/build/subdir1/file0.c

build bin/main0: link bin/main0.o /Users/clausklein/Workspace/build-performance/build/subdir0/file0.o 
build bin/main1: link bin/main1.o /Users/clausklein/Workspace/build-performance/build/subdir1/file0.o 

build all: phony foo bin/main0 bin/main1 
default all

Esto funciona bien con el generador de archivos Make de CMake.

¿Cómo maneja Make el problema del enlace simbólico?

¿Cómo maneja Make el problema del enlace simbólico?

El generador de Makefile actualmente no usa archivos dep y realiza su propio escaneo aproximado. Es probable que se actualice como parte de la adición de compatibilidad con los módulos C++20 al generador de Makefile, momento en el cual la interpretación de las rutas del archivo dep tendrá que reconciliarse de manera similar a lo que se propone aquí.

Una opción es omitir ninja_workdir por ahora y al menos enseñarle a Ninja a conciliar las rutas mixtas suponiendo que getcwd() es la parte superior. De esa manera, al menos las rutas mixtas funcionarán en el caso común sin enlace simbólico. Luego se pueden agregar ninja_workdir para respaldar los casos más complejos más adelante.

Por favor alguien arregle esto. Estoy tan molesto por esto.

Estoy usando ARM-GCC con CMake y VSCode. Cuando uso una compilación en el origen, las rutas son relativas al directorio de "compilación" (en lugar del directorio raíz), lo que hace que VSCode ya no pueda resolver las rutas, lo que significa que no puede simplemente hacer clic en el en la ventana de la línea de comandos, en cambio, debe ubicar cada archivo usted mismo. Cuando uso una compilación fuera de árbol de CMake, rompe el "IntelliSense" de Eclipse y genera problemas con los subproyectos de CMake. Mi solución por ahora es usar MakeFiles, porque usa rutas absolutas por defecto. Pero Ninja es mejor, produce mejores archivos legibles (rules.ninja...) y la salida de compilación en la línea de comando es mejor. Make tiene problemas con la salida de advertencias en la línea de comandos en un contexto de subprocesos múltiples, lo que significa que se intercalan varias advertencias. Lo que hace que construya un solo subproceso, lo que nuevamente es súper molesto.

Por favor alguien arregle esto. Estoy tan molesto por esto.

Estoy usando ARM-GCC con CMake y VSCode. Cuando uso una compilación interna, las rutas son relativas al directorio de "compilación"...

Existe una solución alternativa: ¡elija el directorio de compilación fuera del árbol de fuentes! es decir, _$TMPDIR/..._

Gracias ClausKlein, pero la solución es una compilación fuera de la fuente, pero necesito los archivos dentro de mi árbol, porque otros scripts hacen referencia a ellos. También es un requisito de construcción no estándar.

Mi solución por ahora es cambiar CMake para usar siempre rutas absolutas. No entiendo por qué no hay una opción para esto. Sin embargo, si alguien más necesita esto, aquí está el parche de CMake v3.18.1:

@@ -241,7 +241,7 @@ void cmNinjaTargetGenerator::AddIncludeFlags(std::string& languageFlags,
   // Add include directory flags.
   std::string includeFlags = this->LocalGenerator->GetIncludeFlags(
     includes, this->GeneratorTarget, language,
-    language == "RC", // full include paths for RC needed by cmcldeps
+    true, // full include paths for RC needed by cmcldeps
     false, config);
   if (this->GetGlobalGenerator()->IsGCCOnWindows()) {
     std::replace(includeFlags.begin(), includeFlags.end(), '\\', '/');
@@ -1133,8 +1133,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement(
   const std::string& fileConfig, bool firstForConfig)
 {
   std::string const language = source->GetLanguage();
-  std::string const sourceFileName =
-    language == "RC" ? source->GetFullPath() : this->GetSourceFilePath(source);
+  std::string const sourceFileName = source->GetFullPath();
   std::string const objectDir = this->ConvertToNinjaPath(
     cmStrCat(this->GeneratorTarget->GetSupportDirectory(),
              this->GetGlobalGenerator()->ConfigDirectory(config)));

Atención , hubo un parche para cmake, pero vea https://github.com/ninja-build/ninja/issues/1251

¡Necesitamos un parche para Ninja!

En mi último comentario, mostré un parche para que CMake use rutas absolutas en lugar de rutas relativas. Resulta que esta es una mala idea, porque rompe las dependencias de encabezado de CMake personalizadas con Ninja (por ejemplo, un archivo de encabezado generado depende de un archivo .json). Supongo que este problema se deriva de este problema aquí, que fui demasiado estúpido para entender.

Si a alguien le interesa, ahora uso Ninja con rutas relativas. Creé una extensión para que VSCode pueda hacer clic en rutas relativas dentro de la terminal integrada. extensión

@GrandChris Genial! ¿Alguna posibilidad de que funcione en la pestaña Output también?

@weliveindetail Siéntase libre de crear un nuevo problema en https://github.com/GrandChris/TerminalRelativePath/issues y describa su caso de uso en detalle. Pero la pestaña de salida en VSCode se comporta de manera diferente al terminal integrado y no creo que haya una API para extender el comportamiento en este sentido.

OK gracias. Eventualmente, las rutas relativas en las que se puede hacer clic probablemente deberían resolverse en VSCode o la extensión CMake. Hará ping en su lado.

Como referencia, esto volvió a surgir en CMake Issue 21865 . Es otro ejemplo de un caso en el que no es fácil (¿posible?) hacer que las dependencias descubiertas por depfile usen exactamente la misma representación de ruta que build.ninja .

1917 agrega el enlace ninja_workdir propuesto anteriormente como una característica útil por sí misma. Una vez que se fusione, puedo seguir con una solución para este problema.

@jhasse Me gustaría encontrar una solución aceptable para arreglar esto aguas arriba. ninja_workdir resuelve el problema. He argumentado mi caso arriba. ¿Qué otra alternativa sugieres?

Como ha señalado, el problema (mezclar rutas absolutas de archivo depfile con rutas relativas manifiestas rompe reconstrucciones) es por diseño. Creo que deberíamos crear problemas más específicos, porque hemos tocado varios temas en la discusión (por ejemplo, vincular el directorio de compilación).

Para los dos casos de uso en el comentario inicial, mis alternativas serían:

Esto produce una mejor salida para que los IDE coincidan con los mensajes de error y vuelvan a consultar los archivos originales.

Arregle el IDE o pase /FC o -fabs-path-diagnostics al compilador.

También puede afectar las rutas registradas en la información de depuración.

Esto también debería ser arreglado por el compilador. Sugeriría mirar -fdebug-prefix-map , pero no estoy seguro de cuál es exactamente el problema.

Aquí hay una secuencia de comandos que demuestra el problema: ninja-bug.bash.txt

No realmente, demuestra el comportamiento actual de Ninja. los dos problemas

  1. "mi IDE no puede hacer coincidir la salida del compilador con el archivo correcto"
  2. "Necesito rutas absolutas en la información de depuración"

necesita más explicación. De lo contrario, esto me parece un problema XY (X es "mezclar rutas absolutas y relativas" e Y es 1. o 2.).

Realmente no creo que la solución deba ser "solucionar esto en todas las demás herramientas".

1924 demuestra una solución funcional completa con pruebas, basada en el enfoque ninja_workdir . Un generador que use esto puede resolver todos los problemas anteriores.

Yo tampoco, porque no los veo como soluciones alternativas.

¡Estas NO son opciones GNU gcc!

Am 05.03.2021 um 16:58 schrieb Jan Niklas Hasse [email protected] :

Arregle el IDE o pase /FC https://docs.microsoft.com/de-de/cpp/build/reference/fc-full-path-of-source-code-file-in-diagnostics o -fabs- path-diagnostics https://reviews.llvm.org/D23816 al compilador.

También puede afectar las rutas registradas en la información de depuración.

Aquí hay una secuencia de comandos que demuestra el problema: ninja-bug.bash.txt

No realmente, demuestra el comportamiento actual de Ninja.

Mi publicación que citó reconoce que este es actualmente el comportamiento documentado.
El propósito de este número es cuestionar el diseño por
demostrando una clase de casos de uso que no sirve.

Los dos temas... (1)... (2)... necesitan mayor explicación.

Esos son sólo dos ejemplos de problemas que se hacen más fáciles de resolver por
pasando rutas absolutas a las herramientas. Los caminos absolutos no son irrazonables
solo porque hay otras soluciones disponibles en casos específicos de tal
problemas (utilizando características específicas de herramientas disponibles de algunos proveedores).
Las rutas absolutas ayudan a resolver una gran cantidad de estos problemas sin actualizaciones
al resto del ecosistema. Como publiqué anteriormente :

Podemos debatir los méritos de los caminos relativos versus absolutos para siempre. ninja debería
no ser obstinado al respecto. El problema aquí es reconciliar casos donde
ambos se usan dentro de una sola compilación. El generador del sistema de compilación no siempre puede
controlar lo que las herramientas harán con las rutas.

En sistemas de construcción complejos del mundo real, puede haber un número arbitrario de capas
de scripts, wrappers, herramientas, etc., (de todo tipo de proveedores) entre el
rutas escritas en build.ninja por el generador de archivos de compilación y las rutas reales
encontrado por Ninja en un archivo profundo. A veces, un archivo dado puede ser referenciado por
un archivo de profundidad de una herramienta a la que no se le dio directamente una ruta desde build.ninja .
Para que los depfiles funcionen con el diseño actual de Ninja, todas las herramientas
a la pila se le debe decir exactamente cómo el generador build.ninja elige expresar
esas rutas en declaraciones de compilación, y tener características que las conserven o conviertan
ellos de la misma manera. Esto no es tratable en general.

Ninja puede resolver este problema con un pequeño cambio de diseño: conciliar un
ruta absoluta en un archivo dep con una ruta relativa en build.ninja (y viceversa
viceversa). No estoy pidiendo reconciliar rutas arbitrarias al mismo archivo, solo para
reconocer que /path/to/some/file en un archivo dep es lo mismo que some/file en
el archivo de compilación /path/to/build.ninja .

Hay un precedente para tales actualizaciones de diseño. Cuando Ninja comenzó, la esperanza
era que los caminos siempre los encontraría ninja exactamente en el mismo
Representación byte por byte que escribió el generador de archivos de compilación
build.ninja . Ejecute git blame -M -C -w -- src/util.cc y mire el historial
de CanonicalizePath para ver una serie de casos que se encontraron en los que
la filosofía de diseño tenía que ser relajada. Esta es otra clase de tales casos.

Lo que pasa es que no estoy de acuerdo

Ninja no debe ser obstinado al respecto.

en primer lugar.

Esto no es tratable en general.

Entonces, ¿cuál es el problema específico? Lo siento, estoy un poco confundido.

No estoy de acuerdo con "Ninja no debería ser obstinado sobre eso" en primer lugar... Entonces, ¿cuál es el problema específico?

No se trata de un problema específico, sino de toda una clase de problemas que son mucho más fáciles de resolver con rutas absolutas. No debería importar por qué los desarrolladores quieren pasar rutas absolutas a sus herramientas, solo que quieren usar rutas absolutas por cualquier motivo que se aplique a su caso particular. Los sistemas de construcción existen para servir a sus usuarios, no para dictar políticas. Se supone que Ninja es un lenguaje ensamblador para sistemas de compilación y, sin embargo, no tiene forma de expresar sistemas de compilación utilizando rutas de estilos mixtos.

La política de Ninja para cambios ascendentes es que los problemas deben resolverse mediante generadores de archivos de compilación, y no Ninja ascendente, si se pueden resolver sin pérdida de eficiencia . En este caso, la única forma de proporcionar una reconciliación de estilo ninja_workdir de propósito general de las rutas del archivo dep desde el generador de archivos de compilación es inyectar después de cada comando que genera un archivo dep un comando adicional para revisar las rutas en el archivo dep para que coincidan. el archivo de compilación antes de que ninja lo cargue. Ese comando adicional tendrá su propio costo de tiempo de ejecución que está muy por encima de lo que hace #1924 (una pequeña cantidad de búsquedas adicionales en memoria dentro del proceso ninja ). Por lo tanto, la reconciliación de propósito general es más eficiente de proporcionar en Ninja upstream y, por lo tanto, es un candidato para la inclusión.

Incluso si usa rutas absolutas para todo, en lugar de mezclar rutas absolutas y relativas, existe un molesto problema de ergonomía. Si el usuario le pide a ninja que regenere un archivo de salida específico en lugar de un objetivo falso, por ejemplo, ninja out/my_executable o ninja out/foo/bar.o , debe recordar pasar la ruta absoluta o ninja fallará con un confuso error de "objetivo desconocido". También existe el problema opuesto: el usuario puede pedirle a ninja que reconstruya una ruta absoluta cuando el archivo build.ninja usa rutas relativas.

En una herramienta generadora Ninja que mantengo, soluciono esto haciendo que cada instrucción build incluya tanto la ruta relativa como su ruta absoluta correspondiente como salidas. Funciona, pero realmente se siente como un truco para evitar una limitación en Ninja. (Editar: Además, si build.ninja usa solo rutas relativas y, por lo tanto, aún puede funcionar después de ser movido a una ruta absoluta diferente, agregar alias de ruta absoluta rompería esa capacidad).

Es cierto que este no es exactamente el mismo problema que los depfiles, pero sugiere que Ninja debería ser más consciente de las equivalencias de rutas absolutas y relativas en general.

@comex Gracias, esa es una preocupación válida. ¿Puedes abrir un nuevo número para eso?

No debería importar por qué los desarrolladores quieren pasar rutas absolutas a sus herramientas [...]

Estoy en desacuerdo.

En este caso, la única forma de proporcionar una reconciliación al estilo ninja_workdir de propósito general de las rutas de los archivos [...]

Sin embargo, ¿por qué necesita la reconciliación de estilo ninja_workdir en primer lugar?

Sin embargo, ¿por qué necesita la reconciliación al estilo ninja_workdir en primer lugar?

Permite a los desarrolladores usar rutas relativas en build.ninja mientras manejan rutas absolutas generadas en archivos dep por herramientas que no controlan. De lo contrario, es posible que se vean obligados a usar rutas absolutas en build.ninja para acomodar dichas herramientas en combinación con la limitación por diseño de ninja. Mi propuesta no impide el uso de rutas relativas. Permite un mayor uso de ellos.

Abrí #1925 para implementar la misma reconciliación que #1924, pero sin el enlace ninja_workdir . Eso separa la decisión de reconciliar las rutas de archivo dep de la decisión de admitir rutas lógicas de directorios de trabajo con enlaces simbólicos.

rutas absolutas generadas en depfiles por herramientas que no controlan.

¿Hay algún ejemplo de este tipo de herramientas?

No podemos predecir el comportamiento de todas las herramientas utilizadas por todos en el mundo. Incluso para las herramientas que controlamos, ya hemos discutido varios casos anteriores que son fáciles de resolver con rutas absolutas, pero requieren opciones específicas de herramientas y mucho cuidado para resolver con rutas relativas. CMake prefiere rutas absolutas en varios casos por razones similares. Tengo varios informes de errores sobre el generador Ninja que no hace eso mientras que todos los demás generadores sí lo hacen. Varias veces pasé horas rastreando un problema de dependencias solo para descubrir que es otra instancia de rutas de archivo dep que no se concilian con las rutas de manifiesto de compilación. Las herramientas proporcionan la información que Ninja necesita para capturar dependencias, pero Ninja la ignora.

Su posición se presenta como una opinión de que las rutas relativas son universalmente mejores. Otras personas tienen una opinión diferente de que las rutas absolutas son mejores en algunos casos. No creo que sea el lugar de una herramienta de compilación para evangelizar caminos relativos.

Mi propuesta agrega una pequeña cantidad de infraestructura a Ninja. ¿Qué duele? No tenerlo externaliza un costo mucho mayor.

¡Si eso es verdad!

Y con rutas absolutas, cmake puede eliminar las rutas de inclusión duplicadas del compilador.
Esto reduce el tiempo de construcción de nuevo.

Am 09.03.2021 um 19:20 schrieb Brad King [email protected] :

No creo que sea el lugar de una herramienta de compilación para evangelizar caminos relativos.

Configuré el problema de CMake con respecto a un problema que enfrentamos con los archivos cpp generados por el compilador rápido de Qt y habilité la compilación de Unity. Mis investigaciones locales mostraron que ninja es, con mucho, el sistema de construcción más rápido, pero en esta constelación no es confiable. Ahora me enfrento al problema de cómo puedo encontrar una solución alternativa o justificar el aumento del tiempo de compilación.

CMake acaba de encontrar un problema con las dependencias circulares que, hasta hace poco, estaba enmascarado por este problema de Ninja. Si este problema se hubiera solucionado, habríamos descubierto el problema de CMake mucho antes.

¿Fue útil esta página
0 / 5 - 0 calificaciones