cmakeで共有ライブラリを作成する方法は?


141

自分で作成したMakefileを使用してコンパイルするために使用するライブラリを作成しましたが、今度はcmakeに切り替えます。ツリーは次のようになります(関係のないファイルをすべて削除しました)。

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

だから私がやろうとしていることは、ソースを共有ライブラリにコンパイルし、それをヘッダーファイルと一緒にインストールすることです。

私が見つけたほとんどの例は、いくつかの共有ライブラリを使用して実行可能ファイルをコンパイルしますが、単純な共有ライブラリだけではありません。cmakeを使用する非常に単純なライブラリーを誰かに教えてもらえれば、これも例として使用できるので参考になります。



同じ質問ですが、私のソースを混在させて維持する方法(同じソ​​ースディレクトリ内の.h ans .cpp)はありますが、Cmakeにその作業の成果物であるインクルードディレクトリを生成させる方法はありますか?
Sandburg、

回答:


204

常に最低限必要なバージョンを指定します cmake

cmake_minimum_required(VERSION 3.9)

プロジェクトを宣言する必要があります。cmakeそれは必須でありPROJECT_NAME、便利な変数を定義します(PROJECT_VERSIONそしてPROJECT_DESCRIPTIONこの後者の変数はcmake 3.9を必要とします):

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プロパティを設定します(オプションですが、良い方法です):

set_target_properties(mylib PROPERTIES VERSION ${PROJECT_VERSION})

SOVERSIONメジャー番号に設定することもできVERSIONます。したがってlibmylib.so.1、へのシンボリックリンクになりlibmylib.so.1.0.0ます。

set_target_properties(mylib PROPERTIES SOVERSION 1)

ライブラリのパブリックAPIを宣言します。このAPIは、サードパーティアプリケーション用にインストールされます。プロジェクトツリーで分離することをお勧めします(include/ディレクトリを配置するなど)。プライベートヘッダーはインストールしないでください。ソースファイルと一緒に配置することを強くお勧めします。

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(詳細については、pc(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フォームの変数を展開しないようにcmakeに依頼します${VAR})。

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

最後に、生成されたファイルをインストールします。

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

cmake EXPORT機能を使用することもできます。ただし、この機能はcmakeあり、使用するのが難しいと感じています。

最後に、全体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
@Jezzのすばらしい説明を補足するだけです。上記のすべてのステップの後で、プログラマーはライブラリーをビルドしてインストールできますmkdir build && cd build/ && cmake .. && sudo make install(またはストライプ化されたライブラリーバージョンsudo make install/stripをインストールします)。
silvioprog

1
ライブラリの依存関係を渡すテクニックはありますか?たとえば、mylibがliblog4cxxに依存している場合、それをmylib.pcに流すための良い方法は何でしょうか?
mpr 2018

1
liblog4cxxが提供する場合は@mpr .pcファイルを追加、Requires: liblog4cxxあなたにmylib.pc、それ以外の、あなただけ追加することができます-llog4cxxLibs:
ジェローム・Pouiller

このライブラリを別のプロジェクトでどのように使用しますか?あなたの例を拡張できますか?
Damir Porobic

そして、すべてのヘッダーをPUBLIC_HEADERに追加しますか、それとも他のユーザーが表示できるはずのヘッダーのみを追加しますか?そうでない場合、他のすべてのヘッダーをどのように処理しますか?
Damir Porobic

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)

ただし、CMakeを使用してファイルを別の宛先にコピーした経験はありません。COPY / INSTALLシグニチャーを使用したfileコマンドは、便利なようです。


34
CMAKE_BUILD_TYPEは省略する必要があるため、コンパイルする側が決定します。
ManuelSchneid3r 2016

指定しない${CMAKE_CURRENT_SOURCE_DIR}/include_directories便利ですか!
ジェローム・Pouiller

@Jezz私はそうは思いません、同じディレクトリはプレフィックスなしで含まれます。ただし、サブディレクトリにいる場合は問題になります。
Arnav Borborah

また、汎用の「ソース」ディレクトリにソースとヘッダーを混在させたい場合はどうなりますか?私のソースから「ヘッダー」ディレクトリを作成する「ポスト生成」の可能性はありますか?(多分インストールコマンド)
Sandburg

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

これを2、3日調べた後、これが最新のCMakeのおかげで私のお気に入りの方法です。

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 ***。cmakeファイルを使用する必要はありません。次のように使用できます。

find_package(MyLib REQUIRED)

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

それだけです。標準のディレクトリにインストールされている場合、それが見つかり、他に何もする必要はありません。非標準のパスにインストールされている場合も簡単です。CMakeにMyLibConfig.cmakeの場所を次のように指定するだけです。

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

これが私を助けてくれたのと同じくらいみんなに役立つことを願っています。これを行う従来の方法は非常に面倒でした。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.