Example waf project with vala - linux

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.

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

Scons Install Builder with hard link support

I am using Scons for building an environment which include propagating a partial directory structure including hard links.
So it looks like this, I compile some sources into $BIN directory, some of the created targets are hard links, and in some other module I am scanning the $BIN directory and triggering a builder which either strip the the binaries to the new target, but maintain hard links. So if there are two files which are hard links in source, it copies the first and create hard link to the other target for the second.
Now the problem is if I try to run this with -j4 for example, a race condition could happen, because at the moment the builder tries to create a hard link, the target which is created by strip is not done yet.
Below is my builder:
def GenerateM3Strip(target, source, env):
if type(source) is list:
source = source[0]
if type(target) is list:
target = target[0]
src_stat = os.stat(source.abspath)
if (src_stat.st_nlink > 1
and src_stat.st_ino in GenerateM3Strip.inodes_dict):
previous_target = GenerateM3Strip.inodes_dict[src_stat.st_ino]
if target.get_dir().get_path() in previous_target:
source = previous_target[target.get_dir().get_path()]
print('LinkTarget: %s %s' % (source.get_path(), target.get_path()))
try:
os.unlink(target.get_path())
except Exception:
pass
os.link(source.get_path(), target.get_path())
return
# We have to keep a dictionary of target directory and target pairs, to
# support separate hard links for different directory targets, for example:
# fsdata/default and fsdata/bench
GenerateM3Strip.inodes_dict[src_stat.st_ino] = {
target.get_dir().get_path(): target}
action_str = env.subst(cross + 'strip -o $TARGET $SOURCE',
source=source, target=target)
env.Execute(env.Action(action_str))
GenerateM3Strip.inodes_dict = {}

Unable to load so file from Java in Eclipse On Ubuntu

I have some code that tries to load a C library as follows :-
public ThreadAffinity() {
ctest = (CTest) Native.loadLibrary("ctest", CTest.class);
}
However I get the following error when trying to build the project; The error I get is as follows :-
UnsatisfiedLinkError: Unable to load library 'libctest': liblibctest.so: cannot open shared object file: No such file or directory
at com.sun.jna.NativeLibrary.loadLibrary(NativeLibrary.java:166)
at com.sun.jna.NativeLibrary.getInstance(NativeLibrary.java:239)
at com.sun.jna.Library$Handler.<init>(Library.java:140)
at com.sun.jna.Native.loadLibrary(Native.java:393)
at com.sun.jna.Native.loadLibrary(Native.java:378)
at com.threads.ThreadAffinity.<init>(ThreadAffinity.java:11)
at com.threads.ThreadAffinity.main(ThreadAffinity.java:45)
The current working directory is the root of the project and thats where the so file is located. I also tried modifying the LD_PRELOAD variable to point to my so file; however the error persists.
It works just fine on my OSX where the dylib is located exactly where the so file is currently(project root).
What am I doing wrong?
From the exception:
UnsatisfiedLinkError: Unable to load library 'libctest': liblibctest.so: cannot open shared object file: No such file or directory
It implies you used something like:
public ThreadAffinity() {
ctest = (CTest) Native.loadLibrary("libctest", CTest.class);
}
and not:
public ThreadAffinity() {
ctest = (CTest) Native.loadLibrary("ctest", CTest.class);
}
hence you see the JNA added prefix of lib and postfix of .so added to libctest (liblibctest.so)
LD_PRELOAD is used when you want to prefer one particular version of the same shared library over another, which doesn't apply here.
Define jna.library.path to point to your project root, and JNA should be able to find it.
Also make sure your library has been built as libctest.so and wasn't inadvertently named libctest.dylib.

What directory should I use for "error: 'extra_PROGRAMS' is used but 'extradir' is undefined"?

I have a autoconf/automake system that has a stand-alone target called stand. I don't want stand to be normally built, so I have this in my Makefile.am:
bin_PROGRAMS = grace
extra_PROGRAMS = stand
...
stand_SOURCES = stand.cpp barry.cpp ...
This has worked for a while, but automake just got updated on my system and I'm now getting this error:
src/Makefile.am:4: error: 'extra_PROGRAMS' is used but 'extradir' is undefined
src/Makefile.am:66: warning: variable 'stand_SOURCES' is defined but no program or
src/Makefile.am:66: library has 'stand' as canonical name (possible typo)
So I added this:
extradir = .
But that has caused problems.
I don't want the stand program installed. It's just a test program for me. But it's not part of a formal test suite, it's just for my own purposes. What should I do?
We found the bug! It turns out that extra needs to be capitalized, like this:
bin_PROGRAMS = grace
EXTRA_PROGRAMS = stand
...
stand_SOURCES = stand.cpp barry.cpp ...
You could try conditionally building it:
noinst_PROGRAMS=
if BUILD_STAND
noinst_PROGRAMS += stand
endif
stand_SOURCES = stand.cpp barry.cpp ...
This will not install it since it's in noinst_PROGRAMS and others will normally not build it since BUILD_STAND will normally not be defined for them.

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