Yocto / OE : recipe with CMake install a shared library .so - cmake

I need to figure out how to manage a recipe for a package based on CMake creating a very simple shared library.
The goal is to provide the .so library into the Yocto build system in an atomic way, so can be used by other recipes managing application level.
This is the simple cpp code
#include <iostream>
#include "Student.h"
using namespace std;
Student::Student(string name):name(name){}
void Student::display(){
cout << "A student with name " << this->name << endl;
}
This is kind of CMakeList.txt
cmake_minimum_required(VERSION 2.8.9)
project(directory_test)
set(CMAKE_BUILD_TYPE Release)
#Bring the headers, such as Student.h into the project
include_directories(include)
#However, the file(GLOB...) allows for wildcard additions:
file(GLOB SOURCES "*.cpp")
#Generate the shared library from the sources
add_library(testStudent SHARED ${SOURCES})
#Set the location for library installation
install(TARGETS testStudent DESTINATION lib)
install(FILES student.h DESTINATION include)
This is the recipe studentlib_0.1.bb
SUMMARY = "Cmake application - creates a library"
SECTION = "examples"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
SRC_URI = "\
file://CMakeLists.txt \
file://student.cpp \
file://student.h \
"
S = "${WORKDIR}"
inherit cmake
EXTRA_OECMAKE = ""
The problem is when I build the specific recipe studentlib
$ bitbake studentlib
...
Build Configuration:
BB_VERSION = "1.38.0"
BUILD_SYS = "x86_64-linux"
NATIVELSBSTRING = "universal"
TARGET_SYS = "arm-poky-linux-gnueabi"
MACHINE = "qemuarm"
DISTRO = "poky"
DISTRO_VERSION = "2.5.2"
TUNE_FEATURES = "arm armv5 thumb dsp"
TARGET_FPU = "soft"
...
NOTE: Executing RunQueue Tasks
ERROR: studentlib-0.1-r0 do_package_qa: QA Issue: -dev package contains non-symlink .so: studentlib-dev path '/work/armv5e-poky-linux-gnueabi/studentlib/0.1-r0/packages-split/studentlib-dev/usr/lib/libtestStudent.so' [dev-elf]
ERROR: studentlib-0.1-r0 do_package_qa: QA run found fatal errors. Please consider fixing them.
ERROR: studentlib-0.1-r0 do_package_qa: Function failed: do_package_qa
ERROR: Logfile of failure stored in: /home/me/yocto-qemuarm-sumo/poky/build/tmp/work/armv5e-poky-linux-gnueabi/studentlib/0.1-r0/temp/log.do_package_qa.21681
ERROR: Task (/home/me/yocto-qemuarm-sumo/poky/meta-me/recipes-cmake/studentlib/studentlib_0.1.bb:do_package_qa) failed with exit code '1'
How can I solve this Issue?
I can't find any example for explanation.
Thanks

In Yocto, files (which are installed in ${D} either manually in do_install or by the make, cmake, autotools, etc... in e.g. do_compile) are put in a package when they match one of the regular expression (or glob, not entirely sure about that) contained in FILES_foo.
One recipe can (and usually does) provide multiple packages. So you'd have multiple FILES_foo1 with their own paths to match.
In Yocto, the file is put in the first package where one of the paths in its FILE_foo matches the file. Even if the file matches the paths of other packages, it'll ever be in only one package, the first one.
FWIW, packages are created from leftmost to rightmost in PACKAGES variable in the recipe. By default, the PACKAGES variable is ${PN}-src ${PN}-dbg ${PN}-staticdev ${PN}-dev ${PN}-doc ${PN}-locale ${PACKAGE_BEFORE_PN} ${PN} (c.f. http://git.yoctoproject.org/cgit.cgi/poky/tree/meta/conf/bitbake.conf#n292).
The default FILES_* variables are defined in bitbake.conf as well, c.f. http://git.yoctoproject.org/cgit.cgi/poky/tree/meta/conf/bitbake.conf. Look for everything starting with FILES_.
In there, you can see that by default, FILES_${PN} has ${libdir}/lib*${SOLIBS} (c.f. http://git.yoctoproject.org/cgit.cgi/poky/tree/meta/conf/bitbake.conf#n296) packaged. SOLIBS is, by default, .so.* (c.f. http://git.yoctoproject.org/cgit.cgi/poky/tree/meta/conf/bitbake.conf#n280), which means only dot versions of libraries are packaged in the ${PN} package (if they are not matched by another package before). FILES_${PN}-dev on the other hand packages ${FILES_SOLIBSDEV} which defaults to ${base_libdir}/lib*${SOLIBSDEV} ${libdir}/lib*${SOLIBSDEV}, with SOLIBSDEV in turns defaults to .so (c.f. http://git.yoctoproject.org/cgit.cgi/poky/tree/meta/conf/bitbake.conf#n313, http://git.yoctoproject.org/cgit.cgi/poky/tree/meta/conf/bitbake.conf#n314 and http://git.yoctoproject.org/cgit.cgi/poky/tree/meta/conf/bitbake.conf#n283). Please note that library filenames should all start with lib to be able to be matched by the default FILES_*.
TL;DR: By default, lib*.so.* in FILES_${PN} and lib*.so in FILES_${PN}-dev.
That's the background needed to understand what is expected in which package. The issue is that -dev package should only contain lib*.so symlinks to versioned libraries (i.e. lib*.so.*).
People usually expect versioned libraries so it's easy to know which version is installed and against which version a particular software should be linked against. If the version does not matter or if the major version only matters, those will then link to the unversioned or major versioned symlinks to the versioned library.
Best practice dictates that behavior.
Two possible cases, either you only provide the unversioned library in which case the solution is to version your library in your cmake or in your recipe. Then everything works out of the box.
Or you have a copy of your versioned library named as an unversioned library, in which case you should delete your copy and just make a symlink to the versioned library.
If that is not an option (but please really consider it), you can try to find a way so that ${PN}-dev does not have this library.
There are multiple options: add lib*.so to FILES_${PN} and either remove the ${PN}-dev from the PACKAGES, remove lib*.so from FILES_${PN}-dev, unset FILES_${PN}-dev, ...

Related

How to make the install target dependend on generated (protobuf) files

We have a project, where we have different applications, which come with protobuf definitions, for which we provide python bindings as a side effect. We ran into the problem, that when we want to install them along with the rest of the software, cmake complains that the binding to be created does not exist.
This is a minimal sample which behaves wrong:
// foo.proto
message Foo {
uint32 foo = 1;
}
# CMakeLists.txt
project(foobar)
cmake_minimum_required(VERSION 3.16)
find_package(Protobuf REQUIRED)
protobuf_generate_cpp(FOO_SRC FOO_HDR foo.proto)
protobuf_generate_python(FOO_PY foo.proto)
install(FILES ${FOO_PY} DESTINATION "share/proto/")
$ make install
-- Configuring done
-- Generating done
-- Build files have been written to: /tmp/foobar
Install the project...
-- Install configuration: ""
CMake Error at cmake_install.cmake:41 (file):
file INSTALL cannot find "/tmp/foobar/foo_pb2.py": No such file or
directory.
How can I convince CMake to build the bindings when I run make install?
Functions protobuf_generate_cpp and protobuf_generate_python are actually create custom commands (add_custom_command). This is noted in the documentation for these functions.
For make a custom command to work, it should be some target which consumes (or depends on) the files created by the custom command.
In case of protobuf_generate_cpp, consumption is usually performed with add_library/add_executable commands.
But it is possible to create a custom target which depends on given files:
protobuf_generate_cpp(FOO_SRC FOO_HDR foo.proto)
protobuf_generate_python(FOO_PY foo.proto)
add_custom_target(proto_target ALL DEPENDS ${FOO_SRC} ${FOO_HDR} ${FOO_PY})

How can I specify library path when using Meson?

I'm trying to build a c++ project with Meson.
The thing is, I have some libraries under /opt/conda
but can't figure out how to link the project when running meson build.
It seems to be only searching through /usr/lib directory.
As far as I understood, meson uses cmake and pkg-config to look for libraries.
Then would setting something like CMAKE_PREFIX_PATH be a feasible solution? and if so, how can I do that?
Thanks in advance.
I see two possible approaches to solve your problem.
the first solution uses LIBRARY_PATH, which is different from LD_LIBRARY_PATH as explained later.
the second solution uses a modified meson file to directly pass options to the linker. Optionally, it also uses rpath that eliminates the need to modify LD_LIBRARY_PATH afterward.
First solution
When building your project the linker use LIBRARY_PATH (and not LD_LIBRARY_PATH)
LIBRARY_PATH is used by gcc before compilation to search directories
containing static and shared libraries that need to be linked to your
program.
LD_LIBRARY_PATH is used by your program to search directories
containing shared libraries after it has been successfully compiled
and linked.
further details: LD_LIBRARY_PATH vs LIBRARY_PATH
Maybe you can try
export LIBRARY_PATH=/opt/conda/:$LIBRARY_PATH
before running meson to build your project.
Second solution
Modifying your meson file and use rpath (optional)
An alternative to the previous first solution is to directly modify your Meson file to pass some options to the linker.
Here is something I used in the past you can easily adapt to your problem:
#
# blaspp
#
blaspp_lib = 'blaspp'
blaspp_lib_dir = '/opt/slate/lib'
blaspp_header_dir = '/opt/slate/include'
blaspp_dep = declare_dependency(
link_args : ['-L' + blaspp_lib_dir, '-l' + blaspp_lib],
include_directories : include_directories(blaspp_header_dir))
executable('test_blaspp',
'test_blaspp.cpp',
build_rpath : blaspp_lib_dir,
install_rpath : blaspp_lib_dir,
dependencies : [blaspp_dep])
declare_dependency(...) defines options to pass to the linker (this replaces the need to define LIBRARY_PATH in the first solution)
executable(...) defines rpath. This is an optional step that embeds the extra library path information directly into the executable. If you use this, you will not have to modify the LD_LIBRARY_PATH when running your executable.
Further details: https://amir.rachum.com/blog/2016/09/17/shared-libraries/ (have a look at the "rpath and runpath" section) and see wikipedia: https://en.wikipedia.org/wiki/Rpath
If I understand the documentation correctly, you could use different / others build system as subproject, and it doesn't seem basing on cmake.
You should be able to define CMAKE_PREFIX_PATH in a CMakeList.txt of a cmake project, and access the generated library within meson context:
in your cmake subproject:
add_library(cm_lib SHARED ${SOURCES})
in your meson:
cmake = import('cmake')
# Configure the CMake project
sub_proj = cmake.subproject('libsimple_cmake')
# Fetch the dependency object
cm_lib = sub_proj.dependency('cm_lib')
executable(exe1, ['sources'], dependencies: [cm_lib])
if you only want to propagate any specific library to meson, than it looks like you'll need to bundle those third party library, or using built-in options.
But first of all: Have you check, either /opt/conda is in your LD_LIBRARY_PATH ?
Surprised no one mentioned it but this is how it is done from within meson.
CXX = meson.get_compiler('cpp')
libs_you_need_to_link = ['lib_a', 'lib_b', 'lib_c']
deps = []
foreach lib_name : libs_you_need_to_link
deps += CXX.find_library(lib_name, dirs : ['/opt/conda', '/other/path'])
endforeach

CMake GET_RUNTIME_DEPENDENCIES couldn't find dll library when it is linked through lib (import library)?

Build OS: Windows 10, Cmake 3.16.3.
I use target_link_libraries to link 3rd party .lib file to my .dll library.
But when I use GET_RUNTIME_DEPENDENCIES to install my dll, there is no dependency found.
It happens only on Windows, installing on Linux is ok.
Is there any clues how to solve this problem, or at least how to debug it?
What exact command uses CMake on Windows to determine dependencies?
I call GET_RUNTIME_DEPENDENCIES like this:
file(GET_RUNTIME_DEPENDENCIES
RESOLVED_DEPENDENCIES_VAR RES
UNRESOLVED_DEPENDENCIES_VAR UNRES
CONFLICTING_DEPENDENCIES_PREFIX CONFLICTING_DEPENDENCIES
EXECUTABLES ${EXECS}
LIBRARIES ${LIBS} ${MODULES} ${QTPLUGINS_LIBS}
DIRECTORIES ${RUNTIME_DEPENDENCIES_DIRECTORIES}
POST_EXCLUDE_REGEXES ${PLATFORM_POST_EXCLUDE_REGEXES}
)
Where LIBS contains my dll but no RES no UNRES contains path to 3rd paty dll.
So, there's a serious nastiness to all this runtime-dependency-finding magic in the newer CMakes, and it's not really their fault at all. The problem is that you, I, and roughly 90% of the rest of the CMake user world have been doing find modules wrong #THISWHOLETIME, and now our chickens have come home to roost because, as you've likely discovered, GET_RUNTIME_DEPENDENCIES / RUNTIME_DEPENDENCY_SET, $<TARGET_RUNTIME_DLLS> will all completely sh*t the bed if you try to use them with targets that have (what I now know to be) broken IMPORTED dependencies created by Find modules that don't properly set them up. So, last month I posted this screed (my earlier link) over at the CMake Discourse forum:
Windows libraries, Find modules, and TARGET_RUNTIME_DLLS
The Windows DLL Question™ has come up numerous times before in one form or another, but it’s cast in a new light by $<TARGET_RUNTIME_DLLS>, so here’s a fresh take on it.
If you’re like me (and roughly 90% of all CMake users/developers out there are like me, from what I’ve been able to observe in public projects’ source trees), your approach to writing Find modules on Windows has probably been something like this:
Use the same code on all three desktop platforms
Let CMake discover .lib / .dll.a import libraries instead of actual DLLs, using find_library().
End up creating your targets as UNKNOWN IMPORTED, because if you try to create SHARED IMPORTED library targets with only an import library it won’t work, but UNKNOWN IMPORTED works just fine so meh.
Set the import library as the target’s IMPORTED_LOCATION since that seems to work fine.
Call it a day, because hey — everything compiles.
That’s served us all for years (decades, really) so we’ve mostly just accepted it as the way CMake works on Windows.
But now along comes $<TARGET_RUNTIME_DLLS>. If you’ve tried to actually use it on Windows, you’ve probably discovered is that while all of your CONFIG-mode package dependencies’ DLLs are captured just fine, the generator expression will cheerfully ignore any targets created from a Find module that’s written like I describe above. …Which is probably most of them. (In my own library build, it was all of them, even the ones I didn’t write.)
For $<TARGET_RUNTIME_DLLS> to work, the IMPORTED target has to be correctly defined as a SHARED library target, and it needs to have its IMPORTED_ properties set correctly: import lib path in IMPORTED_IMPLIB, DLL path in IMPORTED_LOCATION.
So, now I have this new module that uses DLLTOOL.EXE and its handy -I flag to get the name of an import library’s DLL, then looks it up using find_program(). (Simply because find_library() won’t match DLLs, and I wanted to look on the PATH. I could’ve used find_file() but I’m pretty sure I’d have to explicitly give it more paths to search.)
The macro takes one argument, the name of your already-configured variable <prefix>_IMPLIB. (Or <prefix>_IMPLIBS, it’s pluralization agnostic and will follow whichever form your input uses when naming its output variable.)
The variable whose name you pass to it should already contain a valid path for an import library. Typically that’s set by find_library(), even though we’ve all been treating them like runtime libraries (DLLs) when they are not.
Armed with find_library(<prefix>_IMPLIB ...) output, implib_to_dll(<prefix>_IMPLIB) will attempt to discover and automatically populate the corresponding variable <prefix>_LIBRARY with the path to the import lib’s associated runtime DLL.
With all of the correct variables set to the correct values, it’s now possible to properly configure SHARED IMPORTED library targets on Windows. $<TARGET_RUNTIME_DLLS> can then be used to discover and operate on the set of DLLs defined by those target(s).
Kind of a pain in the Find, and really does sort of feel like something CMake could be doing at-least-semi-automatically. But, at least for now it works.
Now I just have to rewrite all of my find modules to use it. Sigh.
ImplibUtils.cmake
#[=======================================================================[.rst:
IMPLIB_UTILS
------------
Tools for CMake on WIN32 to associate IMPORTED_IMPLIB paths (as discovered
by the :command:`find_library` command) with their IMPORTED_LOCATION DLLs.
Writing Find modules that create ``SHARED IMPORTED`` targets with the
correct ``IMPORTED_IMPLIB`` and ``IMPORTED_LOCATION`` properties is a
requirement for ``$<TARGET_RUNTIME_DLLS>`` to work correctly. (Probably
``IMPORTED_RUNTIME_DEPENDENCIES`` as well.)
Macros Provided
^^^^^^^^^^^^^^^
Currently the only tool here is ``implib_to_dll``. It takes a single
argument, the __name__ (_not_ value!) of a prefixed ``<prefix>_IMPLIB``
variable (containing the path to a ``.lib`` or ``.dll.a`` import library).
``implib_to_dll`` will attempt to locate the corresponding ``.dll`` file
for that import library, and set the variable ``<prefix>_LIBRARY``
to its location.
``implib_to_dll`` relies on the ``dlltool.exe`` utility. The path can
be set by defining ``DLLTOOL_EXECUTABLE`` in the cache prior to
including this module, if it is not set implib_utils will attempt to locate
``dlltool.exe`` using ``find_program()``.
Revision history
^^^^^^^^^^^^^^^^
2021-11-18 - Updated docs to remove CACHE mentions, fixed formatting
2021-10-14 - Initial version
Author: FeRD (Frank Dana) <ferdnyc#gmail.com>
License: CC0-1.0 (Creative Commons Universal Public Domain Dedication)
#]=======================================================================]
include_guard(DIRECTORY)
if (NOT WIN32)
# Nothing to do here!
return()
endif()
if (NOT DEFINED DLLTOOL_EXECUTABLE)
find_program(DLLTOOL_EXECUTABLE
NAMES dlltool dlltool.exe
DOC "The path to the DLLTOOL utility"
)
if (DLLTOOL_EXECUTABLE STREQUAL "DLLTOOL_EXECUTABLE-NOTFOUND")
message(WARNING "DLLTOOL not available, cannot continue")
return()
endif()
message(DEBUG "Found dlltool at ${DLLTOOL_EXECUTABLE}")
endif()
#
### Macro: implib_to_dll
#
# (Win32 only)
# Uses dlltool.exe to find the name of the dll associated with the
# supplied import library.
macro(implib_to_dll _implib_var)
set(_implib ${${_implib_var}})
set(_library_var "${_implib_var}")
# Automatically update the name, assuming it's in the correct format
string(REGEX REPLACE
[[_IMPLIBS$]] [[_LIBRARIES]]
_library_var "${_library_var}")
string(REGEX REPLACE
[[_IMPLIB$]] [[_LIBRARY]]
_library_var "${_library_var}")
# We can't use the input variable name without blowing away the
# previously-discovered contents, so that's a non-starter
if ("${_implib_var}" STREQUAL "${_library_var}")
message(ERROR "Name collision! You probably didn't pass "
"implib_to_dll() a correctly-formatted variable name. "
"Only <prefix>_IMPLIB or <prefix>_IMPLIBS is supported.")
return()
endif()
if(EXISTS "${_implib}")
message(DEBUG "Looking up dll name for import library ${_implib}")
execute_process(COMMAND
"${DLLTOOL_EXECUTABLE}" -I "${_implib}"
OUTPUT_VARIABLE _dll_name
OUTPUT_STRIP_TRAILING_WHITESPACE
)
message(DEBUG "DLLTOOL returned ${_dll_name}, finding...")
# Check the directory where the import lib is found
get_filename_component(_implib_dir ".." REALPATH
BASE_DIR "${_implib}")
message(DEBUG "Checking import lib directory ${_implib_dir}")
# Add a check in ../../bin/, relative to the import library
get_filename_component(_bindir "../../bin" REALPATH
BASE_DIR "${_implib}")
message(DEBUG "Also checking ${_bindir}")
find_program(${_library_var}
NAMES ${_dll_name}
HINTS
${_bindir}
${_implib_dir}
PATHS
ENV PATH
)
set(${_library_var} "${${_library_var}}" PARENT_SCOPE)
message(DEBUG "Set ${_library_var} to ${${_library_var}}")
endif()
endmacro()
GET_RUNTIME_DEPENDENCIES isn't aware of your configure-time variables, so will you need to specify them manually. This answer states you can pass-on the variables to the install step, but I haven't been able to make it work so far. Fortunately, it does support generator expressions.
Another problem in your snippet is it must be called at install time. For example in an install(CODE ...) block.
So with all this in mind, this should get you started.
install(CODE [[
file(GET_RUNTIME_DEPENDENCIES
RESOLVED_DEPENDENCIES_VAR RES
UNRESOLVED_DEPENDENCIES_VAR UNRES
CONFLICTING_DEPENDENCIES_PREFIX CONFLICTING_DEPENDENCIES
EXECUTABLES $<TARGET_FILE:your_executable_target_name>
LIBRARIES $<TARGET_FILE:a_lib_target_name>
)
message("\n\nFound dependencies :")
foreach(DEP ${RES})
message("${DEP}")
endforeach()
message("\n\nNot found dependencies :")
foreach(DEP ${UNRES})
message("${DEP}")
endforeach()
]])
Build your install target to see the results.
cmake ..
cmake --build . --target install

How to deploy a Find*.cmake file for an Autotools library in the correct place for Yocto?

I created a new layer over an existing Yocto git for my company project.
In this layer I added a few external autotools based libraries.
A few applications need to link against this libraries and the application projects are all cmake based.
Taking one of this libraries (e.g. libcoap) I could easily find some FindCoAP.cmake to add to my library recipe.
Now if I was running on PC, it would simply be a matter of placing this FindCoAP.cmake file in cmake's ${CMAKE_ROOT}/Modules dir, but how should I, from inside a bitbake recipe (do_install hook), proceed to make my Find*.cmake modules available to anyone's dependent projects?
Should I try to get Yocto's cmake CMAKE_ROOT variable from system-information like this or is it a safer and more reliable way?
do_install_append() {
cmake --system-information | grep CMAKE_ROOT | cut -d \" -f2
install -d ${D}/$CMAKE_ROOT}/Modules
install ${S}/FindCoAP.cmake ${D}/$CMAKE_ROOT}/Modules
}
Thanks in advance.
To ship FindFoo.cmake with non-yet-cmake project
The ideal way is to update upstream project itself. So you will update your recipe and package FindFoo.cmake appropriately.
If you want to do it right now:
Add FindFoo.cmake to your layer (into the files directory next to your recipe).
Add that cmake file to SRC_URI (i.e. SRC_URI += "file://FindFoo.cmake").
Install it in do_install into the directory ${D}${datadir}/cmake/Modules/ for example.
Package it to the dev package by FILES_${PN}-dev variable (see example recipes below).
To use that cmake by other recipe
The usual way is to package .cmake files into the ${PN}-dev package. In your case, your application (which depends on the libcoap) will just set DEPENDS = "libcoap" and all the needed files (like headers, libraries and cmake file) will be copied (well, hardlinked) to the sysroot of your application.
CMake modules are packaged in various recipes for example:
libeigen
opencv
json-spirit
Your application is cmake based, so you will use inherit cmake in the recipe. Native module search path is set in cmake.bbclass.
(BTW, I do a build test of libcoap recipe from homeassistant layer and it worked, but obviously there is no cmake shipped.)

'CPACK_RPM_PACKAGE_AUTOPROV' doesn't work when pack existing binaries with CPack

In my project, I use cmake to construct the building system, I need to build an external project(here, I take zeromq for example) with ExternalProject_add, then pack the compiled binaries in a RPM package, but I need the generated RPM to have correct "PROVIDES" information to tell which libraries it provides, just like below
libzmq.so.5()(64bit)
zeromq = 4.1.2-1.el7
zeromq(x86-64) = 4.1.2-1.el7
But somehow, with setting CPACK_RPM_PACKAGE_AUTOPROV to 1, the built RPM still doesn't have correct 'PROVIDES' information, I will get 'PROVIDES' information below, without the provided libraries information
zeromq = 4.1.2-1
zeromq(x86-64) = 4.1.2-1
the CMakeLists.txt(just some key content) for this is
cmake_minimum_required (VERSION 3.4.0 FATAL_ERROR)
set(COMP zeromq)
set(CompVersion 4.1.2)
set(CompURL http://download.zeromq.org/zeromq-${CompVersion}.tar.gz)
set(CompMD5 159c0c56a895472f02668e692d122685)
project(${COMP} VERSION ${CompVersion})
include(ExternalProject)
ExternalProject_add(${COMP}
PREFIX ${COMP}
URL ${CompURL}
URL_MD5 ${CompMD5}
CONFIGURE_COMMAND <SOURCE_DIR>/configure --without-libsodium --prefix=${CMAKE_INSTALL_PREFIX})
install(FILES ${CMAKE_INSTALL_PREFIX}/lib/libzmq.so.5
${CMAKE_INSTALL_PREFIX}/lib/libzmq.so
${CMAKE_INSTALL_PREFIX}/lib/libzmq.so.5.0.0
DESTINATION lib64)
string(REPLACE "." ";" VERSION_LIST ${PROJECT_VERSION})
list(LENGTH VERSION_LIST VERSION_LIST_LENGTH)
list(GET VERSION_LIST 0 CPACK_PACKAGE_VERSION_MAJOR)
list(GET VERSION_LIST 1 CPACK_PACKAGE_VERSION_MINOR)
if(VERSION_LIST_LENGTH GREATER 2)
list(GET VERSION_LIST 2 CPACK_PACKAGE_VERSION_PATCH)
endif()
set(CPACK_GENERATOR "RPM")
set(CPACK_PACKAGE_VENDOR "Test")
set(CPACK_RPM_PACKAGE_GROUP "3rd-party-software")
set(CPACK_RPM_PACKAGE_AUTOPROV 1)
set(CPACK_RPM_PACKAGE_AUTOREQ 0)
set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION
/usr/lib
/usr/lib64)
set(CPACK_RPM_COMPONENT_INSTALL OFF)
include(CPack)
Does someone know why this "CPACK_RPM_PACKAGE_AUTOPROV" option doesn't take effect? how can I make it auto generates these 'PROVIDES' information in the RPM? thanks for your time and it will be very appreciated if you can provide some hints.
CPACK_RPM_PACKAGE_AUTOPROV variable, by its description:
May be used to enable (1, yes) or disable (0, no) automatic listing of shared libraries that are provided by the package.
affects only on targets created by add_library(SHARED).
Neither CMake nor CPack tries to deduce file's type from their extension, that's why manually installed files (via install(FILES)) are not affected.
For add given files to PROVIDES list, use variable CPACK_RPM_PACKAGE_PROVIDES:
May be used to set RPM dependencies (provides). The provided package list of an RPM file could be printed with:
rpm -qp --provides file.rpm
Using install(PROGRAMS instead of install(FILES generates correct provides in the rpm for .so files (at least with cmake 3.13). As per the documentation:
The PROGRAMS form is identical to the FILES form except that the default permissions for the installed file also include OWNER_EXECUTE, GROUP_EXECUTE, and WORLD_EXECUTE. This form is intended to install programs that are not targets, such as shell scripts.
Maybe the documentation could add that it's suitable for shared libs too.
If you want to stick to CPACK_RPM_PACKAGE_PROVIDES, beware that the variable has to be a comma separated list.
(Maybe another possible addition to the documentation).