Setting up a cmake project properly with thirdparty - cmake

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?

Related

Replace LibXML2 with Yocto Built LibXML2

I have been working on this all day, but I think I finally have my base case figured out. I am using a GitHub repo DBCPPP in my application. This repo relies on LibXml2, to ensure it is available LibXml2 is included as a submodule and build with dbcppp through a series of CMakeLists.txt. I am trying to resolve an issue with my build in which the Linux kernel and the DBCPPP recipe are both attempting to install /usr/lib/libxml2.so.2.9.10. I have an open question about it here.
My potential solution is to prevent DBCPPP from creating the libxml2.so.2.9.10 file, and instead build using the libxml2.so.2.9.10 file created by Yocto.
So far my CMakeLists.txt contains:
cmake_minimum_required(VERSION 3.12)
project("libdbcppp" VERSION 0.1.0)
set(LIBXML2_INCLUDE_DIR /mnt/WorkDrive/Documents/EVCC_Application/build-fb/tmp/work/cortexa7t2hf-neon-poky-linux-gnueabi/libxml2/2.9.10-r0/libxml2-2.9.10/include)
set(LIBXML2_LIBRARIES /mnt/WorkDrive/Documents/EVCC_Application/build-fb/tmp/work/cortexa7t2hf-neon-poky-linux-gnueabi/libxml2/2.9.10-r0/image/usr/lib)
#include(FindPkgConfig)
#include(FindLibXml2 REQUIRED)
find_package(LibXml2 REQUIRED)
option(build_tests "Build tests" ON)
option(build_examples "Build examples" ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_STATIC_LIBRARY_PREFIX "")
set(CMAKE_SHARED_LIBRARY_PREFIX "")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
add_definitions("/bigobj")
endif()
include_directories("include")
include_directories("third-party/libxmlmm/libxmlmm")
include_directories("/mnt/WorkDrive/Documents/EVCC_Application/build-fb/tmp/work/cortexa7t2hf-neon-poky-linux-gnueabi/boost")
include_directories("/mnt/WorkDrive/Documents/EVCC_Application/build-fb/tmp/work/cortexa7t2hf-neon-poky-linux-gnueabi/libxml2/2.9.10-r0/libxml2-2.9.10/include")
include_directories("third-party/cxxopts/include")
file(GLOB libxmlmm_header
"third-party/libxmlmm/libxmlmm/*.h"
)
file(GLOB libxmlmm_src
"third-party/libxmlmm/libxmlmm/*.cpp"
)
add_library(libxmlmm SHARED "")
target_link_libraries(libxmlmm LibXml2::LibXml2)
target_sources("libxmlmm"
PRIVATE ${libxmlmm_header}
PRIVATE ${libxmlmm_src}
)
install(TARGETS "libxmlmm" EXPORT ${PROJECT_NAME}Targets DESTINATION ${CMAKE_INSTALL_LIBDIR})
install(
DIRECTORY "libxmlmm"
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/libxmlmm
FILES_MATCHING PATTERN "*.h")
set(CMAKE_STATIC_LIBRARY_PREFIX "")
set(CMAKE_SHARED_LIBRARY_PREFIX "")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
CONFIGURE_FILE(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
IMMEDIATE #ONLY
)
ADD_CUSTOM_TARGET(uninstall
"${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
)
Edit: I am updating my question with my latest CMakeLists.txt. I am integrating this with a Yocto project. This appears to work within Ubuntu but when I added it to the Yocto build I get the error.
error: /mnt/WorkDrive/Documents/MAIN_Application/build-fb/tmp/work/cortexa7t2hf-neon-poky-linux-gnueabi/libxml2/2.9.10-r0/image/usr/lib: read: Is a directory
| collect2: error: ld returned 1 exit status
| ninja: build stopped: subcommand failed.
| WARNING: exit code 1 from a shell command.

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}")

Hot do I link MPFR in CMake?

I'm totally new to cmake, I'm on MacOs and I'm trying to build a c++ library and I need to link my executables to mpfr in order to make it work
This is my CMakeLists.txt file:
cmake_minimum_required(VERSION 3.19)
project(my_project)
set(CMAKE_CXX_STANDARD 14)
add_executable(my_project main.cpp)
find_package(GSL REQUIRED)
target_link_libraries(my_project GSL::gsl GSL::gslcblas)
find_package(Boost REQUIRED)
target_link_libraries(my_project Boost::boost)
find_package(MPFR REQUIRED) # <- It fails here!
target_link_libraries(my_project MPFR::mpfr)
When I try to build my project with CLion I get the following error:
CMake Error at CMakeLists.txt:13 (find_package):
By not providing "FindMPFR.cmake" in CMAKE_MODULE_PATH this project has
asked CMake to find a package configuration file provided by "MPFR", but
CMake did not find one.
Could not find a package configuration file provided by "MPFR" with any of
the following names:
MPFRConfig.cmake
mpfr-config.cmake
Add the installation prefix of "MPFR" to CMAKE_PREFIX_PATH or set
"MPFR_DIR" to a directory containing one of the above files. If "MPFR"
provides a separate development package or SDK, be sure it has been
installed.
After some research I found out that Cmake was linking correctly both GSL and Boost because there are both a /usr/local/share/cmake/Modules/FindGSL.cmake and a /usr/local/share/cmake/Modules/FindBoost.cmake file, So I looked online for a FindMPFR.cmake file to insert into the /usr/local/share/cmake/Modules/ directory, I tried with this one but the error remains the same. What am I doing wrong?
Edit:
Ok now my CMakeLists.txt file looks like this:
cmake_minimum_required(VERSION 3.19)
project(my_project)
set(CMAKE_CXX_STANDARD 14)
add_executable(my_project main.cpp )
# Append the cmake/ directory to the CMAKE_MODULE_PATH
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
find_package(GSL REQUIRED)
message(STATUS "GSL Found: ${GSL_FOUND}")
target_link_libraries(my_project GSL::gsl GSL::gslcblas)
find_package(Boost REQUIRED)
message(STATUS "Boost Found: ${Boost_FOUND}")
target_link_libraries(my_project Boost::boost)
find_package(MPFR REQUIRED)
message(STATUS "MPFR Found: ${MPFR_FOUND}")
target_link_libraries(my_project ${MPFR_LIBRARIES})
And it works fine :)

Resource file gets included twice in Mac OS X application package built using CMake and CPack

I am trying to use CMake and CPack to build and package a Mac OS X application, but I can't figure out the correct way to include resources.
This is what my CMakeLists.txt looks like:
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
PROJECT(foo)
ADD_EXECUTABLE(foo foo.c foo.txt)
SET_TARGET_PROPERTIES(foo PROPERTIES MACOSX_BUNDLE TRUE)
SET_TARGET_PROPERTIES(foo PROPERTIES RESOURCE foo.txt)
INSTALL(TARGETS foo DESTINATION ".")
SET(CPACK_GENERATOR TGZ)
INCLUDE(CPack)
However, when I use it to build a package, foo.txt gets included twice: in the Resources directory of the bundle as expected, but also at the root:
$ cd build
$ cmake ..
$ make package
$ tar -xvzf foo-0.1.1-Darwin.tar.gz
x foo-0.1.1-Darwin/foo.app/Contents/Info.plist
x foo-0.1.1-Darwin/foo.app/Contents/MacOS/foo
x foo-0.1.1-Darwin/foo.app/Contents/Resources/foo.txt
x foo-0.1.1-Darwin/foo.txt
What am I doing wrong?
EDIT
For easier reading, here is what the final, working, CMakeLists.txt looks like (as per Josh's answer and my comment on it):
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
PROJECT(foo)
ADD_EXECUTABLE(foo foo.c foo.txt)
SET_TARGET_PROPERTIES(foo PROPERTIES MACOSX_BUNDLE TRUE)
SET_SOURCE_FILES_PROPERTIES(foo.txt PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
INSTALL(TARGETS foo DESTINATION ".")
SET(CPACK_GENERATOR TGZ)
INCLUDE(CPack)
Removing the line * PROPERTIES RESOURCE foo.txt) should solve the problem.
Since you have included cpack in your cmake file, the generated TGZ will contain all of the files which would be installed with make install. In this case, you have
SET_TARGET_PROPERTIES(foo PROPERTIES MACOSX_BUNDLE TRUE)
which will build foo as an OS X application bundle (doc), and
SET_TARGET_PROPERTIES(foo PROPERTIES RESOURCE TRUE)
specifies foo.txt as a resource files (doc). With both of those PROPERTIES set, make install will create two versions of foo.txt. One in the bundle, foo.app/Contents/Resources/foot.txt, and one in the top level directory, foo.txt. Therefore, CPack will also generate those two versions of foo.txt.

CMake with "standard" directory layout (Linux)

Let's say I have a simple hello project with the pseudo-standard directory layout
helloworld/
src/
main.c
say.c
say-helper.c
include/
say.h
say-helper.h
build/
and after running
cd ~/helloworld/build
cmake ..
make
I would expect the following
helloworld/
build/lib/
libsay.a
libsay.so
libsay.so.1.0.0
tmp/obj/
main.o
say.o
build/bin/
hello
and after make install I would expect
/usr/local/lib/
libsay.a
libsay.so
libsay.so.1.0.0
/usr/local/bin/
hello
What would the CMakeLists.txt look like for this setup?
I've been looking around for examples, but the only one I've found that shows how to add a library and an executable didn't work.
Basic commands to describe the project:
INCLUDE_DIRECTORIES(include)
ADD_LIBRARY(say src/say.c src/say-helper.c)
ADD_EXECUTABLE(hello src/main.c)
TARGET_LINK_LIBRARIES(hello say)
This is for placing the libs and the executable in the build directory, put that in your CMakeLists.txt:
SET (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)
SET (CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
SET (CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
For install you specify
install(TARGETS say hello
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
in your CMakeLists.txt and set CMAKE_INSTALL_PREFIX to /usr/local in your configuration.
I'm not sure if you can build static and dynamic libraries simultaneously with the same name, though. And I don't know how to tell CMake to put the obj files in some specific location.