2015-07-15 18 views
22

Tôi Ubuntu, tôi đang tìm hiểu về cmake và thực hiện, và chỉ cần thử một ví dụ đơn giản. Tôi có hai thư mục: srcbuild. Trong src, tôi có hai tập tin: main.cpp, và CMakeLists.txt, trong đó có (chỉ) các văn bản sau đây:Cmake không thể tìm thấy thư viện bằng cách sử dụng "link_directories"

add_executable(test main.cpp) 
link_directories(/usr/lib/x86_64-linux-gnu) 
target_link_libraries(test protobuf) 

trong /usr/lib/x86_64-linux-gnu, có một thư viện chia sẻ gọi libprotobuf.so, mà tôi muốn liên kết chống lại. My main.cpp sử dụng các chức năng trong thư viện này, bằng cách bao gồm tệp tiêu đề có liên quan, #include <google/protobuf/message.h>.

Bây giờ, trong thư mục build của tôi, tôi chạy cmake ../src và sau đó make. Tuy nhiên, sau đó tôi nhận được các lỗi liên kết cho tôi biết rằng có các tham chiếu không xác định đối với một số hàm trong thư viện protobuf. Nếu tôi thực hiện tìm kiếm thông qua tất cả các tệp và thư mục con trong build, thì không có đề cập đến bất kỳ điều gì liên quan đến protobuf.

Tuy nhiên, nếu tôi xóa dòng link_directories trong tệp CMakeLists.txt của mình và thay vào đó ghi đường dẫn đầy đủ vào thư viện khi chỉ định tệp thực thi, tức là target_link_libraries(test /usr/lib/x86_64-linux-gnu/libprotobuf.so), nó biên dịch và liên kết tốt.

Tại sao link_directories không cho phép cmake tìm thư viện này?

+1

Hướng dẫn sử dụng cmake nói về link_libraries "Lệnh sẽ chỉ áp dụng cho các mục tiêu được tạo sau khi nó được gọi." Mục tiêu có được tạo bằng lệnh add_executable() không? Có lẽ bạn cần phải di chuyển lệnh add_executable() sau link_directories(). – Alain

+0

Nếu tôi làm điều này, tôi nhận được lỗi "Không thể chỉ định thư viện liên kết cho mục tiêu" thử nghiệm "mà không được xây dựng bởi dự án này.' – Karnivaurus

+1

Chỉ cần chắc chắn: thứ tự của lệnh của bạn bây giờ là 1) link_directories(), 2) add_executable() và 3) target_link_libraries()? – Alain

Trả lời

37

Không sử dụng link_directories như thế này trong CMake.

Đây là lỗi thường gặp của người mới bắt đầu, vì nhiều môi trường xây dựng khác hoạt động như thế này, nhưng trong CMake, nó chỉ yêu cầu sự cố. Ngay cả the manpage đặc biệt khuyên chống lại nó:

Lưu ý rằng lệnh này [link_directories] hiếm khi cần thiết. Vị trí thư viện được trả về bởi find_package()find_library() là đường dẫn tuyệt đối. Chuyển các đường dẫn tệp thư viện tuyệt đối tuyệt đối này vào lệnh target_link_libraries() . CMake sẽ đảm bảo mối liên kết tìm thấy chúng.

Vì vậy, thay vào đó, luôn vượt qua đường dẫn tuyệt đối-target_link_libraries và sử dụng find_library để giải quyết các thư mục liên kết:

find_library(PROTOBUF_LIBRARY protobuf HINTS /usr/lib/x86_64-linux-gnu) 
target_link_libraries(test PUBLIC ${PROTOBUF_LIBRARY}) 

này được lợi ích rất lớn mà có thể bạn sẽ có được một chẩn đoán tại CMake cấu hình thời gian nếu không thể tìm thấy thư viện mong muốn, thay vì lỗi liên kết ngẫu nhiên tại thời gian biên dịch. Ngoài ra, điều này cho phép người dùng chỉ định vị trí thư viện thông qua GUI nếu máy đích có bố cục thư mục không chuẩn.

Vì vậy, nếu nó không hoạt động ngay lập tức, hãy chắc chắn kiểm tra kết quả cuộc gọi find_library và tham khảo manpage để theo dõi lý do tại sao nó không tìm thấy thư viện của bạn như dự định.

+5

... nhưng, tại sao nó không hoạt động? Tôi nhận ra nó được khuyên nên chống lại, nhưng nó vẫn không hoạt động? – aardvarkk

+0

Nếu bạn sử dụng pkg_check_modules để tìm một thư viện bạn đã có tất cả thông tin bạn cần và nó có ý nghĩa khi sử dụng pkg_check_modules. – wojciii

18

Đảm bảo rằng cuộc gọi của bạn đến link_directories diễn ra trước khi gọi đến add_executable có liên quan.

Tôi đã nhầm tưởng rằng nó chỉ cần thiết trước khi cuộc gọi đến target_link_libraries, nhưng đó không phải là trường hợp. Sau khi di chuyển cuộc gọi, thư viện được liên kết đúng cách.

0

Dưới đây là một chiết xuất từ ​​documentation:

link_directories (directory1 directory2 ...): Xác định đường dẫn trong đó mối liên kết nên tìm kiếm cho các thư viện. Lệnh sẽ chỉ áp dụng cho các mục tiêu được tạo sau khi được gọi là. Đường dẫn tương đối được cung cấp cho lệnh này được hiểu là tương đối với thư mục nguồn hiện tại, xem CMP0015.

lệnh

add_executable (thử nghiệm main.cpp)

tạo ra một thử nghiệm tên mục tiêu. Ngoài ra bạn musst đặt link_directories lệnh trên add_executable.

Các vấn đề liên quan