SCons manual build step - scons

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.

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

Getting error " not enough arguments in call to s.statsd.SendLoop" when running "go build" command

I'm trying to run go build command for my project but it exits with below error.
alpha#GHOST-RIDER:~/GoWorkspace/src/github.com/hyperledger/firstproject$ go build
# github.com/hyperledger/fabric-sdk-go/internal/github.com/hyperledger/fabric/core/operations
../fabric-sdk-go/internal/github.com/hyperledger/fabric/core/operations/system.go:227:23: not enough arguments in call to s.statsd.SendLoop
have (<-chan time.Time, string, string)
want (context.Context, <-chan time.Time, string, string)
Any help would be appreciated.
As per code fabric is using the different version of this library: github.com/go-kit/kit/metrics/statsd. If you follow the System struct's statsd attribute, you can reach the reference on imports.
In master branch of this lib, SendLoop function requires 4 attributes, so that's the root cause. So this causes error when you compile on your local environment.
I had the same issue and worked around it by checking out a tag of library as below:
cd $GOPATH/src/github.com/go-kit/kit
git fetch --tags
git checkout v0.8.0
found a solution on the hyperledger-fabric-go-sdk group chat.
Add context.Background() in s.statsd.SendLoop like below
s.statsd.SendLoop(context.Background(), s.sendTicker.C, network, address)
in fabric-sdk-go/internal/github.com/hyperledger/fabric/core/operations/system.go file at line 227.
I had a same issue, my solution worked and don't need edit fabric source code.
specify github.com/go-kit/kit to v0.8.0, modify go.mod:
replace github.com/go-kit/kit => github.com/go-kit/kit v0.8.0 // you specific version
require (
... ...
// Maybe other version, go mod tidy update automatically, don't care it.
github.com/go-kit/kit v0.9.0 // indirect
... ...
)
then it worked.

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.

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.

Alias dependencies

I have some complex aliases ex.
Alias('build', [ Program(), Install()...])
Alias('test', [Program(), Install(), RunTest()]
Alias('dist', [Install()])
and finally
Alias('all', [ Alias('build'), Alias('test'), Alias('dist')])
Question:
How to depend Alias('dist') on Alias('test') in Alias('all') ?
I've tried Depends() variations but it seems I've done something wrong.
cheers
P.
UPDATE:
I've managed that by myself.
build = Alias('build', [ Program(), Install()...])
test = Alias('test', [Program(), Install(), RunTest()]
dist = Alias('dist', [Install()])
Depends(test, build)
Depends(dist, test)
Default('dist')
I tend to make named targets for everything (with the dependencies) and then Alias the targets that I want to publish to whoever is running SCons.
prog = env.Program(..., libs)
install = env.Install(..., prog)
test = env.RunTest(..., libs)
Alias('build', prog)
Alias('test', test)
Alias('dist', [ test, install, bump_version ])
I don't know that there's a reason to prefer one method over the other. To me, it seems more natural to set up the dependencies internally, then use Alias to publish the targets that need to be user runnable.

Resources