Correct way to build debian using Cmake and catkin? - cmake

I'm trying to build a debian using CMake/Cpack but am running into an issue. The problem is that I am getting unwanted files in my debian. It is caused by including a subdirectory, which contains a CMakeLists.txt that invokes catkin commands for ROS msg generation.
If I look at the contents of the debian I see generated header files in /usr/include/ and message files in /usr/share. But I only want my debian to have the files in /opt/bin which I specified using install().
Below is a simplified example. If I run the following commands:
mkdir build
cd build
cmake ..
make
cpack
The result is a deb package containing /opt/my-pkg/bin/main (which is great), but it also contains several files in /usr/local, /usr/lib, /usr/share that I don't want to be in the debian. I'm sure there must be a way using CMake/CPack to only create a debian with the specific files I want, but I'm not sure how to do it.
FILE TREE
+ my_project
+ CMakeLists.txt
+ main
+ CMakeLists.txt
+ main.cpp
+ my_msgs
+ CMakeLists.txt
+ package.xml
+ msg
+ BoundingBox.msg
# Top level CMakeLists.txt
cmake_minimum_required(VERSION 3.2 FATAL_ERROR)
project(my_project VERSION 1.0 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 11)
# put all executables into bin directory and all libraries into lib directory
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
# the directory name all targets will be installed to in the debian
set(install_dir "/opt/my-pkg/bin")
# LIST OF ALL DIRECTORIES TO BE BUILT
set(DIRS
my_msgs
main
)
foreach(dir ${DIRS})
add_subdirectory(${dir} ${dir})
endforeach()
# CPACK debian settings
set(CPACK_GENERATOR "DEB")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Matthew Mosley")
include(CPack)
# my_msgs/CMakeLists.txt (this is the CMakeLists.txt that is generating extra unwanted files in my debian)
project(my_msgs)
find_package(catkin REQUIRED
geometry_msgs
message_generation
std_msgs
sensor_msgs
)
add_message_files(FILES BoundingBox.msg)
generate_messages(
DEPENDENCIES
geometry_msgs
std_msgs
sensor_msgs)
# my_msgs/package.xml
<?xml version="1.0"?>
<package>
<name>my_msgs</name>
<version>0.0.0</version>
<description> my_msgs package</description>
<license>BSD</license>
<build_depend>message_generation</build_depend>
<run_depend>message_runtime</run_depend>
<buildtool_depend>catkin</buildtool_depend>
<build_depend>roscpp</build_depend>
<build_depend>std_msgs</build_depend>
<build_depend>uuid_msgs</build_depend>
<build_depend>geometry_msgs</build_depend>
<run_depend>roscpp</run_depend>
<run_depend>std_msgs</run_depend>
<run_depend>uuid_msgs</run_depend>
<run_depend>geometry_msgs</run_depend>
<export>
</export>
</package>

Related

Setting up a cmake project properly with thirdparty

I am trying to get better on CMake. Currently I try to build a toy example that is using OpenCV that I have built from source and installed in a directory called thirdparty.
I can run build
cmake ..
cmake --build .
cmake --install . --prefix ../tmp
In build I can run ./app/TestOpenCV and get a 3x4 zero matrix as output.
If I run ../tmp/bin/TestOpenCV I get
Reason: tried: '/usr/local/lib/libopencv_gapi.406.dylib' (no such file), '/usr/lib/libopencv_gapi.406.dylib' (no such file)
It appears that the linking is not working appropriately when I install the binary. I.e. it searching for the libraries in the wrong location. How can I make this work?
I have the following structure
TestCMake
CMakeLists.txt
app
TestOpenCV.cpp
CMakeLists.txt
thirdparty
installdir
opencv_mac
bin
include
lib
share
TopLevel CMakeLists.txt
cmake_minimum_required(VERSION 3.24)
project(Tutorial VERSION 1.0)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
find_package(OpenCV REQUIRED PATHS "thirdparty/installdir/opencv_mac/lib/cmake/opencv4/" NO_DEFAULT_PATH)
include_directories(SYSTEM ${OpenCV_INCLUDE_DIRS})
add_subdirectory(app)
App level CMakeLists
add_executable(TestOpenCV TestOpenCV.cpp)
target_link_libraries(TestOpenCV ${OpenCV_LIBS})
install(TARGETS TestOpenCV
DESTINATION bin)
How can I make the binary work after installing it?

What's the proper way to package C++ program with CMake and CPack for program installation and standalone execution

I have written a simple c++ program intended to be built and packaged with CMake. The simple program depends on a third-party (OpenCV) library which can be found by find_package(OpenCV REQUIRED) in my CMake project. I want to build and package my simple program including the runtime library (Prerequisite Shared Libraries from OpenCV) so that I can produce a Windows installer file that can be installed and run on other Windows machines.
My project structure is as follows:
HAND-POSE
│ CMakeLists.txt
│ handpose.cpp
│ README.md
├───cmake
│ FixBundle.cmake.in
├───data
│ video.mp4
└───models
pose_deploy.prototxt
pose_iter_102000.caffemodel
I spent some time and got some documentation (here & here) from the CMake website, and tried to adapt my project in the following ways:
The CMakeLists.txt file is as follows:
cmake_minimum_required(VERSION 3.0.0)
project(HandPose VERSION 0.1.0)
set(CMAKE_PREFIX_PATH C:\\OpenCV-4.6.0)
include(CTest)
enable_testing()
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
ADD_EXECUTABLE(handpose handpose.cpp)
TARGET_LINK_LIBRARIES(handpose ${OpenCV_LIBS})
include(InstallRequiredSystemLibraries)
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/cmake/FixBundle.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/FixBundle.cmake
#ONLY
)
install(TARGETS handpose
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib/static)
install(SCRIPT ${CMAKE_CURRENT_BINARY_DIR}/FixBundle.cmake)
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)
The FixBundle.cmake.in file is as follows:
include(BundleUtilities)
# Set bundle to the full path name of the executable already
# existing in the install tree:
set(bundle "Release/handpose#CMAKE_EXECUTABLE_SUFFIX#")
# Set other_libs to a list of full path names to additional
# libraries that cannot be reached by dependency analysis.
# (Dynamically loaded PlugIns, for example.)
# set(other_libs "")
# Set dirs to a list of directories where prerequisite libraries
# may be found:
set(dirs
"#CMAKE_RUNTIME_OUTPUT_DIRECTORY#"
"#CMAKE_LIBRARY_OUTPUT_DIRECTORY#"
"C:\\OpenCV-4.6.0\\x64\\vc16\\bin"
)
fixup_bundle("${bundle}" \"\" "${dirs}")

put external project into a cPack

I try to setup a cMake project which create a package containing the output of multiple external projects. So the idea is, that I use this cMake project to create packages for the deployment.
Now the problem is, that when I use the cMakeLists shown bellow, the output of the external project is not included in the package. Just the internal one is in the package.
The install sequence of the external project seems to work, at least the output is in the install directory. It seams, that the package command doesn't see the binaries and for that reason dosn't put them into the zip archive.
Does anyone know, how to put the output of the external project into the package?
By the way: the external project is also cMake based. It contains a install step but no package step.
cmake_minimum_required (VERSION 3.12)
project(PackedBinaries
VERSION 0.0.42
)
set(GLOBAL_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/temp)
include(ExternalProject)
# Builds external projects.
ExternalProject_Add(
myExternalProject
GIT_REPOSITORY "..."
GIT_TAG "master"
UPDATE_COMMAND ""
PATCH_COMMAND ""
SOURCE_DIR "${PROJECT_BINARY_DIR}/repo"
CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${GLOBAL_OUTPUT_PATH}
TEST_COMMAND ""
)
# Additional executable
add_executable(myInternalProject hello.c)
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install" CACHE PATH "..." FORCE)
set(CPACK_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install" CACHE PATH "..." FORCE)
endif()
install(TARGETS myInternalProject)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/temp DESTINATION "${CMAKE_BINARY_DIR}/install")
set(CPACK_PACKAGE_NAME ${PROJECT_NAME})
set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
set(CPACK_PACKAGE_VERSION_PATCH "0")
set(CPACK_PACKAGE_INSTALL_REGISTRY_KEY ${PROJECT_NAME})
set(CPACK_GENERATOR "ZIP")
# Must be after the last CPACK macros
include(CPack)

CPack adds system directories to generated RPM

I have a CMake project and I use CPack to generate RPMs for my CentOS YUM repository. However, when I attempt to install my generated RPM, I get this error:
file /usr from install of clstrd-0.1.0-1.x86_64 conflicts with file from package filesystem-3.2-20.el7.x86_64
file /usr/bin from install of clstrd-0.1.0-1.x86_64 conflicts with file from package filesystem-3.2-20.el7.x86_64
file /usr/lib from install of clstrd-0.1.0-1.x86_64 conflicts with file from package filesystem-3.2-20.el7.x86_64
Further inspecting the RPM's contents, I see that it includes these files and directories:
$ rpm -qlp clstrd-0.1.0-Linux.rpm
/usr
/usr/bin
/usr/bin/clstrd
/usr/lib
/usr/lib/libclstrd.a
My question is: How do I force CMake to exclude common directories like /usr or /usr/bin from the RPM? Shouldn't this be done automatically?
I have tried CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION with no luck.
Edit: Here are the relevant parts of my CMakeLists.txt
# Targets
add_library(clstrd_lib ${SOURCE_FILES})
...
add_executable(clstrd main.cpp)
target_link_libraries(clstrd clstrd_lib)
...
# Installation configuration.
install(TARGETS clstrd_lib clstrd
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin)
# CPack configuration.
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "MyAwesomePackage")
set(CPACK_PACKAGE_VENDOR "MyAwesomeVendor")
set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.md")
set(CPACK_PACKAGE_VERSION_MAJOR "0")
set(CPACK_PACKAGE_VERSION_MINOR "1")
set(CPACK_PACKAGE_VERSION_PATCH "0")
set(CPACK_PACKAGE_INSTALL_DIRECTORY "CMake ${CMake_VERSION_MAJOR}.${CMake_VERSION_MINOR}")
set(CPACK_PACKAGE_EXECUTABLES "clstrd", "MyAwesomeExecutable")
set(CPACK_RPM_PACKAGE_AUTOREQPROV " no")
set(CPACK_RPM_PACKAGE_REQUIRES, "libpqxx, gtest, gflags, root, root-netx, xrootd-client-libs")
set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION, "/usr /usr/bin /usr/lib")
set(CPACK_SOURCE_GENERATOR "RPM")
include(CPack)
You can try this,
list(APPEND CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "/lib")
list(APPEND CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "/lib/systemd")
list(APPEND CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION "/lib/systemd/system")
Test OK on CentOS7 with cmake 2.8.12.2.
It seems this was a bug in cmake 2.8.9, which was fixed in cmake 2.8.12:
https://public.kitware.com/Bug/view.php?id=13609

Cpack install different files for different package formats

I have a cmake project that uses cpack to produce both a zip file and a debian package and I would like to be able to install different files for the two version of the packages.
To be more specific, here is a sample CMake file that produces both a zip and a debian package:
cmake_minimum_required(VERSION 3.5)
project(test_packaging)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(SOURCE_FILES main.cpp)
add_executable(test_packaging ${SOURCE_FILES})
install(FILES test.txt DESTINATION auxilliary/)
set(CPACK_GENERATOR "ZIP;DEB")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Ford Prefect")
include(CPack)
What I would like to do is to install two different version of the test.txt file in the two different packages? Something like
if(packaging zip)
install(FILES test_zip.txt DESTINATION auxilliary/)
elseif(packaging deb)
install(FILES test_deb.txt DESTINATION auxilliary/)
endif(expression)