web-dev-qa-db-ja.com

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

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

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

したがって、私がやろうとしているのは、ソースを共有ライブラリにコンパイルして、ヘッダーファイルと共にインストールすることです。

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

103
Florian M

cmakeの最小必須バージョンを常に指定する

cmake_minimum_required(VERSION 3.9)

プロジェクトを宣言する必要があります。 cmakeは必須であり、便利な変数PROJECT_NAMEPROJECT_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})

SOVERSIONVERSIONのメジャー番号に設定することもできます。したがって、libmylib.so.1libmylib.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)

ライブラリのインストールルールを作成します。 GNUInstallDirsで定義されている変数CMAKE_INSTALL_*DIRを使用することをお勧めします。

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は、フォーム${VAR}の変数を展開しないようにcmakeに要求します):

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

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

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

cmake EXPORT feature を使用することもできます。ただし、この機能は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)
126
Jezz

この最小限の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コマンドは、役に立つかもしれません。

71
Robert Franke

私は自分でこれを行う方法を学ぼうとしていますが、次のようにライブラリをインストールできるようです:

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

まず、これは私が使用しているディレクトリレイアウトです。

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

これを数日見てから、これは現代の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)

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

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

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

8
Luis