Ninja: misturando caminhos absolutos depfile com caminhos relativos manifestos quebra reconstruções

Criado em 24 fev. 2017  ·  70Comentários  ·  Fonte: ninja-build/ninja

O manual ninja adverte contra tal mistura, mas se tornou uma séria limitação.

O problema é que as pessoas querem que seus sistemas de compilação invoquem o compilador com um caminho absoluto para o arquivo de origem. Isso produz uma saída melhor para os IDEs corresponderem às mensagens de erro e se referirem aos arquivos originais. Também pode afetar os caminhos registrados nas informações de depuração. No entanto, isso entra em conflito com a preferência do ninja por caminhos relativos no manifesto de construção.

Aqui está um script que demonstra o problema: ninja-bug.bash.txt

Comentários muito úteis

Eu realmente não acho que a solução deva ser "contornar isso em todas as outras ferramentas".

1924 demonstra uma correção de trabalho completa com testes, com base na abordagem ninja_workdir . Um gerador usando isso pode resolver todos os problemas acima.

Todos 70 comentários

CC: @nico @chaoren

No CMake, há uma discussão relevante na edição 16675 , edição 13894 e MR 520 .

Como solução alternativa, você pode definir explicitamente o diretório de saída do objeto, até mesmo "." ou "..", mas o caminho absoluto também funciona.
ninjatst.bash.txt

@zlolik IIUC você sugere colocar caminhos absolutos nos nós de gráfico do manifesto de compilação ( build.ninja ). Certamente isso funciona (e é o que o CMake faz em compilações fora do código-fonte), mas meu ponto aqui é que o Ninja desencoraja o uso de caminhos absolutos e ainda os IDEs os exigem na saída.

Também é hipoteticamente possível que um compilador dado -c foo.c possa gerar um caminho absoluto no depfile de qualquer maneira. Se isso acontecer, o Ninja não reconhecerá a dependência devido ao mesmo problema relatado aqui.

Corrigir isso exigirá que o Ninja seja capaz de reconhecer quando um caminho relativo e um caminho absoluto são o mesmo arquivo e têm apenas um nó de gráfico internamente em vez de dois. Fazer isso apenas para processamento depfile pode ser suficiente, pois é razoável pedir aos geradores build.ninja para nomear caminhos consistentemente dentro do manifesto de compilação.

@bradking Em primeiro lugar, concordo com você que temos um problema com o ninja e apenas sugiro uma solução alternativa.
Eu acho que há 3 questões relacionadas:

  1. Lógica com caminho absoluto/relativo de entrada, mais detalhes em #1152 .
  2. Lógica para forçar o caminho absoluto/relativo de saída. O problema com compiladores - a única maneira de dizer ao compilador que você deseja ter um caminho absoluto na saída é usar o caminho absoluto na linha de comando. Não é questão ninja, mas nossa.
  3. Lógica para analisar o caminho absoluto/relativo do depfile. Esse assunto.

Eu uso 2 soluções alternativas:

  1. Use os prefixos $p e $o no caminho do gerador build.ninja para resolver os 2 primeiros problemas. No meu caso $p e $o não são absolutos, mas relativos do diretório atual onde o gerador build.ninja foi executado.
  2. Use algum script para converter depfile para caminho compatível com ninja. Alguns compiladores ainda precisam de chamadas separadas para gerar depfile. Mas não há problema de caminho absoluto enquanto.

Para referência, iniciei um tópico na lista de discussão ninja-build com uma solução proposta.

Outros problemas relacionados a informações de depuração e cobertura: o uso de comandos com caminhos relativos cria também arquivos de informações de depuração com caminhos relativos. O problema é que os arquivos de depuração geralmente são colocados próximos aos arquivos de objeto, não aos arquivos de origem, portanto, os caminhos relativos fazem referência a arquivos inexistentes.

alguma atualização disso? Não houve nenhuma resposta no tópico da lista de discussão...

Olá pessoal,

Também é hipoteticamente possível que um compilador com -c foo.c possa gerar um caminho absoluto no depfile de qualquer maneira.

Os arquivos de dependência do IAR v8 contêm apenas caminhos absolutos.

Encontramos esse problema ao fazer compilações fora do código-fonte com CMake/Ninja/IAR: os arquivos gerados que terminam no diretório binário do CMake são relativos no manifesto Ninja, a saída deps do IAR é absoluta.

Para mim, isso é claramente um problema do Ninja: não deve ter dois nós para o mesmo arquivo, não importa o quê.

Eu li a sugestão do @bradking , mas eu realmente não entendo a parte sobre links simbólicos e porque getcwd() não pode ser usado. Você se importaria de elaborar?

Eu realmente não entendo a parte sobre links simbólicos e por que getcwd() não pode ser usado

@sebknzl o problema é que os caminhos absolutos gravados em build.ninja pelo gerador podem conter links simbólicos que intencionalmente não são resolvidos por um motivo ou outro. getcwd() normalmente retorna um caminho com links simbólicos resolvidos. Se o Ninja interpretasse um caminho relativo no manifesto de compilação ou um depfile relativo a getcwd() , o caminho absoluto que ele constrói pode não corresponder ao que o gerador de manifesto de compilação usou e ainda acabaríamos com dois nós.

O ninja_workdir que proponho no tópico que você vinculou está basicamente dizendo ao Ninja o que o gerador usou como base para caminhos relativos. Na prática realpath(ninja_workdir) == realpath(getcwd()) deve sempre ser verdade, mas isso não significa ninja_workdir == getcwd() . Outra alternativa seria para o Ninja realpath tudo antes de criar os nós, mas isso significaria que $in não se expandiria para o que o gerador pretendia.

@jhasse , veja este problema e minha proposta para resolvê-lo.

Por que não gerar um _build.ninja_ com caminhos absolutos controlados por um CMAKE_NINJA_GENERATOR_OPTION_ ?

ou seja, assim, 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$ 

gerado com ninjatst.bash.txt

@ClausKlein tentamos ensinar o CMake a usar caminhos absolutos. Veja as discussões que vinculei em https://github.com/ninja-build/ninja/issues/1251#issuecomment -282322776. Prefiro não adicionar uma opção que diga "faça as coisas de uma maneira diferente que corrija alguns casos e quebre outros".

Realmente precisamos do recurso Ninja na proposta que vinculei em https://github.com/ninja-build/ninja/issues/1251#issuecomment -487618865 para corrigir isso corretamente.

Tudo bem

Então essa correção para o sistema mesonbuild também estaria disponível ;-)

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

@ClausKlein https://github.com/ClausKlein tentamos ensinar o CMake a usar caminhos absolutos. Veja as discussões que vinculei em #1251 (comentário) https://github.com/ninja-build/ninja/issues/1251#issuecomment-282322776 . Prefiro não adicionar uma opção que diga "faça as coisas de uma maneira diferente que corrija alguns casos e quebre outros".

Nós realmente precisamos do recurso Ninja na proposta que eu vinculei em #1251 (comentário) https://github.com/ninja-build/ninja/issues/1251#issuecomment-487618865 para corrigir isso corretamente.


Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub https://github.com/ninja-build/ninja/issues/1251#issuecomment-598146822 ou cancele a inscrição https://github.com/notifications/unsubscribe-auth/AAN7QWWEDHMDA45DQVPLOUDRHDEVDANCNFSM4DBNL6GA .

Digamos que Ninja usaria ninja_workdir para combinar informações de depfile e temos a situação em que ninja_workdir != getcwd() por causa de um link simbólico. E se o compilador agora imprimir caminhos absolutos usando getcwd() ?

O compilador não deve usar getcwd() para nada, a menos que essas coisas tenham sido passadas como caminhos relativos, caso em que o gerador do sistema de compilação provavelmente precisa assumir a responsabilidade.

Ou podemos considerar tentar normalizar tanto ninja_workdir quanto getcwd() .

Bem, o compilador também não deve retornar um caminho absoluto no depfile quando fornecido caminhos relativos;)

@ClausKlein tentamos ensinar o CMake a usar caminhos absolutos. Veja as discussões que vinculei em #1251 (comentário). Prefiro não adicionar uma opção que diga "faça as coisas de uma maneira diferente que corrija alguns casos e quebre outros".

O que exatamente quebrou quando você usou caminhos absolutos como sugerido por @ClausKlein?

Se o compilador recebe caminhos absolutos, então o arquivo dep que ele gera tem caminhos absolutos, e esses não são reconciliados com caminhos relativos para cabeçalhos no manifesto de compilação, por exemplo, para cabeçalhos gerados. Veja o link ninja-bug.bash.txt no meu primeiro post no início desta edição. Ele mostra um exemplo passo a passo do que acontece e é expresso puramente em termos de Ninja e sem CMake.

Eu li isso, mas por que não usar https://github.com/ninja-build/ninja/issues/1251#issuecomment -284533599? Simplesmente porque Ninja "desencoraja" caminhos absolutos? Em caso afirmativo, trata-se de uma mudança de documentação?

Os arquivos build.ninja são muito menores sem repetir caminhos absolutos em todos os lugares, e isso os torna mais rápidos. Eles também parecem mais bonitos, são mais fáceis de depurar e são mais apropriados para preenchimento de guias de nomes de destino de compilação em shells. IMO é uma boa recomendação para Ninja fazer. Ninja só precisa de um pouco mais de informação para conciliar este caso, e é isso que proponho.

@bradking caminhos relativos nem sempre podem ser curtos:

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

meu exemplo https://github.com/ninja-build/ninja/issues/1251#issuecomment -597877775 parece melhor!

Os geradores do CMake têm uma regra sobre não usar sequências ../ que saem da árvore de construção. Em compilações totalmente fora do código-fonte, usamos caminhos absolutos para a árvore de origem e caminhos relativos dentro da árvore de compilação. Os últimos nunca começam em ../ porque estão sob a árvore de construção.

Eu sei, foi gerado com _mesonbuild_ . ;-)

Mas então, por que não negar a geração em árvore de origem?

Podemos debater os méritos dos caminhos relativos versus absolutos para sempre. Ninja não deve ser opinativo sobre isso. O problema aqui é reconciliar casos em que ambos são usados ​​em uma única compilação. O gerador do sistema de compilação nem sempre pode controlar o que as ferramentas farão com os caminhos. O Ninja deve oferecer suporte a caminhos absolutos/relativos mistos para o mesmo arquivo e pode fazê-lo com uma abordagem simples que descrevi na minha proposta. Para o caso de uso motivador, as alterações são isoladas para análise de depfile.

Ninja deve oferecer suporte a caminhos absolutos/relativos mistos para o mesmo arquivo

Eu concordo!

Obrigado por todas as explicações, estou começando a entender.

E se o Ninja (ao encontrar um caminho absoluto no depfile) fosse realpath tanto cwd quanto o caminho encontrado? Em seguida, ele removeria o cwd com caminho real do depfile-path com caminho real para obter o caminho relativo para corresponder ao cabeçalho gerado. Isso funcionaria?

getcwd() é sempre um caminho real, então esse passo não é necessário. Se Ninja fosse realpath() o caminho absoluto fornecido pelo depfile e verificasse um prefixo cwd que pudesse funcionar. No entanto, realpath() é uma chamada de sistema possivelmente cara, enquanto minha proposta ninja_workdir pode reconciliar caminhos puramente na memória por meio de processamento de string.

A mistura na outra direção também deve ser permitida: um caminho absoluto no manifesto de compilação, mas um caminho relativo no depfile. Eu não acho que Ninja deveria ter que realpath() todo caminho absoluto enquanto analisa build.ninja . Isso provavelmente seria lento.

Poderíamos usar o resultado para determinar o workdir. Por exemplo:

getcwd(): /var/xyz/build
entrada depfile: /home/foo/build/bar.h
realpath(entrada depfile): /var/xyz/build/bar.h
caminho real relativo: bar.h
remova isso da entrada depfile: /home/foo/build -> ninja_workdir

Dessa forma, só precisamos chamar realpath uma vez.

Eu não acho que derivar ninja_workdir automaticamente seja possível em geral. Como sabemos quantos componentes lógicos do caminho lógico contendo o link simbólico original correspondem ao workdir? Podemos fazer isso pegando um componente de cada vez até que seu caminho real corresponda ao cwd, mas isso parece hacky e propenso a erros. Parece arriscado confiar no primeiro link simbólico que se parece com isso. Além disso, teríamos que executar realpath() em todos os caminhos absolutos que encontramos até que um resolva dessa maneira.

O gerador de buildsystem sabe exatamente qual caminho lógico para o workdir ele usou ao gerar caminhos absolutos em instruções de construção e linhas de comando em build.ninja . Portanto, é a fonte de informações mais confiável para o caminho workdir. Nós só precisamos de uma maneira de comunicar essas informações ao Ninja, daí minha proposta de vinculação ninja_workdir .

Não sei se entendi, desculpe. Você pode dar um exemplo em que minha lógica de detecção não funcionaria?

Pode quebrar se o gerador do sistema de compilação colocar um link simbólico dentro da árvore de compilação (apontando para outro lugar na árvore de compilação ou para fora):

getcwd(): /var/xyz/build
entrada depfile: /home/foo/build/subdir-link/bar.h
realpath(entrada depfile): /var/xyz/build/subdir-real/bar.h
caminho real relativo: subdir-real/bar.h
remova isso da entrada depfile: ???

O CMake não faz isso, mas em geral um gerador de buildsystem poderia.

Mesmo que estejamos dispostos a dizer que não é suportado, a detecção ainda pode enfrentar:

getcwd(): /var/xyz/build
1000 entradas de depfile: /home/foo/ext-lib/bar{1,2,...}.h
1000 realpath(entradas de arquivo): /var/xyz/ext-lib/bar{1,2,...}.h
1000 caminhos reais relativos: nenhum sob cwd

Agora imagine que aparece em 1000 depfiles de fontes e nunca há um hit. Isso é 1 milhão de chamadas realpath() sem correspondência para essa heurística. E isso se repete toda vez que uma fonte é reconstruída e seu arquivo dep é analisado novamente.

link simbólico dentro da árvore de construção -> sim, não podemos realmente suportar isso, resultará em todos os tipos de outros problemas de qualquer maneira (sem realpathing em todo o lugar).

O segundo exemplo soa bastante artificial. Normalmente, os depfiles começam com as dependências locais, não com os cabeçalhos do sistema.

Se realmente for um problema de desempenho, podemos armazenar em cache o workdir em .ninja_deps ?

Em uma compilação fora do código-fonte, muito poucas entradas depfile apontarão para a árvore de compilação. Isso será muito comum:

getcwd(): /var/xyz/build
1000 entradas depfile: /home/foo/project-source/bar{1,2,...}.h
1000 realpath(entradas depfile): /var/xyz/project-source/bar{1,2,...}.h
1000 caminhos reais relativos: nenhum sob cwd

Ninja terá que chamar realpath() em todos eles apenas no caso, ou manter algum tipo de tabela de resultados para evitar as chamadas de sistema reais. Ele não pode saber com antecedência quando encontrará um caminho de link simbólico que resolva para o cwd e nem sabe se encontrará um.

Dado que misturar caminhos absolutos e reais no depfile atualmente não funciona, não vejo como isso seria "muito comum"?

depfiles do formulário no meu exemplo já são muito comuns mesmo quando não estão usando links simbólicos ou caminhos mistos. Eu os tenho na maioria das minhas árvores de construção. Ninja não pode saber com antecedência se a heurística é necessária, então ele terá que bloquear em realpath() syscalls apenas no caso.

Talvez eu tenha entendido errado o seu exemplo. Você quer dizer um depfile com 3000 entradas ou esses 3 exemplos separados para depfiles com 1000 entradas cada?

Eu quis dizer 1000 entradas depfile espalhadas por qualquer número de depfiles. Pode ser um. Podem ser muitos. Pode haver 10.000 entradas em um projeto. Seus caminhos podem apontar para qualquer lugar no sistema de arquivos e podem ou não apontar para a árvore de construção.

Você pode dar um exemplo CMakeLists.txt que resulta em uma mistura de caminhos (não precisa ser 1000, apenas um de cada)?

É difícil mostrar em um arquivo CMakeLists.txt porque o CMake atualmente cuida para evitar misturar caminhos na maioria dos casos. No entanto, há problemas no rastreador de problemas do CMake sobre problemas que não podem ser corrigidos sem que o Ninja conserte isso primeiro. Veja por exemplo CMake Issue 13894 . Os usuários querem ser capazes de fornecer caminhos absolutos para o compilador mesmo para fontes (e talvez incluir diretórios) na árvore de compilação ou ao fazer compilações no código-fonte. Isso funciona bem com o gerador Makefile do CMake. Se fizermos isso com o Ninja, os depfiles voltam com caminhos absolutos e não correspondem aos caminhos relativos em build.ninja . Talvez pudéssemos mudar para caminhos absolutos para tudo, mas como discutido acima aqui, não deveríamos ter que fazer isso.

Talvez você possa tentar isso para testes https://github.com/ClausKlein/build-performance/commit/8013836486e3a459474eb374f6c3da5e20983443

O problema mostrado aqui é baseado em https://github.com/ninja-build/ninja/issues/1251#issue -210080507
Ele gera tanto alvo quanto você deseja. ou seja, 2 subduers cada um com 2 arquivos de origem:

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

Isso funciona bem com o gerador Makefile do CMake.

Como o Make lida com o problema do link simbólico?

Como o Make lida com o problema do link simbólico?

O gerador Makefile não está usando depfiles e faz sua própria varredura aproximada. Isso provavelmente será atualizado como parte da adição de suporte a módulos C++20 ao gerador Makefile, ponto em que a interpretação dos caminhos do depfile terá que ser reconciliada de maneira semelhante ao que é proposto aqui.

Uma opção é pular ninja_workdir por enquanto e pelo menos ensinar Ninja a reconciliar os caminhos mistos assumindo que getcwd() é o topo. Dessa forma, pelo menos os caminhos mistos funcionarão no caso comum sem link simbólico. Então ninja_workdir pode ser adicionado para dar suporte aos casos mais complexos posteriormente.

Por favor alguém corrija isso. Estou tão irritado por causa disso.

Estou usando ARM-GCC com CMake e VSCode. Quando uso uma compilação no código-fonte, os caminhos são relativos ao diretório "build" (em vez do diretório raiz), o que faz com que o VSCode não consiga mais resolver os caminhos, o que significa que você não pode simplesmente clicar no paths na janela de linha de comando, em vez disso, você precisa localizar cada arquivo por conta própria. Quando eu uso uma compilação fora da árvore do CMake, ele quebra o "IntelliSense" do Eclipse e causa problemas com os subprojetos do CMake. Minha solução por enquanto é usar MakeFiles, pois usa Paths absolutos por padrão. Mas Ninja é melhor, produz arquivos mais legíveis (rules.ninja...) e a saída de compilação na linha de comando é melhor. O Make tem problemas com a saída de avisos na linha de comando em um contexto multithread, ou seja, vários avisos são intercalados. O que me faz construir thread único, o que é novamente super irritante.

Por favor alguém corrija isso. Estou tão irritado por causa disso.

Estou usando ARM-GCC com CMake e VSCode. Quando uso uma compilação no código-fonte, os caminhos são relativos ao diretório "build" ...

Existe uma solução alternativa: escolha o diretório de compilação fora da árvore de origem! ou seja, _$TMPDIR/..._

Obrigado ClausKlein, mas a solução alternativa é uma compilação fora do código-fonte, mas preciso dos arquivos dentro da minha árvore, porque ela é referenciada por outros scripts. Também é um requisito de compilação não padrão.

Minha solução por enquanto é alterar o CMake para sempre usar caminhos absolutos. Não entendo porque não existe essa opção. No entanto, se alguém precisar disso, aqui está o patch do 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)));

Atenção , houve um patch para cmake, mas veja https://github.com/ninja-build/ninja/issues/1251

Precisamos de um patch para Ninja!

No meu último comentário, mostrei um patch para o CMake usar caminhos absolutos em vez de caminhos relativos. Acontece que isso é uma má ideia, porque quebra as dependências de cabeçalho CMake personalizadas com o Ninja (por exemplo, um arquivo de cabeçalho gerado depende de um arquivo .json). Acho que este problema deriva desta questão aqui, que eu era muito estúpido para entender.

Se alguém estiver interessado nisso, agora uso Ninja com caminhos relativos. Eu criei uma extensão para o VSCode poder clicar em caminhos relativos dentro do terminal integrado. extensão

@GrandChris Ótimo! Alguma chance de fazê-lo funcionar na guia Output também?

@weliveindetail Sinta-se à vontade para criar um novo problema em https://github.com/GrandChris/TerminalRelativePath/issues e descreva seu caso de uso em detalhes. Mas a guia de saída no VSCode se comporta de maneira diferente do terminal integrado e não acho que haja uma API para estender o comportamento a esse respeito.

Ok obrigado. Eventualmente, os caminhos relativos clicáveis ​​provavelmente devem ser resolvidos no VSCode ou na extensão CMake. Vai pingar do lado deles.

Para referência, isso apareceu novamente no CMake Issue 21865 . É outro exemplo de um caso em que não é fácil (possível?) fazer com que as dependências descobertas pelo depfile usem exatamente a mesma representação de caminho que build.ninja .

1917 adiciona a ligação ninja_workdir proposta acima como um recurso útil por si só. Depois que isso for mesclado, posso acompanhar com uma correção para esse problema.

@jhasse , gostaria de apresentar uma solução aceitável para corrigir isso a montante. ninja_workdir resolve o problema. Eu argumentei meu caso acima. Que outra alternativa você sugere?

Como você apontou, o problema (misturar caminhos absolutos depfile com caminhos relativos manifestos quebra reconstruções) é por design. Acho que deveríamos criar questões mais específicas, porque tocamos em várias questões na discussão (por exemplo, vincular o diretório de compilação).

Para os dois casos de uso no comentário inicial, minhas alternativas seriam:

Isso produz uma saída melhor para os IDEs corresponderem às mensagens de erro e se referirem aos arquivos originais.

Corrija o IDE ou passe /FC ou -fabs-path-diagnostics para o compilador.

Também pode afetar os caminhos registrados nas informações de depuração.

Isso também deve ser corrigido pelo compilador. Sugiro olhar para -fdebug-prefix-map , mas não tenho certeza de qual é exatamente o problema.

Aqui está um script que demonstra o problema: ninja-bug.bash.txt

Não realmente, demonstra o comportamento atual de Ninja. As duas questões

  1. "meu IDE não pode corresponder a saída do compilador ao arquivo correto"
  2. "Preciso de caminhos absolutos nas informações de depuração"

precisam de mais explicações. Caso contrário, isso parece um problema XY para mim (X sendo "misturando caminhos absolutos e relativos" e Y sendo 1. ou 2.).

Eu realmente não acho que a solução deva ser "contornar isso em todas as outras ferramentas".

1924 demonstra uma correção de trabalho completa com testes, com base na abordagem ninja_workdir . Um gerador usando isso pode resolver todos os problemas acima.

Eu também não, porque não vejo isso como soluções alternativas.

Estas NÃO são opções do GNU gcc!

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

Corrija o IDE ou passe /FC https://docs.microsoft.com/de-de/cpp/build/reference/fc-full-path-of-source-code-file-in-diagnostics ou -fabs- path-diagnostics https://reviews.llvm.org/D23816 para o compilador.

Também pode afetar os caminhos registrados nas informações de depuração.

Aqui está um script que demonstra o problema: ninja-bug.bash.txt

Não realmente, demonstra o comportamento atual de Ninja.

Meu post que você citou reconhece que este é atualmente o comportamento documentado.
O objetivo desta edição é questionar o design ,
demonstrando uma classe de casos de uso que ela não atende.

As duas questões... (1) ... (2) ... precisam de mais explicações.

Esses são apenas dois exemplos de problemas que são mais fáceis de resolver
passando caminhos absolutos para ferramentas. Caminhos absolutos não são irracionais
apenas porque outras soluções estão disponíveis em instâncias específicas de tais
problemas (usando recursos específicos de ferramentas disponíveis de alguns fornecedores).
Caminhos absolutos ajudam a resolver uma grande classe desses problemas sem atualizações
para o resto do ecossistema. Como postei anteriormente :

Podemos debater os méritos dos caminhos relativos versus absolutos para sempre. Ninja deveria
não seja opinativo sobre isso. O problema aqui é conciliar os casos em que
ambos são usados ​​em uma única compilação. O gerador do sistema de compilação nem sempre
controlar o que as ferramentas farão com os caminhos.

Em sistemas complexos de construção do mundo real, pode haver um número arbitrário de camadas
de scripts, wrappers, ferramentas, etc., (de todos os tipos de fornecedores) entre o
caminhos escritos em build.ninja pelo gerador do arquivo de compilação e os caminhos reais
encontrado por Ninja em um depfile. Às vezes, um determinado arquivo pode ser referenciado por
um depfile de uma ferramenta que não recebeu diretamente um caminho de build.ninja .
Para que os depfiles funcionem sob o design atual do Ninja, todo o conjunto de ferramentas
pilha precisa ser informada exatamente como o gerador build.ninja escolhe expressar
esses caminhos em instruções de construção e têm recursos para preservá-los ou convertê-los
eles da mesma forma. Isso não é tratável em geral.

Ninja pode resolver este problema com uma pequena mudança de design: reconciliar um
caminho absoluto em um depfile com um caminho relativo em build.ninja (e vice
vice-versa). Não estou pedindo para reconciliar caminhos arbitrários para o mesmo arquivo, apenas para
reconhecer que /path/to/some/file em um depfile é o mesmo que some/file em
o arquivo de construção /path/to/build.ninja .

Há precedentes para essas atualizações de design. Quando Ninja começou, a esperança
era que os caminhos sempre seriam encontrados por ninja exatamente da mesma forma
representação byte a byte que o gerador de arquivo de compilação escreveu
build.ninja . Execute git blame -M -C -w -- src/util.cc e veja o histórico
de CanonicalizePath para ver uma série de casos encontrados em que esse
filosofia de design tinha que ser relaxada. Esta é outra classe de tais casos.

A coisa é que eu discordo

Ninja não deve ser opinativo sobre isso.

em primeiro lugar.

Isso não é tratável em geral.

Então, qual é o problema específico? Desculpe estou um pouco confuso.

Eu discordo com "Ninja não deve ser opinativo sobre isso" em primeiro lugar .... Então, qual é o problema específico?

Não se trata de um problema específico, mas de uma classe inteira de problemas que são muito mais fáceis de resolver com caminhos absolutos. Não importa por que os desenvolvedores querem passar caminhos absolutos para suas ferramentas, apenas que eles querem usar caminhos absolutos por qualquer motivo que se aplique ao seu caso particular. Os sistemas de construção existem para servir seus usuários, não para ditar políticas. O Ninja supostamente é uma linguagem assembly para sistemas de compilação, e ainda não tem como expressar sistemas de compilação usando caminhos de estilo misto.

A política do Ninja para mudanças upstream é que os problemas devem ser resolvidos por geradores de arquivos de compilação, e não pelo Ninja upstream, se eles puderem ser resolvidos sem perda de eficiência . Nesse caso, a única maneira de fornecer reconciliação de uso geral ninja_workdir -estilo de depfile caminhos do gerador de arquivo de compilação é injetar após cada comando que gera um depfile um comando extra para revisar os caminhos no depfile para corresponder o arquivo de compilação antes que o ninja o carregue. Esse comando extra terá seu próprio custo de tempo de execução que está muito acima do que #1924 faz (um pequeno número de pesquisas extras na memória dentro do processo ninja ). Portanto, a reconciliação de uso geral é mais eficiente para fornecer no Ninja upstream e, portanto, é candidata à inclusão.

Mesmo que você use caminhos absolutos para tudo, em vez de misturar caminhos absolutos e relativos, há um problema de ergonomia irritante. Se o usuário pedir ninja para gerar novamente um arquivo de saída específico em vez de um alvo falso, por exemplo, ninja out/my_executable ou ninja out/foo/bar.o , ele deve se lembrar de passar o caminho absoluto, ou ninja falhará com um erro confuso de "destino desconhecido". O problema oposto também existe: o usuário pode pedir ao ninja para reconstruir um caminho absoluto quando o arquivo build.ninja usa caminhos relativos.

Em uma ferramenta geradora do Ninja que mantenho, conto com isso fazendo com que cada instrução build inclua o caminho relativo e seu caminho absoluto correspondente como saídas. Funciona, mas realmente parece um truque para contornar uma limitação no Ninja. (Edit: Além disso, se o build.ninja usa apenas caminhos relativos e, portanto, ainda pode funcionar depois de ser movido para um caminho absoluto diferente, adicionar aliases de caminho absoluto quebraria essa capacidade.)

Admitidamente, isso não é exatamente o mesmo problema que os depfiles, mas sugere que o Ninja deve estar mais ciente das equivalências de caminho absoluto versus relativo em geral.

@comex Obrigado, essa é uma preocupação válida. Você pode abrir um novo tópico para isso?

Não importa porque os desenvolvedores querem passar caminhos absolutos para suas ferramentas [...]

Discordo.

Nesse caso, a única maneira de fornecer reconciliação de uso geral ninja_workdir -estilo de caminhos depfile [...]

Por que você precisa da reconciliação no estilo ninja_workdir em primeiro lugar?

Por que você precisa da reconciliação no estilo ninja_workdir em primeiro lugar?

Ele permite que os desenvolvedores usem caminhos relativos em build.ninja enquanto ainda manipulam caminhos absolutos gerados em depfiles por ferramentas que eles não controlam. Caso contrário, eles podem ser forçados a usar caminhos absolutos em build.ninja para acomodar tais ferramentas em combinação com a limitação de design do ninja. Minha proposta não impede o uso de caminhos relativos. Permite mais uso deles.

Abri #1925 para implementar a mesma reconciliação que #1924, mas sem a ligação ninja_workdir . Isso separa a decisão de reconciliar caminhos depfile da decisão de suportar caminhos lógicos de workdir com links simbólicos.

[...] caminhos absolutos gerados em depfiles por ferramentas que eles não controlam.

Existe um exemplo para tal ferramental?

Não podemos prever o comportamento de todas as ferramentas usadas por todos no mundo. Mesmo para ferramentas que controlamos, já discutimos vários casos acima que são fáceis de resolver com caminhos absolutos, mas exigem opções específicas de ferramentas e muito cuidado para resolver com caminhos relativos. O CMake prefere caminhos absolutos em vários casos por motivos semelhantes. Eu tenho vários relatórios de bugs sobre o gerador Ninja não fazer isso enquanto todos os outros geradores fazem. Várias vezes passei horas rastreando um problema de dependências apenas para descobrir que é outra instância de caminhos depfile que não estão sendo reconciliados com caminhos de manifesto de compilação. As ferramentas estão fornecendo as informações que o Ninja precisa para capturar as dependências, mas o Ninja as está ignorando.

Sua posição aparece como uma opinião de que os caminhos relativos são universalmente melhores. Outras pessoas têm uma opinião diferente de que os caminhos absolutos são melhores em alguns casos. Não acho que seja o lugar de uma ferramenta de construção para evangelizar caminhos relativos.

Minha proposta adiciona uma pequena quantidade de infraestrutura ao Ninja. O que dói? Não tê-lo externaliza um custo muito maior.

Sim, isso é verdade!

E com caminhos absolutos, cmake é capaz de eliminar caminhos de inclusão duplicados do compilador.
Isso reduz o tempo de compilação novamente.

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

Não acho que seja o lugar de uma ferramenta de construção para evangelizar caminhos relativos.

Eu configurei o problema do CMake em relação a um problema que estamos enfrentando com os arquivos cpp gerados pelo compilador rápido do Qt e habilitei a compilação da unidade. Minhas investigações locais mostraram que o ninja é de longe o sistema de construção mais rápido, mas nesta constelação não é confiável. Agora estou enfrentando o problema de como posso encontrar uma solução alternativa ou justificar o aumento do tempo de compilação.

O CMake acabou de encontrar um problema com dependências circulares que, até recentemente, eram mascaradas por esse problema do Ninja. Se esse problema tivesse sido corrigido, teríamos descoberto o problema do CMake muito antes.

Esta página foi útil?
0 / 5 - 0 avaliações