meson and git information - meson-build

I need to provide to the binary built with meson build system some git information regarding branch and version used:
git describe --tags
git descibe --help
the problem I have is how retrieve this information with meson,
with the make build I use the following instruction:
GITREF = $(shell git describe --all)
LIB1_VER = $(shell cd ../../lib1;git describe --tags;cd - &>NULL)
so in meson for GITREF I've tried
info_dep = vcs_tag(command : ['git descibe --all'],
input : 'infoBuild.h.in',
output : 'infoBuild.h',
replace_string : 'BRANCHNAME')
where infobuild.h.in is:
#define GITREF "BRANCHNAME"
but when I go to compile with ninja I got
/usr/local/bin/meson --internal vcstagger ../../src/prog1/info/infoBuild.h.in src/prog1/info/infoBuild.h 1.1.0 /home/mariano/clonesIntel/projMes/src/prog1/info BRANCHNAME '(.*)' '/home/mariano/clonesIntel/ProjMes/src/prog1/info/git describe --all'
but I don't find any infoBuild.h,
more over for the LIB1_VER is more difficult because it is in an external folder,
I could overcome this issue with a bash script but is there a way to retrieve both information in meson build?

I see an immediate problem in that it's going to try to run a command 'git describe --all', which is not what you want, as meson will be sure to escape the spaces in your shell so that it treats that as the a single filename, you want ['git', 'describe', '--all']. Of course, that could just be a type in your example.
One option you might consider is a run_command and configure_file, which is a command run at compile time, and produces a result object that you can get string values from. The disadvantage of this compared to vcs_tag (or a custom_target) is that it happens at configure time, as opposed to build time, so you need to reconfigure to update your tags:
res = run_command(['git', 'describe', '--all'], capture : true, check : true)
describe = res.stdout()
version_h = configure_file(
input : 'version.h.in',
output : 'version.h',
configuration : {'PLACEHOLDER' : describe}
)

Related

i18n.merge_file can't translate desktop file

I'm trying to convert autotools project to Meson and stuck on translation of desktop file.
There is no problem to get all .mo files created.
POTFILES and LINGUAS are in 'po' folder as per manual.
Only problem is i18n.merge_file is not generating file with translations.
My meson.build looks like
...
package = meson.project_name()
i18n = import('i18n')
add_project_arguments('-DGETTEXT_PACKAGE="#0#"'.format(package), language:'c')
subdir('po')
i18n.merge_file(
input: 'data/clipit.desktop.in',
output: 'clipit.desktop',
type: 'desktop',
po_dir: 'po',
install: true,
install_dir: '/usr/share/applications'
)
...
po/meson.build
i18n.gettext(package, preset: 'glib')
clipit.desktop.in
[Desktop Entry]
_Name=ClipIt
_Comment=Clipboard Manager
Icon=clipit-trayicon-offline
Exec=clipit
Terminal=false
Type=Application
Categories=GTK;GNOME;Application;Utility;
After ninja install output is:
[Desktop Entry]
Icon=clipit-trayicon-offline
Exec=clipit
Terminal=false
Type=Application
Categories=GTK;GNOME;Application;Utility;
It is based on (https://mesonbuild.com/Porting-from-autotools.html) but also tried to follow 'eye of gnome' meson.build. No luck.
Current version of code on github.
Edit:
Leaving snippet that can be used, as meson documentation don't cover using intltool.
custom_target('clipit.desktop',
input : 'data/clipit.desktop.in',
output : 'clipit.desktop',
command: [intltool_merge, '-d', '-u', join_paths(meson.source_root(), 'po'), '#INPUT#', '#OUTPUT#'],
install : true,
install_dir : get_option('datadir') / 'applications')
The reason why this doesn't work, is that this isn't valid input to gettext :)
The underscore at the start of the _Name and _Comment fields are because of intltool, another translation tool similar to gettext. To solve this, just remove the underscore of those fields. This will work for .desktop files. For more information, you can also take a few hints from https://wiki.gnome.org/MigratingFromIntltoolToGettext
On a side note, you shouldn't direct install to '/usr/share/applications', since someone might want to choose a custom prefix or datadir (see Meson - Built-in options for more info). It's better to use install_dir: get_option('datadir') / 'applications'.

How to run post build commands in meson?

How can I do in meson to run a command after building a target?
Eg. I have an executable:
executable('target.elf', 'source1.c', 'source2.c')
And after target.elf built I want to execute a command (eg. chmod -x target.elf) on it.
I tried custom_target(), but that requires an output. I don't have new output, I just have target.elf. I tried run_command() but I didn't know how to execute it after the building.
executable now has an argument install_mode (added 0.47.0) to specify the file mode in symbolic format and optionally the owner/uid and group/gid for the installed files.
I just noticed that yasushi-shoji has provided this answer already.
The following code should do.
project('tutorial', 'c')
exec = executable('target.elf', 'main.c', build_by_default : false)
custom_target('final binary',
depends : exec,
input : exec,
output : 'fake',
command : ['chmod', '+x', '#INPUT#'],
build_by_default : true)
Note that because I want to always run the fake target, I'm using custom_target(). However, the command chmod + x demo doesn't generate the file fake specified in custom_target(), successive ninja command will always run the target.
If you don't want this behaviour, there are two ways:
You can write a script which chmod the target.elf and then copies it to target, thus effectively creates the target file. Make sure to change the output file in the meson.build if you do so.
If you don't mind typing ninja chmod instead of ninja, you can use run_target().
# optional
run_target('chmod',
command : ['chmod', '+x', exec])
Another alternative is to use install_mode for executable().
Also note that you should always use find_program() instead of plain chmod. This example doesn't use it for simplicity.

How can I concatenate multiple files into one in Meson?

I'm having trouble with a basic task in Meson where I need multiple files concatenated into one during build; basically:
cat *.txt > compiled.txt
or
cat foo.txt bar.txt baz.txt > compiled.txt
However whether I use custom_target(), generator() or any other function, Meson either can't find the compiled.txt or can't handle transitioning from multiple input files to a single output file.
Is there an easy way to achieve this?
Update:
Using run_command() I've managed to build compiled.txt and have it appear in the source directory. Ultimately I want compiled.txt (which I've listed in the gresource.xml) to be compiled by gnome.compile_resources(). Is there a way I can run this command and pass the file directly to that function to process?
Use custom_target(), pass the output to dependencies of gnome.compile_resources(). Note you will need a fairly recent glib for it to work.
See also: http://mesonbuild.com/Gnome-module.html#gnomecompile_resources
Moved solution from question to answer:
Solution:
I ended up not using gresources, but still needed this solution to concatenate files
cat_prog = find_program('cat')
parts_of_the_whole = files(
'part1.txt',
'part2.txt'
)
concat_parts = custom_target(
'concat-parts',
command: [ cat_prog, '#INPUT#' ],
capture: true,
input: parts_of_the_whole,
output: 'compiled.txt',
install_dir: appdatadir,
install: true,
build_by_default: true
)

rpm spec file skeleton to real spec file

The aim is to have skeleton spec fun.spec.skel file which contains placeholders for Version, Release and that kind of things.
For the sake of simplicity I try to make a build target which updates those variables such that I transform the fun.spec.skel to fun.spec which I can then commit in my github repo. This is done such that rpmbuild -ta fun.tar does work nicely and no manual modifications of fun.spec.skel are required (people tend to forget to bump the version in the spec file, but not in the buildsystem).
Assuming the implied question is "How would I do this?", the common answer is to put placeholders in the file like ##VERSION## and then sed the file, or get more complicated and have autotools do it.
We place a version.mk file in our project directories which define environment variables. Sample content includes:
RELPKG=foopackage
RELFULLVERS=1.0.0
As part of a script which builds the RPM, we can source this file:
#!/bin/bash
. $(pwd)/Version.mk
export RELPKG RELFULLVERS
if [ -z "${RELPKG}" ]; then exit 1; fi
if [ -z "${RELFULLVERS}" ]; then exit 1; fi
This leaves us a couple of options to access the values which were set:
We can define macros on the rpmbuild command line:
% rpmbuild -ba --define "relpkg ${RELPKG}" --define "relfullvers ${RELFULLVERS}" foopackage.spec
We can access the environment variables using %{getenv:...} in the spec file itself (though this can be harder to deal with errors...):
%define relpkg %{getenv:RELPKG}
%define relfullvers %{getenv:RELFULLVERS}
From here, you simply use the macros in your spec file:
Name: %{relpkg}
Version: %{relfullvers}
We have similar values (provided by environment variables enabled through Jenkins) which provide the build number which plugs into the "Release" tag.
I found two ways:
a) use something like
Version: %(./waf version)
where version is a custom waf target
def version_fun(ctx):
print(VERSION)
class version(Context):
"""Printout the version and only the version"""
cmd = 'version'
fun = 'version_fun'
this checks the version at rpm build time
b) create a target that modifies the specfile itself
from waflib.Context import Context
import re
def bumprpmver_fun(ctx):
spec = ctx.path.find_node('oregano.spec')
data = None
with open(spec.abspath()) as f:
data = f.read()
if data:
data = (re.sub(r'^(\s*Version\s*:\s*)[\w.]+\s*', r'\1 {0}\n'.format(VERSION), data, flags=re.MULTILINE))
with open(spec.abspath(),'w') as f:
f.write(data)
else:
logs.warn("Didn't find that spec file: '{0}'".format(spec.abspath()))
class bumprpmver(Context):
"""Bump version"""
cmd = 'bumprpmver'
fun = 'bumprpmver_fun'
The latter is used in my pet project oregano # github

How to use the program's exit status at compile time?

This question is subsequent to my previous one: How to integrate such kind of source generator into CMake build chain?
Currently, the C source file is generated from XS in this way:
set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/${file_src_by_xs} PROPERTIES GENERATED 1)
add_custom_target(${file_src_by_xs}
COMMAND ${XSUBPP_EXECUTABLE} ${XSUBPP_EXTRA_OPTIONS} ${lang_args} ${typemap_args} ${file_xs} >${CMAKE_CURRENT_BINARY_DIR}/${file_src_by_xs}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
DEPENDS ${file_xs} ${files_xsh} ${_XSUBPP_TYPEMAP_FILES}
COMMENT "generating source from XS file ${file_xs}"
)
The GENERATED property let cmake don't check the existence of this source file at configure time, and add_custom_target let the xsubpp always re-run at each compile. The reason for always rerun is because xsubpp will generate an incomplete source file even if it fails, so there are possibility that the whole compiling continues with an incomplete source file.
I found it is time consuming to always re-run source generator and recompile it. So I want to have it re-run only when dependent XS files are modified. However, if I do so, the incomplete generated source file must be deleted.
So my question is: is there any way to remove the generated file, only when the program exit abnormally at compile time?
Or more generic: is there any way to run a command depending on another command's exit status at compile time?
You can always write a wrapper script in your favorite language, e.g. Perl or Ruby, that runs xsubpp and deletes the output file if the command failed. That way you can be sure that if it exists, it is correct.
In addition, I would suggest that you use the OUTPUT keyword of add_custom_command to tell CMake that the file is a result of executing the command. (And, if you do that, you don't have to set the GENERATED property manually.)
Inspired by #Lindydancer's answer, I achieved the purpose by multiple COMMANDs in one target, and it don't need to write an external wrapper script.
set(source_file_ok ${source_file}.ok)
add_custom_command(
OUTPUT ${source_file} ${source_file_ok}
DEPENDS ${xs_file} ${xsh_files}
COMMAND rm -f ${source_file_ok}
COMMAND xsubpp ...... >${source_file}
COMMAND touch ${source_file_ok}
)
add_library(${xs_lib} ${source_file})
add_dependencies(${xs_lib} ${source_file} ${source_file_ok})
The custom target has 3 commands. The OK file only exists when xsubpp is success, and this file is added as a dependency of the library. When xsubpp is not success, the dependency on the OK file will force the custom command to be run again.
The only flaw is cross-platform: not all OS have touch and rm, so the name of these two commands should be decided according to OS type.