O Xcode 4 não consegue localizar arquivos de cabeçalho públicos da dependência de biblioteca estática

91

Títulos alternativos para auxiliar na pesquisa

  • O Xcode não consegue encontrar o cabeçalho
  • .H ausente no Xcode
  • Arquivo Xcode .h não encontrado
  • Arquivo de problema léxico ou pré-processador não encontrado

Estou trabalhando em um projeto de aplicativo iOS que veio do Xcode 3. Agora mudei para o Xcode 4, meu projeto constrói uma série de bibliotecas estáticas.

Essas bibliotecas estáticas também declaram cabeçalhos públicos e esses cabeçalhos são usados ​​pelo código do aplicativo. No Xcode 3.x, os cabeçalhos foram copiados (como uma fase de construção) para o e public headers directory, no projeto do aplicativo, public headers directoryforam adicionados ao headers search list.

No Xcode 4, o diretório de construção é movido para ~/Library/Developer/Xcode/DerivedData/my-project.

O problema é como faço referência a esse novo local nas configurações de pesquisa de cabeçalhos? Parece que:

  • public headers directoryé relativo ao DerivedDatadiretório, mas
  • headers search diretório é relativo a outra coisa (possivelmente a localização do projeto)

Como devo configurar um destino de biblioteca estática para o desenvolvimento de iOS no Xcode 4 que garantirá que os arquivos de cabeçalho sejam disponibilizados para os clientes que usam a biblioteca estática ao tentar compilar como uma dependência?

Richard Stelling
fonte
Pode estar relacionado com nomes de caminho. Por favor, verifique esta postagem. [Bibliotecas estáticas no Xcode 4] [1] [1]: stackoverflow.com/questions/6074576/static-libraries-in-xcode-4/…
Diego Marafetti

Respostas:

124

Cada uma das soluções que vi para esse problema parecia deselegante (copiar cabeçalhos no projeto do aplicativo) ou excessivamente simplificada a ponto de funcionar apenas em situações triviais.

A resposta curta

Adicione o seguinte caminho aos caminhos de pesquisa do cabeçalho do usuário

"$ (BUILD_ROOT) /../ IntermediateBuildFilesPath / UninstalledProducts"

Por que isso funciona?

Primeiro, precisamos entender o problema. Em circunstâncias normais, ou seja, quando você executa, testa, cria um perfil ou analisa, o Xcode cria seu projeto e coloca a saída no diretório Build / Products / Configuration / Products, que está disponível por meio da macro $ BUILT_PRODUCTS_DIR .

A maioria dos guias sobre bibliotecas estáticas recomenda definir o caminho da pasta de cabeçalhos públicos como $ TARGET_NAME , o que significa que seu arquivo lib se torna $ BUILT_PRODUCTS_DIR /libTargetName.a e seus cabeçalhos são colocados em $ BUILT_PRODUCTS_DIR / TargetName. Contanto que seu aplicativo inclua $ BUILT_PRODUCTS_DIR em seus caminhos de pesquisa, as importações funcionarão nas 4 situações fornecidas acima. No entanto, isso não funcionará quando você tentar arquivar.

O arquivamento funciona um pouco diferente

Quando você arquiva um projeto, o Xcode usa uma pasta diferente chamada ArchiveIntermediates. Nessa pasta, você encontrará / YourAppName / BuildProductsPath / Release-iphoneos /. Esta é a pasta para a qual $ BUILT_PRODUCTS_DIR aponta quando você faz um arquivo. Se você olhar lá, verá que há um link simbólico para o arquivo de biblioteca estática construída, mas a pasta com os cabeçalhos está faltando.

Para encontrar os cabeçalhos (e o arquivo lib), você precisa ir para IntermediateBuildFilesPath / UninstalledProducts /. Lembra-se de quando lhe foi dito para definir Ignorar instalação como SIM para bibliotecas estáticas? Bem, este é o efeito que a configuração tem quando você faz um arquivo.

Nota lateral: Se você não configurar para pular a instalação, seus cabeçalhos serão colocados em outro local e o arquivo lib será copiado para seu arquivo, impedindo você de exportar um arquivo .ipa que você pode enviar para a App Store .

Depois de muita pesquisa, não consegui encontrar nenhuma macro que correspondesse exatamente à pasta UninstalledProducts, daí a necessidade de construir o caminho com "$ (BUILD_ROOT) /../ IntermediateBuildFilesPath / UninstalledProducts"

Resumo

Para sua biblioteca estática, certifique-se de pular a instalação e de que seus cabeçalhos públicos sejam colocados em $ TARGET_NAME.

Para seu aplicativo, defina os caminhos de pesquisa do cabeçalho do usuário como "$ (BUILT_PRODUCTS_DIR)", que funciona bem para compilações regulares, e "$ (BUILD_ROOT) /../ IntermediateBuildFilesPath / UninstalledProducts", que funciona para compilações de arquivo.

Colin
fonte
Como isso se relaciona com a pasta DerivedData?
Richard Stelling
As compilações regulares vão para: DerivedData / WorkspaceName-hash / Build / Products / Debug-iphoneos / TargetName.app --- As compilações do arquivo vão para: DerivedData / WorkspaceName-hash / Build / Intermediates / ArchiveIntermediates / TargetName / BuildProductsPath / Release-iphoneos / TargetName.app
Colin
3
Para mim, usar "$ (BUILD_ROOT) /../ IntermediateBuildFilesPath / UninstalledProducts" com a caixa de seleção recursiva não funcionou. Assim que usei "$ (BUILD_ROOT) /../ IntermediateBuildFilesPath / UninstalledProducts / <nameOfStaticLibrary>" sem o sinalizador recursivo, funcionou para mim.
TPoschel de
7
Observe que seu $ (BUILD_ROOT) /../ IntermediateBuildFilesPath / UninstalledProducts é realmente $(TARGET_BUILD_DIR). Mesmo durante o arquivamento. ;)
Pascal
1
Para mim no Xcode 5: $ (BUILD_ROOT) /../ IntermediateBuildFilesPath / UninstalledProducts / include / NAME OF BIBLIOTECA Eu não defini como SIM: Sempre pesquise caminhos de usuário.
xarly
84

Encontrei o mesmo problema ao desenvolver minha própria biblioteca estática e, embora a resposta de Colin tenha sido muito útil, tive que modificá-la um pouco para funcionar de forma consistente e simples ao executar e arquivar projetos no Xcode 4 usando um espaço de trabalho.

O que é diferente no meu método é que você pode usar um único caminho de cabeçalho do usuário para todas as suas configurações de compilação.

Meu método é o seguinte:

Crie um espaço de trabalho

  1. No Xcode 4, vá para Arquivo, Novo, Espaço de trabalho.
  2. No Finder, você pode arrastar os projetos .xcodeproj para a biblioteca estática que deseja usar e para o novo aplicativo que você está construindo que usa a biblioteca. Consulte o Apple Docs para obter mais informações sobre como configurar espaços de trabalho: https://developer.apple.com/library/content/featuredarticles/XcodeConcepts/Concept-Workspace.html

Configurações do projeto de biblioteca estática

  1. Certifique-se de que todos os cabeçalhos da biblioteca estática estejam configurados para copiar para "Público". Isso é feito nas configurações do destino da biblioteca estática> Fases de construção. Na fase "Copiar cabeçalhos", certifique-se de que todos os seus cabeçalhos estejam na seção "Público".
  2. Em seguida, vá para Build Settings, encontre "Public Headers Folder Path" e digite um caminho para sua biblioteca. Eu escolho usar isto:

include / LibraryName

Eu adotei isso do uso com RestKit e descobri que funciona melhor com todas as minhas bibliotecas estáticas. O que isso faz é instruir o Xcode a copiar todos os cabeçalhos que movemos para a seção de cabeçalhos "Públicos" na etapa 1 para a pasta que especificamos aqui, que reside na pasta Dados Derivados durante a construção. Como no RestKit, gosto de usar uma única pasta "incluir" para conter cada biblioteca estática que estou usando em um projeto.

Também não gosto de usar macros aqui porque isso nos permitirá usar um único caminho de pesquisa de cabeçalho de usuário posteriormente, quando configurarmos o projeto usando a biblioteca estática.

  1. Encontre "Ignorar instalação" e certifique-se de que esteja definido como SIM.

Configurações para o projeto usando a biblioteca estática

  1. Adicione a biblioteca estática como uma estrutura em Build Phases> Link Binary With Libraries e adicione o arquivo libLibraryName.a para qualquer biblioteca estática que deseja usar.
  2. Em seguida, certifique-se de que o projeto esteja definido para pesquisar os caminhos de pesquisa do usuário. Isso é feito em Build Settings> Always Search User Paths e certifique-se de que esteja definido como YES.
  3. Na mesma área, encontre os Caminhos de pesquisa do cabeçalho do usuário e adicione:

    "$ (PROJECT_TEMP_DIR) /../ UninstalledProducts / include"

Isso diz ao Xcode para procurar bibliotecas estáticas dentro da pasta de compilação intermediária que o Xcode cria durante o processo de compilação. Aqui, temos a pasta "incluir" que estamos usando para nossos locais de biblioteca estática que configuramos na etapa 2 para as configurações do projeto de biblioteca estática. Esta é a etapa mais importante para fazer com que o Xcode encontre corretamente suas bibliotecas estáticas.

Configure o espaço de trabalho

Aqui, queremos configurar o espaço de trabalho para que ele construa a biblioteca estática quando construirmos nosso aplicativo. Isso é feito editando o esquema usado em nosso aplicativo.

  1. Certifique-se de ter selecionado o esquema que criará seu aplicativo.
  2. No menu suspenso de esquema, escolha Editar esquema.
  3. Selecione Construir no topo da lista à esquerda. Adicione um novo alvo pressionando + no painel do meio.
  4. Você deve ver a biblioteca estática exibida para a biblioteca que está tentando vincular. Escolha a biblioteca estática do iOS.
  5. Clique em Executar e Arquivar. Isso diz ao esquema para compilar as bibliotecas para a biblioteca estática sempre que você construir seu aplicativo.
  6. Arraste a biblioteca estática acima do destino do seu aplicativo. Isso faz com que as bibliotecas estáticas sejam compiladas antes do destino do aplicativo.

Comece a usar a biblioteca

Agora, você deve ser capaz de importar sua biblioteca estática usando

import <LibraryName/LibraryName.h>

Este método contorna o incômodo de ter que ter caminhos de cabeçalho de usuário diferentes para configurações diferentes, então você não deve ter problemas para compilar para arquivos.

Por que isso funciona?

Tudo depende deste caminho:

"$(PROJECT_TEMP_DIR)/../UninstalledProducts/include"

Como configuramos nossa biblioteca estática para usar "Ignorar instalação", os arquivos compilados são movidos para a pasta "UninstalledProjects" dentro do diretório temporário de construção. Nosso caminho aqui também resolve para a pasta "incluir" que configuramos para nossa biblioteca estática e usamos para nosso caminho de pesquisa de cabeçalho do usuário. Os dois trabalhando juntos permitem que o Xcode saiba onde encontrar nossa biblioteca durante o processo de compilação. Como esse diretório de construção temporário existe para as configurações de Depuração e Liberação, você só precisa de um único caminho para o Xcode pesquisar bibliotecas estáticas.

gdavis
fonte
3
Você é demais, cara! Isso é muito útil e funciona conforme você descreveu.
neevek
1
impressionante. Para onde devo enviar flores :)
Ramesh,
1
Depois de configurar isso, alguns de vocês podem encontrar " ...] seletor não reconhecido enviado para a classe 0x ... ". Caso o faça, tente adicionar isso aos Alvos do seu projeto-> Projeto-> Configurações de Compilação-> Vinculação-> Outros Sinalizadores de Linker : -all_load
MkVal
Certifique-se de que os caminhos de pesquisa do cabeçalho do usuário estejam entre aspas, se houver espaços.
respectTheCode
O Xcode 4.6.2 não está gravando nada em "$ (PROJECT_TEMP_DIR) /../ UninstalledProducts / include" para mim. Alguma ideia do que estou perdendo? Ou o comportamento do Xcode mudou novamente?
c roald
16

O projeto Xcode 4 falha ao compilar uma biblioteca estática

Pergunta relacionada: “arquivo de problema léxico ou pré-processador não encontrado” no Xcode 4

Os erros podem incluir; arquivos de cabeçalho ausentes, "problema léxico ou pré-processador"

Soluções:

  1. Verifique se os "caminhos do cabeçalho do usuário" estão corretos
  2. Defina "Sempre pesquisar caminhos de usuário" como SIM
  3. Crie uma chamada de grupo "Indexando cabeçalhos" em seu projeto e arraste os cabeçalhos para este grupo, NÃO adicione a nenhum destino quando solicitado.
Richard Stelling
fonte
11
Outra etapa facilmente esquecida, mas extremamente importante: verifique se os caminhos de pesquisa estão entre aspas duplas para escapar de quaisquer espaços. Eu sempre esqueço de fazer isso.
Brad
Obrigado @Brad, esta é realmente uma observação muito importante e útil.
Julian D.
15

Este foi um tópico muito útil. Ao pesquisar minha própria situação, descobri que a Apple tem um documento de 12 páginas datado de setembro de 2012 com o título "Usando bibliotecas estáticas no iOS". Aqui está o link do pdf: http://developer.apple.com/library/ios/technotes/iOSStaticLibraries/iOSStaticLibraries.pdf

É muito mais simples do que a maioria das discussões na Internet e, com alguns pequenos mods para explicar como as bibliotecas externas que estou usando estão configuradas, está funcionando bem para mim. A parte mais importante é provavelmente:

Se o destino da sua biblioteca tiver uma fase de construção “Copiar cabeçalhos”, você deve excluí-la; As fases de construção de cabeçalhos de cópia não funcionam corretamente com destinos de biblioteca estática ao executar a ação “Arquivar” no Xcode.

Novos destinos de biblioteca estática criados com o Xcode 4.4 ou posterior virão com uma fase de cópia de arquivos configurada apropriadamente para cabeçalhos, portanto, você deve verificar se já tem um antes de criar um. Se você não fizer isso, pressione “Adicionar fase de construção” na parte inferior do editor de destino e escolha “Adicionar arquivos de cópia”. Divulgue a nova fase de compilação de Copiar Arquivos e defina o Destino como “Diretório de Produtos”. Defina o subcaminho para incluir / $ {PRODUCT_NAME}. Isso copiará os arquivos em uma pasta com o nome de sua biblioteca (obtida da configuração de construção do PRODUCT_NAME), dentro de uma pasta chamada include, dentro do diretório de produtos criados. A pasta de inclusão dentro de um diretório de produtos de construção está no caminho de pesquisa de cabeçalho padrão para aplicativos, portanto, este é um local apropriado para colocar arquivos de cabeçalho.

Estou certo de que, em muitas situações existentes, a abordagem da Apple pode não ser suficiente. Eu posto isso aqui para qualquer um que está apenas começando sua jornada no caminho do jardim da biblioteca estática - este pode ser o melhor ponto de partida para casos simples.

Michael J.
fonte
para aqueles que seguem o link acima .. cuidado: a etapa que pede para você excluir os arquivos de modelo fictícios ao criar o projeto de biblioteca .. NÃO EXCLUA O arquivo * .pch .. ele virá assombrá-lo eventualmente + o acima conselhos não funcionam com categorias .. há uma correção para isso (vi em algum lugar)
abbood
Obrigado por fornecer um link para uma abordagem oficial da Apple para a construção de bibliotecas estáticas. Comecei construindo minha biblioteca estática usando essa abordagem , mas não consegui arquivar. @abbood - Qual é o problema em excluir o arquivo pch gerado?
augusto callejas
se você excluir o arquivo .pch .. o projeto simplesmente não compilará .. (para fins de arquivamento ou não) ..
abbood
Isso não funciona para mim.Quando tento importar a instrução com "", ela não funciona, eu preciso <>. Além disso, ao arquivar, não é possível localizar cabeçalhos.Alguma idéia?
user1010819
4

http://developer.apple.com/library/ios/#technotes/iOSStaticLibraries/Articles/creating.html

Por documentação da Apple:

Sua biblioteca terá um ou mais arquivos de cabeçalho que os clientes dessa biblioteca precisam importar. Para configurar quais cabeçalhos são exportados para clientes, selecione seu projeto de biblioteca para abrir o editor de projeto, selecione o destino da biblioteca para abrir o editor de destino e selecione a guia de fases de construção. Se o destino da sua biblioteca tiver uma fase de construção “Copiar cabeçalhos”, você deve excluí-la; As fases de construção de cabeçalhos de cópia não funcionam corretamente com destinos de biblioteca estática ao executar a ação “Arquivar” no Xcode.

dmarnel
fonte
3

Dê uma olhada na solução de Jonah Wlliam (no meio) e no modelo GitHub (nos comentários) para uma visão. http://blog.carbonfive.com/2011/04/04/using-open-source-static-libraries-in-xcode-4/

d1bru
fonte
4
Embora isso possa responder tecnicamente à pergunta, é preferível que você inclua as partes essenciais do artigo vinculado em sua resposta e forneça o link para referência. Não fazer isso deixa a resposta em risco de apodrecimento do link.
jscs
2

Adicione $ (OBJROOT) / UninstalledProducts / exactPathToHeaders aos Caminhos de pesquisa do cabeçalho.

Por algum motivo, a caixa de seleção recursiva não funcionou para mim e tive que adicionar o resto do caminho para onde os cabeçalhos estão localizados.

No Log Navigator no Xcode (a guia à direita do navegador dos pontos de interrupção), você pode ver o histórico de construção. Se você selecionar a falha de construção real, poderá expandir seus detalhes para ver o PATH setenv e verificar se o caminho para seus arquivos de cabeçalho está lá.

Collin
fonte
Boa observação sobre a caixa de seleção recursiva, mesmo problema aqui.
Codezy
Sim, eu tive que especificar uma determinada subpasta também, verificar recursiva não funcionou.
Oliver Pearmain
No entanto, acabei usando este caminho (simplesmente porque é mais curto) "$ (PROJECT_TEMP_DIR) /../ UninstalledProducts / SubProjectHeaders"
Oliver Pearmain
2

No meu caso, meu espaço de trabalho tinha alguns projetos de biblioteca estática e um deles tem dependência do outro, incluindo arquivos de cabeçalho. O problema era com a ordem de construção. Na página Editar Esquema na seção Compilar, desmarquei a opção paralelizar e organizei a ordem dos destinos de acordo com as dependências e resolvi pelo problema

Vamshi
fonte
1

Adicione o seguinte caminho para seus caminhos de pesquisa de cabeçalho de usuário:

$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts

Isso foi verificado!

Yirenjun
fonte
1

Correndo o risco de mostrar como sou idiota ... Tenho sofrido com o XCode me recusando a encontrar meus arquivos .h a tarde toda.

Então eu percebi.

Como estava usando o "XCode 4", decidi "inteligentemente" colocar todos os meus projetos em subpastas de uma pasta chamada " Projetos XCode 4 ".

Esses espaços no nome da pasta bagunçaram muito o XCode!

Renomear esta pasta para " XCode_4_Projects " trouxe alegria (e menos palavrões) de volta à minha vida.

Lembre-me de novo, em que ano estamos?

Talvez alguém pudesse contar aos desenvolvedores da Apple ...

Mike Gledhill
fonte
1

Nenhuma dessas respostas funcionou para mim. Aqui está o que aconteceu. Adicione exatamente o seguinte (copie e cole, incluindo as aspas duplas) à configuração de criação de Caminhos de pesquisa do cabeçalho do usuário :

"$(BUILD_ROOT)/../IntermediateBuildFilesPath/UninstalledProducts/include/"

Observe a adição do subdiretório "/ include /" em comparação com outras respostas. Como outros usuários apontaram, a opção "recursiva" não parece fazer nada, então você pode ignorá-la.

Meu projeto agora foi capaz de arquivar com êxito ao importar arquivos de cabeçalho de biblioteca estática no seguinte formato:

#import "LibraryName/HeaderFile.h"

Você não precisa habilitar a configuração Always Search User Paths , a menos que esteja incluindo os cabeçalhos de sua biblioteca estática com colchetes angulares ( #import <LibraryName/HeaderFile.h>), mas você realmente não deveria fazer isso de qualquer maneira se não for um cabeçalho de sistema / estrutura.

devios1
fonte
1

Nenhuma das respostas acima funcionou para mim no Xcode 7, mas elas me deram uma boa ideia. Para os caras que lutam com o Xcode 7, resolvi isso adicionando o seguinte ao User Header Search Paths (inclua aspas)

"$(BUILT_PRODUCTS_DIR)/usr/local/include"

Altere a parte relativa do URL de usr/local/includeacordo com o que está lá na configuração 'Public Header Folder Path' da biblioteca estática

Evol Gate
fonte
0

Este é um problema relacionado que me levou a esta pergunta, então estou adicionando minha solução estritamente para documentação / poderia economizar mais horas de suor

Arquivo DropboxSDK.h não encontrado

Depois de dias tentando fazer o VES compilar para iOS, eventualmente encontrei esse problema. O DropboxSDK.hestava definitivamente ao alcance de search headersEu até o adicionei ao framework headerscaminho de pesquisa, included o .hdiretamente e fiz todos os tipos de grandes comprimentos para tentar ser DropboxSDK.hencontrado.

Solução

EXPLICITY arraste o DropboxSDK.frameworkarquivo para o Xcode Project Navigatione certifique-se de que Copy Files if neededestá marcado. Além disso, certifique-se de que seu alvo seja verificado conforme necessário.

Aviso

Definir a localização explícita da estrutura em build phasesnão funcionou para mim. Tive que arrastar o .framework para o Xcode e garantir que os arquivos foram copiados para o meu projeto.

# mbp2015 # xcode7 # ios9

Jacksonkr
fonte
0

Existem várias maneiras complexas de fazer isso, e algumas soluções muito inteligentes são propostas neste tópico.

O principal problema de todas essas soluções é que elas diminuem seriamente a portabilidade da biblioteca.

  • Cada vez que você precisa iniciar um novo projeto usando sua biblioteca e arquivá-lo no iTunes, é um inferno de configuração.
  • Cada vez que você precisa compartilhar seu projeto com sua equipe ou clientes, ele pode falhar por qualquer motivo (contexto, versão do Xcode, qualquer que seja, ..)

Minha escolha foi, finalmente, simplesmente usar frameworks - sempre - como recomendado pela Apple (Vídeos WWDC).

É tão mais fácil e faz o mesmo trabalho no final!

Outra solução bastante elegante que parece funcionar é usar o Private Cocoapods. O Cocoapods faz todo o trabalho de configuração, cópia do cabeçalho e assim por diante.

Frameworks rock!

alce
fonte
1
Onde você define isso? simply use frameworks - always -
Neil Faulkner
Não está definido em nenhum lugar. É simplesmente uma escolha arquitetônica. Frameworks são 'bibliotecas modernas' que são muito mais fáceis de vincular e gerenciar. No momento desta mensagem, o swift ainda não permite construir bibliotecas binárias.
Moose
0

Aqui está o que resolveu o mesmo problema para mim.

Eu tenho um App Target e um iMessage Extension Target. Então eu tinha 2 SDKs (meu próprio), aos quais o App Target se vincula.

O problema era: meu destino iMessage também estava usando os 2 SDKs meus (projetos separados), mas não estava vinculando a eles nas fases de construção -> Vincular binário às bibliotecas. Tive que adicionar meus 2 SDKs ao iMessage Target lá, para corresponder ao meu destino de aplicativo, e agora ele arquiva.

Portanto, a moral da história é: se você tiver vários alvos, como extensões, certifique-se de que todos os seus alvos estejam vinculados às bibliotecas de que precisam. Ele foi capaz de construir e implantar no simulador e no dispositivo, mas não arquivar.

FranticRock
fonte
0

Atualização: Xcode 9

As respostas acima não funcionaram para mim usando o Xcode 9, mas essa resposta funcionou perfeitamente para mim. Eu adicionei $(OBJROOT)/UninstalledProducts/$(PLATFORM_NAME)/includeaos meus "Caminhos de pesquisa de cabeçalho" e o Xcode vinculou o cabeçalho da minha biblioteca estática sem problemas.

Mohammed Abdullatif
fonte
-18

Evite problemas e faça isso = crie uma nova conta de usuário em seu Mac - abra o projeto com a nova conta de usuário - todos os problemas desaparecem. Economize seu tempo e mantenha sua sanidade. todas aquelas respostas nerds não ajudam !!

Boa sorte

Max
fonte