2013-07-07 55 views
56

Tôi đã viết một thư viện mà tôi đã sử dụng để biên dịch bằng cách sử dụng một Makefile tự viết, nhưng bây giờ tôi muốn chuyển sang cmake. Cây trông như thế này (tôi loại bỏ tất cả các tập tin không liên quan):Cách tạo thư viện dùng chung với cmake?

. 
├── include 
│   ├── animation.h 
│   ├── buffers.h 
│   ├── ... 
│   ├── vertex.h 
│   └── world.h 
└── src 
    ├── animation.cpp 
    ├── buffers.cpp 
    ├── ... 
    ├── vertex.cpp 
    └── world.cpp 

Vì vậy, những gì tôi đang cố gắng làm chỉ là để dịch chương trình nguồn thành một thư viện chia sẻ và sau đó cài đặt nó với các tập tin tiêu đề.

Hầu hết các ví dụ mà tôi đã tìm thấy thực thi biên dịch với một số thư viện được chia sẻ nhưng không bao giờ chỉ là một thư viện được chia sẻ đơn giản. Nó cũng sẽ hữu ích nếu ai đó chỉ có thể cho tôi biết một thư viện rất đơn giản sử dụng cmake, vì vậy tôi có thể sử dụng điều này làm ví dụ.

+0

liên quan http://stackoverflow.com/questions/2152077/is-it-possible-to-get-cmake-to-build-both-a -Mã-và-chia-phiên bản-of-the-sam –

Trả lời

28

Luôn thể chỉ định phiên bản yêu cầu tối thiểu của cmake

cmake_minimum_required(VERSION 3.9) 

Bạn nên tuyên bố một dự án. cmake nói nó là bắt buộc và nó sẽ xác định các biến thuận tiện PROJECT_NAME, PROJECT_VERSIONPROJECT_DESCRIPTION (biến thứ hai này đòi hỏi cmake 3.9):

project(mylib VERSION 1.0.1 DESCRIPTION "mylib description") 

Khai báo một đối tượng thư viện mới. Vui lòng tránh sử dụng file(GLOB ...). Tính năng này không cung cấp quy trình biên dịch đã được tham dự. Nếu bạn là lười biếng, sao chép-dán đầu ra của ls -1 sources/*.cpp:

add_library(mylib SHARED 
    sources/animation.cpp 
    sources/buffers.cpp 
    [...] 
) 

Đặt VERSION bất động sản (không bắt buộc nhưng nó là một thực hành tốt):

set_target_properties(mylib PROPERTIES VERSION ${PROJECT_VERSION}) 

Bạn cũng có thể thiết lập SOVERSION đến số chính của VERSION. Vì vậy, libmylib.so.1 sẽ là một liên kết tượng trưng đến libmylib.so.1.0.0.

set_target_properties(mylib PROPERTIES SOVERSION 1) 

Khai báo API công khai của thư viện của bạn. API này sẽ được cài đặt cho ứng dụng của bên thứ ba. Thực hành tốt là cô lập nó trong cây dự án của bạn (như đặt nó vào thư mục include/). Lưu ý rằng, các tiêu đề riêng tư không được cài đặt và tôi khuyên bạn nên đặt chúng với các tệp nguồn.

set_target_properties(mylib PROPERTIES PUBLIC_HEADER include/mylib.h) 

Nếu bạn làm việc với thư mục con, sẽ không thuận tiện khi đưa đường dẫn tương đối như "../include/mylib.h".Vì vậy, vượt qua mục hàng đầu trong danh bạ bao gồm:

target_include_directories(mylib PRIVATE .) 

hoặc

target_include_directories(mylib PRIVATE include) 
target_include_directories(mylib PRIVATE src) 

Tạo cài đặt quy tắc cho thư viện của bạn. Tôi đề nghị sử dụng các biến CMAKE_INSTALL_*DIR quy định tại GNUInstallDirs:

include(GNUInstallDirs) 

Và tuyên bố các file cài đặt:

install(TARGETS mylib 
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 
    PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 

Bạn cũng có thể xuất khẩu một tập tin pkg-config. file này cho phép ứng dụng của bên thứ ba để dễ dàng nhập thư viện của bạn:

Tạo một tập tin mẫu có tên mylib.pc.in:

[email protected][email protected] 
[email protected][email protected] 
libdir=${exec_prefix}/@[email protected] 
includedir=${prefix}/@[email protected] 

Name: @[email protected] 
Description: @[email protected] 
Version: @[email protected] 

Requires: 
Libs: -L${libdir} -lmylib 
Cflags: -I${includedir} 

Trong CMakeLists.txt của bạn, thêm một quy tắc để mở rộng @ macro (@ONLY yêu cầu cmake để không mở rộng biến dạng ${VAR}):

configure_file(mylib.pc.in mylib.pc @ONLY) 

Và cuối cùng, cài đặt tập tin được tạo:

install(FILES ${CMAKE_BINARY_DIR}/mylib.pc DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig) 

Bạn có thể cũng sử dụng cmake EXPORT feature. Tuy nhiên, tính năng này chỉ tương thích với cmake và tôi thấy khó sử dụng.

Cuối cùng toàn bộ CMakeLists.txt nên trông giống như:

cmake_minimum_required(VERSION 3.9) 
project(mylib VERSION 1.0.1 DESCRIPTION "mylib description") 
include(GNUInstallDirs) 
add_library(mylib SHARED src/mylib.c) 
set_target_properties(mylib PROPERTIES 
    VERSION ${PROJECT_VERSION} 
    SOVERSION 1 
    PUBLIC_HEADER api/mylib.h) 
configure_file(mylib.pc.in mylib.pc @ONLY) 
target_include_directories(mylib PRIVATE .) 
install(TARGETS mylib 
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} 
    PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 
install(FILES ${CMAKE_BINARY_DIR}/mylib.pc 
    DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig) 
+2

Chỉ cần bổ sung lời giải thích tuyệt vời của @ Jezz: sau tất cả các bước trên, lập trình viên có thể xây dựng và cài đặt thư viện bằng 'mkdir build && cd build/&& cmake .. && sudo make install' (hoặc' sudo make install/strip' để cài đặt phiên bản thư viện _striped_). – silvioprog

64

tập tin CMakeLists.txt tối thiểu này biên dịch một thư viện chia sẻ đơn giản:

cmake_minimum_required(VERSION 2.8) 

project (test) 
set(CMAKE_BUILD_TYPE Release) 

include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) 
add_library(test SHARED src/test.cpp) 

Tuy nhiên, tôi không có kinh nghiệm sao chép tập tin vào một địa điểm khác nhau với CMake. Lệnh tập tin với chữ ký COPY/INSTALL có vẻ như nó có thể hữu ích.

+14

CMAKE_BUILD_TYPE nên được bỏ qua, vì vậy quyết định là tùy thuộc vào người biên dịch. – ManuelSchneid3r

+0

Việc chỉ định '$ {CMAKE_CURRENT_SOURCE_DIR} /' trong 'include_directories' có hữu ích không? – Jezz

15

Tôi đang cố gắng tìm hiểu làm thế nào để làm điều này bản thân mình, và có vẻ như bạn có thể cài đặt thư viện như thế này:

cmake_minimum_required(VERSION 2.4.0) 

project(mycustomlib) 

# Find source files 
file(GLOB SOURCES src/*.cpp) 

# Include header files 
include_directories(include) 

# Create shared library 
add_library(${PROJECT_NAME} SHARED ${SOURCES}) 

# Install library 
install(TARGETS ${PROJECT_NAME} DESTINATION lib/${PROJECT_NAME}) 

# Install library headers 
file(GLOB HEADERS include/*.h) 
install(FILES ${HEADERS} DESTINATION include/${PROJECT_NAME}) 
Các vấn đề liên quan