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

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.

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...

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

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>

CMake - how to block executing installation scripts during packaging?

My CMakeLists.txt file contains commands, which should be executed by make install, and all this works fine. The sample CMakeLists.txt below is a short excerpt from my actual CMake file (the tm0001.cpp content is not important here - it might be any C++ program):
cmake_minimum_required(VERSION 3.12)
project(tm0001)
set(CMAKE_CXX_STANDARD 11)
add_executable(${PROJECT_NAME} tm0001.cpp)
install(
TARGETS ${PROJECT_NAME}
DESTINATION /usr/local/bin
PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
)
install(CODE "message(\"-- This must be called during installation only\")")
set(CPACK_PACKAGE_CONTACT "HEKTO")
set(CPACK_GENERATOR "DEB")
include(CPack)
I see the message command is executed by make package as well, which is not I want.
How to tell CMake not to execute installation scripts by the make package command? I couldn't find any way to do that with the CMake if command.
As it already said in the comment, it's an extremely bad idea to "work w/ systemd" (and doing anything not related to build or packaging of your project) from install commands. The install command (even SCRIPT and CODE signatures) are intended to be used for install actions and not for any other side effects.
The correct way to act here is to produce a native package (DEB/RPM) w/ post-install script, where using the system-provided macros (like described here), you can install your package properly. Take a look to CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA for the way to provide package install actions.
The other bad thing is to use the hardcoded path (/usr/bin/). And BTW, a better place for the (pure) daemon app I suggest /usr/sbin/. Take a look to GNUInstallDirs module shipped w/ CMake for further references.
What I did was to specify install commands with CODE/SCRIPT as separate component e.g. install(CODE ... COMPONENT post-install).
Then also added other non-code install commands as a different component e.g. install(FILES ... COMPONENT files-install)
The CPack then needs to be configured to package only files-install component (solution to this can be found easily - hint: use CPACK_COMPONENTS_ALL_IN_ONE_PACKAGE, CPACK_COMPONENTS_ALL and CPACK_(RPM/DEB/...)_COMPONENT_INSTALL variables).
Of course then the resulting package won't run these CODE components during installing the package - they need to be added separately as a post install script.
I'm answering my own question, because the existing answer doesn't address my main problem. I couldn't find any way (on the CMake level) to block install commands from running during make package - even the postinst script is called by this command.
Fortunately, I could modify the postinst script itself to do nothing in case it's called not by the dpkg:
if [ -z ${DPKG_ADMINDIR} ]; then
echo "postinst: missing 'dpkg' environment (not an error during packaging)"
exit 0
fi
It's a trick of course, but it worked for me.

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