เชื่อมโยง CMake ไปยังไลบรารีภายนอก


126

จะทำให้ CMake เชื่อมโยงไฟล์ปฏิบัติการไปยังไลบรารีที่ใช้ร่วมกันภายนอกที่ไม่ได้สร้างภายในโครงการ CMake เดียวกันได้อย่างไร

เพียงแค่target_link_libraries(GLBall ${CMAKE_BINARY_DIR}/res/mylib.so)ทำให้ข้อผิดพลาด

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)

หลังจากที่ผมคัดลอกห้องสมุดเข้าไปใน bin/resdir

ฉันลองใช้ find_library(RESULT mylib.so PATHS ${CMAKE_BINARY_DIR}/res)

ซึ่งล้มเหลวด้วยRESULT-NOTFOUND.

คำตอบ:


101

กำหนดเส้นทางการค้นหาไลบรารีก่อน:

LINK_DIRECTORIES(${CMAKE_BINARY_DIR}/res)

แล้วก็ทำ

TARGET_LINK_LIBRARIES(GLBall mylib)

44
การใช้link_directoriesเป็นกำลังใจแม้จะอยู่ในเอกสารของตัวเอง ฉันคิดว่ามันจะดีกว่าที่นี่หากจะแก้ปัญหาการfind_libraryโทรที่ล้มเหลวในคำถามเดิมหรือใช้วิธีแก้ปัญหาของ @ Andre
Fraser

4
ฉันพบว่าเป้าหมายไลบรารีที่ "นำเข้า" มีประสิทธิภาพมากขึ้นเนื่องจากกำหนดเป้าหมายไปยังตำแหน่งของไลบรารีเฉพาะแทนที่จะให้เส้นทางการค้นหาทั่วโลก ดูคำตอบของ Andre
Mark Lakata

1
คุณควรใช้find_libraryและใช้เส้นทางนี้แทนการเข้ารหัสอย่างหนัก cf. คำตอบของฉัน
usr1234567

121

คำตอบของ arrowdodger ถูกต้องและเป็นที่ต้องการในหลาย ๆ โอกาส ฉันอยากจะเพิ่มทางเลือกให้กับคำตอบของเขา:

คุณสามารถเพิ่มเป้าหมายไลบรารี "นำเข้า" แทนลิงก์ไดเร็กทอรี สิ่งที่ต้องการ:

# 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 )

จากนั้นเชื่อมโยงราวกับว่าไลบรารีนี้สร้างขึ้นโดยโครงการของคุณ:

TARGET_LINK_LIBRARIES(GLBall mylib)

วิธีการดังกล่าวจะทำให้คุณมีความยืดหยุ่นมากขึ้นเล็ก ๆ น้อย ๆ : ลองดูที่add_library ()คำสั่งและหลายเป้าหมายคุณสมบัติที่เกี่ยวข้องกับห้องสมุดที่นำเข้า

ฉันไม่รู้ว่าวิธีนี้จะช่วยแก้ปัญหา "libs เวอร์ชันอัปเดต" ของคุณได้หรือไม่


2
นั่นอาจเป็นadd_library( mylib SHARED IMPORTED )หรือคุณได้รับadd_library called with IMPORTED argument but no library typeข้อผิดพลาด
Marvin

4
@Andre: ฉันคิดว่าหลังจากIMPORTED_LOCATIONวงเล็บเปิดผิด
Ela782

5
คุณต้องเพิ่มGLOBALหลังจากนั้นIMPORTEDหากคุณต้องการเข้าถึงไลบรารีที่นำเข้าในไดเรกทอรีที่อยู่เหนือปัจจุบัน:add_library(breakpad STATIC IMPORTED GLOBAL)
Roman Kruglov

@Andre IMPORTED_LOCATION ดูเหมือนจะต้องการพา ธ ไปยังไฟล์แทนที่จะเป็นไดเร็กทอรีที่มีไฟล์
SOUser

1
@SOUser: ใช่ IMPORTED_LOCATION ควรชี้ไปที่ไฟล์ไม่ใช่ไปที่ไดเร็กทอรี ฉันได้แก้ไขแล้วเดาว่าผู้เขียนจะไม่บ่น
Tsyvarev

65

ฉันคิดว่าคุณต้องการเชื่อมโยงไปยังไลบรารีชื่อfooโดยปกติชื่อไฟล์จะเป็นลิงค์foo.dllหรือlibfoo.so.

1. ค้นหาห้องสมุด
คุณต้องหาห้องสมุด นี่เป็นความคิดที่ดีแม้ว่าคุณจะรู้เส้นทางไปยังห้องสมุดของคุณ CMake จะผิดพลาดหากห้องสมุดหายไปหรือมีชื่อใหม่ สิ่งนี้จะช่วยให้สังเกตเห็นข้อผิดพลาดได้ตั้งแต่เนิ่นๆและทำให้ผู้ใช้เข้าใจได้ชัดเจนว่าอะไรเป็นสาเหตุของปัญหา
เพื่อค้นหาห้องสมุดfooและจัดเก็บเส้นทางที่FOO_LIBใช้งาน

    find_library(FOO_LIB foo)

CMake จะคิดเองว่าชื่อไฟล์จริงเป็นอย่างไร มันจะตรวจสอบในสถานที่ตามปกติเช่น/usr/lib, และเส้นทางใน/usr/lib64PATH

คุณทราบตำแหน่งของห้องสมุดแล้ว เพิ่มลงในCMAKE_PREFIX_PATHเมื่อคุณเรียก CMake จากนั้น CMake จะค้นหาห้องสมุดของคุณในเส้นทางที่ผ่านไปด้วย

บางครั้งคุณต้องเพิ่มคำแนะนำหรือคำต่อท้ายเส้นทางดูรายละเอียดในเอกสารประกอบ: https://cmake.org/cmake/help/latest/command/find_library.html

2. เชื่อมโยงไลบรารี จาก 1. คุณมีชื่อเต็มของไลบรารีในFOO_LIB. คุณใช้สิ่งนี้เพื่อเชื่อมโยงไลบรารีกับเป้าหมายของคุณGLBallในรูปแบบ

  target_link_libraries(GLBall PRIVATE "${FOO_LIB}")

คุณควรเพิ่มPRIVATE, PUBLICหรือINTERFACEหลังจากเป้าหมาย cf เลย เอกสารประกอบ: https://cmake.org/cmake/help/latest/command/target_link_libraries.html

หากคุณไม่เพิ่มตัวระบุการเปิดเผยตัวใดตัวหนึ่งเหล่านี้อาจมีลักษณะเหมือนPRIVATEหรือPUBLICขึ้นอยู่กับเวอร์ชันของ CMake และนโยบายที่ตั้งไว้

3. เพิ่มการรวม (ขั้นตอนนี้อาจไม่บังคับ)
หากคุณต้องการรวมไฟล์ส่วนหัวด้วยให้ใช้find_pathคล้ายกับfind_libraryและค้นหาไฟล์ส่วนหัว จากนั้นเพิ่มไดเร็กทอรีรวมที่target_include_directoriesคล้ายกับtarget_link_libraries.

เอกสารประกอบ: https://cmake.org/cmake/help/latest/command/find_path.html และ https://cmake.org/cmake/help/latest/command/target_include_directories.html

ถ้าใช้ได้สำหรับซอฟต์แวร์ภายนอกคุณสามารถแทนที่find_libraryและโดยfind_pathfind_package


5
IMHO นี่คือคำตอบที่ดีที่สุด อย่างไรก็ตามฉันมีปัญหาเพราะฉันไม่ได้เรียก "find_library" หลัง "project" และ "target_link_libraries" หลังจาก "add_executable"
smoothware

1
find_packageง่ายกว่าการทำตามขั้นตอนเหล่านี้มาก
activedecay

2
ฉันเดาว่าฉันไม่เข้าใจขั้นตอนที่ 2 สำหรับไลบรารีที่ใช้ร่วมกัน $ {FOO_LIB} จะเป็นเช่น /full/path/to/libfoo.dylib นั้นมีประโยชน์อย่างไร? target_link_libraries ไม่ได้สร้าง "-L / full / path / to -lfoo" ดังนั้น find_library จึงไม่ส่งคืนสิ่งที่เป็นประโยชน์นอกเหนือจากการตรวจสอบว่าไลบรารีอยู่ในตำแหน่งที่ฉันรู้อยู่แล้ว ฉันขาดอะไรไป?
guymac

target_link_libraries(mylib "${FOO_LIB}")? เป้าหมายนั้นmylibแทนที่จะเป็นเป้าหมายที่แท้จริงของเขาGLBall? ไม่สมเหตุสมผลกับฉันมากนัก
Bersan

5

อีกทางเลือกหนึ่งในกรณีที่คุณทำงานกับ Appstore ต้องมี "สิทธิ" และจำเป็นต้องเชื่อมโยงกับ Apple-Framework

เพื่อให้สิทธิ์ทำงานได้ (เช่น GameCenter) คุณต้องมีขั้นตอน "Link Binary with Libraries" จากนั้นเชื่อมโยงกับ "GameKit.framework" CMake "ฉีด" ไลบรารีใน "ระดับต่ำ" ลงในบรรทัดคำสั่งดังนั้น Xcode จึงไม่รู้เกี่ยวกับเรื่องนี้จริงๆและด้วยเหตุนี้คุณจะไม่ได้รับการเปิดใช้งาน GameKit ในหน้าจอความสามารถ

วิธีหนึ่งในการใช้ CMake และมี "Link with Binaries" -buildstep คือการสร้าง xcodeproj ด้วย CMake จากนั้นใช้ 'sed' เพื่อ 'ค้นหาและแทนที่' และเพิ่ม GameKit ในแบบที่ XCode ชอบ ...

สคริปต์มีลักษณะดังนี้ (สำหรับ 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

บันทึกลงใน "gamecenter.sed" แล้ว "ใช้" แบบนี้ (มันเปลี่ยน xcodeproj ของคุณ!)

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

คุณอาจต้องเปลี่ยนคำสั่งสคริปต์เพื่อให้เหมาะกับความต้องการของคุณ

คำเตือน: มีแนวโน้มที่จะแตกด้วย Xcode-version ที่แตกต่างกันเนื่องจากรูปแบบโครงการอาจเปลี่ยนแปลงได้หมายเลขเฉพาะ (ฮาร์ดโค้ด) อาจไม่ซ้ำกันจริงๆ - และโดยทั่วไปวิธีแก้ปัญหาโดยคนอื่นจะดีกว่า - ดังนั้นเว้นแต่คุณจะต้องสนับสนุน Appstore + สิทธิ์ (และบิลด์อัตโนมัติ) อย่าทำเช่นนี้

นี่เป็นข้อบกพร่องของ CMake โปรดดูที่http://cmake.org/Bug/view.php?id=14185และhttp://gitlab.kitware.com/cmake/cmake/issues/14185


โดยเฉพาะอย่างยิ่ง - การรับ cmake เพื่อเชื่อมโยงกับไลบรารีภายนอกไม่ใช่ปัญหา (มีหลายวิธีด้านบน) การทำให้สิ่งนี้ทำงานในรูปแบบอัตโนมัติเพื่อให้ทำงานร่วมกับ Apple Appstore และการให้สิทธิ์เป็นสิ่งที่ท้าทาย ในกรณีเฉพาะนั้นโซลูชันข้างต้นไม่ทำงานเนื่องจาก XCode จะไม่ 'เห็น' ไลบรารีที่เชื่อมโยงในลักษณะนั้นและการให้สิทธิ์จะไม่ทำงาน Afaik cmake ไม่สามารถเพิ่ม libaries ตามที่ xcode ต้องการใน 'วิธีที่เข้ากันได้กับ appstore' อีกครั้งอย่าลังเลที่จะให้ความกระจ่างแก่ฉัน
kalmiya

1
โอ้ที่น่าเศร้า เพื่อความสมบูรณ์ของลิงก์ไปยังเครื่องมือติดตามปัญหาใหม่ซึ่งขณะนี้ไม่มี commnets: gitlab.kitware.com/cmake/cmake/issues/14185
usr1234567

ปัญหาได้รับการแก้ไขเมื่อ 5 เดือนที่แล้วดังนั้น CMake เวอร์ชันล่าสุดจึงไม่ควรมีอยู่อีกต่อไป ดูgitlab.kitware.com/cmake/cmake/issues/14185
usr1234567
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.