Create tar archive with Cmake - makefile

I have used the *_OUTPUT_PATH variables in my CMakeLists.txt file to specify specific locations for my binaries and library files, and that seems to be working "automatically"
I would like as part of a "build" for one final step to happen, which is to create a tarball of the binaries that output directory.
What do I need to add to create a tar?

You can use a CMake custom target to invoke CMake in command mode and have it produce a tarball from the binaries in the output directory. Here is a CMakeLists.txt that sketches the necessary steps:
project(TarExample)
set (EXECUTABLE_OUTPUT_PATH "${CMAKE_CURRENT_BINARY_DIR}/executables")
add_executable(foo foo.cpp)
add_custom_target(create_tar ALL COMMAND
${CMAKE_COMMAND} -E tar "cfvz" "executables.tgz" "${EXECUTABLE_OUTPUT_PATH}")
add_dependencies(create_tar foo)
The custom target generates a gzipped tarball from the files in the directory EXECUTABLE_OUTPUT_PATH. The add_dependencies call ensures that the tarball is created as a final step.
To produce an uncompressed tarball, use the option cfv instead of cfvz.

Related

How can i setup meson and ninja on Ubuntu-Linux to produce the expected .a file by use of MakeFile?

Some years ago on Ubuntu 16.0.4 I've used this library: git clone https://github.com/Beckhoff/ADS and using only the make command I got build, compile and finally on the main directory I found a file called AdsLib-Linux.a and maybe nothing more than this.
Now I'm on Ubuntu 20.04 I need this library once again but this times make dosn't produce the same output and looking forth to the ReadMe instructions I finally used that instead of make:
meson build
ninja -C build
That now create a new directory build but no .a file as before on the root directory. Instead a new file in the build directory libADSLib.a is there. The same thing happens using right the make command.
Maybe the author changed over the years something on the config files or the behavior of the tools have changed, but I cannot get the former file anymore and I need it for other referencing code that now is not executing anymore.
Looking to the MakeFile I found that in the example folder, differently from the one on the parent directory, the MakeFile has something like that:
$(warning ATTENTION make is deprecated and superseeded by meson)
...
${PROGRAM}: LIB_NAME = ../AdsLib-${OS_NAME}.a
...
But all i've tried reading the guides on meson and ninja about setup, configure, build, and so on, did not produce anymore that file.
I've tried also to first build and then copy all files form the example folder to the parent directory and then build again, but again no .a file there.
How's the right way to configure the build process corectly so that this -Linux.a file is created. Or if not possibile anymore, what does it now produce I can use instead of what produced before?
Meson is a build system generator, similar to CMake or somewhat like ./configure, you need to run meson, then run ninja to actually build something.
You need to run both meson and ninja:
meson setup builddir
ninja -C builddir
Once you do that successfully, there will be a libAdsLib.a inside the builddir directory.
Let me correct a bit #dcbaker, according to their README you should setup build as build directory:
# configure meson to build the library into "build" dir
meson build
# let ninja build the library
ninja -C build
Of course, in general, it shouldn't be specific, but their example code is written in a weird way so this path is hard-coded. So, to use the example:
# configure meson to build example into "build" dir
meson example/build example
# let ninja build the example
ninja -C example/build
# and run the example
./example/build/example
About the library: it's now libAdsLib.a and produced in build directory. The name is set here and it's now in linux naming style, the old one - not. So, you have options:
Update your configuration/build files (Makefile?) where you use it
Copy or make symbolic link, e.g.
$ ln -s <>/build/libAdsLib.a <target_path>/AdsLib-Linux.a
Above it's very dependent on your development environment, do you have installation or setup scripts for it? do you permissions to modify/configure parameters for target application? do you need to support both old and new names? - many questions not related to original question about meson.

CMake substitute text in a file generated by a target

I have cmake target which runs a setup.exe on windows which installs a tool using add_custom_target as follows
# TOOL_TEMP_INSTALL_PATH is the installation path which is set earlier in cmake
add_custom_target(
install_tool
COMMAND ${TOOL_TEMP_DIR}/setup.exe /DIR=${TOOL_TEMP_INSTALL_PATH}
)
After the installation, I want to replace text in a configuration file located at ${TOOL_TEMP_INSTALL_PATH}/tool.ini replacing a line of text "LICENSE_FILE=Enter License server" with "LICENSE_FILE=30309#server"
Following commands will achieve this but this needs to be run after install_tool target is built.
file(READ "${TOOL_TEMP_INSTALL_PATH}/tool.ini" filedata)
string(REGEX REPLACE "LICENSE_FILE=Enter License server here"
"LICENSE_FILE=30309#server" filedata "${filedata}")
file(WRITE "${TOOL_TEMP_INSTALL_PATH}/tool.ini" "${filedata}")
How can I add these commands as a dependency to install_tool? Or is there a better way to achieve this on windows?
Since you want to run two things in order as part of the same target, you can use multiple COMMAND entries in the same target. The difficulty is that COMMAND can't handle CMake code, but only system commands. The typical solution is to call CMake in a subshell on a script file:
COMMAND ${CMAKE_COMMAND} -P path_to_script
So, place your file modification commands in a file in your source tree called license-install.cmake, and add another COMMAND to your add_custom_target
Hint: You might consider add_custom_command instead, so you can specify a file in the installed tree as a dependency. This will allow CMake to see the installed tool as a build product, and to skip the install step if the tool is already installed. You'll still need an add_custom_target with a dependency on your command output to hook it in correctly.

How to tell rpmbuild to use extracted folder instead of archive?

I installed a sources rpm for Linux kernel on Centos. And I need to make modifications to the kernel and build it. The kernel.spec file has the line that tells rpmbuild to get the sources to build from the archive file
Source0: linux-%{rpmversion}-%{pkgrelease}.tar.xz
The archive is in the typical location: ~/rpmbuild/SOURCES/linux-%{rpmversion}-%{pkgrelease}.tar.xz
I extracted the archive in the same directory, and that is ~/rpmbuild/SOURCES/linux-%{rpmversion}-%{pkgrelease}
How to tell rpmbuild to get the sources from the extracted version which has my changes and not from the archive?
I already tried the trivial solution to just remove ".tar.xz" extension, but that did not work:
error: File /root/rpmbuild/SOURCES/linux-3.10.0-957: Is a directory

How to install Criterion to specific folder?

I have Criterion framework (https://github.com/Snaipe/Criterion), I want to build it from source and install to specific directory so headers of criterion should be located in
/usr/include/
and libraries libcriterion.so in /usr/lib64 folder
I use this command to build and install:
mkdir build
cd build
cmake ..
cmake --build .
make install
it installs .so files to /usr/local/ folder, bash command find / -name "*criterion*" shows this:
/usr/local/lib/libcriterion.so
/usr/local/lib/libcriterion.so.3
/usr/local/lib/libcriterion.so.3.1.0
/usr/local/share/pkgconfig/criterion.pc
/usr/local/include/criterion
/usr/local/include/criterion/criterion.h
How can I fix my command so that after installation libcriterion.so was located in /usr/lib64 directory ?
Using CMake command line options does not allow changing the library install location as requested. You could change use the -DCMAKE_INSTALL_PREFIX=... option, but that would affect the include location, as well.
However, since you have access to the source code, you could simply modify the CMakeLists.txt file and set the library install location by adding a command like this:
install(TARGETS ${PROJECT_NAME}
LIBRARY DESTINATION lib64
)
For further details, I may link to the CMake documentation.
By the way: There is no need to create the build directory explicitly, your script could look like this
cmake -H. -Bbuild
cmake --build build
cmake --build build --target install

Add 'install' target to 'all' in CMake

I have a CMake project with the following directory tree:
build/
assets/
dest/
<other files>
dest is a directory where all installed files should go:
The executable, which goes to dest/ with a simple make, this is controlled with CMAKE_RUNTIME_OUTPUT_DIRECTORY
The assets, located on assets/, which go to dest/ after a make install.
But I don't want to issue make install to copy all files do the dest/ dir: I want a simple make to do this.
In this sense, how do I add the install target to the default one (all)? Or, is there a better way to solve this?
Using the following wont cause recursion. Requires CMake >= 3.15.
add_custom_command(
TARGET ${MY_TARGET} POST_BUILD
COMMAND ${CMAKE_COMMAND} --install ${CMAKE_BINARY_DIR} --config $<CONFIG>
)
Extra : You may want to provide a default (local) install path so this doesn't fail on Windows.
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX "install" CACHE PATH "Default install path." FORCE)
endif()
This will execute the install target after building <target_name> (which could be all):
add_custom_command(
TARGET <target_name>
POST_BUILD
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target install
)
I've solved this problem by using the following macro to generate data dependency rules for the specified target. These rules require only a make and not a make install.
The macro maps an arbitrary file from your source tree into a "staging" tree, where each tree structure may be different, and you may optionally rename the file. The staged data is kept up-to-date, so if you change it in your source tree then it'll be updated the next time you make.
# Macro used to create dependencies for staging data files (e.g. config files, assets) and keeping them up-to-date.
# The given "source" file is copied (and possibly renamed) to "staged" for the given "target".
#
# It works by creating a rule that creates "staged" by copying "source", then creating a target that depends upon "staged",
# then making the given "target" depend upon the new target. Or in makefile speak:
#
# staged: source
# cp source staged
#
# targetData1: staged
#
# target: <existing dependencies...> targetData1
# <existing commands...>
#
# The intermediate rule is used for parallel build robustness. For details, see:
# http://www.cmake.org/cmake/help/v2.8.12/cmake.html#command:add_custom_command
#
# Example:
# target = myExeTarget
# source = "${CMAKE_CURRENT_SOURCE_DIR}/../../data/images/bush1.png"
# staged = "${STAGING_DATA_DIR}/images/bush1.png"
macro(add_data_dependency target source staged)
add_custom_command(
OUTPUT "${staged}"
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${source}" "${staged}" # Dir(s) will be created if needed.
DEPENDS "${source}"
)
if (NOT DEFINED add_data_dependency_counter)
#message(status "Setting tmp counter......")
set(add_data_dependency_counter "0")
endif()
math(EXPR add_data_dependency_counter "${add_data_dependency_counter} + 1")
#message(status "tmp counter is ${add_data_dependency_counter}......")
set(customTarget "${target}Data${add_data_dependency_counter}")
add_custom_target(${customTarget} DEPENDS "${staged}")
add_dependencies(${target} ${customTarget})
endmacro()
In your case, usage would be something like:
add_data_dependency(myTarget "${CMAKE_CURRENT_SOURCE_DIR}/assets/file1.ext" "${CMAKE_CURRENT_SOURCE_DIR}/dest/file1.ext")
add_data_dependency(myTarget "${CMAKE_CURRENT_SOURCE_DIR}/assets/file2.ext" "${CMAKE_CURRENT_SOURCE_DIR}/dest/file2.ext")
add_data_dependency(myTarget "${CMAKE_CURRENT_SOURCE_DIR}/assets/rename_me.ext" "${CMAKE_CURRENT_SOURCE_DIR}/dest/renamed.ext")
:
:
Then whenever you make, the files will be copied if missing or out-of-date (assuming that myTarget is part of all).
The normal way to use CMake is to create a build directory outside your project and all compiled binaries are put there. When you are finished developing and want to install some binaries into your system then you call make install. In this way you keep your project source folder free from all compiler generated stuff.
Example file directory structure:
my_project/
my_project_build/
from my_project_build you call cmake ../my_project to generate build files. Call make to build it and all binaries will be in my_project_build.

Resources