service plugin and qdecimal library has been added
This commit is contained in:
@@ -0,0 +1,220 @@
|
||||
#!python
|
||||
# -*-python-*-
|
||||
#
|
||||
# SCons extension library for large C/C++ projects.
|
||||
# Author: Semih Cemiloglu <semih.cemiloglu@gmail.com>
|
||||
# Initial: 2016-01-20
|
||||
# This file and all associated files have 'BSD License' copyright terms
|
||||
#
|
||||
|
||||
# Standard modules
|
||||
import os
|
||||
import sys
|
||||
import atexit
|
||||
import subprocess
|
||||
# Scons modules
|
||||
import SCons
|
||||
from SCons.Script import *
|
||||
|
||||
|
||||
|
||||
def getVersion():
|
||||
return SCons.__version__
|
||||
|
||||
def printBuildFailures():
|
||||
for bf in GetBuildFailures():
|
||||
print "%s failed: %s" % (bf.node, bf.errstr)
|
||||
|
||||
def findQtDir(defDir=None):
|
||||
""" Detect Qt version on the platform. """
|
||||
qtdir = os.environ.get('QT5DIR',None)
|
||||
if qtdir:
|
||||
return qtdir
|
||||
qtdir = os.environ.get('QTDIR',None)
|
||||
if qtdir:
|
||||
return qtdir
|
||||
return defDir
|
||||
|
||||
|
||||
def constructVariables(cfgFile=None):
|
||||
"""
|
||||
Construct variables from command line arguments given to scons
|
||||
ARGUMENTS and ARGLIST
|
||||
"""
|
||||
vars = Variables(cfgFile)
|
||||
vars.Add('verbose','Set to non-zero for verbose output', 0)
|
||||
vars.Add(EnumVariable('build_mode', 'Build mode', 'dbg',
|
||||
allowed_values=('dbg', 'rel'),
|
||||
map={'debug':'dbg', 'release':'rel'}))
|
||||
vars.Add(BoolVariable('use_plat', 'Use platform as build variant', 0))
|
||||
vars.Add(BoolVariable('run_tests', 'Run tests at the end', 0))
|
||||
vars.Add(PathVariable('build_dir',
|
||||
'Path to build directory',
|
||||
'sbuild',
|
||||
PathVariable.PathIsDirCreate))
|
||||
vars.Add(BoolVariable('dump', 'Dump contents of environment', 0))
|
||||
|
||||
# Add --prefix option to be able to specify installation directory
|
||||
# outside of prect directory tree.
|
||||
AddOption('--prefix',
|
||||
dest='prefix',
|
||||
type='string',
|
||||
default=None,
|
||||
nargs=1,
|
||||
action='store',
|
||||
metavar='DIR',
|
||||
help='installation prefix')
|
||||
|
||||
return vars
|
||||
|
||||
|
||||
def checkUnknownVariables(vars):
|
||||
"""
|
||||
Check if vars contains unknown variables for an environment.
|
||||
"""
|
||||
unknown = vars.UnknownVariables()
|
||||
if unknown:
|
||||
print "Unknown variables:", unknown.keys()
|
||||
#This should be warning only
|
||||
#Exit(1)
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
def setupEnvironment(env):
|
||||
"""
|
||||
Prepare a scons construction environment for building.
|
||||
"""
|
||||
# Directories that build output will be generated into
|
||||
platform = sys.platform
|
||||
bld_mode = env['build_mode']
|
||||
bld_dir = env['build_dir']
|
||||
if env['use_plat']:
|
||||
bld_pdir = '%s/%s' % (bld_dir, platform)
|
||||
else:
|
||||
bld_pdir = bld_dir
|
||||
bld_vdir = '%s/%s' % (bld_pdir, bld_mode)
|
||||
|
||||
|
||||
# Store build directories and setup build output data structures
|
||||
env.AppendUnique(
|
||||
PRJ_BLD_DIR = Dir(bld_dir),
|
||||
PRJ_BLD_VDIR = Dir(bld_vdir),
|
||||
PRJ_BLD_BIN = Dir('%s/bin' % bld_vdir),
|
||||
PRJ_BLD_LIB = Dir('%s/lib' % bld_vdir),
|
||||
PRJ_EXES = {},
|
||||
PRJ_TSTS = {},
|
||||
PRJ_LIBS = {},
|
||||
PRJ_OBJS = {}
|
||||
)
|
||||
|
||||
# If project install location (prefix) is specified
|
||||
if env['PREFIX']:
|
||||
# Define installation locations
|
||||
env.AppendUnique(
|
||||
PRJ_INST_DIR = Dir(env['PREFIX']),
|
||||
PRJ_INST_BIN = Dir('%s/bin' % env['PREFIX']),
|
||||
PRJ_INST_LIB = Dir('%s/lib' % env['PREFIX'])
|
||||
)
|
||||
|
||||
# Baseline compile/link flags
|
||||
if platform == 'win32':
|
||||
if 'cl' in env['CC']:
|
||||
if env['build_mode'] == 'dbg':
|
||||
env.MergeFlags('-MTd -W1 -D_DEBUG -RTCs -Zi')
|
||||
else:
|
||||
env.MergeFlags('-MT -O1 -DNDEBUG')
|
||||
if env['verbose']:
|
||||
env.AppendUnique(CCFLAGS='-Bt')
|
||||
env.AppendUnique(LINKFLAGS=['-verbose:lib', '-time'])
|
||||
else:
|
||||
print "Unrecognized compiler: %s" % env['CC']
|
||||
elif 'linux' in platform:
|
||||
# Replace LINKCOM to position LINKFLAGS at the very end of
|
||||
# link command line
|
||||
env.Replace(LINKCOM='$LINK -o $TARGET $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS $LINKFLAGS')
|
||||
env.AppendUnique(LINKFLAGS = ['-lm' ])
|
||||
env.AppendUnique(CCFLAGS = ['-fPIC','-DPIC'])
|
||||
if env['build_mode'] == 'dbg':
|
||||
env.MergeFlags('-g')
|
||||
else:
|
||||
env.MergeFlags('-O2 -w')
|
||||
if env['verbose']:
|
||||
env.AppendUnique(CCFLAGS='-v')
|
||||
else:
|
||||
# Warning only, rely on SCons to come up with meaningful defaults
|
||||
print "Unrecognized platform: %s" % platform
|
||||
|
||||
|
||||
# Inform user about the build mode
|
||||
print "Will build for %s mode..." % bld_mode
|
||||
# Help output to be shown to users
|
||||
Help("""
|
||||
Type: 'scons' to build all libraries and executables.
|
||||
""")
|
||||
# At the abnormal exit show information about build failures
|
||||
atexit.register(printBuildFailures)
|
||||
return 0
|
||||
|
||||
|
||||
def readSConscriptFiles(env, src_dirs):
|
||||
for sd in src_dirs:
|
||||
env.SConscript(
|
||||
'%s/SConscript' % sd,
|
||||
variant_dir='%s/%s' % (env['PRJ_BLD_VDIR'],sd),
|
||||
duplicate=0,
|
||||
exports='env'
|
||||
)
|
||||
|
||||
# Firstly, install project outputs to variant directories
|
||||
for lib in env['PRJ_LIBS'].values():
|
||||
env.Install("$PRJ_BLD_LIB", lib)
|
||||
for exe in env['PRJ_EXES'].values():
|
||||
env.Install("$PRJ_BLD_BIN", exe)
|
||||
for exe in env['PRJ_TSTS'].values():
|
||||
env.Install("$PRJ_BLD_BIN", exe)
|
||||
|
||||
# Add a 'install' target for project output files
|
||||
# This will support calls to scons with "install" target
|
||||
# scons --prefix=/path/to/gsl install
|
||||
if env['PREFIX']:
|
||||
env.Alias('install', env['PREFIX'])
|
||||
for lib in env['PRJ_LIBS'].values():
|
||||
env.Install("$PRJ_INST_LIB", lib)
|
||||
for exe in env['PRJ_EXES'].values():
|
||||
env.Install("$PRJ_INST_BIN", exe)
|
||||
# Note that we don't install test applications
|
||||
|
||||
|
||||
if env['dump']:
|
||||
print env.Dump()
|
||||
|
||||
if env['run_tests']:
|
||||
runTests(env)
|
||||
|
||||
|
||||
|
||||
def useProgress(mode=None, interval=5):
|
||||
"""
|
||||
use and show progress indicator when building
|
||||
"""
|
||||
if mode == 'target':
|
||||
Progress('Evaluating $TARGET\r')
|
||||
else:
|
||||
Progress(['-\r', '\\\r', '|\r', '/\r'], interval)
|
||||
|
||||
|
||||
|
||||
def runTests(env):
|
||||
for exe in env['PRJ_TSTS'].values():
|
||||
cmd = exe[0].abspath
|
||||
print "Executing: %s" % cmd
|
||||
rv = subprocess.call(cmd)
|
||||
if rv == 0:
|
||||
print "PASS: %s" % os.path.basename(cmd)
|
||||
else:
|
||||
print "FAIL: %s" % os.path.basename(cmd)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,351 @@
|
||||
####################################
|
||||
The SCons qt5 tool
|
||||
####################################
|
||||
|
||||
Basics
|
||||
======
|
||||
This tool can be used to compile Qt projects, designed for versions 5.x.y and higher.
|
||||
It is not usable for Qt3 and older versions, since some of the helper tools
|
||||
(``moc``, ``uic``) behave different.
|
||||
|
||||
Install
|
||||
-------
|
||||
Installing it, requires you to copy (or, even better: checkout) the contents of the
|
||||
package's ``qt5`` folder to
|
||||
|
||||
#. "``/path_to_your_project/site_scons/site_tools/qt5``", if you need the Qt5 Tool in one project only, or
|
||||
#. "``~/.scons/site_scons/site_tools/qt5``", for a system-wide installation under your current login.
|
||||
|
||||
For more infos about this, please refer to
|
||||
|
||||
* the SCons User's Guide, sect. "Where to put your custom Builders and Tools" and
|
||||
* the SCons Tools Wiki page at `http://scons.org/wiki/ToolsIndex <http://scons.org/wiki/ToolsIndex/>`_.
|
||||
|
||||
How to activate
|
||||
---------------
|
||||
For activating the tool "qt5", you have to add its name to the Environment constructor,
|
||||
like this
|
||||
|
||||
::
|
||||
|
||||
env = Environment(tools=['default','qt5'])
|
||||
|
||||
|
||||
On its startup, the Qt5 tool tries to read the variable ``QT5DIR`` from the current
|
||||
Environment and ``os.environ``. If it is not set, the value of ``QTDIR`` (in
|
||||
Environment/``os.environ``) is used as a fallback.
|
||||
|
||||
So, you either have to explicitly give the path of your Qt5 installation to the
|
||||
Environment with
|
||||
|
||||
::
|
||||
|
||||
env['QT5DIR'] = '/usr/local/Trolltech/Qt-5.2.3'
|
||||
|
||||
|
||||
or set the ``QT5DIR`` as environment variable in your shell.
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
Under Linux, "qt5" uses the system tool ``pkg-config`` for automatically
|
||||
setting the required compile and link flags of the single Qt5 modules (like QtCore,
|
||||
QtGui,...).
|
||||
This means that
|
||||
|
||||
#. you should have ``pkg-config`` installed, and
|
||||
#. you additionally have to set ``PKG_CONFIG_PATH`` in your shell environment, such
|
||||
that it points to $``QT5DIR/lib/pkgconfig`` (or $``QT5DIR/lib`` for some older versions).
|
||||
|
||||
Based on these two environment variables (``QT5DIR`` and ``PKG_CONFIG_PATH``),
|
||||
the "qt5" tool initializes all ``QT5_*``
|
||||
construction variables listed in the Reference manual. This happens when the tool
|
||||
is "detected" during Environment construction. As a consequence, the setup
|
||||
of the tool gets a two-stage process, if you want to override the values provided
|
||||
by your current shell settings:
|
||||
|
||||
::
|
||||
|
||||
# Stage 1: create plain environment
|
||||
qtEnv = Environment()
|
||||
# Set new vars
|
||||
qtEnv['QT5DIR'] = '/usr/local/Trolltech/Qt-5.2.3
|
||||
qtEnv['ENV']['PKG_CONFIG_PATH'] = '/usr/local/Trolltech/Qt-5.2.3/lib/pkgconfig'
|
||||
# Stage 2: add qt5 tool
|
||||
qtEnv.Tool('qt5')
|
||||
|
||||
|
||||
|
||||
|
||||
Suggested boilerplate
|
||||
=====================
|
||||
Based on the requirements above, we suggest a simple ready-to-go setup
|
||||
as follows:
|
||||
|
||||
SConstruct
|
||||
|
||||
::
|
||||
|
||||
# Detect Qt version
|
||||
qtdir = detectLatestQtDir()
|
||||
|
||||
# Create base environment
|
||||
baseEnv = Environment()
|
||||
#...further customization of base env
|
||||
|
||||
# Clone Qt environment
|
||||
qtEnv = baseEnv.Clone()
|
||||
# Set QT5DIR and PKG_CONFIG_PATH
|
||||
qtEnv['ENV']['PKG_CONFIG_PATH'] = os.path.join(qtdir, 'lib/pkgconfig')
|
||||
qtEnv['QT5DIR'] = qtdir
|
||||
# Add qt5 tool
|
||||
qtEnv.Tool('qt5')
|
||||
#...further customization of qt env
|
||||
|
||||
# Export environments
|
||||
Export('baseEnv qtEnv')
|
||||
|
||||
# Your other stuff...
|
||||
# ...including the call to your SConscripts
|
||||
|
||||
|
||||
In a SConscript
|
||||
|
||||
::
|
||||
|
||||
# Get the Qt5 environment
|
||||
Import('qtEnv')
|
||||
# Clone it
|
||||
env = qtEnv.clone()
|
||||
# Patch it
|
||||
env.Append(CCFLAGS=['-m32']) # or whatever
|
||||
# Use it
|
||||
env.StaticLibrary('foo', Glob('*.cpp'))
|
||||
|
||||
|
||||
The detection of the Qt directory could be as simple as directly assigning
|
||||
a fixed path
|
||||
|
||||
::
|
||||
|
||||
def detectLatestQtDir():
|
||||
return "/usr/local/qt5.3.2"
|
||||
|
||||
|
||||
or a little more sophisticated
|
||||
|
||||
::
|
||||
|
||||
# Tries to detect the path to the installation of Qt with
|
||||
# the highest version number
|
||||
def detectLatestQtDir():
|
||||
if sys.platform.startswith("linux"):
|
||||
# Simple check: inspect only '/usr/local/Trolltech'
|
||||
paths = glob.glob('/usr/local/Trolltech/*')
|
||||
if len(paths):
|
||||
paths.sort()
|
||||
return paths[-1]
|
||||
else:
|
||||
return ""
|
||||
else:
|
||||
# Simple check: inspect only 'C:\Qt'
|
||||
paths = glob.glob('C:\\Qt\\*')
|
||||
if len(paths):
|
||||
paths.sort()
|
||||
return paths[-1]
|
||||
else:
|
||||
return os.environ.get("QTDIR","")
|
||||
|
||||
|
||||
|
||||
A first project
|
||||
===============
|
||||
The following SConscript is for a simple project with
|
||||
some cxx files, using the QtCore, QtGui
|
||||
and QtNetwork modules:
|
||||
|
||||
::
|
||||
|
||||
Import('qtEnv')
|
||||
env = qtEnv.Clone()
|
||||
env.EnableQt5Modules([
|
||||
'QtGui',
|
||||
'QtCore',
|
||||
'QtNetwork'
|
||||
])
|
||||
# Add your CCFLAGS and CPPPATHs to env here...
|
||||
|
||||
env.Program('foo', Glob('*.cpp'))
|
||||
|
||||
|
||||
|
||||
MOC it up
|
||||
=========
|
||||
For the basic support of automocing, nothing needs to be
|
||||
done by the user. The tool usually detects the ``Q_OBJECT``
|
||||
macro and calls the "``moc``" executable accordingly.
|
||||
|
||||
If you don't want this, you can switch off the automocing
|
||||
by a
|
||||
|
||||
::
|
||||
|
||||
env['QT5_AUTOSCAN'] = 0
|
||||
|
||||
|
||||
in your SConscript file. Then, you have to moc your files
|
||||
explicitly, using the Moc5 builder.
|
||||
|
||||
You can also switch to an extended automoc strategy with
|
||||
|
||||
::
|
||||
|
||||
env['QT5_AUTOSCAN_STRATEGY'] = 1
|
||||
|
||||
|
||||
Please read the description of the ``QT5_AUTOSCAN_STRATEGY``
|
||||
variable in the Reference manual for details.
|
||||
|
||||
For debugging purposes, you can set the variable ``QT5_DEBUG``
|
||||
with
|
||||
|
||||
::
|
||||
|
||||
env['QT5_DEBUG'] = 1
|
||||
|
||||
|
||||
which outputs a lot of messages during automocing.
|
||||
|
||||
|
||||
Forms (.ui)
|
||||
===========
|
||||
The header files with setup code for your GUI classes, are not
|
||||
compiled automatically from your ``.ui`` files. You always
|
||||
have to call the Uic5 builder explicitly like
|
||||
|
||||
::
|
||||
|
||||
env.Uic5(Glob('*.ui'))
|
||||
env.Program('foo', Glob('*.cpp'))
|
||||
|
||||
|
||||
|
||||
Resource files (.qrc)
|
||||
=====================
|
||||
Resource files are not built automatically, you always
|
||||
have to add the names of the ``.qrc`` files to the source list
|
||||
for your program or library:
|
||||
|
||||
::
|
||||
|
||||
env.Program('foo', Glob('*.cpp')+Glob('*.qrc'))
|
||||
|
||||
|
||||
For each of the Resource input files, its prefix defines the
|
||||
name of the resulting resource. An appropriate "``-name``" option
|
||||
is added to the call of the ``rcc`` executable
|
||||
by default.
|
||||
|
||||
You can also call the Qrc5 builder explicitly as
|
||||
|
||||
::
|
||||
|
||||
qrccc = env.Qrc5('foo') # ['foo.qrc'] -> ['qrc_foo.cc']
|
||||
|
||||
|
||||
or (overriding the default suffix)
|
||||
|
||||
::
|
||||
|
||||
qrccc = env.Qrc5('myprefix_foo.cxx','foo.qrc') # -> ['qrc_myprefix_foo.cxx']
|
||||
|
||||
|
||||
and then add the resulting cxx file to the sources of your
|
||||
Program/Library:
|
||||
|
||||
::
|
||||
|
||||
env.Program('foo', Glob('*.cpp') + qrccc)
|
||||
|
||||
|
||||
|
||||
Translation files
|
||||
=================
|
||||
The update of the ``.ts`` files and the conversion to binary
|
||||
``.qm`` files is not done automatically. You have to call the
|
||||
corresponding builders on your own.
|
||||
|
||||
Example for updating a translation file:
|
||||
|
||||
::
|
||||
|
||||
env.Ts5('foo.ts','.') # -> ['foo.ts']
|
||||
|
||||
|
||||
By default, the ``.ts`` files are treated as *precious* targets. This means that
|
||||
they are not removed prior to a rebuild, but simply get updated. Additionally, they
|
||||
do not get cleaned on a "``scons -c``". If you want to delete the translation files
|
||||
on the "``-c``" SCons command, you can set the variable "``QT5_CLEAN_TS``" like this
|
||||
|
||||
::
|
||||
|
||||
env['QT5_CLEAN_TS']=1
|
||||
|
||||
|
||||
Example for releasing a translation file, i.e. compiling
|
||||
it to a ``.qm`` binary file:
|
||||
|
||||
::
|
||||
|
||||
env.Qm5('foo') # ['foo.ts'] -> ['foo.qm']
|
||||
|
||||
|
||||
or (overriding the output prefix)
|
||||
|
||||
::
|
||||
|
||||
env.Qm5('myprefix','foo') # ['foo.ts'] -> ['myprefix.qm']
|
||||
|
||||
|
||||
As an extension both, the Ts5() and Qm5 builder, support the definition of
|
||||
multiple targets. So, calling
|
||||
|
||||
::
|
||||
|
||||
env.Ts5(['app_en','app_de'], Glob('*.cpp'))
|
||||
|
||||
|
||||
and
|
||||
|
||||
::
|
||||
|
||||
env.Qm5(['app','copy'], Glob('*.ts'))
|
||||
|
||||
|
||||
should work fine.
|
||||
|
||||
Finally, two short notes about the support of directories for the Ts5() builder. You can
|
||||
pass an arbitrary mix of cxx files and subdirs to it, as in
|
||||
|
||||
::
|
||||
|
||||
env.Ts5('app_en',['sub1','appwindow.cpp','main.cpp']))
|
||||
|
||||
|
||||
where ``sub1`` is a folder that gets scanned recursively for cxx files by ``lupdate``.
|
||||
But like this, you lose all dependency information for the subdir, i.e. if a file
|
||||
inside the folder changes, the .ts file is not updated automatically! In this case
|
||||
you should tell SCons to always update the target:
|
||||
|
||||
::
|
||||
|
||||
ts = env.Ts5('app_en',['sub1','appwindow.cpp','main.cpp'])
|
||||
env.AlwaysBuild(ts)
|
||||
|
||||
|
||||
Last note: specifying the current folder "``.``" as input to Ts5() and storing the resulting
|
||||
.ts file in the same directory, leads to a dependency cycle! You then have to store the .ts
|
||||
and .qm files outside of the current folder, or use ``Glob('*.cpp'))`` instead.
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user