How do I derive an executable name from a source file in Meson build? - meson-build

I'm trying to create a list of unit test targets in Meson, with each test case built from a single source file. The source files are defined with a files() command in a subdirectory:
my_test_files = files(['test_foo.c','test_bar.c','test_baz.c'])
What I'd like to do is something like this in the top-level build:
foreach t_file : my_test_files
t_name = t.split('.')[0]
test(t_name, executable(t_name, t_file, ...))
endforeach
I know it's possible to do this if the file names are plain strings, but the above approach fails with a 'File object is not callable' error.
Is there a more 'Mesonic' way to derive the executable / test name from the source file name?

It should work if you define your variable simply as array, e.g.:
my_test_files = ['test_foo.c','test_bar.c','test_baz.c']
the loop stays the same, except some typo fixed with:
foreach t_file : my_test_files
t_name = t_file.split('.')[0]
test(t_name, executable(t_name, t_file, ...))
endforeach
instead of building array of file objects. This is because executable() accepts input files in many forms: as file objects (which you tried to do) and as strings either source files (that should be compiled) or object files (to be linked) - detected by file name extension.
For more flexibility and better control, one can use array of arrays (which is, of course, extendable and may contain anything that is needed to generate tests):
foo_files = files('test_foo.c')
bar_files = files('test_bar.c')
baz_files = files('test_baz.c')
test_files = [
['foo', foo_files, foo_deps],
['bar', bar_files, []],
['baz', baz_files, baz_deps]]
foreach t : test_files
test(t[0], executable(t[0], t[1], dependencies=t[2], ...))
endforeach

Related

After Reading a *.lst file(multiple lines with different filenames along with its path),How to find specific filename with its path in CMAKE?

Lets Consider a lst file "txt_filelist.lst" which has different text files mentioned with different path's, Now After reading the "txt_filelist.lst" file how to identify a specific text file along with its path in CMAKE?
txt_filelist.lst File:
`variants\EXX\application\a2l\srcxx_xx_xx\xx_xx_xx.txt`
`variants\EXX\application\a2l\srcxx_xx_xx\xx_xx_xx.txt`
`variants\EXX\application\a2l\srcxx_xx_xx\xx_xx_xx.txt`
`variants\EXX\application\a2l\srcxx_xx_xx\xx_xx_xx.txt`
After reading the lst file txt_filelist.lst How can I first identify the srcxx_xx_xx.txt in the lst and then secondly How can I fetch its entire path as variants\EXX\application\a2l\srcxx_xx_xx\xx_xx_xx.txt in CMAKE?
Thanks in Advance..!!!
You can use file(STRINGS) to read the lines of the file to a list variable. get_filename_component can be used to separate file names according to your needs. Using file(TO_NATIVE_PATH) may be necessary, if you use get_filename_component in a way that yields a path containing separators, but most tools should be able to work with forward slashes, even on Windows:
file(STRINGS txt_filelist.lst FILE_LINES LENGTH_MINIMUM 1)
message("=========================")
foreach(LINE IN LISTS FILE_LINES)
get_filename_component(FILE_NAME "${LINE}" NAME)
get_filename_component(FILE_DIR "${LINE}" DIRECTORY)
file(TO_NATIVE_PATH "${LINE}" FILE_PATH_NATIVE)
message(
"------------------------
LINE = '${LINE}'
FILE_NAME = '${FILE_NAME}'
FILE_DIR = '${FILE_DIR}'
FILE_PATH_NATIVE = '${FILE_PATH_NATIVE}'
"
)
endforeach()
message("=========================")
Note: The LENGTH_MINIMUM 1 option is there to ignore empty lines. This may not be necessary depending on the input you get.

CMake: How can I compile defines and flags as string constants into my C(++) program?

I'd like my C or C++ program that is built via CMake to be able to print (or otherwise make use of) the macro definitions and (other) C/C++ flags it was compiled with. So I want CMake to generate/configure a header or source file that defines respective strings constants and that is then built as part of/into my program.
CMake features several commands (like file() or execute_process()) that would be executed when (respectively before) the build system is generated and thus would allow me to write such a source file, but I'm having trouble with getting the effective macro definitions and flags used for my target. E.g. there seem to be COMPILE_DEFINITIONS for the directory, the target, and for the configuration. Is there a way to get the macro definitions/C(++) flags that are effectively used for building my target? And how do I best write them into a source file?
I've noticed, when using the Makefiles generator apparently a file "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/MyTarget.dir/flags.make" is created, which seems to contain pretty much what I'm looking for. So if there's no other way, I can probably make use of that file, but obviously that won't work for other generators and it comes with its own challenges (the file is generated after execute_process()).
The approach I finally went with sets the CXX_COMPILER_LAUNCHER property to use a compiler wrapper script that injects the actual compiler command line into a source file. Since I have multiple libraries/executables to which I want to add the respective information, I use a CMake function that adds a source file containing the info to the target.
function(create_module_build_info _target _module _module_include_dir)
# generate BuildInfo.h and BuildInfo.cpp
set (BUILD_MODULE ${_module})
set (BUILD_MODULE_INCLUDE_DIR ${_module_include_dir})
configure_file(${CMAKE_SOURCE_DIR}/BuildInfo.h.in
${CMAKE_BINARY_DIR}/include/${_module_include_dir}/BuildInfo.h
#ONLY)
configure_file(${CMAKE_SOURCE_DIR}/BuildInfo.cpp.in
${CMAKE_CURRENT_BINARY_DIR}/BuildInfo.cpp
#ONLY)
# Set our wrapper script as a compiler launcher for the target. For
# BuildInfo.cpp we want to inject the build info.
get_property(_launcher TARGET ${_target} PROPERTY CXX_COMPILER_LAUNCHER)
set_property(TARGET ${_target} PROPERTY CXX_COMPILER_LAUNCHER
${CMAKE_SOURCE_DIR}/build_info_compiler_wrapper.sh ${_launcher})
get_property(_compile_flags SOURCE BuildInfo.cpp PROPERTY COMPILE_FLAGS)
set_property(SOURCE BuildInfo.cpp PROPERTY COMPILE_FLAGS
"${_compile_flags} -D_BUILD_INFO=${CMAKE_CURRENT_BINARY_DIR}/BuildInfo_generated.cpp,${_module}")
# add BuildInfo.cpp to target
target_sources(${_target} PRIVATE BuildInfo.cpp)
endfunction()
The function can simply be called after defining the target. Parameters are the target, a name that is used as a prefix of the constant name to be generated, and a name that is part of the path of the header file to be generated. The compiler flag -D_BUILD_INFO=... is only added to the generated source file and it will be used by the wrapper script as an indicator that the constant definition should be added to that source file. All other compiler lines are just invoked as is by the script.
The template source file "BuildInfo.cpp.in":
#include "#BUILD_MODULE_INCLUDE_DIR#/BuildInfo.h"
The template header file "BuildInfo.h.in":
#pragma once
#include <string>
extern const std::string #BUILD_MODULE#_COMPILER_COMMAND_LINE;
The compiler wrapper script "build_info_compiler_wrapper.sh":
#!/usr/bin/env bash
set -e
function createBuildInfoTempFile()
{
local source="$1"
local target="$2"
local prefix="$3"
local commandLine="$4"
cp "$source" "$target"
cat >> "$target" <<EOF
const std::string ${prefix}_COMPILER_COMMAND_LINE = "$commandLine";
EOF
}
# Process script arguments. We copy them to array variable args. If we find an
# argument "-D_BUILD_INFO=*", we remove it and will inject the build info
# variable definition into (a copy of) the input file.
generateBuildInfo=false
buildInfoTempFile=
buildInfoVariablePrefix=
args=()
while [ $# -ge 1 ]; do
case "$1" in
-D_BUILD_INFO=*)
if [[ ! "$1" =~ -D_BUILD_INFO=([^,]+),(.+) ]]; then
echo "error: failed to get arguments for build info generation" >&2
exit 1
fi
generateBuildInfo=true
buildInfoTempFile="${BASH_REMATCH[1]}"
buildInfoVariablePrefix="${BASH_REMATCH[2]}"
shift
continue
;;
esac
args+=("$1")
shift
done
if $generateBuildInfo; then
# We expect the last argument to be the source file. Check!
case "${args[-1]}" in
*.c|*.cxx|*.cpp|*.cc)
createBuildInfoTempFile "${args[-1]}" "$buildInfoTempFile" "$buildInfoVariablePrefix" "${args[*]}"
args[-1]="$buildInfoTempFile"
;;
*)
echo "error: Failed to find source file in compiler arguments for build info generation feature." >&2
exit 1
;;
esac
fi
"${args[#]}"
Obviously the script can be made smarter. E.g. instead of assuming it is the last argument it could find the actual index of the input source file. It could also process the command line to separate preprocessor definitions, include paths, and other flags.
Note that "-D_BUILD_INFO=..." argument is used instead of some parameter that the compiler wouldn't know (e.g. "--generate-build-info"), so that IDEs won't run into issues when passing the arguments directly to the compiler for whatever purposes.

Meson equivalent of automake's CONFIG_STATUS_DEPENDENCIES?

I have a project whose build options are complicated enough that I have to run several external scripts during the configuration process. If these scripts, or the files that they read, are changed, then configuration needs to be re-run.
Currently the project uses Autotools, and I can express this requirement using the CONFIG_STATUS_DEPENDENCIES variable. I'm experimenting with porting the build process to Meson and I can't find an equivalent. Is there currently an equivalent, or do I need to file a feature request?
For concreteness, a snippet of the meson.build in progress:
pymod = import('python')
python = pymod.find_installation('python3')
svf_script = files('scripts/compute-symver-floor')
svf = run_command(python, svf_script, files('lib'),
host_machine.system())
if svf.returncode() == 0
svf_results = svf.stdout().split('\n')
SYMVER_FLOOR = svf_results[0].strip()
SYMVER_FILE = svf_results[2].strip()
else
error(svf.stderr())
endif
# next line is a fake API expressing the thing I can't figure out how to do
meson.rerun_configuration_if_files_change(svf_script, SYMVER_FILE)
This is what custom_target() is for.
Minimal example
svf_script = files('svf_script.sh')
svf_depends = files('config_data_1', 'config_data_2') # files that svf_script.sh reads
svf = custom_target('svf_config', command: svf_script, depend_files: svf_depends, build_by_default: true, output: 'fake')
This creates a custom target named svf_config. When out of date, it runs the svf_script command. It depends on the files in the svf_depends file object, as well as
all the files listed in the command keyword argument (i.e. the script itself).
You can also specify other targets as dependencies using the depends keyword argument.
output is set to 'fake' to stop meson from complaining about a missing output keyword argument. Make sure that there is a file of the same name in the corresponding build directory to stop the target from always being considered out-of-date. Alternatively, if your configure script(s) generate output files, you could list them in this array.

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 does one load some variables at runtime in Photoshop Script?

I have about 200 folders with X images in each of them.
I have a master script in the root folder that does some stuff to the images.
Each folder has some variables specific to it and its contents.
I want my master script, when it parses folder Y, load some sort of a config file from within folder Y to get those variables, then when folder Z is to be parsed, load the config file from that one.
I know of #include "config.jsx" that I use at the moment to load it but its at the beginning of the script, I need something dynamic and doesn't need to be a jsx at all.
I store all my parameters in xml format and read that in using the XML objects in extendscript. As long as your parameters file is always named something like 'config.xml' it is easily located.
var file = new File( /c/folder/file.xml );
file.open("r");
var str = file.read();
var xml = new XML(str);