Commit ac8502f0 authored by Mats Wichmann's avatar Mats Wichmann

Show how to make examples non-default

A scheme is introduced which allows separating targets indended to
be built by default from ones not intended to be built by default.
One example is converted to show how it works.

Since this makes use of added methods (extending scons' own API),
took the opportunity to properly document these, and added a
documentation file in a new doc subdirectory to make it easier
for developers to find out about these methods.

Also added a debug scheme, which makes it more clear where to
put tracing statements in between the two passes of scons -
the script is invoked at the very end of the scan pass, before
the build pass begins but when everything should be defined.

Change-Id: I0a636fa34c18ace23720f22bfdd8511afa611ddb
Signed-off-by: default avatarMats Wichmann <mats@linux.com>
parent 2cd19c54
......@@ -92,12 +92,15 @@ SConscript(dirs=[
# Append target information to the help information (if needed)
# To see help info, execute:
# $ scons [options] -h
# Note some help is option-dependent, e.g. java-related options are
# not added to the help unless BUILD_JAVA is seen
# Note some help is option or target dependent, e.g. java-related
# options are not added to the help unless BUILD_JAVA is seen
#
# This is not really needed unless requesting help, consider adding check:
#if env.GetOption('help'):
env.PrintTargets()
if env.GetOption('help'):
env.PrintTargets()
# to install the generated pc file into custom prefix location
env.UserInstallTargetPCFile('iotivity.pc', 'iotivity.pc')
# If we need to extract some of what scons knows at the end of
# the scan phase for debugging, can use debug.scons to print things
SConscript('debug.scons')
......@@ -181,9 +181,9 @@ help_vars.AddVariables(
'Build with sample',
default='ON',
allowed_values=('ON', 'OFF')),
# ANDROID_NDK set at end after default computed
# ANDROID_HOME set at end after default computed
# ANDROID_GRADLE set at end after default computed
# ANDROID_NDK set at end after default computed
# ANDROID_HOME set at end after default computed
# ANDROID_GRADLE set at end after default computed
BoolVariable('WITH_ENV',
'Use compiler options from environment',
default=False),
......@@ -392,23 +392,51 @@ if host in ['windows']:
# Ensure scons is able to change its working directory
env.SConscriptChdir(1)
# To cut down how much is built, enable the Default(DefTarg) line.
# Only those targets added to the alias "DefaultTargets" will
# then be built by default, else scons will by default build
# all targets it finds. "DefaultTargets" is added to by calls
# to InstallTarget and AppendTarget, unless those methods are
# passed the argument default=False
#
DefTarg = Alias("DefaultTargets")
# Default(DefTarg)
######################################################################
# Convenience functions to "extend" SCons
#
# Functions are added into scope of the rest of the build system
# by calling AddMethod
#
# These should probably move to site_init for better findability
######################################################################
def SetDir(env, dir):
"""
Set up the target directory for building.
Sets up the scons Variant directory, which is where objects
built under scons control will go, rather than in the source tree.
Also shortcuts some of the available scons mechansims by saving the
paths in the construction environment. Since this sets the
variant dir, this should be called only once, using the main
main construction environment. These are retrieved by:
env.get('SRC_DIR')
env.get('BUILD_DIR')
SRC_DIR will be the passed directory, while BUILD_DIR is
constructed based on target system/arch and release mode.
On Windows:
'dir'/out/windows/<win32 or uwp>/<target_arch>/<release or debug>/
On all others:
'dir'/out/<target_os>/<target_arch>/<release or debug>/
Args:
env: construction environment
dir: the source directory
"""
def __set_dir(env, dir):
#
# Set the source and build directories
# Source directory: 'dir'
# Build directory: 'dir'/out/<target_os>/<target_arch>/<release or debug>/
# On windows, the build directory will be:
# 'dir'/out/windows/<win32 or uwp>/<target_arch>/<release or debug>/
#
# You can get the directory as following:
# env.get('SRC_DIR')
# env.get('BUILD_DIR')
#
if not os.path.exists(dir + '/SConstruct'):
msg = '''
*************************************** Error *********************************
......@@ -438,49 +466,134 @@ def __set_dir(env, dir):
env.Replace(BUILD_DIR=build_dir)
env.Replace(SRC_DIR=dir)
env.AddMethod(SetDir)
def __src_to_obj(env, src, home=''):
'''
Make sure builds happen in BUILD_DIR (by default they
would happen in the directory of the source file)
Note this does not seem to be used, VariantDir is used instead
'''
def SrcToObj(env, src, home=''):
"""
Build an object in BUILD_DIR.
Uses BUILD_DIR, SetDir should have been called previously.
Note this is used only in the android compat script.
Args:
env: construction environment
src: source directory
home: the part of the path to chop off
"""
obj = env.get('BUILD_DIR') + src.replace(home, '')
if env.get('OBJSUFFIX'):
obj += env.get('OBJSUFFIX')
return env.Object(obj, src)
def __install(ienv, targets, name=''):
'''
Copy files to internal place (not for install to system)
only use UserInstall() for copying files to system using "scons install"
'''
env.AddMethod(SrcToObj)
def InstallTarget(ienv, targets, name=None, default=True):
"""
Copy a built target to the common location.
The iotivity build puts the libraries and executables in a common
location to make it easy to run the executables in place without
worrying about the rpath (for systems that have it), or to account
for no rpath option being available (Windows systems). This not
the same as "installing", see the UserInstall* methods for that.
As side effects, the target is added to either the list of default
targets or non-default targets, which are later handed to the Help
function to help display options to the user. If this is a default
target, it is also added to the DefaultTargets alias.
Args:
ienv: the construction environment of the caller.
targets: list of targets to copy.
name: if set, the name to copy to; else use the target name.
default: whether this is a default target or not.
Notes:
If used for copying a library, a race condition may occur on
Windows systems if parallel building is enabled. The separate
operations from the SharedLibrary builder and the Command builder
calling Copy may see Python release the Global Interpreter Lock
in between steps, and another task may conclude the library
is ready before the copy has taken place, and then report a
missing dependency. A workaround is to generate the library
directly into the common location so it does not need to be
copied after building.
See Also:
AppendTarget
"""
for filename in ienv.GetBuildPath(targets):
basename = os.path.basename(filename)
dst = env.get('BUILD_DIR') + basename
i_n = Command(dst, filename, Copy("$TARGET", "$SOURCE"))
if '' == name:
if not name:
name = basename
ienv.Alias(name, i_n)
env.AppendUnique(TS=[name])
# note the aliases are added to the target lists in the
# main construction environment, not the one we're called from
if default:
env.AppendUnique(DefaultBuild=[name])
Alias("DefaultTargets", name)
else:
env.AppendUnique(NoDefaultBuild=[name])
def __chrpath(target, source, env):
'''
Remove RPATH (if installed elsewhere)
'''
if target_os in ['linux', 'tizen']:
env.Command(None, target, 'chrpath -d $SOURCE')
env.AddMethod(InstallTarget)
def __installlib(ienv, targets, name=''):
'''
Install files to system, using "scons install" and remove rpath info if present
If prefix or lib install dir is not specified, for developer convenience
files are copied in relative "deploy" folder along executables (rpath is kept)
to avoid overlap with "internal place" above
'''
def AppendTarget(ienv, name, targets=None, default=True):
"""
Add targets to target list.
The target 'name' is added to either the list of default targets
or non-default targets, which are later handed to the Help function
to help display options to the user. If this is a default target,
it is also added to the DefaultTargets alias.
Args:
ienv: the construction environment of the caller.
name: target name to add.
targets: aliases the 'name' target will expand to.
default: whether this is a default target or not.
See Also:
AppendTarget
"""
if targets:
env.Alias(name, targets)
if default:
env.AppendUnique(DefaultBuild=[name])
Alias("DefaultTargets", name)
else:
env.AppendUnique(NoDefaultBuild=[name])
env.AddMethod(AppendTarget)
def UserInstallTargetLib(ienv, targets, name=None):
"""
Install built libraries to a "system" location.
Install files to system location, when running "scons install".
If PREFIX is set it is used with a 'lib' suffix, unless
LIB_INSTALL_DIR is also set in which case it is used unchanged.
If neither, a 'deploy' subdirectory of the common build location
is used. Unless deploy was used, the rpath is stripped.
Args:
ienv: construction environment of caller
targets: libraries to install
name: currently unused (future: installation name)
"""
def __chrpath(target, source, env):
"""
Remove RPATH if present.
"""
if target_os in ['linux', 'tizen']:
env.Command(None, target, 'chrpath -d $SOURCE')
user_prefix = env.get('PREFIX')
if user_prefix:
user_lib = env.get('LIB_INSTALL_DIR')
......@@ -495,14 +608,22 @@ def __installlib(ienv, targets, name=''):
ienv.AddPostAction(action, __chrpath)
ienv.Alias("install", action)
env.AddMethod(UserInstallTargetLib)
def __installbin(ienv, targets, name=''):
'''
' Install files to system, using "scons install"
' If prefix is not specified, for developer convenience
' files are copied in relative "deploy" folder along libraries
'''
def UserInstallTargetBin(ienv, targets, name=None):
"""
Install built binaries to a "system" location.
Install files to system location, when running "scons install".
If PREFIX is set it is used with a 'bin' suffix, else a 'deploy'
subdirectory of the common build location is used.
Args:
ienv: construction environment of caller
targets: libraries to install
name: currently unused (future: installation name)
"""
user_prefix = env.get('PREFIX')
if user_prefix:
dst_dir = user_prefix + '/bin'
......@@ -510,8 +631,24 @@ def __installbin(ienv, targets, name=''):
dst_dir = env.get('BUILD_DIR') + '/deploy'
ienv.Alias("install", ienv.Install(dst_dir , targets))
env.AddMethod(UserInstallTargetBin)
def UserInstallTargetHeader(ienv, targets, dir="", name=None):
"""
Install header files to a "system" location.
Install files to system location, when running "scons install".
If PREFIX is set it is used with an 'include/iotivity' suffix, else a
'deploy/include' subdirectory of the common build location is used.
If dir is present, it as appended to the installation path.
def __installheader(ienv, targets, dir, name):
Args:
ienv: construction environment of caller
targets: headers to install
dir: additional subdirectory to use in install location
name: currently unused (future: installation name)
"""
user_prefix = env.get('PREFIX')
if user_prefix:
i_n = ienv.Install(user_prefix + '/include/iotivity/' + dir, targets)
......@@ -519,8 +656,24 @@ def __installheader(ienv, targets, dir, name):
i_n = ienv.Install(env.get('BUILD_DIR') + 'deploy/include/' + dir, targets)
ienv.Alias("install", i_n)
env.AddMethod(UserInstallTargetHeader)
def __installpcfile(ienv, targets, name):
def UserInstallTargetPCFile(ienv, targets, name=None):
"""
Install pkg-config files to a "system" location.
Install files to system location, when running "scons install".
If PREFIX is set it is used with a 'lib/pkgconfig' suffix, unless
LIB_INSTALL_DIR is also set in which case it is used with a 'pkgconfig'
suffix. If neither, a 'deploy/pkgconfig' subdirectory of the common
build location is used.
Args:
ienv: construction environment of caller
targets: files to install
name: currently unused (future: installation name)
"""
user_prefix = env.get('PREFIX')
if user_prefix:
user_lib = env.get('LIB_INSTALL_DIR')
......@@ -532,66 +685,86 @@ def __installpcfile(ienv, targets, name):
i_n = ienv.Install(env.get('BUILD_DIR') + 'deploy/pkgconfig', targets)
ienv.Alias("install", i_n)
env.AddMethod(UserInstallTargetPCFile)
def __installextra(ienv, targets, subdir="."):
'''
Install extra files, by default use file relative location as subdir
or use any other prefix of your choice, or in explicit "deploy" folder
'''
def UserInstallTargetExtra(ienv, targets, subdir=None):
"""
Install files to system location.
Install "extra" files not covered by the other system-install methods,
such as tests, xml files, security data files, etc., when doing
"scons install". If PREFIX is set it is used with a 'lib/iotivity' suffix,
unless LIB_INSTALL_DIR is also set in which case it is used with an
'iotivity' suffix. If neither, a 'deploy/extra' subdirectory of the
common build location is used. If subdir is set, it is added to
the end of whichever install path is selected. If not set, the
tail of the path is computed.
Args:
ienv: construction environment of caller
targets: files to install
subdir: if set, use as the tail of the installation path
"""
user_lib = env.get('LIB_INSTALL_DIR')
user_prefix = env.get('PREFIX')
if subdir is None:
subdir = Dir('.').srcnode().path
if user_lib:
dst = user_lib + '/iotivity/' + subdir
elif user_prefix:
dst = user_prefix + '/lib/iotivity/' + subdir
else:
dst = env.get('BUILD_DIR') + '/deploy/extra/' + subdir
for target in targets:
if "." == subdir:
dst = Dir('.').srcnode().path
else:
dst = subdir
if user_lib:
dst = user_lib + '/iotivity/' + dst
elif user_prefix:
dst = user_prefix + '/lib/iotivity/' + dst
else:
dst = env.get('BUILD_DIR') + '/deploy/extra/' + dst
i_n = ienv.Install(dst, target)
ienv.Alias('install', i_n)
env.AddMethod(UserInstallTargetExtra)
def __append_target(ienv, name, targets=None):
if targets:
env.Alias(name, targets)
env.AppendUnique(TS=[name])
def AddPthreadIfNeeded(ienv):
"""
Set a linker flag to enable POSIX threads, if needed.
def __add_pthread_if_needed(ienv):
Args:
ienv: construction environment of caller
"""
if 'gcc' == ienv.get('CC') and target_os not in ['android']:
ienv.AppendUnique(LINKFLAGS="-pthread")
env.AddMethod(AddPthreadIfNeeded)
def __print_targets(env):
Help('''
def PrintTargets(env):
"""
Add message about IoTivity build targets to help message.
Args:
env: construction envrionment
"""
Help("""
===============================================================================
Targets:\n ''')
for t in env.get('TS'):
Default Targets:\n """)
for t in env.get("DefaultBuild"):
Help(t + ' ')
Help('''
Default: all targets will be built. You can specify the target to build:
if env.get("NoDefaultBuild"):
Help("\n\nNon-default Targets:\n ")
for t in env.get('NoDefaultBuild'):
Help(t + ' ')
Help("""
All default targets will be built. You can specify any target(s) to build:
$ scons [options] [target]
===============================================================================
''')
env.AddMethod(__set_dir, 'SetDir')
env.AddMethod(__print_targets, 'PrintTargets')
env.AddMethod(__src_to_obj, 'SrcToObj')
env.AddMethod(__append_target, 'AppendTarget')
env.AddMethod(__add_pthread_if_needed, 'AddPthreadIfNeeded')
env.AddMethod(__install, 'InstallTarget')
env.AddMethod(__installlib, 'UserInstallTargetLib')
env.AddMethod(__installbin, 'UserInstallTargetBin')
env.AddMethod(__installheader, 'UserInstallTargetHeader')
env.AddMethod(__installpcfile, 'UserInstallTargetPCFile')
env.AddMethod(__installextra, 'UserInstallTargetExtra')
""")
env.AddMethod(PrintTargets)
env.SetDir(env.GetLaunchDir())
env['ROOT_DIR'] = env.GetLaunchDir() + '/..'
......@@ -927,7 +1100,7 @@ def ScanJSON(env, directory=None):
targets += Command(dst, src, Copy("$TARGET", "$SOURCE"))
return targets
AddMethod(env, ScanJSON)
env.AddMethod(ScanJSON)
######################################################################
env.SConscript('external_libs.scons')
......
#******************************************************************
#
# Copyright 2019 Open Connectivity Foundation
#
#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# put end-of-scan-phase debug stuff here
# comment out when not using
from __future__ import print_function
Import("env")
from pprint import pprint
#pprint(env.Dump())
#if COMMAND_LINE_TARGETS:
# print("COMMAND_LINE_TARGETS:")
# pprint(COMMAND_LINE_TARGETS)
#if DEFAULT_TARGETS:
# print("DEFAULT_TARGETS:")
# pprint([str(t) for t in DEFAULT_TARGETS])
#if BUILD_TARGETS:
# print("BUILD_TARGETS:")
# pprint([str(t) for t in BUILD_TARGETS])
#print("Named targets for default building:")
#pprint(sorted(env.get('DefaultBuild')))
#if env.get("NoDefaultBuild"):
# print("Named targets not built by default:")
# pprint(sorted(env.get('NoDefaultBuild')))
#from SCons.Script.SConscript import global_exports
#print("Exports:")
#pprint(list(global_exports.keys()))
Return()
Convenience Methods Added to 'env' by IoTivity Project
======================================================
Methods
---------
`AddPthreadIfNeeded(ienv)`
: Set a linker flag to enable POSIX threads, if needed.
Args:
ienv: construction environment of caller
`AppendTarget(ienv, name, targets=None, default=True)`
: Add targets to target list.
The target 'name' is added to either the list of default targets
or non-default targets, which are later handed to the Help function
to help display options to the user. If this is a default target,
it is also added to the DefaultTargets alias.
Args:
ienv: the construction environment of the caller.
name: target name to add.
targets: aliases the 'name' target will expand to.
default: whether this is a default target or not.
See Also:
AppendTarget
`InstallTarget(ienv, targets, name=None, default=True)`
: Copy a built target to the common location.
The iotivity build puts the libraries and executables in a common
location to make it easy to run the executables in place without
worrying about the rpath (for systems that have it), or to account
for no rpath option being available (Windows systems). This not
the same as "installing", see the UserInstall* methods for that.
As side effects, the target is added to either the list of default
targets or non-default targets, which are later handed to the Help
function to help display options to the user. If this is a default
target, it is also added to the DefaultTargets alias.
Args:
ienv: the construction environment of the caller.
targets: list of targets to copy.
name: if set, the name to copy to; else use the target name.
default: whether this is a default target or not.
Notes:
If used for copying a library, a race condition may occur on
Windows systems if parallel building is enabled. The separate
operations from the SharedLibrary builder and the Command builder
calling Copy may see Python release the Global Interpreter Lock
in between steps, and another task may conclude the library
is ready before the copy has taken place, and then report a
missing dependency. A workaround is to generate the library
directly into the common location so it does not need to be
copied after building.
See Also:
AppendTarget
`PrintTargets(env)`
: Add message about IoTivity build targets to help message.
Args:
env: construction envrionment
`ScanJSON(env, directory=None)`
: scanner
`SetDir(env, dir)`
: Set up the target directory for building.
Sets up the scons Variant directory, which is where objects
built under scons control will go, rather than in the source tree.
Also shortcuts some of the available scons mechansims by saving the
paths in the construction environment. Since this sets the
variant dir, this should be called only once, using the main
main construction environment. These are retrieved by:
env.get('SRC_DIR')
env.get('BUILD_DIR')
SRC_DIR will be the passed directory, while BUILD_DIR is
constructed based on target system/arch and release mode.
On Windows:
'dir'/out/windows/<win32 or uwp>/<target_arch>/<release or debug>/
On all others:
'dir'/out/<target_os>/<target_arch>/<release or debug>/
Args:
env: construction environment
dir: the source directory
`SrcToObj(env, src, home='')`
: Build an object in BUILD_DIR.
Uses BUILD_DIR, SetDir should have been called previously.
Note this is used only in the android compat script.
Args:
env: construction environment
src: source directory
home: the part of the path to chop off
`UserInstallTargetBin(ienv, targets, name=None)`
: Install built binaries to a "system" location.
Install files to system location, when running "scons install".
If PREFIX is set it is used with a 'bin' suffix, else a 'deploy'
subdirectory of the common build location is used.
Args:
ienv: construction environment of caller
targets: libraries to install
name: currently unused (future: installation name)
`UserInstallTargetExtra(ienv, targets, subdir=None)`
: Install files to system location.
Install "extra" files not covered by the other system-install methods,
such as tests, xml files, security data files, etc., when doing
"scons install". If PREFIX is set it is used with a 'lib/iotivity' suffix,
unless LIB_INSTALL_DIR is also set in which case it is used with an
'iotivity' suffix. If neither, a 'deploy/extra' subdirectory of the
common build location is used. If subdir is set, it is added to
the end of whichever install path is selected. If not set, the