CPACK : RPM incorrectly includes directory not part of install files
Unless I'm blind, I'm surprised this hasn't been reported before..
Given a rather trivial example from libwoff2:
install(
TARGETS woff2common woff2dec woff2enc
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
)
install(
DIRECTORY include/woff2
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libwoff2common.pc"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libwoff2dec.pc"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libwoff2enc.pc"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
and adding cpack config:
set(CPACK_PACKAGE_VENDOR "root@localhost")
set(CPACK_PACKAGE_DESCRIPTION "WOFF2 decoder library")
set(CPACK_PACKAGE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
include(CPack)
You end up with an RPM that contains:
/usr/include/woff2
/usr/include/woff2/decode.h
/usr/include/woff2/encode.h
/usr/include/woff2/output.h
/usr/lib64/libwoff2common.so
/usr/lib64/libwoff2common.so.1.0.2
/usr/lib64/libwoff2dec.so
/usr/lib64/libwoff2dec.so.1.0.2
/usr/lib64/libwoff2enc.so
/usr/lib64/libwoff2enc.so.1.0.2
/usr/lib64/pkgconfig
/usr/lib64/pkgconfig/libwoff2common.pc
/usr/lib64/pkgconfig/libwoff2dec.pc
/usr/lib64/pkgconfig/libwoff2enc.pc
Note the directory -- "/usr/lib64/pkgconfig"
RPM thus screams as it should given it's already part of pkgconfig.
# rpm -ivh /dev/shm/woff2/woff2-0.1.1-Linux.rpm
Preparing... ################################# [100%]
file /usr/lib64/pkgconfig from install of woff2-0.1.1-1.x86_64 conflicts with file from package pkgconfig-1:0.27.1-4.el7.x86_64
You can of course work around it by adding an ignore like:
list(APPEND CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION
"${CMAKE_INSTALL_LIBDIR}/usr/lib64/pkgconfig"
)
.. but why is that needed at all? There is a directory install target for include/woff2 which is handled correctly. There isn't for pkgconfig.
There appears to be some logic in the CPackRPM module but it's not clear why those particular paths where chosen nor why they aren't being added to?
Trace output:
/usr/share/cmake/Modules/Internal/CPack/CPackRPM.cmake(235):
set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST /etc /etc/init.d /usr /usr/bin /usr/include /usr/lib /usr/libx32 /usr/lib64 /usr/share /usr/share/aclocal /usr/share/doc )
...
/usr/share/cmake/Modules/Internal/CPack/CPackRPM.cmake(508):
if(IS_SYMLINK /dev/shm/woff2/_CPack_Packages/Linux/RPM/woff2-0.1.1-Linux//usr/lib64/pkgconfig )
/usr/share/cmake/Modules/Internal/CPack/CPackRPM.cmake(595):
elseif(IS_DIRECTORY /dev/shm/woff2/_CPack_Packages/Linux/RPM/woff2-0.1.1-Linux//usr/lib64/pkgconfig )
/usr/share/cmake/Modules/Internal/CPack/CPackRPM.cmake(596):
set(DIRECTIVE %dir )
/usr/share/cmake/Modules/Internal/CPack/CPackRPM.cmake(599):
string(APPEND INSTALL_FILES %dir "/usr/lib64/pkgconfig"
)
/usr/share/cmake/Modules/Internal/CPack/CPackRPM.cmake(506):
unset(DIRECTIVE )
Relevant part of generated spec:
%files
%defattr(-,root,root,-)
%dir "/usr/include/woff2" <--- correct
"/usr/include/woff2/decode.h"
"/usr/include/woff2/encode.h"
"/usr/include/woff2/output.h"
"/usr/lib64/libwoff2common.so"
"/usr/lib64/libwoff2common.so.1.0.2"
"/usr/lib64/libwoff2dec.so"
"/usr/lib64/libwoff2dec.so.1.0.2"
"/usr/lib64/libwoff2enc.so"
"/usr/lib64/libwoff2enc.so.1.0.2"
%dir "/usr/lib64/pkgconfig" <---- bogus
"/usr/lib64/pkgconfig/libwoff2common.pc"
"/usr/lib64/pkgconfig/libwoff2dec.pc"
"/usr/lib64/pkgconfig/libwoff2enc.pc"
Final edit.. I hope. There are many projects that have hit this but I don't see any of them referencing an existing bugreport pushed upstream. Most appear to have hard coded various paths which really defeats the point.
I lied, another update. Looked more into why - it's a mess. CPACK doesn't appear to really use anything from cmake build itself, thus it has no idea what install targets even exist! RPM quite literally generates the list from scratch:
function(cpack_rpm_prepare_content_list)
# get files list
file(GLOB_RECURSE CPACK_RPM_INSTALL_FILES LIST_DIRECTORIES true RELATIVE "${WDIR}" "${WDIR}/*")
set(CPACK_RPM_INSTALL_FILES "/${CPACK_RPM_INSTALL_FILES}")
string(REPLACE ";" ";/" CPACK_RPM_INSTALL_FILES "${CPACK_RPM_INSTALL_FILES}")
Then proceeds to apply it's own filter logic.. completely ignoring any config. That is BIZZARE. No wonder certain directories had to be added manually. Was this intentional??