scons Alias leading to python exception - scons

AttributeError 'Alias' object has no attribute 'RDirs'' trying to evaluate${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, env, RDirs, TARGET, SOURCE)}'
This results from using the Alias() command that has the same alias name as a Program TARGET. We do this in many places, but in some instances, the above python exception is emitted. this only occurs when attempt to build for two variants (debug and release) simultaneously. Running either a single variant, or renaming the alias to not identically match the name of the Program target will work around the problem. However, as I mentioned, we do this in dozens of SConscripts, but only a few emit the exception.
TARGET = myprog
prog - env.Program(target=TARGET, source=SOURCE)
Alias(TARGET, [prog]))

I was able to solve it by explicitly using the File() command:
TARGET = File(myprog)
prog - env.Program(target=TARGET, source=SOURCE)
Alias(TARGET, [prog]))

Related

Remove outdated intermediate files before the build

I have a project where a lot of the source files needs to be modified by a script before they are compiled.
The build process has 2 steps:
Run a script on the original sources to create intermediate sources.
Compile the intermediate sources.
It works fine when the original source files is modified or a new one is created.
In such cases SCons is able to build / rebuild the appropriate files.
However, when a source file is deleted, the corresponding intermediate file is not removed, which may end in successful build where it should fail due to missing source.
Example:
SConscript:
env = Environment()
source_files = ['main.cc.template', 'some-header.hh.template']
def make_intermediate(env, source):
target = source[:-9] # Remove ".template" from the file name
return env.Command(target, source, Copy("$TARGET", "$SOURCE")) # Modify the source
env.AddMethod(make_intermediate, 'MakeIntermediate')
intermediates = Flatten([env.MakeIntermediate(x) for x in source_files])
env.Program('my-program', intermediates)
main.cc.template:
#include "some-header.hh"
int main() {
return get_number();
}
some-header.hh.template:
inline int get_number() {
return 0;
}
This compiles correctly but if you remove the file some-header.hh.template from the list and from the filesystem, it still compiles while it shouldn't.
You need to manually remove the intermediate file some-header.hh from the file system or else you'll get a false-positive result of build and subsequent tests.
I would like to automate the deletion process to prevent inevitable broken commits that will happen if I won't.
I've managed to create a dirty solution of the problem:
env = Environment()
source_files = ['main.cc.template']
def make_intermediate(env, source):
target = source[:-9] # Remove ".template" from the file name
return env.Command(target, source, Copy("$TARGET", "$SOURCE")) # Modify the source
env.AddMethod(make_intermediate, 'MakeIntermediate')
intermediates = Flatten([env.MakeIntermediate(x) for x in source_files])
# --- The new starts code here ---
old_intermediates = Glob('*.hh') + Glob('*.cc')
intermediates_to_delete = [x for x in old_intermediates if x not in intermediates]
for x in intermediates_to_delete:
x.remove()
# --- The new code ends here ---
env.Program('my-program', intermediates)
This more or less works.
However, the files are removed too late and SCons seem to already be aware of their presence which causes the build error to origin from SCons and not the C++ compiler.
Because of that, the error message is less helpful. Also, I don't know if such operations are good for the stability of the SCons itself.
The error I'm getting is:
scons: *** [main.o] /home/piotr/tmp/some-header.hh: No such file or directory
Is there a clear way to delete outdated intermediate files?
Your approach is more or less correct.
SCons doesn't have any built-in mechanism to remove such dangling intermediate files; you need to write your own.
The error you're getting is caused by the fact you've used the SCons function Glob. It creates File nodes and makes SCons aware of existence of those files.
(Btw, the SCons function remove() is not designed to be called outside of a builder; you shouldn't do that.)
To avoid the problem, you need to delete the file before SCons has a chance to search for it.
You can just replace SCons function with standard Python library, like pathlib.
(It will require some tinkering to convert intermediates to pathlib objects too, but it won't be that much more code.)
A fixed solution:
env = Environment()
source_files = ['main.cc.template']
def make_intermediate(env, source):
target = source[:-9] # Remove ".template" from the file name
return env.Command(target, source, Copy("$TARGET", "$SOURCE")) # Modify the source
env.AddMethod(make_intermediate, 'MakeIntermediate')
intermediates = Flatten([env.MakeIntermediate(x) for x in source_files])
# --- The new starts code here ---
from pathlib import Path
old_intermediates = list(Path.cwd().glob('*.hh')) + list(Path.cwd().glob('*.cc'))
current_intermediates = [Path(x.get_path()).resolve() for x in intermediates]
intermediates_to_delete = [x for x in old_intermediates if x.resolve() not in current_intermediates]
for x in intermediates_to_delete:
print('unlink:', x)
x.unlink()
# --- The new code ends here ---
env.Program('my-program', intermediates)
This gives the expected error message:
main.cc:1:10: fatal error: some-header.hh: No such file or directory
1 | #include "some-header.hh"
| ^~~~~~~~~~~~~~~~
compilation terminated.
scons: *** [main.o] Error 1

Why do OpenGL-based VTK targets in drake executed via `bazel test` sometimes fail on Linux?

While a binary works with bazel run, when I run a test using bazel test, such as:
$ bazel test //systems/sensors:rgbd_camera_test
I encounter a slew of errors from VTK / OpenGL:
ERROR: In /vtk/Rendering/OpenGL2/vtkXOpenGLRenderWindow.cxx, line 820
vtkXOpenGLRenderWindow (0x55880715b760): failed to create offscreen window
ERROR: In /vtk/Rendering/OpenGL2/vtkOpenGLRenderWindow.cxx, line 816
vtkXOpenGLRenderWindow (0x55880715b760): GLEW could not be initialized.
ERROR: In /vtk/Rendering/OpenGL2/vtkShaderProgram.cxx, line 453
vtkShaderProgram (0x5588071d5aa0): Shader object was not initialized, cannot attach it.
ERROR: In /vtk/Rendering/OpenGL2/vtkOpenGLRenderWindow.cxx, line 1858
vtkXOpenGLRenderWindow (0x55880715b760): Hardware does not support the number of textures defined.
May I ask why this happens?
(Note: This post is a means to migrate from http://drake.mit.edu/faq.html to StackOverflow for user-based questions.)
The best workaround at the moment is to first mark the test as as local in the BUILD.bazel file, either with local = 1, or tags = [.., "local"]. Doing so will make the specific target run without sandboxing, such that it has an environment similar to that of bazel run.
As an example, in systems/sensors/BUILD.bazel:
drake_cc_googletest(
name = "rgbd_camera_test",
# ...
local = 1,
# ...
)
If this does not work, then try running the test in Bazel without sandboxing:
$ bazel test --spawn_strategy=standalone //systems/sensors:rgbd_camera_test
Please note that you can possibly add --spawn_strategy=standalone to your ~/.bazelrc, but be aware that this means your development testing environment may deviate even more from other developer's testing environments.

Win10: ASDF can't load system (ASDF_OUTPUT_TRANSLATION error)

Update 2
I think #faré is right, it's an output translation problem.
So I declared the evironment variable ASDF_OUTPUT_TRANSLATIONS and set it to E:/. Now (asdf:require-system "my-system") yields a different error: Uneven number of components in source to destination mapping: "E:/" which led me to this SO-topic.
Unfortunately, his solution doesn't work for me. So I tried the other answer and set ASDF_OUTPUT_TRANSLATIONS to (:output-translations (t "E:/")). Now I get yet another error:
Invalid source registry (:OUTPUT-TRANSLATIONS (T "E:/")).
One and only one of
:INHERIT-CONFIGURATION or
:IGNORE-INHERITED-CONFIGURATION
is required.
(will be skipped)
Original Posting
I have a simple system definition but can't get ASDF to load it.
(asdf-version 3.1.5, sbcl 1.3.12 (upgraded to 1.3.18 AMD64), slime 2.19, Windows 10)
What I have tried so far
Following the ASDF manual: "4.1 Configuring ASDF to find your systems"
There it says:
For Windows users, and starting with ASDF 3.1.5, start from your
%LOCALAPPDATA%, which is usually ~/AppData/Local/ (but you can ask in
a CMD.EXE terminal echo %LOCALAPPDATA% to make sure) and underneath
create a subpath config/common-lisp/source-registry.conf.d/
That's exactly what I did:
Echoing %LOCALAPPDATA% which evaluates to C:\Users\my-username\AppData\Local
Underneath I created the subfolders config\common-lisp\source-registry.conf.d\ (In total: C:\Users\my-username\AppData\Local\config\common-lisp\source-registry.conf.d\
The manual continues:
there create a file with any name of your choice but with the type conf, for instance 50-luser-lisp.conf; in this file, add the following line to tell ASDF to recursively scan all the subdirectories under /home/luser/lisp/ for .asd files: (:tree "/home/luser/lisp/")
That’s enough. You may replace /home/luser/lisp/ by wherever you want to install your source code.
In the source-registry.conf.d folder I created the file my.conf and put in it (:tree "C:/Users/my-username/my-systems/"). This folder contains a my-system.asd.
And here comes the weird part:
If I now type (asdf:require-system "my-system") in the REPL I get the following error:
Can't create directory C:\Users\my-username\AppData\Local\common-lisp\sbcl-1.3.12-win-x86\C\Users\my-username\my-systems\C:\
So the problem is not that ASDF doesn't find the file, it does -- but (whatever the reason) it tries to create a really weird subfolder hierarchy which ultimately fails because at the end it tries to create the folder C: but Windows doesn't allow foldernames containing a colon.
Another approach: (push path asdf:*central-registry*)
If I try
> (push #P"C:/Users/my-username/my-systems/" asdf:*central-registry*)
(#P"C:/Users/my-username/my-systems/"
#P"C:/Users/my-username/AppData/Roaming/quicklisp/quicklisp/")
> (asdf:require-system "my-system")
I get the exact same error.
I don't know what to do.
Update
Because of the nature of the weird path ASDF was trying to create I thought maybe I could bypass the problem by specifying a relative path instead of an absolute one.
So I tried
  (:tree "\\Users\\my-username\\my-systems")
in my conf file. Still the same error.
Ahem. It looks like an output-translations problem.
I don't have a Windows machine right now, but this all used to work last time I tried.
Can you setup some ad hoc output-translations for now that will make it work?

Example waf project with vala

there is a nice waf vala example here:
https://code.launchpad.net/~asabil/vala/vala-project-template.waf
and it shows a library and an application in vala. Unfortunately the program in this example does not actually USE the library (which defines method "hello"). When I try to call it from the program, I get compilation errors.
I am not able to modify the wscript's to load the library properly. What is the trick here? Thanks.
What I have added is this line in the program:
My.Lib.hello();
But it won't compile:
Waf: Entering directory `/home/lzap/work/shellmail/TEST/vala-template/_build_'
[1/6] valac: src/hello-gtk.vala -> _build_/default/src/hello-gtk.c
../src/hello-gtk.vala:16.9-16.10: error: The name `My' does not exist in the context of `Sample.create_widgets._lambda0_'
Waf: Leaving directory `/home/lzap/work/shellmail/TEST/vala-template/_build_'
Build failed: -> task failed (err #1):
{task: valac_task hello-gtk.vala -> hello-gtk.c}
I guess I need to change the program wscript:
#!/usr/bin/env python
def build(bld):
prog = bld(features='cc cprogram')
# symbolic name used to reference this object
prog.name = 'hello-gtk.program'
# name of the resulting program
prog.target = 'hello-gtk'
prog.source = 'hello-gtk.vala'
# libraries to link against
prog.uselib = 'GTK+'
# Vala packages to use
prog.packages = 'gtk+-2.0'
# Extra vapi dirs
#prog.vapi_dirs = '../my_lib'
# Enable threading
#prog.threading = True
The hello method is not an static method, but an instance method, so, you need to create a My.Lib instance first and then call the method.
var obj = new My.Lib();
obj.hello();
If this still failing, try to add using My; on hello-gtk.vala.

SCons manual build step

Is it possible to get SCons to remind me to perform a manual step using it's dependancy tracking?
My build uses the .swc output from a .fla, which you can't do using a command-line.
I tried something like:
env.Command(target, sources + SHARED_SOURCES,
Action(lambda target, source, env: 1, "Out of date: $TARGET"))
But with that method, I have to use Decider('make') or I get:
$ scons --debug=explain
scons: rebuilding `view_bin\RoleplaySkin.swc' because `view_src\RoleplaySkin.fla' changed
Out of date: view_bin\RoleplaySkin.swc
scons: *** [view_bin\RoleplaySkin.swc] Error 1
And, more importantly, SCons never realizes it's cache is out of date, so any change in the Environment or sources since it wrote the signature in .sconsign.dblite means it will allways try to rebuild (and therefore, always fail).
What about using the Precious method to protect the *.swc output before converting it into a *.fla?
How about creating your own RemindMe builder which reminds you and fails to build the target?
It would look something like this:
def remind_me(target, source, env):
os.remove(target.abspath) #we do not build, we destroy
print ("This is a friendly reminder, your $SOURCE is out of date, run manual build step")
return None
reminder = Builder(action = remind_me,
suffix = '.swc',
src_suffix = '.fla')
env = Environment(BUILDERS = {'RemindMe' : reminder})
#Run builder like this
swc_file = env.RemindMe('some_fla_file')
final_target = env.BuildWithSWC(some_other_target,swc_file)
This is however only a theory, I have never tried actually deleting the target instead of creating it. It might be worth a try at least.

Resources