Collegamento CMake alla libreria esterna


126

Come fare in modo che CMake colleghi un eseguibile a una libreria condivisa esterna che non è stata creata nello stesso progetto CMake?

Il solo fatto target_link_libraries(GLBall ${CMAKE_BINARY_DIR}/res/mylib.so)dà l'errore

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)

dopo aver copiato la libreria nella directory binaria bin/res.

Ho provato a usare find_library(RESULT mylib.so PATHS ${CMAKE_BINARY_DIR}/res)

Che fallisce con RESULT-NOTFOUND.

Risposte:


101

Imposta prima il percorso di ricerca delle librerie:

LINK_DIRECTORIES(${CMAKE_BINARY_DIR}/res)

E poi fallo e basta

TARGET_LINK_LIBRARIES(GLBall mylib)

44
L'uso di link_directoriesè sconsigliato, anche nella propria documentazione. Penso che qui sarebbe meglio risolvere la find_librarychiamata fallita nella domanda originale, o usare la soluzione di @ Andre.
Fraser

4
Trovo che la destinazione della libreria "importata" sia più robusta, in quanto mira alla posizione della libreria particolare, fornendo invece semplicemente un percorso di ricerca globale. Vedi la risposta di Andre.
Mark Lakata

1
Dovresti sempre usare find_librarye usare questo percorso invece di codificarlo come hardcoded, cfr. la mia risposta .
usr1234567

121

La risposta di arrowdodger è corretta e preferita in molte occasioni. Vorrei semplicemente aggiungere un'alternativa alla sua risposta:

È possibile aggiungere una destinazione di libreria "importata", invece di una directory di collegamento. Qualcosa di simile a:

# 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 poi collega come se questa libreria fosse stata costruita dal tuo progetto:

TARGET_LINK_LIBRARIES(GLBall mylib)

Un tale approccio ti darebbe un po 'più di flessibilità: dai un'occhiata al comando add_library () e alle numerose proprietà di destinazione relative alle librerie importate .

Non so se questo risolverà il tuo problema con le "versioni aggiornate di librerie".


2
Probabilmente è così add_library( mylib SHARED IMPORTED )o ottieni un add_library called with IMPORTED argument but no library typeerrore
Marvin

4
@Andre: Penso che dopo IMPORTED_LOCATIONla parentesi di apertura sia sbagliato
Ela782

5
è necessario aggiungere GLOBALdopo IMPORTEDse si desidera accedere alla libreria importata nelle directory sopra l'attuale:add_library(breakpad STATIC IMPORTED GLOBAL)
Roman Kruglov

@Andre IMPORTED_LOCATION sembra richiedere il percorso del file invece della directory contenente il file
SOUser

1
@SOUser: Sì, IMPORTED_LOCATION dovrebbe puntare al file, non alla directory. L'ho risolto, immagino che l'autore non si lamenterà.
Tsyvarev

65

Presumo che tu voglia collegarti a una libreria chiamata foo , il suo nome di file è solitamente qualcosa di link foo.dllo libfoo.so.

1. Trova la libreria
Devi trovare la libreria. Questa è una buona idea, anche se conosci il percorso della tua libreria. CMake verrà visualizzato in errore se la libreria è scomparsa o ha un nuovo nome. Questo aiuta a individuare l'errore in anticipo e a chiarire all'utente (magari tu stesso) cosa causa un problema.
Per trovare una libreria foo e memorizzare il percorso in FOO_LIBuso

    find_library(FOO_LIB foo)

CMake scoprirà da solo come è il nome del file effettivo. Esso controlla soliti posti come /usr/lib, /usr/lib64ed i percorsi in PATH.

Conosci già la posizione della tua libreria. Aggiungilo a CMAKE_PREFIX_PATHquando chiami CMake, quindi CMake cercherà anche la tua libreria nei percorsi passati.

A volte è necessario aggiungere suggerimenti o suffissi di percorso, vedere la documentazione per i dettagli: https://cmake.org/cmake/help/latest/command/find_library.html

2. Collega la libreria Da 1. hai il nome completo della libreria in FOO_LIB. Lo usi per collegare la libreria al tuo target GLBallcome in

  target_link_libraries(GLBall PRIVATE "${FOO_LIB}")

Dovresti aggiungere PRIVATE, PUBLICo INTERFACEdopo l'obiettivo, cfr. la documentazione: https://cmake.org/cmake/help/latest/command/target_link_libraries.html

Se non aggiungi uno di questi specificatori di visibilità, si comporterà come PRIVATEo PUBLIC, a seconda della versione di CMake e dei criteri impostati.

3. Aggiungi include (questo passaggio potrebbe non essere obbligatorio.)
Se si desidera includere anche file di intestazione, utilizzare find_pathsimile a find_librarye cercare un file di intestazione. Quindi aggiungi la directory include con target_include_directoriessimile a target_link_libraries.

Documentazione: https://cmake.org/cmake/help/latest/command/find_path.html e https://cmake.org/cmake/help/latest/command/target_include_directories.html

Se disponibile per il software esterno, è possibile sostituire find_librarye find_pathcon find_package.


5
IMHO questa è la migliore risposta. Tuttavia, ho avuto problemi perché non stavo chiamando "find_library" dopo "project" e "target_link_libraries" dopo "add_executable".
smoothware

1
find_packageè molto più semplice che seguire questi passaggi
activedecay

2
Immagino di non aver capito il passaggio 2. Per una libreria condivisa $ {FOO_LIB} sarà come /full/path/to/libfoo.dylib. In che modo è utile? target_link_libraries non sta creando "-L / full / path / to -lfoo", quindi find_library non restituisce nulla di utile, oltre a verificare che la libreria sia nella posizione in cui già so che si trova. Cosa mi manca?
guymac

target_link_libraries(mylib "${FOO_LIB}")? L'obiettivo è mylibinvece del suo obiettivo effettivo , GLBall? non ha molto senso per me
Bersan

5

Un'altra alternativa, nel caso tu stia lavorando con l'Appstore, necessiti di "Entitlements" e come tale devi collegarti con un Apple-Framework.

Per i diritti al lavoro (ad esempio GameCenter) si bisogno di avere un "Link binario con le librerie" -buildstep e quindi collegare con "GameKit.framework". CMake "inietta" le biblioteche su un "basso livello" in linea di comando, quindi Xcode non realmente sanno, e come tale si non ottenere GameKit abilitata nella schermata di capacità.

Un modo per usare CMake e avere un "Link with Binaries" -buildstep è generare xcodeproj con CMake, quindi usare 'sed' per 'cercare e sostituire' e aggiungere il GameKit nel modo in cui piace a XCode ...

Lo script ha questo aspetto (per 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

salvalo in "gamecenter.sed" e poi "applicalo" in questo modo (cambia il tuo xcodeproj!)

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

Potrebbe essere necessario modificare i comandi di script in base alle proprie esigenze.

Attenzione: è probabile che si rompa con una versione diversa di Xcode poiché il formato del progetto potrebbe cambiare, il numero univoco (codificato) potrebbe non essere realmente univoco e generalmente le soluzioni di altre persone sono migliori, quindi a meno che non sia necessario supportare l'Appstore + Autorizzazioni (e build automatizzate), non farlo.

Questo è un bug di CMake, vedere http://cmake.org/Bug/view.php?id=14185 e http://gitlab.kitware.com/cmake/cmake/issues/14185


Nello specifico, ottenere il collegamento di cmake con una libreria esterna non è il problema (ci sono diverse soluzioni sopra). Farlo funzionare in modo automatizzato, in modo che funzioni con l'Appstore di Apple e le autorizzazioni è una sfida. In quel caso specifico, le soluzioni di cui sopra non funzionano perché XCode non "vedrà" le librerie collegate in quel modo e le autorizzazioni non funzioneranno. Afaik cmake non può aggiungere le biblioteche nel modo in cui xcode ne ha bisogno in un "modo compatibile con l'appstore" - ancora una volta, sentiti libero di illuminarmi.
Kalmiya

1
Oh, è triste. Per completezza il collegamento al nuovo tracker dei problemi, che attualmente non contiene comunicazioni: gitlab.kitware.com/cmake/cmake/issues/14185
usr1234567

Il problema è stato risolto 5 mesi fa, quindi con una versione recente di CMake non dovrebbe più essere presente. Vedi gitlab.kitware.com/cmake/cmake/issues/14185
usr1234567
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.