চ্যামেক দিয়ে ভাগ করে নেওয়া লাইব্রেরি কীভাবে তৈরি করবেন?


141

আমি একটি লাইব্রেরি লিখেছি যা আমি একটি স্ব-লিখিত মেকফিল ব্যবহার করে সংকলন করতাম তবে এখন আমি চটকে স্যুইচ করতে চাই। গাছটি দেখতে দেখতে (আমি সমস্ত অপ্রাসঙ্গিক ফাইলগুলি সরিয়েছি):

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

সুতরাং আমি যা করার চেষ্টা করছি তা হ'ল উত্সটি একটি ভাগ করা লাইব্রেরিতে সংকলন করা এবং তারপরে এটি হেডার ফাইলগুলির সাথে ইনস্টল করা।

বেশিরভাগ উদাহরণ যেগুলি আমি কিছু ভাগ করে নেওয়া লাইব্রেরির সাথে এক্সিকিউটেবলগুলি সংকলন করে পেয়েছি তবে কখনই কেবল একটি সরল শেয়ার্ড লাইব্রেরি নেই। এটি যদি সহায়ক হয় তবে যদি কেউ আমাকে খুব সাধারণ লাইব্রেরি বলতে পারেন যা চতুর ব্যবহার করে, তাই আমি এটি উদাহরণ হিসাবে ব্যবহার করতে পারি।



একই প্রশ্ন, তবে কি আমার উত্সগুলি মিশ্রিত করার কোনও উপায় আছে (একই উত্স ডিরেক্টরিতে .h Ans .cpp) তবে চামকে তার কাজের একটি অন্তর্ভুক্ত ডিরেক্টরি, পণ্য উত্পাদন করতে দেবে?
স্যান্ডবুর্গ

উত্তর:


204

সর্বদা সর্বনিম্ন প্রয়োজনীয় সংস্করণ নির্দিষ্ট করুন cmake

cmake_minimum_required(VERSION 3.9)

আপনি একটি প্রকল্প ঘোষণা করা উচিত। cmakeবলেছেন এটা বাধ্যতামূলক এবং এটা সুবিধাজনক ভেরিয়েবল নির্ধারণ করবে PROJECT_NAME, PROJECT_VERSIONএবং PROJECT_DESCRIPTION(3.9 cmake এই আধুনিক পরিবর্তনশীল অবশ্যম্ভাবী):

project(mylib VERSION 1.0.1 DESCRIPTION "mylib description")

একটি নতুন লাইব্রেরির লক্ষ্য ঘোষণা করুন। দয়া করে এর ব্যবহার এড়িয়ে চলুন file(GLOB ...)। এই বৈশিষ্ট্যটি সংকলন প্রক্রিয়াটিতে অংশীদারিত্বের সরবরাহ করে না। আপনি যদি অলস হন তবে এর কপি-পেস্ট আউটপুট ls -1 sources/*.cpp:

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

VERSIONসম্পত্তি সেট করুন (alচ্ছিক তবে এটি একটি ভাল অনুশীলন):

set_target_properties(mylib PROPERTIES VERSION ${PROJECT_VERSION})

আপনি SOVERSIONএকটি বড় সংখ্যা সেট করতে পারেন VERSION। সুতরাং libmylib.so.1একটি syMLink হবে libmylib.so.1.0.0

set_target_properties(mylib PROPERTIES SOVERSION 1)

আপনার লাইব্রেরির সর্বজনীন এপিআই ঘোষণা করুন। এই API টি তৃতীয় পক্ষের অ্যাপ্লিকেশনের জন্য ইনস্টল করা হবে। এটি আপনার প্রকল্পের গাছে আলাদা করা ভাল অনুশীলন (এটি include/ডিরেক্টরি স্থাপনের মতো )। লক্ষ্য করুন যে, প্রাইভেট শিরোনামগুলি ইনস্টল করা উচিত নয় এবং আমি উত্স ফাইলগুলির সাথে সেগুলি রাখার জন্য দৃ strongly়ভাবে পরামর্শ দিই।

set_target_properties(mylib PROPERTIES PUBLIC_HEADER include/mylib.h)

আপনি যদি সাব-ডাইরেক্টরিগুলির সাথে কাজ করেন তবে আপেক্ষিক পাথগুলি অন্তর্ভুক্ত করা খুব সুবিধাজনক নয় "../include/mylib.h"। সুতরাং, অন্তর্ভুক্ত ডিরেক্টরিতে একটি শীর্ষ ডিরেক্টরি পাস করুন:

target_include_directories(mylib PRIVATE .)

অথবা

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

আপনার গ্রন্থাগারের জন্য একটি ইনস্টল বিধি তৈরি করুন। আমি CMAKE_INSTALL_*DIRসংজ্ঞায়িত ভেরিয়েবলগুলি ব্যবহার করার পরামর্শ দিই GNUInstallDirs:

include(GNUInstallDirs)

এবং ইনস্টল করার জন্য ফাইলগুলি ঘোষণা করুন:

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

আপনি একটি pkg-configফাইল রফতানিও করতে পারেন । এই ফাইলটি আপনার তৃতীয় পক্ষের অ্যাপ্লিকেশনটিকে সহজেই আপনার গ্রন্থাগারটি আমদানির অনুমতি দেয়:

নামে একটি টেম্পলেট ফাইল তৈরি করুন mylib.pc.in( আরও তথ্যের জন্য পিসি (5) ম্যানপেজ দেখুন):

prefix=@CMAKE_INSTALL_PREFIX@
exec_prefix=@CMAKE_INSTALL_PREFIX@
libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@

Name: @PROJECT_NAME@
Description: @PROJECT_DESCRIPTION@
Version: @PROJECT_VERSION@

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

আপনার মধ্যে CMakeLists.txt, @ম্যাক্রোগুলি প্রসারিত করার জন্য একটি বিধি যুক্ত করুন ( @ONLYফর্মের ভেরিয়েবলগুলি প্রসারণ না করার জন্য চাকা করতে বলুন ${VAR}):

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

এবং পরিশেষে, উত্পন্ন ফাইল ইনস্টল করুন:

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

আপনি cmake EXPORTবৈশিষ্ট্য ব্যবহার করতে পারেন । তবে এই বৈশিষ্ট্যটি কেবলমাত্র তার সাথে সামঞ্জস্যপূর্ণ cmakeএবং এটি ব্যবহার করা আমার পক্ষে কঠিন find

শেষ পর্যন্ত পুরো CMakeLists.txtদেখতে হবে:

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)

10
কেবলমাত্র @ জেজের দুর্দান্ত ব্যাখ্যার পরিপূরক: উপরের সমস্ত পদক্ষেপের পরে প্রোগ্রামার mkdir build && cd build/ && cmake .. && sudo make install(বা স্ট্রাইপযুক্ত লাইব্রেরি সংস্করণ sudo make install/stripইনস্টল করে ) দ্বারা লাইব্রেরিটি তৈরি এবং ইনস্টল করতে পারে ।
সিলভিওপ্রোগ

1
আপনার কাছে লাইব্রেরি নির্ভরতা নিরসনের কৌশল আছে কি? উদাহরণস্বরূপ, যদি মাইলিব liblog4cxx এর উপর নির্ভর করে তবে মাইলিব.পিসি থেকে সমস্ত পথ ধরে প্রবাহিত হওয়ার ভাল উপায় কী হবে?
এমআরপি

1
@mpr যদি liblog4cxx কোনও .pcফাইল সরবরাহ করে তবে Requires: liblog4cxxআপনার যুক্ত করুন mylib.pc, অন্যথায় আপনি কেবল এতে যুক্ত -llog4cxxকরতে পারেন Libs:
জেরুমে পাউিলার

আমি এই প্রকল্পটি অন্য প্রকল্পে কীভাবে ব্যবহার করব? আপনি আপনার উদাহরণ প্রসারিত করতে পারেন?
দামির পোরোবিক

এবং আপনি কি PUBLIC_HEADER এ সমস্ত শিরোলেখ যুক্ত করেন বা অন্য ব্যবহারকারীদের দেখতে পারা উচিত এমন একমাত্র? যদি তা না হয় তবে অন্যান্য সমস্ত শিরোলেখ দিয়ে আপনি কী করবেন?
দামির পোরোবিক

84

এই ন্যূনতম CMakeLists.txtফাইলটি একটি সাধারণ ভাগ করা লাইব্রেরি সংকলন করে:

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)

তবে, সিএমকেকের সাথে ফাইলগুলি অন্য কোনও গন্তব্যে অনুলিপি করার আমার কোনও অভিজ্ঞতা নেই। কপি / ইনস্টল স্বাক্ষরযুক্ত ফাইল কমান্ডটি দেখে মনে হচ্ছে এটি কার্যকর হতে পারে।


34
CMAKE_BUILD_TYPE বাদ দেওয়া উচিত, তাই সিদ্ধান্তটি যিনি সংকলন করেন তার উপর নির্ভর করে।
ম্যানুয়েলস্কিনিড 3 ই

উল্লেখ করে ${CMAKE_CURRENT_SOURCE_DIR}/include_directoriesদরকারী কি?
14

@ জিজ আমি এটি মনে করি না, একই ডিরেক্টরিটি উপসর্গ ছাড়া অন্তর্ভুক্ত হয়ে যায়। আপনি যদি উপ-ডিরেক্টরিতে থাকতেন তবে তা বিবেচ্য হবে।
অরনাভ বোরবোরাহ

এবং যদি আমি আমার উত্স এবং আমার শিরোনামগুলিকে একটি জেনেরিক "উত্স" ডিরেক্টরিতে মিশ্রিত করতে চাই তবে কী হবে? আমার উত্স থেকে "শিরোনাম" ডিরেক্টরি তৈরি করার কোনও "পোস্ট প্রজন্ম" সম্ভাবনা আছে কি? (সম্ভবত কমান্ডগুলি ইনস্টল করুন)
স্যান্ডবুর্গ

24

আমি নিজে এটি কীভাবে করব তা শেখার চেষ্টা করছি এবং মনে হচ্ছে আপনি লাইব্রেরিটি এভাবে ইনস্টল করতে পারেন:

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

12

প্রথমত, এটি আমি ব্যবহার করছি ডিরেক্টরি বিন্যাস:

.
├── include
   ├── class1.hpp
   ├── ...
   └── class2.hpp
└── src
    ├── class1.cpp
    ├── ...
    └── class2.cpp

কয়েক দিন এটি একবার দেখার পরে, এটি আধুনিক সিএমকে ধন্যবাদ জানাতে আমার প্রিয় উপায়:

cmake_minimum_required(VERSION 3.5)
project(mylib VERSION 1.0.0 LANGUAGES CXX)

set(DEFAULT_BUILD_TYPE "Release")

if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
  message(STATUS "Setting build type to '${DEFAULT_BUILD_TYPE}' as none was specified.")
  set(CMAKE_BUILD_TYPE "${DEFAULT_BUILD_TYPE}" CACHE STRING "Choose the type of build." FORCE)
  # Set the possible values of build type for cmake-gui
  set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()

include(GNUInstallDirs)

set(SOURCE_FILES src/class1.cpp src/class2.cpp)

add_library(${PROJECT_NAME} ...)

target_include_directories(${PROJECT_NAME} PUBLIC
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
    $<INSTALL_INTERFACE:include>
    PRIVATE src)

set_target_properties(${PROJECT_NAME} PROPERTIES
    VERSION ${PROJECT_VERSION}
    SOVERSION 1)

install(TARGETS ${PROJECT_NAME} EXPORT MyLibConfig
    ARCHIVE  DESTINATION ${CMAKE_INSTALL_LIBDIR}
    LIBRARY  DESTINATION ${CMAKE_INSTALL_LIBDIR}
    RUNTIME  DESTINATION ${CMAKE_INSTALL_BINDIR})
install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${PROJECT_NAME})

install(EXPORT MyLibConfig DESTINATION share/MyLib/cmake)

export(TARGETS ${PROJECT_NAME} FILE MyLibConfig.cmake)

সিএমকে চালানো এবং লাইব্রেরি ইনস্টল করার পরে, ফাইন্ড ***। Cmake ফাইলগুলি ব্যবহার করার দরকার নেই, এটি এটি ব্যবহার করা যেতে পারে:

find_package(MyLib REQUIRED)

#No need to perform include_directories(...)
target_link_libraries(${TARGET} mylib)

এটি হ'ল, যদি এটি একটি স্ট্যান্ডার্ড ডিরেক্টরিতে ইনস্টল করা থাকে তবে এটি পাওয়া যাবে এবং অন্য কিছু করার দরকার নেই। যদি এটি একটি মানহীন পথে ইনস্টল করা থাকে তবে এটি খুব সহজ, কেবল মাইলিবকনফিগ.কমকে কোথায় ব্যবহার করতে হবে তা সিএমকে জানান:

cmake -DMyLib_DIR=/non/standard/install/path ..

আমি আশা করি এটি আমাকে যতটা সহায়তা করেছে সবাইকে ততটাই সহায়তা করবে। এটি করার পুরানো উপায়গুলি বেশ জটিল ছিল।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.