Liên kết CMake đến thư viện bên ngoài


126

Làm cách nào để CMake liên kết tệp thực thi với thư viện chia sẻ bên ngoài không được xây dựng trong cùng một dự án CMake?

Chỉ làm target_link_libraries(GLBall ${CMAKE_BINARY_DIR}/res/mylib.so)là sai

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)

sau khi tôi sao chép thư viện vào dir nhị phân bin/res.

Tôi đã thử sử dụng find_library(RESULT mylib.so PATHS ${CMAKE_BINARY_DIR}/res)

Mà không thành công với RESULT-NOTFOUND.

Câu trả lời:


101

Đặt đường dẫn tìm kiếm thư viện trước:

LINK_DIRECTORIES(${CMAKE_BINARY_DIR}/res)

Và sau đó chỉ cần làm

TARGET_LINK_LIBRARIES(GLBall mylib)

44
Việc sử dụng link_directorieskhông được khuyến khích, ngay cả trong tài liệu riêng của nó. Tôi nghĩ sẽ tốt hơn ở đây nếu giải quyết find_librarycuộc gọi không thành công trong câu hỏi ban đầu hoặc sử dụng giải pháp của @ Andre.
Fraser

4
Tôi thấy mục tiêu thư viện "đã nhập" mạnh mẽ hơn, vì nó nhắm mục tiêu đến vị trí của thư viện cụ thể, thay vì chỉ đưa ra một đường dẫn tìm kiếm toàn cục. Hãy xem câu trả lời của Andre.
Mark Lakata

1
Bạn nên luôn sử dụng find_libraryvà sử dụng đường dẫn này thay vì viết mã khó, x. câu trả lời của tôi .
usr1234567

121

Câu trả lời của arrowdodger là đúng và được ưa thích trong nhiều trường hợp. Tôi chỉ muốn thêm một câu trả lời thay thế cho câu trả lời của anh ấy:

Bạn có thể thêm một mục tiêu thư viện "đã nhập", thay vì một thư mục liên kết. Cái gì đó như:

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

Và sau đó liên kết như thể thư viện này được xây dựng bởi dự án của bạn:

TARGET_LINK_LIBRARIES(GLBall mylib)

Cách tiếp cận như vậy sẽ giúp bạn linh hoạt hơn một chút: Hãy xem lệnh add_library ()nhiều thuộc tính đích liên quan đến các thư viện đã nhập .

Tôi không biết liệu điều này có giải quyết được vấn đề của bạn với "các phiên bản cập nhật của libs" hay không.


2
Điều đó có thể xảy ra add_library( mylib SHARED IMPORTED )hoặc bạn gặp add_library called with IMPORTED argument but no library typelỗi
Marvin

4
@Andre: Tôi nghĩ rằng sau khi IMPORTED_LOCATIONdấu ngoặc mở là sai
Ela782

5
bạn cần thêm GLOBALsau IMPORTEDnếu bạn muốn truy cập thư viện đã nhập trong các thư mục phía trên thư mục hiện tại:add_library(breakpad STATIC IMPORTED GLOBAL)
Roman Kruglov

@Andre IMPORTED_LOCATION dường như đòi hỏi đường dẫn đến tập tin thay vì thư mục chứa các tập tin
SOUser

1
@SOUser: Có, IMPORTED_LOCATION phải trỏ đến tệp, không phải thư mục. Mình đã sửa rồi, đoán là tác giả sẽ không phàn nàn.
Tsyvarev

64

Tôi giả sử bạn muốn liên kết đến một thư viện có tên là foo , tên tệp của nó thường là một liên kết nào đó foo.dllhoặc libfoo.so.

1. Tìm thư viện
Bạn phải tìm thư viện. Đây là một ý tưởng hay, ngay cả khi bạn biết đường dẫn đến thư viện của mình. CMake sẽ báo lỗi nếu thư viện biến mất hoặc có tên mới. Điều này giúp phát hiện lỗi sớm và làm rõ cho người dùng (có thể là chính bạn) điều gì gây ra sự cố.
Để tìm foo thư viện và lưu trữ đường dẫn đang FOO_LIBsử dụng

    find_library(FOO_LIB foo)

CMake sẽ tự tìm ra tên tệp thực tế như thế nào. Nó kiểm tra các vị trí thông thường như /usr/lib, /usr/lib64và các đường dẫn trong PATH.

Bạn đã biết vị trí của thư viện của mình. Thêm nó vào CMAKE_PREFIX_PATHkhi bạn gọi CMake, sau đó CMake cũng sẽ tìm kiếm thư viện của bạn trong các đường dẫn đã qua.

Đôi khi bạn cần thêm gợi ý hoặc hậu tố đường dẫn, hãy xem tài liệu để biết chi tiết: https://cmake.org/cmake/help/latest/command/find_library.html

2. Liên kết thư viện Từ 1. bạn có tên thư viện đầy đủ FOO_LIB. Bạn sử dụng điều này để liên kết thư viện với mục tiêu của bạn GLBallnhư trong

  target_link_libraries(GLBall PRIVATE "${FOO_LIB}")

Bạn nên thêm PRIVATE, PUBLIChoặc INTERFACEsau khi mục tiêu, xem tài liệu: https://cmake.org/cmake/help/latest/command/target_link_libraries.html

Nếu bạn không thêm một trong các chỉ số hiển thị này, nó sẽ hoạt động giống như PRIVATEhoặc PUBLIC, tùy thuộc vào phiên bản CMake và các chính sách đã đặt.

3. Thêm bao gồm (Bước này có thể không bắt buộc.)
Nếu bạn cũng muốn bao gồm các tệp tiêu đề, hãy sử dụng find_pathtương tự find_libraryvà tìm kiếm tệp tiêu đề. Sau đó, thêm thư mục bao gồm target_include_directoriestương tự với target_link_libraries.

Tài liệu: https://cmake.org/cmake/help/latest/command/find_path.htmlhttps://cmake.org/cmake/help/latest/command/target_include_directories.html

Nếu có sẵn cho các phần mềm bên ngoài, bạn có thể thay thế find_libraryfind_pathbằng find_package.


4
IMHO đây là câu trả lời tốt nhất. Tuy nhiên, tôi đã gặp sự cố vì không gọi "find_library" sau "project" và "target_link_libraries" sau "add_executable".
mềm mượt mà

1
find_packagerất đơn giản hơn nhiều so với làm theo các bước
activedecay

2
Tôi đoán là tôi không hiểu bước 2. Đối với thư viện được chia sẻ $ {FOO_LIB} sẽ giống như /full/path/to/libfoo.dylib. Làm thế nào là hữu ích? target_link_libraries không tạo "-L / full / path / to -lfoo", vì vậy find_library không trả về bất kỳ thứ gì hữu ích, ngoài việc xác minh rằng thư viện ở vị trí mà tôi đã biết. Tôi đang thiếu gì?
guymac

target_link_libraries(mylib "${FOO_LIB}")? Mục tiêu mylibthay vì mục tiêu thực tế của anh ta GLBall,? không có nhiều ý nghĩa đối với tôi
Bersan

5

Một giải pháp thay thế khác, trong trường hợp bạn đang làm việc với Appstore, cần "Quyền lợi" và do đó cần liên kết với Apple-Framework.

Để các Tiện ích hoạt động (ví dụ: GameCenter), bạn cần có bước xây dựng "Liên kết nhị phân với Thư viện" và sau đó liên kết với "GameKit.framework". CMake "đưa" các thư viện ở "cấp độ thấp" vào dòng lệnh, do đó Xcode không thực sự biết về nó và như vậy bạn sẽ không kích hoạt GameKit trong màn hình Khả năng.

Một cách để sử dụng CMake và có "Liên kết với Binaries" -buildstep là tạo xcodeproj với CMake, sau đó sử dụng 'sed' để 'tìm kiếm & thay thế' và thêm GameKit theo cách XCode thích ...

Tập lệnh trông như thế này (đối với 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

lưu nó vào "gamecenter.sed" và sau đó "áp dụng" nó như thế này (nó thay đổi xcodeproj của bạn!)

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

Bạn có thể phải thay đổi các lệnh script để phù hợp với nhu cầu của mình.

Cảnh báo: nó có khả năng bị hỏng với phiên bản Xcode khác vì định dạng dự án có thể thay đổi, số duy nhất (mã cứng) có thể không thực sự là duy nhất - và nói chung các giải pháp của người khác tốt hơn - vì vậy trừ khi bạn cần Hỗ trợ Appstore + Quyền lợi (và các bản dựng tự động), không làm điều này.

Đây là lỗi CMake, hãy xem http://cmake.org/Bug/view.php?id=14185http://gitlab.kitware.com/cmake/cmake/issues/14185


Cụ thể - để cmake liên kết với thư viện bên ngoài không phải là vấn đề (có một số giải pháp ở trên). Làm cho điều này hoạt động theo cách tự động để nó hoạt động với Apple Appstore và các quyền lợi là một thách thức. Trong trường hợp cụ thể đó, các giải pháp trên không hoạt động vì XCode sẽ không 'nhìn thấy' các thư viện được liên kết theo cách đó và các quyền sẽ không hoạt động. Afaik cmake không thể thêm các libaries theo cách xcode cần nó theo 'cách tương thích với appstore' - một lần nữa, hãy thông cảm cho tôi.
kalmiya

1
Ôi, thật là buồn. Cho đầy đủ vào liên kết để theo dõi vấn đề mới, mà hiện nay không chứa không commnets: gitlab.kitware.com/cmake/cmake/issues/14185
usr1234567

Sự cố đã được giải quyết cách đây 5 tháng, vì vậy với phiên bản CMake gần đây, nó sẽ không còn nữa. Xem gitlab.kitware.com/cmake/cmake/issues/14185
usr1234567
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.