How to run post build commands in meson? - meson-build

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.

Related

meson and git information

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

Execute root commands to link before starting execution

Is there a way to tell root to execute (say) the following commands at the start?
.L /usr/lib/libgsl.so
.L /usr/lib/libgslcblas.so
I find it convenient as I have to execute this every time I start root. My .C file has uses these libraries.
I found an option -e but I cannot use it for more than one line of commands.
Sure, just add the following into a ~/.rootlogon.C (or create one in case you don't have it):
{
// old content here
gROOT->ProcessLine(".L /usr/lib/libgsl.so");
gROOT->ProcessLine(".L /usr/lib/libgslcblas.so");
}

Running a python script as part of a cmake build

I'm using cmake for the first time and am just not having luck finding examples that help me figure out what I'm doing wrong. The functionality seems very basic, but nothing I've tried thus far has given me any meaningful output or error.
I have a PRELOAD command for a document, and this works fine as long as the document has already been created.
set(variable_name
PRELOAD ${_source_directory}/Documents/output.txt AS output.txt
)
But I want the document generation(which is accomplished via a python script) to be part of the cmake build process as well. The command I want to run is
python_script.py ${_source_directory}/Documents/input.txt
${_source_directory}/Documents/output.txt
and I want that to run before the PRELOAD statement is executed.
Here's an example of what I've tried
add_custom_command(
OUTPUT ${_source_directory}/Documents/output.txt
COMMAND python_script.py ${_source_directory}/Documents/input.txt
${_source_directory}/Documents/output.txt
)
set(variable_name
PRELOAD ${_source_directory}/Documents/output.txt AS output.txt
)
But that gives me the same error as if the add_custom_command wasn't even there ("No rule to make target ${_source_directory}/Documents/output.txt").
You do/understand it wrong. As it was mentioned in comments set() has nothing like PRELOAD.
The correct way is to use add_custom_target() which would produce an output.txt in desired directory and then add_dependencies() for target you want to build and which would use the output.txt.

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.

How to write a custom command that runs whenever a file A is newer than file B?

I need to write a custom command that runs whenever file A is newer than file B.
How do I do this in CMake?
Sounds like you want something similar to this:
add_custom_command(OUTPUT B
COMMAND ${CMAKE_COMMAND} -Dinput=A -P script_that_generates_B.cmake
DEPENDS A
)
Where "B" is the full path to the output file, "A" is the full path to some input file, and the command is something that runs at build time to produce B whenever A changes.
In order for the rule producing B to be executed at build time, something else must depend on B also. It should appear either as a DEPENDS of an add_custom_target that is in "all" or as a source file to an add_library or add_executable command to trigger the command to run.
EDIT:
You can also use the
if(file1 IS_NEWER_THAN file2)
construct at CMake configure time, if necessary. The documentation of the IF command is rather lengthy, but searching on this page for IS_NEWER_THAN yields this nugget:
"True if file1 is newer than file2 or if one of the two files doesn't exist. Behavior is well-defined only for full paths."