Link do CMake para a biblioteca externa

126

Como fazer com que o CMake vincule um executável a uma biblioteca compartilhada externa que não é criada no mesmo projeto do CMake?

Apenas fazendo target_link_libraries(GLBall ${CMAKE_BINARY_DIR}/res/mylib.so)dá o erro

make[2]: *** No rule to make target `res/mylib.so', needed by `GLBall'.  Stop.
make[1]: *** [CMakeFiles/GLBall.dir/all] Error 2
make: *** [all] Error 2
(GLBall is the executable)

depois que eu copiei a biblioteca no diretório binário bin/res.

Eu tentei usar find_library(RESULT mylib.so PATHS ${CMAKE_BINARY_DIR}/res)

O que falha com RESULT-NOTFOUND.

Prime
fonte

Respostas:

101

Defina o caminho de pesquisa das bibliotecas primeiro:

LINK_DIRECTORIES(${CMAKE_BINARY_DIR}/res)

E então apenas faça

TARGET_LINK_LIBRARIES(GLBall mylib)
arrowd
fonte
43
O uso de link_directoriesé desencorajado, mesmo em sua própria documentação. Eu acho que seria melhor aqui resolver a find_librarychamada que falhou na pergunta original ou usar a solução de @ Andre.
Fraser
4
Acho que o destino da biblioteca "importada" é mais robusto, pois tem como alvo o local da biblioteca em particular, simplesmente fornecendo um caminho de pesquisa global. Veja a resposta de Andre.
Mark Lakata
1
Você sempre deve usar find_librarye usar esse caminho em vez de codificá-lo, cf. a minha resposta .
precisa saber é o seguinte
121

A resposta de arrowdodger é correta e preferida em várias ocasiões. Eu simplesmente gostaria de adicionar uma alternativa à sua resposta:

Você pode adicionar um destino de biblioteca "importado", em vez de um diretório de link. Algo como:

# Your-external "mylib", add GLOBAL if the imported library is located in directories above the current.
add_library( mylib SHARED IMPORTED )
# You can define two import-locations: one for debug and one for release.
set_target_properties( mylib PROPERTIES IMPORTED_LOCATION ${CMAKE_BINARY_DIR}/res/mylib.so )

E, em seguida, vincule como se essa biblioteca tivesse sido criada por seu projeto:

TARGET_LINK_LIBRARIES(GLBall mylib)

Essa abordagem daria a você um pouco mais de flexibilidade: Dê uma olhada no comando add_library () e nas muitas propriedades de destino relacionadas às bibliotecas importadas .

Não sei se isso resolverá o seu problema com "versões atualizadas das bibliotecas".

André
fonte
2
Isso provavelmente seria add_library( mylib SHARED IMPORTED )ou você recebe um add_library called with IMPORTED argument but no library typeerro
Marvin
4
@Andre: Eu acho que após IMPORTED_LOCATIONo colchete de abertura está errado
Ela782
5
você precisará adicionar GLOBALdepois IMPORTEDse quiser acessar a biblioteca importada em diretórios acima do atual:add_library(breakpad STATIC IMPORTED GLOBAL)
Roman Kruglov
@Andre IMPORTED_LOCATION parece exigir o caminho para o arquivo em vez do diretório que contém o arquivo
SOUser
1
@SOUser: Sim, IMPORTED_LOCATION deve apontar para o arquivo, não para o diretório. Eu consertei isso, acho que o autor não vai reclamar.
Tsyvarev 7/12
64

Suponho que você deseja vincular a uma biblioteca chamada foo , seu nome de arquivo é geralmente algo como link foo.dllou libfoo.so.

1. Encontre a biblioteca
Você precisa encontrar a biblioteca. É uma boa ideia, mesmo se você souber o caminho para sua biblioteca. O CMake irá errar se a biblioteca desaparecer ou tiver um novo nome. Isso ajuda a detectar erros com antecedência e esclarecer ao usuário (você mesmo) o que causa um problema.
Para encontrar uma biblioteca foo e armazenar o caminho em FOO_LIBuso

    find_library(FOO_LIB foo)

O CMake vai descobrir como é o nome do arquivo real. Ele verifica os lugares habituais, como /usr/lib, /usr/lib64e os caminhos em PATH.

Você já sabe a localização da sua biblioteca. Adicione-o ao CMAKE_PREFIX_PATHquando você chamar o CMake; o CMake também procurará sua biblioteca nos caminhos passados.

Às vezes, você precisa adicionar dicas ou sufixos de caminho, consulte a documentação para obter detalhes: https://cmake.org/cmake/help/latest/command/find_library.html

2. Vincular a biblioteca A partir de 1. você tem o nome completo da biblioteca FOO_LIB. Você usa isso para vincular a biblioteca ao seu destino, GLBallcomo em

  target_link_libraries(GLBall PRIVATE "${FOO_LIB}")

Você deve adicionar PRIVATE, PUBLICou INTERFACEapós o destino, cf. a documentação: https://cmake.org/cmake/help/latest/command/target_link_libraries.html

Se você não adicionar um desses especificadores de visibilidade, ele se comportará como PRIVATEou PUBLIC, dependendo da versão do CMake e do conjunto de políticas.

3. Adicionar inclusões (Esta etapa pode não ser obrigatória.)
Se você também deseja incluir arquivos de cabeçalho, use find_pathsemelhante a find_librarye procure um arquivo de cabeçalho. Em seguida, adicione o diretório include com target_include_directoriessimilar a target_link_libraries.

Documentação: https://cmake.org/cmake/help/latest/command/find_path.html e https://cmake.org/cmake/help/latest/command/target_include_directories.html

Se estiver disponível para o software externo, pode substituir find_librarye find_pathpor find_package.

usr1234567
fonte
4
IMHO esta é a melhor resposta. No entanto, tive problemas porque não estava chamando "find_library" após "project" e "target_link_libraries" após "add_executable".
smoothware
1
find_packageé muito mais simples do que seguir estas etapas
activedecay
2
Acho que não entendo a etapa 2. Para uma biblioteca compartilhada, $ {FOO_LIB} será como /full/path/to/libfoo.dylib. Como isso é útil? target_link_libraries não está criando "-L / full / path / to -lfoo", portanto, find_library não está retornando nada útil, além de verificar se a biblioteca está no local em que eu já sei. o que estou perdendo?
guymac
target_link_libraries(mylib "${FOO_LIB}")? O alvo é, em mylibvez de seu alvo real GLBall,? não faz muito sentido para mim
Bersan
5

Mais uma alternativa, no caso de você estar trabalhando com a Appstore, precisa de "Direitos" e, como tal, precisa se vincular a um Apple-Framework.

Para que os Direitos funcionem (por exemplo, GameCenter), você precisa ter um build "Vincular Binário com Bibliotecas" e, em seguida, vincular com "GameKit.framework". O CMake "injeta" as bibliotecas em um "nível baixo" na linha de comando; portanto, o Xcode realmente não sabe sobre isso e, como tal, você não ativará o GameKit na tela Recursos.

Uma maneira de usar o CMake e ter um link "Link com binários" é gerar o xcodeproj com o CMake e, em seguida, usar 'sed' para 'pesquisar e substituir' e adicionar o GameKit da maneira que o XCode gosta ...

O script fica assim (para o Xcode 6.3.1).

s#\/\* Begin PBXBuildFile section \*\/#\/\* Begin PBXBuildFile section \*\/\
    26B12AA11C10544700A9A2BA \/\* GameKit.framework in Frameworks \*\/ = {isa = PBXBuildFile; fileRef = 26B12AA01C10544700A9A2BA \/\* GameKit.framework xxx\*\/; };#g

s#\/\* Begin PBXFileReference section \*\/#\/\* Begin PBXFileReference section \*\/\
    26B12AA01C10544700A9A2BA \/\* GameKit.framework xxx\*\/ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameKit.framework; path = System\/Library\/Frameworks\/GameKit.framework; sourceTree = SDKROOT; };#g

s#\/\* End PBXFileReference section \*\/#\/\* End PBXFileReference section \*\/\
\
\/\* Begin PBXFrameworksBuildPhase section \*\/\
    26B12A9F1C10543B00A9A2BA \/\* Frameworks \*\/ = {\
        isa = PBXFrameworksBuildPhase;\
        buildActionMask = 2147483647;\
        files = (\
            26B12AA11C10544700A9A2BA \/\* GameKit.framework in Frameworks xxx\*\/,\
        );\
        runOnlyForDeploymentPostprocessing = 0;\
    };\
\/\* End PBXFrameworksBuildPhase section \*\/\
#g

s#\/\* CMake PostBuild Rules \*\/,#\/\* CMake PostBuild Rules \*\/,\
            26B12A9F1C10543B00A9A2BA \/\* Frameworks xxx\*\/,#g
s#\/\* Products \*\/,#\/\* Products \*\/,\
            26B12AA01C10544700A9A2BA \/\* GameKit.framework xxx\*\/,#g

salve-o em "gamecenter.sed" e, em seguida, "aplique-o" desta maneira (ele altera seu xcodeproj!)

sed -i.pbxprojbak -f gamecenter.sed myproject.xcodeproj/project.pbxproj

Pode ser necessário alterar os comandos de script para atender às suas necessidades.

Aviso: é provável que seja diferente da versão do Xcode, pois o formato do projeto pode mudar, o número exclusivo (codificado) pode não ser realmente único - e geralmente as soluções de outras pessoas são melhores -, a menos que você precise oferecer suporte à Appstore + Direitos (e compilações automatizadas), não faça isso.

Este é um erro do CMake, consulte http://cmake.org/Bug/view.php?id=14185 e http://gitlab.kitware.com/cmake/cmake/issues/14185

kalmiya
fonte
Especificamente - conseguir que o cmake se vincule a uma biblioteca externa não é o problema (existem várias soluções acima). Fazer com que isso funcione de maneira automatizada, para que funcione com a Apple Appstore e direitos é um desafio. Nesse caso específico, as soluções acima não funcionam porque o XCode não 'verá' as bibliotecas vinculadas dessa maneira, e os direitos simplesmente não funcionarão. O Afaik cmake não pode adicionar as bibliotecas da maneira que o xcode precisa, de uma 'maneira compatível com a appstore' - novamente, sinta-se à vontade para me esclarecer.
precisa saber é
1
Oh isso é triste. Para completar, o link para o novo rastreador de problemas, que atualmente não contém commnets: gitlab.kitware.com/cmake/cmake/issues/14185
usr1234567
O problema foi resolvido há 5 meses, portanto, com uma versão recente do CMake, ele não deveria mais estar presente. Veja gitlab.kitware.com/cmake/cmake/issues/14185
usr1234567