Build extlibs libs straight to destination 57/26157/9
authorMats Wichmann <mats@linux.com>
Wed, 4 Jul 2018 20:17:05 +0000 (14:17 -0600)
committerMats Wichmann <mats@linux.com>
Thu, 23 Aug 2018 13:36:26 +0000 (13:36 +0000)
As described in IOT-1986, Windows builders (in particular) have occasional
problems with multi-process builds - that is -j with a number larger
than one.  Libraries are built with a {Static,Shared}Library() call which
builds in the directory where the SConscript is executing, following
which we "install" into the top-level directory, where link instructions
will find them (the top dir is always in LIBPATH), and where tests and
other binaries expect to find them. For example, from these instructions:

  static_libmbedx509 = mbex509_env.StaticLibrary('mbedx509', mbeX509_src)
  mbex509_env.InstallTarget(static_libmbedx509, 'mbedx509')

For that, we see this abridged sequence from a Linux build log:

  scons: building `extlibs/mbedtls/libmbedx509.a' because it doesn't exist
  Preparing target extlibs/mbedtls/libmbedx509.a...
  Building extlibs/mbedtls/libmbedx509.a with action:
    $AR $ARFLAGS $TARGET $SOURCES
  Building extlibs/mbedtls/libmbedx509.a with action:
    $RANLIB $RANLIBFLAGS $TARGET
  ranlib extlibs/mbedtls/libmbedx509.a
  scons: building `out/linux/x86_64/debug/libmbedx509.a' because it doesn't exist
  Preparing target out/linux/x86_64/debug/libmbedx509.a...
  Building out/linux/x86_64/debug/libmbedx509.a with action:
    Copy("$TARGET", "$SOURCE")
  Copy("out/linux/x86_64/debug/libmbedx509.a", "extlibs/mbedtls/libmbedx509.a")

The actual target that matters for dependency computation is the result
of the library build, and that target is "done" when the StaticLibrary
call is complete, so other processes which depend on that target can be
released by the SCons Taskmaster to run at that point.  File copies are
not necessarily atomic on Windows Python, and worse, the build-plus-copy
is certainly not atomic, so sometimes one of the released processes
finds the "installed" library is not there (yet) when it tries to
link to it.

At least one of the sconscripts in extlibs has tried to mitigate this
problem by not doing the InstallTarget(), and instead pointing clients
of the library right to the directory it is built in by adding to the
LIBPATH construction variable. This is also done for a couple of libs in
build_common/windows/SConscript. This change is the other side of the same
coin - instead of pointing builds to a bunch of places where a library was
built, just build straight into the location where we want the library,
still avoiding the copy step.  In other words, instead of saying:

  StaticLibrary(target='foo', source=foo_src)
  env.AppendUniqe(LIBPATH, this-dir)

we can say:

  StaticLibrary(target='<somepath>/foo', source=foo_src)

Sorry for the long message - the upshot is, to test this idea, start
by converting the extlibs libraries to build straight into the place we
want them; if it works out, convert the others later.

Change-Id: I81858f221a2e0a0ee913dcd452fc607fcf79e7b2
Signed-off-by: Mats Wichmann <mats@linux.com>
Bug: https://jira.iotivity.org/browse/IOT-1986

extlibs/cjson/SConscript
extlibs/gtest/SConscript
extlibs/libcoap/SConscript
extlibs/mbedtls/SConscript
extlibs/sqlite3/SConscript
extlibs/yaml/SConscript

index 932eb2a..bde8da5 100644 (file)
 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 
 Import('env')
+build_dir = env.get('BUILD_DIR')
 
 cjson_env = env.Clone()
-
 if cjson_env.get('TARGET_OS') in ['windows', 'msys_nt']:
     # Macro needed for Windows builds to avoid __declspec(dllexport)
     # and __declspec(dllimport) for cJSON APIs.
     cjson_env.AppendUnique(CPPDEFINES=['CJSON_HIDE_SYMBOLS'])
 
-libcjson = cjson_env.StaticLibrary('cjson', ['cJSON.c'], OBJPREFIX='libcjson_')
-cjson_env.InstallTarget(libcjson, 'cjson')
+libcjson = cjson_env.StaticLibrary(build_dir + 'cjson', ['cJSON.c'],
+                                   OBJPREFIX='libcjson_')
+cjson_env.UserInstallTargetLib(libcjson)
index b2e96dd..e66070b 100644 (file)
@@ -7,10 +7,9 @@
 
 import os
 Import('env')
-
-gtest_env = env.Clone()
-target_os = gtest_env.get('TARGET_OS')
-src_dir = gtest_env.get('SRC_DIR')
+target_os = env.get('TARGET_OS')
+src_dir = env.get('SRC_DIR')
+build_dir = env.get('BUILD_DIR')
 
 targets_need_gtest = ['darwin', 'linux', 'msys_nt', 'windows']
 
@@ -25,6 +24,7 @@ gtest_zip_file = 'release-' + GTEST_VERSION + '.zip'
 gtest_url = 'https://github.com/google/googletest/archive/' + gtest_zip_file
 gtest_zip_path = os.path.join(src_dir, 'extlibs', 'gtest', gtest_zip_file)
 
+gtest_env = env.Clone()
 # nothing to do if this target doesn't use gtest
 if target_os not in targets_need_gtest:
     Return("gtest_env")
@@ -98,12 +98,10 @@ elif target_os in ['windows'] and 'IOTIVITY_GTEST_HAS_BEEN_BUILT' not in env:
     gtest_build_env.AppendUnique(CPPPATH=[os.path.join(gtest_dir, 'include')])
     gtest_build_env.AppendUnique(CXXFLAGS=['/EHsc'])
     gtest_build_env.AppendUnique(CCFLAGS=['/W4', '/WX'])
-    gtest = gtest_build_env.StaticLibrary(
-        target='gtest', source=['%s/src/gtest-all.cc' % gtest_dir])
-    gtest_main = gtest_build_env.StaticLibrary(
-        target='gtest_main', source=['%s/src/gtest_main.cc' % gtest_dir])
-    gtest_env.InstallTarget(gtest, 'gtest')
-    gtest_env.InstallTarget(gtest_main, 'gtest_main')
+    gtest = gtest_build_env.StaticLibrary(target=build_dir + 'gtest',
+                           source=gtest_dir + '/src/gtest-all.cc')
+    gtest_main = gtest_build_env.StaticLibrary(target=build_dir + 'gtest_main',
+                           source=gtest_dir + '/src/gtest_main.cc')
 
     gtest_vars = Variables()
     gtest_vars.AddVariables(('IOTIVITY_GTEST_HAS_BEEN_BUILT', '', '1'))
index dae6017..74395ba 100755 (executable)
@@ -28,12 +28,12 @@ import SCons.Util
 
 Import('env')
 
-libcoap_env = env.Clone()
-target_os = libcoap_env.get('TARGET_OS')
-src_dir = libcoap_env.get('SRC_DIR')
-ca_transport = libcoap_env.get('TARGET_TRANSPORT')
-with_tcp = libcoap_env.get('WITH_TCP')
-with_upstream_libcoap = libcoap_env.get('WITH_UPSTREAM_LIBCOAP')
+target_os = env.get('TARGET_OS')
+src_dir = env.get('SRC_DIR')
+build_dir = env.get('BUILD_DIR')
+ca_transport = env.get('TARGET_TRANSPORT')
+with_tcp = env.get('WITH_TCP')
+with_upstream_libcoap = env.get('WITH_UPSTREAM_LIBCOAP')
 
 # Temporary LibCoAP URL is a fork of the original.
 # Once a pull request is merged, change this back to the obgm original below.
@@ -89,6 +89,7 @@ info_forkedcoap = '''
 *******************************************************************************
 '''
 
+libcoap_env = env.Clone()
 if with_upstream_libcoap == '0':
     print(info_forkedcoap)
 else:
@@ -301,13 +302,11 @@ else:
         libcoap_src = [src for src in libcoap_src if 'coap_io_lwip.c' not in src.path]
 
 # finally ready to build:
-libcoap = libcoap_env.StaticLibrary('coap', libcoap_src, OBJPREFIX='libcoap_')
+libcoap = libcoap_env.StaticLibrary(build_dir + 'coap', libcoap_src, OBJPREFIX='libcoap_')
+libcoap_env.UserInstallTargetLib(libcoap)
 
 # set for use by other scripts:
 if with_upstream_libcoap == '1':
     env.AppendUnique(LIBCOAP_INC='#/extlibs/libcoap/libcoap/include')
 else:
     env.AppendUnique(LIBCOAP_INC='#/resource/csdk/connectivity/lib/libcoap-4.1.1/include')
-
-libcoap_env.InstallTarget([libcoap], 'coap')
-libcoap_env.UserInstallTargetLib(libcoap)
index 8b7b30a..47388d8 100644 (file)
@@ -28,8 +28,9 @@ import subprocess
 from shutil import copyfile
 
 target_os = env.get('TARGET_OS')
-root_dir = env.get('SRC_DIR')
-mbedtls_dir = os.path.join(root_dir, 'extlibs', 'mbedtls', 'mbedtls')
+src_dir = env.get('SRC_DIR')
+build_dir = env.get('BUILD_DIR')
+mbedtls_dir = os.path.join(src_dir, 'extlibs', 'mbedtls', 'mbedtls')
 start_dir = os.getcwd()
 mbedtls_config_file = 'config-iotivity.h' if target_os != 'windows' else 'config-iotivity_windows.h'
 
@@ -110,8 +111,8 @@ os.chdir(start_dir)
 # Copy IoTivity's version of the mbedtls build configuration file
 # from extlibs/mbedtls/iotivity-config.h
 # to extlibs/mbedtls/mbedtls/include/mbedtls/config.h
-iotivity_config = os.path.join(root_dir, 'extlibs', 'mbedtls', mbedtls_config_file)
-mbedtls_config = os.path.join(root_dir, 'extlibs', 'mbedtls', 'mbedtls',
+iotivity_config = os.path.join(src_dir, 'extlibs', 'mbedtls', mbedtls_config_file)
+mbedtls_config = os.path.join(src_dir, 'extlibs', 'mbedtls', 'mbedtls',
                               'include', 'mbedtls', 'config.h')
 
 try:
@@ -219,17 +220,14 @@ mbeX509_src = [
 ]
 
 mbedcrypto_env = mbedtls_env.Clone()
-static_libmbedcrypto = mbedcrypto_env.StaticLibrary('mbedcrypto', mbedcrypto_src)
-mbedcrypto_env.InstallTarget(static_libmbedcrypto, 'mbedcrypto')
+static_libmbedcrypto = mbedcrypto_env.StaticLibrary(build_dir + 'mbedcrypto', mbedcrypto_src)
 mbedcrypto_env.UserInstallTargetLib(static_libmbedcrypto, 'mbedcrypto')
 
 mbex509_env = mbedtls_env.Clone()
 mbex509_env.AppendUnique(LIBS=['mbedcrypto'])
-static_libmbedx509 = mbex509_env.StaticLibrary('mbedx509', mbeX509_src)
-mbex509_env.InstallTarget(static_libmbedx509, 'mbedx509')
+static_libmbedx509 = mbex509_env.StaticLibrary(build_dir + 'mbedx509', mbeX509_src)
 mbex509_env.UserInstallTargetLib(static_libmbedx509, 'mbedx509')
 
 mbedtls_env.AppendUnique(LIBS=['mbedx509', 'mbedcrypto'])
-static_libmbedtls = mbedtls_env.StaticLibrary('mbedtls', mbedtls_src)
-mbedtls_env.InstallTarget(static_libmbedtls, 'mbedtls')
+static_libmbedtls = mbedtls_env.StaticLibrary(build_dir + 'mbedtls', mbedtls_src)
 mbedtls_env.UserInstallTargetLib(static_libmbedtls, 'mbedtls')
index a1449b1..aef67c6 100644 (file)
@@ -6,10 +6,10 @@ import os
 import shutil
 
 Import('env')
-sqlite_env = env.Clone()
 
-target_os = sqlite_env.get('TARGET_OS')
-src_dir = sqlite_env.get('SRC_DIR')
+target_os = env.get('TARGET_OS')
+src_dir = env.get('SRC_DIR')
+build_dir = env.get('BUILD_DIR')
 
 targets_need_sqlite = ['android', 'msys_nt', 'windows', 'ios']
 sqlite_dir = src_dir + '/extlibs/sqlite3/'
@@ -27,6 +27,8 @@ sqlite_zip_file = sqlite_tmp_dir + '.zip'
 sqlite_c_tmp = os.path.join(sqlite_tmp_dir, 'sqlite3.c')
 sqlite_h_tmp = os.path.join(sqlite_tmp_dir, 'sqlite3.h')
 
+sqlite_env = env.Clone()
+
 if target_os in targets_need_sqlite:
     print('*** Checking for presence of %s ***' % sqlite_package)
     os.listdir(sqlite_dir)
@@ -42,8 +44,5 @@ if target_os in targets_need_sqlite:
 if target_os in ['windows']:
     if sqlite_env.get('MSVC_UWP_APP') == '1':
         sqlite_env.AppendUnique(CPPDEFINES=['SQLITE_OS_WINRT'])
-    libsqlite3 = sqlite_env.StaticLibrary('sqlite3', sqlite_c)
-    # In multi-threaded builds, SCons appears to proceed to using sqlite3.lib
-    # before finishing InstallTarget(libsqlite3, 'sqlite3') here. So, use the
-    # generated LIB directly, without installing it.
-    env.AppendUnique(LIBPATH=[os.path.join(env.get('BUILD_DIR'), 'extlibs/sqlite3')])
+    libsqlite3 = sqlite_env.StaticLibrary(build_dir + 'sqlite3', sqlite_c)
+    sqlite_env.UserInstallTargetLib(libsqlite3)
index 17457c5..e12c588 100644 (file)
@@ -21,8 +21,8 @@
 import os
 Import('env')
 
-yaml_env = env.Clone()
 src_dir = env.get('SRC_DIR')
+build_dir = env.get('BUILD_DIR')
 
 yamlDir = os.path.join(src_dir, 'extlibs', 'yaml', 'yaml')
 
@@ -35,6 +35,7 @@ if not os.path.exists(yamlDir):
 '''
     Exit(msg)
 
+yaml_env = env.Clone()
 ######################################################################
 # Build flags
 ######################################################################
@@ -55,6 +56,5 @@ yaml_env.AppendUnique(
 # Source files and Targets
 ######################################################################
 yaml_src = [env.Glob('yaml/src/*.cpp'), env.Glob('yaml/src/contrib/*.cpp')]
-yamlsdk = yaml_env.StaticLibrary('YamlParser', yaml_src)
-
-yaml_env.InstallTarget(yamlsdk, 'libYaml')
+yamlsdk = yaml_env.StaticLibrary(build_dir + 'YamlParser', yaml_src)
+yaml_env.UserInstallTargetLib(yamlsdk)