CMake with "standard" directory layout (Linux) - cmake

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.

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?

How to use CMake to create a package that installs to '/etc' and '/var'?

I've got CMake (3.02) installing to a DESTDIR when I invoke:
$ make -C build DESTDIR=$(pwd)/build/rootfs install
This results in a file layout that I'm happy with: binaries are located in the .../build/rootfs/usr/local/bin directory and the init scripts are in .../build/rootfs/etc/init.d. To accomplish that, I used a mixture of relative and absolute paths in my CMakeLists.txt file:
set(CPACK_SET_DESTDIR ON)
...
INCLUDE(CPack)
...
set(ROOTFS_BIN_DIR bin)
set(ROOTFS_ETC_INITD_DIR /etc/init.d)
...
INSTALL(TARGETS myDaemon DESTINATION ${ROOTFS_BIN_DIR})
INSTALL(PROGRAMS myDaemon.sh RENAME myDaemon DESTINATION ${ROOTFS_ETC_INITD_DIR})
With that, I think 'working', I'm trying to create a simple tarball package which will eventually become a debian package (with pre/post install/remove scripts) but when I invoke:
$ make -C build DESTDIR=$(pwd)/build/rootfs package
I'm getting errors because cpack is attempting to write my init scripts to the system's /etc/init.d directory (instead of $(pwd)/build/rootfs/etc/init.d). If I wanted that, then $sudo !! would solve the problem. The error (replaced full path with ...):
CMake Error at .../build_src/cmdServer/cmake_install.cmake:44 (file):
file INSTALL cannot copy file
".../src/cmdServer/cmdServer.sh" to
"/etc/init.d/cmdServer".
I'm not using a lot of CPACK directives: in my top level CMakeLists.txt file I have:
SET(CPACK_SET_DESTDIR ON)
SET(CPACK_GENERATOR TGZ)
INCLUDE(CPack)
How can I package my init scripts correctly?
I've been referencing:
https://cmake.org/pipermail/cmake/2008-April/020833.html
and https://cmake.org/pipermail/cmake/2006-November/011890.html

How to create a custom target that copies a library?

I am trying to create a custom target that just copies a library to the LIBRARY_OUTPUT_PATH. Below is my CMakeLists.txt.
The contents of the MYCOMPONENT folder is mylib.so and CMakeLists.txt.
cmake_minimum_required(VERSION 2.8)
project( MYCOMPONENT )
add_custom_target( MYTARGET
COMMAND ${CMAKE_COMMAND} -E copy ./mylib.so ${LIBRARY_OUTPUT_PATH} )
I do the following:
cd MYCOMPFOLDER
mkdir build_debug
cd build_debug
cmake -DLIBRARY_OUTPUT_PATH=<mycompfolderfullpath>/build_debug/bin ..
Now I do an ls of build_debug and I get:
CMakeCache.txt CMakeFiles cmake_install.cmake Makefile
ls CMakeFiles/
3.5.1 CMakeTmp Makefile2
cmake.check_cache feature_tests.bin Makefile.cmake
CMakeDirectoryInformation.cmake feature_tests.c progress.marks
CMakeOutput.log feature_tests.cxx TargetDirectories.txt
CMakeRuleHashes.txt MYCOMPONENT.dir
ls CMakeFiles/MYCOMPONENT.dir/
build.make cmake_clean.cmake DependInfo.cmake progress.make
From build_debug, "find . -name mylib.so" is nowhere, so of course the "make MYTARGET" fails. How do I get cmake to properly handle mylib.so? This is a third party library, we don't build it, the target is to make sure it gets copied to the LIBRARY_OUTPUT_PATH from this folder so other components can link against it from there.
Don't use relative paths in -E copy part. Variables CMAKE_SOURCE_DIR, CMAKE_CURRENT_SOURCE_DIR, CMAKE_BINARY_DIR and CMAKE_CURRENT_BINARY_DIR are at your disposal.

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.

Linking libs with make/g++ under ubuntu

lets say my makefile looks like this:
CXX = g++
OGLLIBS = -lglut32 -lglu32 -lopengl32
projname : projname.o
${CXX} -o projname $< ${OGLLIBS}
Then in which directory does g++ look for the libraries? I was assuming . but if I put the libs there it still complains about not finding them (*.lib is the correct file or does unix use another ending?!)
Folders
unix uses the folders /lib (for system lib) and /usr/lib
your own libraries or newly installed should be in /usr/local/lib but you need to add "-I/usr/local/lib" as compiler flag.
file ending
is .so for shared libs basicly
looking for libs
your can tell your compiler to add other directories to look for libs by setting a variable called LD_LIBRARY_PATH=/root-to-my-libs