Boost-build/BJam language - checking the value of a flag - bjam

I need to edit a .jam file used by boost-build for a specific kind of projects. The official manual on BJAM language says:
One of the toolsets that cares about DEF files is msvc. The following line should be added to it. flags msvc.link DEF_FILE
;
Since the DEF_FILE variable is not used by the msvc.link action, we need to modify it to be: actions link bind DEF_FILE { $(.LD) ....
/DEF:$(DEF_FILE) .... } Note the bind DEF_FILE part. It tells bjam to
translate the internal target name in DEF_FILE to a corresponding
filename in the link
So apparently just printing DEF_FILE with ECHO wouldn't work. How can it be expanded to a string variable or something that can actually be checked?
What I need to do is to print an error message and abort the build in case the flag is not set. I tried:
if ! $(DEF_FILE)
{
errors.user-error "file not found" ;
EXIT ;
}
but this "if" is always true
I also tried putting "if ! $_DEF_FILE {...}" inside the "actions" contained but apparently it is ignored.

I am not sure I understand the global task you have. However, if you wanted to add checking for non-empty DEF_FILE -- expanding on the documentation bit you quote, you need to add the check in msvc.link function.
If you have a command line pattern (specified with 'actions') its content is what is passed to OS for execution. But, you can also have a function with the same name, that will be called before generating the actions. For example, here's what current codebase have:
rule link.dll ( targets + : sources * : properties * )
{
DEPENDS $(<) : [ on $(<) return $(DEF_FILE) ] ;
if <embed-manifest>on in $(properties)
{
msvc.manifest.dll $(targets) : $(sources) : $(properties) ;
}
}
You can modify this code to additionally:
if ! [ on $(<) return $(DEF_FILE) ] {
ECHO "error" ;
}

Related

Getting the build type/variant inside a bjam Jamfile / echo a feature?

So, let's say, I call bjam debug, or bjam release, or bjam clean, possibly with other target names, and I'd like to have the build action or type (debug, release, clean) available in a script.
Here https://android.googlesource.com/platform/external/boost/+/ac861f8c0f33538060790a8e50701464ca9982d3/Jamroot I found an example, that I modified like this:
import modules ;
tbuildcmd = "" ;
if clean in [ modules.peek : ARGV ]
{
tbuildcmd = clean ;
}
else if release in [ modules.peek : ARGV ]
{
tbuildcmd = release ;
}
else if debug in [ modules.peek : ARGV ]
{
tbuildcmd = debug ;
}
echo "tbuildcmd $(tbuildcmd)" ;
And this works fine, it seems - but I was wondering, is there a better method to get the build command/type as a variable? For instance, they say in https://www.boost.org/doc/libs/1_35_0/doc/html/bbv2/tutorial.html :
The release and debug that we've seen in bjam invocations are just a shorthand way to specify values of the variant feature. For example, the command above could also have been written this way:
bjam variant=release inlining=off debug-symbols=on
So, there is apparently a "variant" "feature" - but how can I use / echo it? I tried echo $(<variant>) and that failed.

How to fix error message in tcl script having command [exec bjobs] when no jobs are running?

when I am running a Tcl script that contains the following lines:
set V [exec bjobs ]
puts "bjobs= ${V}"
When jobs are present it's working properly but, no jobs are running it is showing an error like this:
No unfinished job found
while executing
"exec bjobs "
invoked from within
"set V [exec bjobs ]"
How to avoid this error? Please let me know how to avoid this kind of errors.
It sounds to me like the bjobs program has a non-zero exit code in this case. The exec manual page includes this example in a subsection WORKING WITH NON-ZERO RESULTS:
To execute a program that can return a non-zero result, you should wrap
the call to exec in catch and check the contents of the -errorcode
return option if you have an error:
set status 0
if {[catch {exec grep foo bar.txt} results options]} {
set details [dict get $options -errorcode]
if {[lindex $details 0] eq "CHILDSTATUS"} {
set status [lindex $details 2]
} else {
# Some other error; regenerate it to let caller handle
return -options $options -level 0 $results
}
}
This is more easily written using the try command, as that makes it
simpler to trap specific types of errors. This is done using code like
this:
try {
set results [exec grep foo bar.txt]
set status 0
} trap CHILDSTATUS {results options} {
set status [lindex [dict get $options -errorcode] 2]
}
I think you could write this as:
try {
set V [exec bjobs ]
} trap CHILDSTATUS {message} {
# Not sure how you want to handle the case where there's nothing...
set V $message
}
puts "bjobs= ${V}"
if {[catch {exec bjobs} result]} {
puts "bjobs have some issues. Reason : $result"
} else {
puts "bjobs executed successfully. Result : $result"
}
Reference : catch
Note carefully in the exec man
page:
If any of the commands in the pipeline exit abnormally or are killed or
suspended, then exec will return an error [...]
If any of the commands
writes to its standard error file and that standard error is not
redirected and
-ignorestderr is not specified, then exec will return an
error.
So if bjobs returns non-zero or prints to stderr when there are no jobs, exec needs catch or try as Donal writes.

zsh: Do I need to close file descriptors?

I use the following code to both output something to stdout, and pipe it to a program:
function example() {
local fd1
{
exec {fd1}>&1
{ echo hi >&$fd1 } | true
} always { exec {fd1}>&- }
}
I am wondering if I can safely drop always { exec {fd1}>&- }. fd1 goes out of scope after the function finishes anyways.
You need to keep always { exec {fd1}>&- }. If you get rid of that, the variable containing the file descriptor will go out of scope, but the file descriptor won't be closed, resulting in leaking it. You can see this by doing ls -l /proc/$$/fd before and after running your function without that line. Each run of the function will permanently add another FD to that list. Eventually, you'll run out of file descriptors and won't be able to open any new ones, which will break things.

Default Representation/Drawing method in VMD

In VMD I want to load every new file with the drawing method CPK. This doesn't seem not to be an option in the .vmdrc file for some technical reasons.
How can I do this from the VMD command line (so that I can make a script)?
Or is there some other solution/workaround/hack to make this work?
There are several ways to achieve what you want:
(1) put the following line in the correct location of your .vmdrc
mol default style CPK
(2) use the VMD Preferences Panel (last item in the Extensions menu of the main window) to generate a .vmdrc file that meets your expectations(s). The setting you're looking for is in the Representations tab.
(3) for more advanced settings (i.e. default settings applied to molecules already loaded when vmd read the startup .vmdrc file), you can use the following (works for me on VMD 1.9.2):
proc reset_viz {molid} {
# operate only on existing molecules
if {[lsearch [molinfo list] $molid] >= 0} {
# delete all representations
set numrep [molinfo $molid get numreps]
for {set i 0} {$i < $numrep} {incr i} {
mol delrep $i $molid
}
# add new representations
mol representation CPK
# add other representation stuff you want here
mol addrep $molid
}
}
proc reset_viz_proxy {args} {
foreach {fname molid rw} $args {}
eval "after idle {reset_viz $molid}"
}
## put a trace on vmd_initialize_structure
trace variable vmd_initialize_structure w reset_viz_proxy
after idle {
if { 1 } {
foreach molid [molinfo list] {
reset_viz $molid
}
}
}
This piece of code is adapted from this Axel Kohlmeyer website.
HTH,
I found a convenient solution.
In .bashrc add:
vmda () {
echo -e "
mol default style CPK
user add key Control-w quit
" > /tmp/vmdstartup
echo "mol new $1" > /tmp/vmdcommand
vmd -e /tmp/vmdcommand -startup /tmp/vmdstartup
}
Look at a structure with
vmda file.pdb
and close the window (quit the application) with Ctrl+w, like other windows.

Unix If file exists, rename

I am working on a UNIX task where i want check if a particular log file is present in the directory or not. If it is present, i would like to rename it by appending a timestamp at the end. The format of the file name is as such: ServiceFileName_0.log
This is what i have so far but it wouldn't rename when i run the script, even though there is a file with the name ServiceFileName_0.log present.
renameLogs()
{
#If a ServiceFileName log exists, rename it
if [ -f $MY_DIR/logs/ServiceFileName_0.log ];
then
mv ServiceFileName_0.log ServiceFileName_0.log.%M%H%S
fi
}
Pls Help!
Thanks
renameLogs()
{
if [ -f $MY_DIR/logs/ServiceFileName_0.log ]
then mv $MY_DIR/ServiceFileName_0.log $MY_DIR/ServiceFileName_0.log.$(date +%M%H%S)
fi
}
Use the directory prefix consistently. Also you need to specify the time properly, as shown.
Better, though (less repetition):
renameLogs()
{
logfile="$MY_DIR/logs/ServiceFileName_0.log"
if [ -f "$logfile" ]
then mv "$logfile" "$logfile.$(date +%H%M%S)"
fi
}
NB: I've reordered the format from MMHHSS to the more conventional HHMMSS order. If you work with date components too, you should seriously consider using the ordering recommended by ISO 8601, which is [YYYY]mmdd. It groups all the log files for a month together in an ls listing, which is usually helpful. Using ddmm order means that the files for the first of each month are grouped together, then the files for the second of each month, etc. This is usually less desirable.
You might need to prefix the file name with the $MY_DIR path, just like you did in the test.
You could replace this:
mv ServiceFileName_0.log ServiceFileName_0.log.%M%H%S
with this
mv $MY_DIR/logs/ServiceFileName_0.log $MY_DIR/logs/ServiceFileName_0.log.%M%H%S
This isn't your apparent immediate problem, but the if construct is wrong: it introduces a time-of-check to time-of-use race condition. In between the if [ -f check and the mv, some other process could come along and change things so you can't move the file anymore even though the check succeeded.
To avoid this class of bugs, always write code that starts by attempting the operation you want to do, then if it failed, figure out why. In this case, what you want is to do nothing if the source file didn't exist, but report an error if the operation failed for any other reason. There is no good way to do that in portable shell, you need something that lets you inspect errno. I'd probably write this C helper:
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main(int argc, char **argv)
{
if (argc != 3) {
fprintf(stderr, "usage: %s source destination\n", argv[0]);
return 2;
}
if (rename(argv[1], argv[2]) && errno != ENOENT) {
fprintf(stderr, "rename '%s' to '%s': %s\n",
argv[1], argv[2], strerror(errno));
return 1;
}
return 0;
}
and then use it like so:
renameLogs()
{
( cd "$MY_DIR/logs"
rename_if_exists ServiceFileName_0.log ServiceFileName_0.log.$(date +%M%H%S)
)
}
The ( cd construct fixes your immediate problem, and unlike the other suggestions, avoids another race in which some other process comes along and messes with the logs directory or its parent directories.
Obligatory shell scripting addendum: Always enclose variable expansions in double quotes, except in the rare cases where you want the expansion to be subject to word splitting.

Resources