Entendendo a instalação de componentes - Como o Delphi encontra os arquivos de um pacote?
Escrito por Carlos B. Feitoza Filho | |
Categoria: Artigos | |
Categoria Pai: Addicted 2 Delphi! | |
Acessos: 57436 |
Páginas dentro deste artigo
Como o Delphi encontra os arquivos de um pacote?
É de extrema importância conhecer como o Delphi funciona para poder saber resolver problemas comuns. Entender como o Delphi encontra os arquivos de um pacote é um requisito básico, seja você um desenvolvedor comum ou um desenvolvedor de componentes. Como desenvolvedor comum, por exemplo, se você já programa há algum tempo e já instalou componentes, certamente você já deve ter visto uma mensagem parecida com esta:
Unit MinhaUnit was compiled with a different version of MinhaOutraUnit.TMinhaClasse
Este é um dos erros mais frequentes causados por uma instalação inadequada de pacotes e pode ocorrer até mesmo dentro de projetos comuns (não pacotes), sendo mais raros nestes últimos. Ao entender como o Delphi encontra os arquivos de um projeto qualquer ficará mais fácil resolver problemas como este, bem como evitar que eles ocorram, fazendo sempre o uso correto das configurações de "Paths" que o Delphi considera.
A forma como o Delphi procura os arquivos de um pacote é a mesma forma que ele usa para encontrar os arquivos de qualquer projeto que nele se compila. Antes de explicar como isso é feito, é necessário entender que uma unit pode estar disponível de forma compilada (.dcu) ou código-fonte (.pas) e o Delphi tem preferências especiais quando encontra estes arquivos:
- Se estiver disponível apenas o arquivo .pas ele será usado, sendo compilado normalmente
- Se estiver disponível apenas o arquivo .dcu ele será usado, mas não será compilado, porque não é necessário
- Se ambos os arquivos estiverem disponíveis, será usado sempre o arquivo .pas, o qual será compilado normalmente
De agora em diante ao me referenciar a uma unit eu estarei falando de um arquivo que representa uma unit do Delphi e que pode ser, ou um .dcu, ou um .pas. Isso servirá apenas para que eu não tenha que me referir aos dois arquivos, que no final representam a mesma coisa de formas diferentes.
Finalmente, conhecendo a ordem de preferência que o Delphi usa para selecionar uma unit, podemos agora verificar de forma simples e linear (em ordem de busca), como ele faz para achar as units que estão referenciadas nas cláusulas uses:
- Procura dentre as units listadas explicitamente no arquivo .dpk
- Procura no mesmo diretório que contém o arquivo .dpk
- Procura dentre os caminhos listados no Search Path (projeto)
- Procura dentre os caminhos listados no Library Path (global)
Caso uma unit não esteja em nenhum destes 4 lugares o seu projeto não vai compilar de jeito nenhum, mas gostaria de relatar aqui algo que constatei. Vou até deixar este relato destacado.
Nos testes que eu fiz para determinar os 4 locais de busca, aconteceu algo muito estranho. Eu compilei um projeto de teste com uma unit na mesma pasta do arquivo .dpk, em seguida a apaguei esperando receber um erro de compilação, já que a unit não existia mais. Para minha surpresa o projeto compilou normalmente e até mesmo o arquivo .dcu correspondente ao arquivo .pas que eu apaguei foi criado! Não consegui descobrir como o compilador fez isso, mas ao fechar e abrir o Delphi o comportamento foi o esperado, isto é, o projeto não mais compilou. Até onde eu sei, isso é um comportamento muito bizarro, portanto, fica como dica de boa prática, fechar o Delphi e abri-lo novamente, sempre que se mover ou apagar units, principalmente quando se estiver desenvolvendo componentes, já que é imprescindível que os arquivos sendo referenciados pelo projeto existam de fato e não por conta de algum cache sobrenatural
Além de units, um esquema de busca semelhante é usado para outros arquivos do projeto, tais como arquivos .res, .dfm e .inc. Estes arquivos são incluídos no projeto por diretivas especiais {$R}, para arquivos .res e .dfm, e {$I}, para arquivos .inc. Ambas as diretivas aceitam o caractere especial "*" (veja o significado deste caractere na explicação sobre arquivos .dfm, mais acima) e também um caminho que pode ser absoluto ou relativo. Vejamos alguns pormenores de cada uma destas formas de uso das diretivas:
- Ao usar caminhos absolutos, caso este caminho contenha espaços, aspas simples devem ser usadas em volta do mesmo. Referências por caminhos absolutos, como é de se imaginar, não têm ambiguidades, logo não há dúvidas de que um arquivo referenciado desta forma deve existir impreterivelmente no local indicado e ponto final. Já ao usar caminhos relativos, será considerado como ponto de partida o diretório onde a unit com a referência a {$R} ou {$I} estiver. A regra de uso de aspas simples também se aplica aqui, bem como o fato de que o caminho é totalmente conhecido e sem ambiguidades
- Ao usar o caractere * é necessário entender que ele se transforma meramente no nome da unit onde a referência a {$R} ou {$I} estiver, portanto, {$I *.inc} dentro de uma unit de nome teste.pas, na verdade deve ser lida como {$I teste.inc}
No segundo uso mostrado acima, como teremos apenas o nome de um arquivo, sem caminhos relativos ou completos, a busca por ele seguirá a seguinte regra:
- Procura no mesmo diretório onde a unit com a referência a {$R} ou {$I} estiver
- Procura no mesmo diretório que contém o arquivo .dpk
- Procura dentre os caminhos listados no Search Path (projeto)
- Procura dentre os caminhos listados no Library Path (global)
Foi detectado que o problema do cache sobrenatural descrito no quadro acima também afeta estes arquivos especiais, só que, ao contrário das units, o problema ocorreu ao remover um arquivo .inc que estava na mesma pasta de uma unit que o usava. Mesmo sem o arquivo .inc presente, ainda assim a compilação foi bem sucedida e o arquivo .inc carregado era aquele que estaria na pasta. Bizarro! Ao reiniciar o Delphi o comportamento foi o esperado mais uma vez, portanto, muito cuidado ao mover ou excluir tais arquivos. Lembre-se sempre de reiniciar o Delphi.
O Delphi não busca arquivos em caminhos listados no Path do Windows. Isso é uma má prática hoje em dia. Não polua seu sistema ou o de seus clientes com arquivos desnecessariamente. Apenas arquivos .bpl que são carregados pelo Delphi, precisam estar em caminhos listados no Path do Windows e mesmo assim estes caminhos são exclusivos no Delphi, ou seja, não espere encontrar arquivos .bpl dentro de pastas como C:\Windows\System32, C:\Windows\System ou C:\Windows\SysWOW64. A prática de colocar estes arquivos nestes caminhos de sistema foi felizmente abolida! Se você é um programador das antigas, já deve ter colocado algumas BPLs na pasta System ou System32, mas não faça mais isso! Existe uma pasta específica para este tipo de arquivo. Esta pasta pode ser configurada no mesmo local onde se encontram o Library Path e o Browsing Path (explicados posteriormente neste artigo). A configuração se chama Package Output Directory. Os nome desta configuração pode variar um pouco, mas não será difícil identificá-la.