Changes to support Python 3 87/22787/16
authorMats Wichmann <mats@linux.com>
Wed, 11 Oct 2017 16:30:22 +0000 (10:30 -0600)
committerMats Wichmann <mats@linux.com>
Wed, 25 Oct 2017 16:06:33 +0000 (16:06 +0000)
SCons 3 works with Python 3.x.  Try to eliminate places where the
scons scripts don't work with Py3.  The most "interesting" one is that
subprocess calls to run an external system command do not return a
string, so if we need to do "if substring in string" type queries on
the subprocess return, we need to call a decoder method to turn it into
a string. SCons provides SCons.Util.to_String for this purpose.

Also on strings, there is no longer a 'string_escape' encoder, Py3
strings are unicode so 'unicode_escape' is available. This is handled
with a try block.

Another change is in lambda usage: Python 3 abolished tuple argument
unpacking, and since lambdas only take a single argument usages which
look like multiple arguments (but are actually a tuple), this has an
effect in a couple of places.  The 2to3 tool suggested the changes here.

The local imports in build_common/iotivityconfig were changed to use
the relative-import syntax (a preceding dot). This has been around for
a long time, so causes no problem for Python 2 (in since 2.4).

Python 3 eliminates the cmp method, so the call to sort the help
message by argument name generated a syntax error.  It turns out
the sort named argument can also take a boolean value (undocumented;
scons3 docs will fix that for next release), so instead set sort=True.

Change-Id: I0582e99a83f6ca5246dc566727c0b04b5ed4199b
Signed-off-by: Mats Wichmann <mats@linux.com>
14 files changed:
SConstruct
build_common/SConscript
build_common/darwin/SConscript
build_common/external_builders.scons
build_common/iotivityconfig/__init__.py
build_common/iotivityconfig/compiler/default_configuration.py
build_common/iotivityconfig/compiler/factory.py
build_common/iotivityconfig/compiler/gcc_configuration.py
build_common/tools/UnpackAll.py
extlibs/libcoap/SConscript
extlibs/mbedtls/SConscript
extlibs/tinycbor/SConscript
java/SConscript
resource/csdk/security/unittest/SConscript

index 0da7e31..2a793c9 100644 (file)
@@ -23,6 +23,8 @@
 #
 ##
 import os
+import SCons
+print("Processing using SCons version " + SCons.__version__)
 
 # Load common build config
 SConscript('build_common/SConscript')
index e02aeba..caa1138 100755 (executable)
@@ -4,6 +4,7 @@
 #    release/debug, target os, target arch, cross toolchain, build environment etc
 ##
 import os
+import sys
 import platform
 import re
 
@@ -507,6 +508,7 @@ def __add_pthread_if_needed(ienv):
     if 'gcc' == ienv.get('CC') and target_os not in ['android']:
         ienv.AppendUnique(LINKFLAGS="-pthread")
 
+
 def __print_targets(env):
     Help('''
 ===============================================================================
@@ -547,7 +549,10 @@ user_prefix = env.get('PREFIX')
 user_lib = env.get('LIB_INSTALL_DIR')
 
 if not user_prefix:
-    user_prefix = env.get('BUILD_DIR').encode('string_escape')
+    try:
+        user_prefix = env.get('BUILD_DIR').encode('string_escape')
+    except LookupError:
+        user_prefix = env.get('BUILD_DIR').encode('unicode_escape')
 
 if not user_lib:
     user_lib = '$${prefix}/lib'
@@ -892,7 +897,7 @@ help_vars.AddVariables(
                  validator=PathVariable.PathAccept),
 )
 help_vars.Update(env)
-Help(help_vars.GenerateHelpText(env, sort=cmp))
+Help(help_vars.GenerateHelpText(env, sort=True))
 # Replicate change that occured after help_var initialisation from env
 if target_os == "yocto":
     env['TARGET_OS'] = 'linux'
index ab65efc..1b10cf3 100644 (file)
@@ -7,6 +7,7 @@
 import os
 import subprocess
 from distutils.version import StrictVersion
+import SCons.Util
 
 Import('env')
 
@@ -18,7 +19,7 @@ target_os = env.get('TARGET_OS')
 # output not guaranteed not to change (has already happened)
 # These two commands are used to query the xcode environment:
 tc_path = subprocess.check_output('xcode-select -p', shell=True).rstrip()
-tc_sdks = subprocess.check_output('xcodebuild -showsdks', shell=True)
+tc_sdks = subprocess.check_output('xcodebuild -showsdks', shell=True).rstrip()
 
 # 'xcodebuild -showsdks'  returns information formatted as:
 #
@@ -34,7 +35,7 @@ mac_sdks = []
 ios_sdks = []
 sim_sdks = []
 collecting = False
-for line in tc_sdks.split('\n'):
+for line in SCons.Util.to_String(tc_sdks).split('\n'):
     if collecting:
         if "-sdk" in line:
             # drop the trailing "-sdk sdktag
@@ -113,7 +114,7 @@ else:
 if env.get('SECURED') == '1':
     env.AppendUnique(LIBS=['mbedtls', 'mbedx509', 'mbedcrypto'])
 
-sys_root = tc_path
+sys_root = SCons.Util.to_String(tc_path)
 tmpl = '/Platforms/%s.platform/Developer/SDKs/%s%s.sdk/'
 if target_os == 'darwin':
     sys_root += tmpl % ('MacOSX', 'MacOSX', sys_version)
index 92ea648..0b6dafb 100644 (file)
 ##
 import os
 import subprocess
-import urllib2
+try:
+    from urllib2 import urlopen
+except ModuleNotFoundError:
+    from urllib.request import urlopen
 import SCons.Errors
 
 Import('env')
@@ -68,8 +71,8 @@ def __prepare_lib(ienv, libname, lib=None, path=None, script=None):
 def __configure(env, cwd, cmd):
     print("Configuring using [%s/%s] ..." % (cwd, cmd))
     # build it now (we need the shell, because some programs need it)
-    devnull = open(os.devnull, "wb")
-    handle = subprocess.Popen(cmd, shell=True, cwd=cwd, stdout=devnull)
+    with open(os.devnull, "wb") as devnull:
+        handle = subprocess.Popen(cmd, shell=True, cwd=cwd, stdout=devnull)
 
     if handle.wait() != 0:
         raise SCons.Errors.BuildError("Run configuring script [%s]" % (cmd))
@@ -83,14 +86,16 @@ def __download(ienv, target, url):
     try:
         print("Download %s from %s" % (target, url))
         print("Downloading ...")
-        stream = urllib2.urlopen(url)
-        file = open(target, 'wb')
-        file.write(stream.read())
-        file.close()
-        print("Download %s from %s complete" % (target, url))
-        return target
+        # Python2 does not have a context manager for urlopen
+        stream = urlopen(url)
+        with open(target, 'wb') as file:
+            file.write(stream.read())
     except Exception as e:
         raise SCons.Errors.StopError('%s [%s]' % (e, url))
+    finally:
+        print("Download %s from %s complete" % (target, url))
+        stream.close()
+        return target
 
 
 # Install header file(s) to <src_dir>/deps/<target_os>/include
index d84d361..e0c308d 100644 (file)
@@ -17,7 +17,7 @@
 # This file contains compiler tests for use in scons 'Configure'
 # tests.
 
-from compiler import factory
+from .compiler import factory
 
 def _check_for_broken_gcc_headers(context, flag):
     # Check for issue in some older (pre-C++11) C library headers that
index ed90f40..76f000d 100644 (file)
@@ -14,7 +14,7 @@
 # limitations under the License.
 # ------------------------------------------------------------------------
 
-from configuration import Configuration
+from .configuration import Configuration
 
 # Default (very simple) compiler configuration
 class DefaultConfiguration(Configuration):
index 7b0bee7..975a081 100644 (file)
@@ -14,8 +14,8 @@
 # limitations under the License.
 # ------------------------------------------------------------------------
 
-from default_configuration import *
-from gcc_configuration import *
+from .default_configuration import *
+from .gcc_configuration import *
 
 # Canonicalize the C or C++ compiler name to "gcc" if gcc is being
 # used to simplify mapping to the GCC compiler configuration since GCC
index fbc8f38..436caeb 100644 (file)
@@ -14,7 +14,7 @@
 # limitations under the License.
 # ------------------------------------------------------------------------
 
-from configuration import Configuration
+from .configuration import Configuration
 
 # GCC compiler-specific configuration
 class GccConfiguration(Configuration):
@@ -31,7 +31,7 @@ class GccConfiguration(Configuration):
         # flag is required to compile C99 code without warning or
         # error.
 
-        from default_configuration import DefaultConfiguration
+        from .default_configuration import DefaultConfiguration
         def_config = DefaultConfiguration(self._context)
 
         return """
index 3c25fb4..c2822f7 100644 (file)
@@ -158,7 +158,7 @@ def __fileextractor_win_7zip( env, count, no, i ) :
 def __getExtractor( source, env ) :
     # we check each unpacker and get the correc  list command first, run the command and
     # replace the target filelist with the list values, we sorte the extractors by their priority
-    for unpackername, extractor in sorted(env["UNPACK"]["EXTRACTOR"].iteritems(), key = lambda (k,v) : (v["PRIORITY"],k)):
+    for unpackername, extractor in sorted(iter(env["UNPACK"]["EXTRACTOR"].items()), key = lambda k_v : (k_v[1]["PRIORITY"],k_v[0])):
 
         # if the run command not set, we continue the extractor search, otherwise we check the extractor parameters
         if not SCons.Util.is_String(extractor["RUN"]) :
@@ -267,7 +267,7 @@ def __emitter( target, source, env ) :
     # a string we push it back to the target list
     try :
         if callable(extractor["LISTEXTRACTOR"]) :
-            target = filter(lambda s: SCons.Util.is_String(s), [extractor["LISTEXTRACTOR"](env, len(target), no, i) for no, i in enumerate(target)])
+            target = [s for s in [extractor["LISTEXTRACTOR"](env, len(target), no, i) for no, i in enumerate(target)] if SCons.Util.is_String(s)]
     except Exception as e :
         raise SCons.Errors.StopError( "%s" % (e) )
 
index fb55fe0..9780586 100644 (file)
@@ -28,6 +28,7 @@ import os
 import glob
 import datetime
 import subprocess
+import SCons.Util
 
 Import('env')
 
@@ -68,8 +69,8 @@ if with_upstream_libcoap == '1':
         Exit(msg)
 
     os.chdir(libcoap_dir)
-    out = subprocess.check_output('git log --format=%d -n 1', shell=True)
-    if libcoap_version not in out:
+    out = subprocess.check_output('git log --format=%d -n 1', shell=True).rstrip()
+    if libcoap_version not in SCons.Util.to_String(out):
         print('''
 ******************************* Info: *****************************************
 * Your libCoAP repo is not up to date with the latest version we require (%s).
index 68daf89..b9ec6cf 100644 (file)
@@ -20,6 +20,7 @@
 
 Import('env')
 import SCons.Errors
+import SCons.Util
 import os
 import sys
 import re
@@ -53,8 +54,8 @@ os.chdir(mbedtls_dir)
 # with that name doesn't exist.
 # Tizen uses its own process to prepare the mbedTLS repo in gbsbuild.sh.
 if os.path.exists('.git/HEAD'):
-    out = subprocess.check_output('git tag -l ' + mbedtls_revision, shell=True)
-    if mbedtls_revision not in out:
+    out = subprocess.check_output('git tag -l ' + mbedtls_revision, shell=True).rstrip()
+    if mbedtls_revision not in SCons.Util.to_String(out):
         print(out)
         msg = '''
 *********************************** Error: ************************************
index 69455fe..a23078d 100644 (file)
@@ -20,6 +20,7 @@
 
 import os
 import subprocess
+import SCons.Util
 
 Import('env')
 
@@ -46,8 +47,8 @@ os.chdir(cborDir)
 # This code also assumes tinycbor_revision is a tag; if it changes to a branch
 # or an arbitrary commit, disable this check below.
 if target_os != 'tizen' and os.path.exists('.git/HEAD'):
-    out = subprocess.check_output('git tag -l ' + cborRevision, shell=True)
-    if cborRevision not in out:
+    out = subprocess.check_output('git tag -l ' + cborRevision, shell=True).rstrip()
+    if cborRevision not in SCons.Util.to_String(out):
         print(out)
         msg = '''
 *********************************** Error: ************************************
index 4349095..f0e9431 100644 (file)
@@ -157,7 +157,7 @@ def find_scons_java_version(env):
         print('\t***** Java build will likely fail or have errors in the build output. *****')
         print('\t***** Recommend updating to the latest version of SCons               *****')
         return None
-    for line in java_ver.split('\n'):
+    for line in SCons.Util.to_String(java_ver).split('\n'):
         # handle building with versions of Java not supported by SCons
         if ' 1.9' in line:
             print('\tJava version 1.9 found.')
index d3bebac..95c7014 100644 (file)
@@ -26,7 +26,6 @@ Import('test_env')
 
 # SConscript file for Local PKI google tests
 srmtest_env = test_env.Clone()
-src_dir = srmtest_env.get('SRC_DIR')
 target_os = srmtest_env.get('TARGET_OS')
 rd_mode = srmtest_env.get('RD_MODE')
 
@@ -102,13 +101,17 @@ unittest = srmtest_env.Program('unittest', [
     'crlresourcetest.cpp'
 ])
 
-unittest_src_dir = os.path.join(src_dir, 'resource', 'csdk', 'security', 'unittest') + os.sep
-unittest_build_dir = os.path.join(srmtest_env.get('BUILD_DIR'), 'resource', 'csdk', 'security', 'unittest')
-unittest_build_dir = os.path.normpath(unittest_build_dir) + os.sep
-
+# this path will be passed as a command-line parameter,
+# so needs encoding to avoid problems with escapes on Windows
+unittest_build_dir = Dir('.').abspath + os.sep
+try:                   # if success, this will be Python 2.x
+    unittest_build_dir = unittest_build_dir.encode('string_escape')
+    unittest_build_dir = unittest_build_dir.replace("\\", "\\\\")
+except LookupError:    # this will be Python 3.x - unicode strings
+    unittest_build_dir = unittest_build_dir.encode('unicode_escape')
+    unittest_build_dir = str(unittest_build_dir).replace("\\", "\\\\")
 srmtest_env.AppendUnique(CPPDEFINES=[
-    'SECURITY_BUILD_UNITTEST_DIR=' +
-    unittest_build_dir.encode('string_escape').replace("\\", "\\\\")
+    'SECURITY_BUILD_UNITTEST_DIR=' + unittest_build_dir
 ])
 
 unittest += srmtest_env.ScanJSON('resource/csdk/security/unittest')