cmake: difference between "make install" and "make package" - cmake

I'm using CMake to generate my makefiles. My deployable target is an RPM, and that's all working well. Per the file system guidelines, my RPM installs to
/opt/mytool
/bin - executables
/lib64 - libraries
/etc/opt/mytool - configuration files
The RPM gets built by CPack using make package
During development testing, I don't want to install an RPM. It requires elevated privileges and limits any given machine to one (developer) version at a time. Before I got all the RPM stuff working, I was able to "make install" and create a simple install tree like this:
install
/opt/mytool
bin
lib64
However, the introduction of the config files to a different location has gummed up the works. I'd like this to be extended to include
install
/etc/opt/mytool
but I can live without it. Unfortunately, when I try make install I get this error:
Install the project...
-- Install configuration: "Debug"
CMake Error at cmake_install.cmake:49 (file):
file cannot create directory: /etc/opt/mytool. Maybe need administrative
privileges.
The offending part of the CMakeLists.txt file is
install(FILES ${PROJECT_SOURCE_DIR}/../Config/mytool.cfg
DESTINATION /etc/opt/mytool
)
I've looked at CMake rpm installing a file in /etc/init.d, but my RPM builds just fine (and I'm using CMake 3)
What is the difference between make install and make package (I can infer that the latter is running CPack, and it works just fine)? How can I create a development install tree

The difference between the two build targets is that package creates an RPM file in your case while install copies the resources given to the install() command to the location provided to the DESTINATION parameter:
DESTINATION
Specify the directory on disk to which a file will be
installed. If a full path (with a leading slash or drive letter) is
given it is used directly. If a relative path is given it is
interpreted relative to the value of the CMAKE_INSTALL_PREFIX
variable. The prefix can be relocated at install time using the
DESTDIR mechanism explained in the CMAKE_INSTALL_PREFIX variable
documentation.
You specified to copy files to /etc/opt/mytool for which you obviously have no write permissions and encounter the cited error.
You have two options to resolve this, the second one is clearly preferred, because it allows every developer to provide their own, system-local setting, where to temporarily install dev files:
set a DESTINATION path for which you have write permissions
set a relative path and call cmake with an additional argument to specify where your development install tree is:
cmake -H<source path> -B<build path> -DCMAKE_INSTALL_PREFIX=<install path>

Related

clion wsl "CMake 3.20 or higher is required. You are running version 3.16.3"

so I just downloaded wslusing the wsl --install command using PowerShell
now I'm trying to connect it to Clion which works
i cant add images so here is a link to it
but when i'm tying to build the project i get this error
"CMake Error at CMakeLists.txt:1 (cmake_minimum_required):
CMake 3.20 or higher is required. You are running version 3.16.3"
my cmake file:
cmake_minimum_required(VERSION 3.20)
project(ex2 C)
set(CMAKE_C_STANDARD 99)
add_executable(ex2
ex2.c ex2.h
main1.c
main2.c)
i tried updating wsl using wsl --update (in powershell)
The CMake installation inside the WSL is used. Unfortunately currently snap doesn't seem to be available in WSL, but installing the latest CMake version isn't too complicated nonetheless:
(optional) uninstall the old cmake installation in WSL; personally I don't see any benefit in multiple CMake installations, but there may be valid reasons for this. Most likely this will just makes the use of cmake more complex, since you need to remember which cmake version is used.
Download the appropriate cmake version from the cmake website ( https://cmake.org/download/ ). The version to choose is the tar.gz file under binary distributions for the x86_64 target. To get version 3.21.4 (currently the latest release), you can download the file from https://github.com/Kitware/CMake/releases/download/v3.21.4/cmake-3.21.4-linux-x86_64.tar.gz (Identical to the link on the CMake download page).
Unpack the archive from WSL. Navigate to the directory where you want the cmake installation to recide. This will add the cmake-3.21.4-linux-x86_64 directory containing all the files required to work with cmake to the current working directory. Let's assume you want to add the cmake files to the /opt directory. Furthermore let's assume the windows user name to be fabian, C: to be the primary hard drive and the download to be saved to the Downloads directory in the user directory:
cd /opt
tar -xf /mnt/c/Users/fabian/Downloads/cmake-3.21.4-linux-x86_64.tar.gz
(optional) make CMake available without specifying the path; this could be done as described here: https://unix.stackexchange.com/questions/3809/how-can-i-make-a-program-executable-from-everywhere ; don't do this, if an existing cmake installation is already available in the command line assuming you did install cmake to /opt, the cmake binary recides at /opt/cmake-3.21.4-linux-x86_64/bin
You should now be able to use cmake specifying either the full path to the executable (/opt/cmake-3.21.4-linux-x86_64/bin/cmake assuming you used the /opt directory) or directly via a command after opening the WLS commandline again (provided you followed step 4).
Now the only thing left to do should be telling CLion about the location of the cmake executable. Note that I haven't tested this, since I don't use this IDE. It's working fine using Visual Studio Code though...

How can I manage the installation directory with CMake when cross-compiling?

I am cross-compiling a C library using CMake and a toolchain file. My toolchain file sets CMAKE_SYSROOT to the appropriate value so compilation works with no issues. However, when installing, the library does not install to the directory pointed to by CMAKE_SYSROOT. I can achieve that effect by running make install DESTDIR=xxx though.
I understand that there are two separate concepts here:
The cross-compilation toolchain, which consists of binaries that can be run on my local architecture
The CMAKE_SYSROOT which is the root directory of a target-architecture filesystems, containing header files and libraries, passed to e.g. gcc through the --sysroot flag.
I have two questions:
Is it a good idea to conflate the sysroot where my cross-compilation toolchain lives, with the sysroot where all my cross-compiled libraries will be installed? It feels to me like it should be the same, but am not sure, and to CMake it appears they are distinct concepts. Update: answered in the comments below, these are indeed distinct concepts.
What is the modern CMake way to specify the installation directory when cross-compiling like described above? Update: I believe this should be the same as CMAKE_SYSROOT, and I feel CMake should offer a way to only define this once somewhere.
Thanks!
There is no interference between sysroot and install directory (prefix).
Sysroot is given by CMAKE_SYSROOT variable and denotes prefix for tools used during build process.
Install directory(prefix) is given by CMAKE_INSTALL_PREFIX variable and denotes the path, where the project will be used upon installation. E.g. with install prefix /usr/local the project's executable foo expects to be run as /usr/local/bin/foo.
Note, that with default installation procedure, CMake installs files to the host machine. For install files onto the target machine, this procedure is needed to be adjusted. Parameter DESTDIR=xxx for make install is a way for install files directly to the target machine. Another way is to create a package (e.g. with CPack) on host, and install that package on target machine.
Note, that in the above paragraph it is irrelevant, whether cross-compilation took a place or not: it is possible to build the project on one machine and install it to the other, but similar one, without any cross-compilation.

cpack and install(CODE ...) - CPACK_PACKAGING_INSTALL_PREFIX vs CMAKE_INSTALL_PREFIX

as a "post-install hook" I need to execute an install command like
install(CODE "execute_process(COMMAND some_command ${CMAKE_INSTALL_PREFIX}/some_folder"))
which creates a file in some_folder based on the files which were previously installed into some_folder (it compiles an index/cache of those files).
This works fine for the install target, however as soon as using cpack ${CMAKE_INSTALL_PREFIX} is not the correct location anymore.
Is there a variable like ${CMAKE_CURRENT_INSTALL_PREFIX} that always points towards the current installation directory, regardless of wether the default install target or cpack is used and can be used for this purpose?
The only alternative I see is to try to execute the command at an earlier stage on the original files, create a temporary file and install the temporary file. Unfortunately this is much more error prone, as some_command should be run on the "final" files after installation (in order to create a valid cache)
The answer turns out to be extremely simple (kudos to Nils Gladitz from IRC):
Escaping the variable ${CMAKE_INSTALL_PREFIX} with a backslash delays its expansion until install time at which it holds the correct value also for installs via CPack:
install(CODE "execute_process(COMMAND some_command \${CMAKE_INSTALL_PREFIX}/some_folder"))

cmake: install executables and create links to them

I'm using cmake and cpack to build my project and build packages. I'm creating a few executables in my project, let's call them EXE1 and EXE2.
When creating different versions of these executables, I want to name to reflect the version of the executable (let's say EXE1_1.0.0). I can change the name of the output for a target by doing set_target_properties.
However, now when doing an install, I want to do create a symlink to this versioned name of the executable, i.e. I want to have
the "versioned" executable installed in bin directory, i.e. EXE1_1.0.0
create a symlink to the "versioned" executable, i.e. create symlink EXE1, which points to EXE1_1.0.0
Can someone suggest me how to do this?
Second question is:
How to install configuration files /etc/MYPROJECT/ directory? What DESTINATION I need to use for configuration files, like I use bin for executables and lib for libraries? Is using an absolute path like /etc an acceptable practice with cmake?
I asked this question on cmake mailing list subsequently, and this is the response I received:
The validity of the answer will depend on which CMake version you use
and which set of platform you want to support.
Symlinks are not that portable
a) Creation may not be [currently] done portably but if you are
targeting Unix you can use cmake -E create_symlink to create one.
b) Depending on the CPack generator you use and CMake/CPack version
symlinks may be embedded in the package or not.
i.e. CPack pre 2.8.7 cannot create ZIP archive which contains
symlinks CPack 2.8.8 can do that now.
Then you can use an install(SCRIPT ... or install(CODE ...) to do that
at install time.
Another option if you are using RPM is to use package specific post
install script. cpack --help-variable
CPACK_RPM_POST_INSTALL_SCRIPT_FILE
this last solution will off course only work for CPack RPM.
For second question
You can use absolute destination path, they should be handled just
fine by CPack DEB and RPM, I don't know for other.
If your software should be installed on Windows this is won't work
with archive generator (ZIP, TGZ, etc...) and/or NSIS.
May be you can do something like:
if(UNIX AND NOT APPLE) set(CONFDEST "/etc/${CMAKE_PROJECT_NAME}")
else() set(CONFDEST "etc") endif()
install(FILES yourconffile DESTINATION ${CONFDEST})

CMake rpm installing a file in /etc/init.d

I want to install a file in
/etc/init.d directory
I have written code
INSTALL(FILES ${CMAKE_SOURCE_DIR}/app/script/appd DESTINATION /etc/init.d/appd)
but when I run packing code using cmake I get error
CMake Error at /home/vivek/workspace/app/build/standalone/cmake_install.cmake:54 (FILE):
file cannot create directory: /etc/init.d/appd. Maybe need
administrative privileges.
How can I set cmake to install a file inside /etc/init.d directory ?
You can do this, but you may need to explicitly set:
set(CPACK_SET_DESTDIR ON)
prior to:
include(CPack)
in your CMakeLists.txt file. (You will need to do this only for older versions on CMake/CPack, prior to 2.8.3)
The reason you need to do this is that you are specifying a full path name as the DESTINATION of one of your installed files. In order to do that properly in the packing phase, CPack needs to use a DESTDIR environment variable in its "make install" call.
We didn't do this automatically by default for backwards compatibility reasons.
But then, this bug was fixed in version 2.8.3 so that it could be done transparently and automatically with install rules that use full path names:
http://public.kitware.com/Bug/view.php?id=7000
Hopefully, you can use either CPACK_SET_DESTDIR to ON for your rpm packages, OR use a more recent version of CMake/CPack that includes the automatic fix.
You can't. Only thing you can do is to ask user to run make install for your app with administrative priveleges.
Also, you can try detecting presense of sudo command and add_custom_command() which would install your files with sudo.