SCons as an egg in zc.buildout - scons

Is there an easy way to install SCons as an egg using zc.buildout? My initial thought was that since it uses distutils I would be able to install it using zc.recipe.egg and thought that the egg would be set up in such a way that the SCons scripts go to ${buildout:directory}/bin and SCons gets added to the PYTHONPATH.
[buildout]
parts =
python
[python]
recipe = zc.recipe.egg
interpreter = mython
eggs =
SCons == 2.0.1
Unfortunately, I don't think SCons' setup.py is written in such a way that it works well with zc.recipe.egg. I end up with:
${buildout:directory}/eggs/scons-2.0.1-py2.6.egg/
${buildout:directory}/eggs/scons-2.0.1-py2.6.egg/scons-2.0.1/
${buildout:directory}/eggs/scons-2.0.1-py2.6.egg/scons-2.0.1/SCons/
${buildout:directory}/eggs/scons-2.0.1-py2.6.egg/EGG-INFO/scripts/
This would work if (2) were on PYTHONPATH and the contents of (4) were copied or linked to the bin directory.
Ideally, I would like to install this as an egg to make use of my global eggs-directory; I don't want to have several copies of the same build tool. Is it possible to accomplish this goal using existing recipes, or should I write my own recipe?
EDIT: I made a personal copy and modified SCons' setup.py arguments so that a scons entry point will be created. The only changes I made: remove 'cmdclass', add 'entry_points'.
arguments = {
'name' : "scons",
...
'scripts' : scripts,
'entry_points' : {
'console_scripts':
['scons = SCons.Script:main']
}
}
This kind of works. It gives me a scons script in bin/scons, but not sconsign, scons-time, or scons.bat. I put it in a tar in /var/www/eggs and serve it with apache.
[buildout]
parts =
python
[python]
recipe = zc.recipe.egg:scripts
interpreter = mython
eggs =
scons == 2.0.1
find-links =
http://localhost/eggs/
Not sure if I want to continue in this direction.

Oh my. I looked into the setup.py for SCons, and it is a bit of a mess. It even stubbornly only installs in /usr/local when installing on a Mac. It certainly is not suitable for use with setuptools (and thus zc.buildout).
You can use zc.recipe.command to run the setup.py script with ${buildout:executable} setup.py and configure it to install in a parts subdir, then use a separate part to symlink all the scripts into bin/:
[buildout]
parts = scons
[scons-download]
recipe = gocept.download
url = http://prdownloads.sourceforge.net/scons/scons-2.0.1.tar.gz
md5sum = beca648b894cdbf85383fffc79516d18
[scons-install]
recipe = plone.recipe.command
command = ${buildout:executable} ${scons-download:location}/setup.py install --prefix=${buildout:parts-directory}/scons-install
location = ${buildout:parts-directory}/scons-install
[scons]
recipe = cns.recipe.symlink
symlink =
scons
scons-time
sconsign
symlink_base = ${scons-install:location}/bin
symlink_target = ${buildout:bin-directory}
So, we ignore setuptools altogether, do not build an egg, but instead just download the tarball, run setup.py manually, then symlink the interesting parts.

Related

Purify build using scons

I need to do purify build using SCons. Normally in nmake we would do
Nmake install -purify_7.0.1.0-008
How to do the same in SCons? Do I need to add any change in SConstruct file?
You'll need to prefix SHCC,CC, SHCXX, CXX, SHLINK, LINK with purify, and likely add the path to your purify binary to env['ENV']['PATH']
You'll need to do this anywhere (in the main SConstruct, all SConscripts, and if you have any code in site_scons) which creates an Environment() to use.
If you create one Enviroment() and that gets exported to your SConscripts where it's then env.Clone()'d, then you'd only have to change it in the initial env=Environment()
Here's an example (not tested):
env=Environment() # this is your existing code
for v in ['SHCC','CC','SHCXX','CXX','LINK','SHLINK']:
orig_value = env.subst('$%s'%v)
env['v'] = "purify "+ orig_value
print("Changing $%s from :\n%s\nto:\n%s",v, orig_value, env['v'])

Pypi package : where is my executable?

(Archlinux/Python3.5)
I'm working on a small Python3 project made up of only one Python file . With the help of tutorials like this one, I've created a Pypi package with the following commands :
$ python setup.py sdist bdist_wheel register -r pypi (ok, no error msg)
$ python setup.py sdist bdist_wheel upload -r pypi (ok, no error msg)
... and I thought I would juste have to write :
$ sudo pip install katal (ok, no error msg)
and then, e.g. :
$ katal --version
... in order to use it.
But the last command fails : there's no katal or Katal command; if I take a look at /usr/lib/Python3.5/site-packages/ , I only see the following files (no .py file have been installed !) :
/usr/lib/python3.5/site-packages/Katal-0.0.9.dist-info/DESCRIPTION.rst
/usr/lib/python3.5/site-packages/Katal-0.0.9.dist-info/METADATA
/usr/lib/python3.5/site-packages/Katal-0.0.9.dist-info/RECORD
/usr/lib/python3.5/site-packages/Katal-0.0.9.dist-info/WHEEL
/usr/lib/python3.5/site-packages/Katal-0.0.9.dist-info/metadata.json
/usr/lib/python3.5/site-packages/Katal-0.0.9.dist-info/top_level.txt
I've obviously forgotten something... But what ? My setup.py clearly defines where is the unique package of my project (=take everything but the test directory, including the katal sub-directory) :
packages=find_packages(exclude=['tests*']),
Any help would be appreciated !
in your setup.py, there is a section which is commented out:
...
##entry_points={
## 'console_scripts': [
## 'sample=sample:main',
## ],
##
...
This is where I would normally define an executable, please see this tutorial. You can also define a scripts argument to setup which works a little differently (and might match your use case a little better), but that is covered in the tutorial I linked to.

How to add a new library using Yocto

I am using Yocto and I just would like to integrate a new library in my project.
I create a new recipe name "libxerces" which contains a file "libxerces-3.1.1.bb". The bb file is quite simple because it is based on autotools :
DESCRIPTION = "Xerces-c is a validating xml parser written in C++"
HOMEPAGE = "http://xerces.apache.org/xerces-c/"
PRIORITY = "optional"
LICENSE = "Apache-2.0"
LIC_FILES_CHKSUM = "file://LICENSE;md5=3b83ef96387f14655fc854ddc3c6bd57"
PR = "r1"
SRC_URI = "http://mirror.bit.edu.cn/apache//xerces/c/3/sources/xerces-c-${PV}.tar.gz"
s="${WORKDIR}/xerces-c-${PV}"
inherit autotools pkgconfig
SRC_URI[md5sum] = "6a8ec45d83c8cfb1584c5a5345cb51ae"
SRC_URI[sha256sum] = "a42785f71e0b91d5fd273831c87410ce60a73ccfdd207de1b805d26d44968736"
PACKAGES =+ "${PN}-utils"
FILES_${PN} = "${libdir}/*.so"
FILES_${PN}-utils = "${bindir}/*"
FILES_${PN}-staticdev = "${libdir}/*.a"*
BBCLASSEXTEND += "native"
I added "libxerces" to my bb image by using IMAGE_INSTALL += " libxerces". Then, I try to build my image thru bitbake my-image-test and eveything is done correctly but libxerces returns an error because it can not be installed. Howerver, I note that libxerces-dbg, libxerces-utils, libxerces-samples are visible under /tmp/work/deploy/ipk. I know that libxml2 is integrated by default into poky layer but I have to use xerces..
I solved the error
ERROR: Unable to install packages.
Collected errors:
* opkg_install_cmd: Cannot install package libxerces.
overriding the PACKAGES variable.
In your case:
PACKAGES = "${PN} ${PN}-utils ${PN}-staticdev"
I think that is because the .so files goes to ${PN}-dev package by default.
I hope there is a smarter solution, but for now I fixed in this way.
If you are building a library and the library offers static linking, you can control which static library files (*.a files) get included in the built library.
The PACKAGES and FILES_* variables in the meta/conf/bitbake.conf configuration file define how files installed by the do_install task are packaged. By default, the PACKAGES variable includes ${PN}-staticdev, which represents all static library files.
FILES_${PN}-staticdev ="" # for static libs
FILES_${PN}-dev ="" # for dynamic libs
FILES_${PN}-dbg ="" # for debug options
you need to add above line to your recipe

SCons: Separate debug/release build dirs with a hierarchical build

I just started learning to use SCons, anticipating that it solves some of my issues with make. I'm creating a source hierarchy to understand the basics of SCons.
Let's start with this folder structure:
test/foo: contains main.cpp, main.h
test/bar: contains its own main.cpp, main.h
test/common: contains utils.cpp and utils.h used by both foo and bar
test/external/moo: the source to some external library, containing 'configure' which produces 'Makefile' (not using SCons), so SCons needs to invoke 'make' after 'configure'; I suspect this part might be tricky when build dirs are used
test/build/debug: build dir for debug
test/build/release: build dir for release
Here's what I'd like to do:
Have two types of builds: debug/release where the only difference is that debug specifies -DDEBUG to g++
Use build dirs so that no .o files are created in my source tree. Let's call these build dirs "build/debug" and "build/release"
Be able to invoke ./configure and make on another project that does not use SCons, followed by linking libmoo.a it produces with my project
Have the builds be perfectly parallel (scons -j9 for an 8-core?)
Have some debug/release-independent way of specifying libraries to link. Something like:
env.Program(target='foo', source=['foo/main.cpp', '#build/(DEBUG_OR_RELEASE)/lib/libsomething.a'])
What would the very basic SConstruct/SConscript files to do the above look like? Even just pointers in the right directions would be great too!
Thanks in advance :-)
I do this for builds for multiple platforms (rather than debug/release) but the concept's the same. The basic idea is that you need 2 files in the project root - a SConstruct to set up the build directories (or "variant directories" as they are known in scons), then a SConscript that describes the actual build steps.
In the SConstruct file you'd specify the variant directory and its corresponding source directory:
SConscript(dirs='.',
variant_dir=variant_dir,
duplicate=False,
exports="env")
Now you want variant_dir to depend on a flag. You'd use AddOption or Variables to do this. Here's one example of a complete top-level SConstruct to do that:
# build with `scons --debug-build` for debug.
AddOption(
'--debug-build',
action='store_true',
help='debug build',
default=False)
env = Environment()
if GetOption('debug_build'):
env.ParseFlags('-DDEBUG')
variant_dir = 'build/debug'
else:
variant_dir = 'build/release'
SConscript(dirs='.',
variant_dir=variant_dir,
duplicate=False,
exports="env")
AddOption is easiest to use, but if you use Variables then you can cache the result between runs, rather than having to spell out "scons --debug-build" each time.
All the directory setup and associated cruft is in the SConstruct. Now the SConscript file is quite simple and doesn't need to worry about build directories at all.
Import('env')
env.Program(target='foo_prog', source=['foo/main.cpp', 'lib/libmoo.a'])
# foo_prog since foo already exists as the name of the directory...
This is about the simplest way I've found to set up different build directories without getting weird errors. It's also pretty flexible - you can add different platform builds just by modifying the "env" in the top-level script without having to alter the actual meat of the build.
The only spanner in the works in your question is the way to compile autoconf-style projects directly from SCons. The easiest way is probably with a couple of Command() calls, but SCons likes to know about the inputs and outputs of each step, so this can get hacky. Also, you have to rely on the autoconf build having a correct VPATH setup - some projects don't work if you try and compile outside the source tree. Anyway, a way to compile autoconf projects would be something like this:
import os
Import('env')
# get the path to the configure script from the "moo" source directory
conf = env.File('moo/configure').srcnode().abspath
# Create the "moo" build directory in the build dir
build_dir = env.Dir('.').path
moo_dir = os.path.join(build_dir, 'moo')
Mkdir(moo_dir)
# run configure from within the moo dir
env.Command('moo/Makefile', 'moo/Makefile.am',
conf, chdir=moo_dir)
# run make in the moo dir
env.Command('moo/libmoo.a', 'moo/Makefile',
'make', chdir=moo_dir)
env.Program(target='foo_prog', source=['foo/main.cpp', 'moo/libmoo.a'])
Running the configure step from the source directory while the current working directory is somewhere in the build hierarchy is awkward. The make step is less messy, but still needs to know about the current build directory. Since you specify "libmoo.a" as an output of the make step and libmoo.a as an input to the program, all the dependencies Just Work, so a parallel build works fine. Parallel builds only break down when you fudge dependencies too much.
I know this is an old question, I just want to add an alternative to:
be able to know the current variant in the sconscript file (not only in the parent)
and to be able to build multiple variants in a single scons command
In the sconstruct file (the parent), we define a ListVariable named variants with the list of the variants that we allow (eg. ['release', 'debug']).
Then to be able to know the current variant in the sconscript file, we just loop option we have defined and export it into the sconscript.
I use genv as variable name to notate global environment:
# sconstruct
opts = Variables()
opts.AddVariables(
ListVariable('variants', 'list of variants to build', 'all', names = ['debug','release']),
)
genv = Environment( options = opts )
for variant in genv['variants']:
SConscript('sconscript', exports=['genv', 'variant'], variant_dir='#build/'+variant, duplicate=False)
In the sconscript file we Clone de genv and we can use the variant variable to do our setup in the local environment env:
# sconscript
Import('*')
import os.path
env = genv.Clone()
if variant == 'debug':
env.Append( CPPFLAGS = ['/Zi'])
src = 'src/hello.cpp'
app,ext = os.path.splitext(os.path.basename(src))
obj = env.Object ('obj/'+app, src)
bin = env.Program('bin/'+app, obj)
Using a ListVariable allows us to call
scons variants=release
or
scons variants=debug
or
scons variants=all
This last command (and the default command) builds all the variants.
There's a good solution to define multiple build modes ('debug', 'release') in the SCons Wiki:
http://www.scons.org/wiki/SconstructMultiple
That's how the richq SConstruct file would look like:
#get the mode flag from the command line
#default to 'release' if the user didn't specify
mymode = ARGUMENTS.get('mode', 'release')
#check if the user has been naughty: only 'debug' or 'release' allowed
if not (mymode in ['debug', 'release']):
print "Error: expected 'debug' or 'release', found: " + mymode
Exit(1)
#tell the user what we're doing
print '**** Compiling in ' + mymode + ' mode...'
env = Environment()
if mode == 'debug':
env.Append(CPPDEFINES = ['DEBUG'])
variant_dir = 'build/debug'
else:
variant_dir = 'build/release'
SConscript(dirs = '.', variant_dir = variant_dir, duplicate = False, exports = "env")
You then call scons mode=release (or just scons as the release is the default mode), or scons mode=debug.

Implementation of an 'install' target with SCons

I try to setup a build system to build a shared lib MySharedLib and a binary MyBinary that rely on MySharedLib. The build system should be able to install MySharedLib and MyBinary when asked for it, and only when asked for it.
import os.path
env = Environment()
env.Append(CCFLAGS='-g -Wall -ansi -O2')
prefix = '/usr/local'
lib_dir = os.path.join(prefix, 'lib')
bin_dir = os.path.join(prefix, 'bin')
Export('env prefix lib_dir bin_dir')
libMySharedLib = SConscript('libMySharedLib/SConscript')
MyBinary = SConscript('MyBinary/SConscript')
env.Alias('install', env.Install(lib_dir, libMySharedLib))
env.Alias('install', env.Install(bin_dir, MyBinary))
When I run SCons with no command line arguments, MySharedLib and MyBinary are built, but it also it try to install them. I want them installed only just when I ask for the install target. I tried many times, read the docs, but I can't figure it out.
By default, and when no target are set into the scons script, scons builds every target in '.'. You can control which targets to build by default with the Default function:
lib = SConscript('libMySharedLib/SConscript')
bin = SConscript('MyBinary/SConscript')
env.Alias('install', env.Install(lib_dir, lib))
env.Alias('install', env.Install(bin_dir, bin))
# By default (scons called with no explicit target), only build bin
Default(bin)
AFAIK, there is no way to tell scons to build nothing, although you could create a dummy target I suppose.

Resources