valgrind default switched to off.
[iotivity.git] / build_common / SConscript
1 # -*- mode: python; python-indent-offset: 4; indent-tabs-mode: nil -*-
2 ##
3 # This script includes generic build options:
4 #    release/debug, target os, target arch, cross toolchain, build environment etc
5 ##
6 import os
7 import sys
8 import platform
9 import re
10
11 project_version = '2.0.0'
12
13 # Map of build host to possible target os
14 host_target_map = {
15     'linux': ['linux', 'android', 'yocto', 'tizen', 'webos'],
16     'windows': ['windows', 'android'],
17     'darwin': ['darwin', 'ios', 'android'],
18     'msys_nt': ['msys_nt'],
19 }
20
21 # Map of target os to possible target architecture
22 os_arch_map = {
23     'linux': [
24         'x86', 'x86_64', 'arm', 'armv7l', 'arm-v7a', 'armeabi-v7a', 'arm64', 'mips',
25         'mipsel', 'mips64', 'mips64el', 'i386', 'powerpc', 'sparc', 'aarch64',
26         'armv6l', 'armv7l'
27     ],
28     'tizen': ['x86', 'x86_64', 'arm', 'arm-v7a', 'armeabi-v7a', 'arm64', 'armv7l'],
29     'webos': ['arm'],
30     'android': [
31         'x86', 'x86_64', 'armeabi', 'armeabi-v7a', 'armeabi-v7a-hard',
32         'arm64-v8a'
33     ],
34     'windows': ['x86', 'amd64', 'arm'],
35     'msys_nt': ['x86', 'x86_64'],
36     'darwin': ['i386', 'x86_64'],
37     'ios': ['i386', 'x86_64', 'armv7', 'armv7s', 'arm64'],
38     'yocto': [
39         'i586', 'i686', 'x86_64', 'arm', 'aarch64', 'powerpc', 'powerpc64',
40         'mips', 'mipsel'
41     ],
42 }
43
44 # Fetch host from Python platform information and smash case
45 host = platform.system().lower()
46
47 # In case of msys_nt, the host string contains an internal Windows version
48 # which is not interesting for lookups in the maps.
49 # Canonicalize the msys_nt-XX.X system name to msys-nt
50 if 'msys_nt' in host:
51     host = 'msys_nt'
52
53 if host not in host_target_map:
54     msg = "\nError: building on host os '%s' is not currently supported.\n" % host
55     Exit(msg)
56
57 ######################################################################
58 # Get build options from command line
59 ######################################################################
60 target_os = ARGUMENTS.get('TARGET_OS', host).lower()
61
62 if target_os not in host_target_map[host]:
63     msg = "\nError: host '%s' cannot currently build target '%s'" % (host, target_os)
64     msg += "\n\tchoices: %s\n" % host_target_map[host]
65     Exit(msg)
66
67 # work out a reasonable default for target_arch if not specified by user
68 if target_os == 'android':
69     default_arch = 'x86'
70 elif target_os == 'webos':
71     default_arch = 'arm'
72 else:
73     default_arch = platform.machine()
74     if target_os == 'windows':
75         default_arch = default_arch.lower()
76     if target_os == 'linux' and default_arch in ('i586', 'i686'):
77         default_arch = 'x86'
78     if target_os == 'tizen' and default_arch in ('i586', 'i686'):
79         default_arch = 'x86'
80
81 target_arch = ARGUMENTS.get('TARGET_ARCH', default_arch)  # target arch
82
83 default_with_upstream_libcoap = 0
84
85 if ARGUMENTS.get('TEST'):
86     logging_default = False
87 else:
88     release_mode = False
89     if ARGUMENTS.get('RELEASE', True) in [
90             'y', 'yes', 'true', 't', '1', 'on', 'all', True
91     ]:
92         release_mode = True
93     logging_default = (release_mode is False)
94
95 # generate a list of unique targets: convert to set() for uniqueness,
96 # then convert back to a list
97 targetlist = list(set(x for l in list(host_target_map.values()) for x in l))
98
99 ######################################################################
100 # Common build options
101 ######################################################################
102
103 help_vars = Variables()
104 help_vars.AddVariables(
105     ('PROJECT_VERSION',
106                  'The version of IoTivity',
107                  project_version),
108     BoolVariable('VERBOSE',
109                  'Show compilation',
110                  default=False),
111     BoolVariable('RELEASE',
112                  'Build for release?',
113                  default=True),
114     EnumVariable('TARGET_OS',
115                  'Target platform',
116                  default=host,
117                  allowed_values=targetlist),
118     EnumVariable('SECURED',
119                  'Build with DTLS',
120                  default='1',
121                  allowed_values=('0', '1')),
122     ListVariable('TARGET_TRANSPORT',
123                  'Target transport',
124                  default='ALL',
125                  names=('ALL', 'BT', 'BLE', 'IP', 'NFC')),
126     BoolVariable('WITH_TCP',
127                  'Build with TCP adapter',
128                  default=False),
129     BoolVariable('WITH_PROXY',
130                  'Build with CoAP-HTTP Proxy',
131                  default=True),
132     ListVariable('WITH_MQ',
133                  'Build with MQ publisher/broker',
134                  default='OFF',
135                  names=('OFF', 'SUB', 'PUB', 'BROKER')),
136     BoolVariable('WITH_CLOUD',
137                  'Build including AccountManager class and Cloud Client sample',
138                  default=False),
139     BoolVariable('WITH_TEST',
140                  'Build unit tests',
141                  default=True),
142     ListVariable('RD_MODE',
143                  'Resource Directory build mode',
144                  default='CLIENT',
145                  names=('CLIENT', 'SERVER')),
146     BoolVariable('SIMULATOR',
147                  'Build with simulator module',
148                  default=False),
149     EnumVariable('TARGET_ARCH',
150                  'Target architecture',
151                  default=default_arch,
152                  allowed_values=os_arch_map[target_os]),
153     EnumVariable('MULTIPLE_OWNER',
154                  'Enable multiple owner',
155                  default='0',
156                  allowed_values=('0', '1')),
157     EnumVariable('EXC_PROV_SUPPORT',
158                  'Except OCPMAPI library(libocpmapi.so)',
159                  default='0',
160                  allowed_values=('0', '1')),
161     EnumVariable('TEST',
162                  'Run unit tests',
163                  default='0',
164                  allowed_values=('0', '1')),
165     BoolVariable('LOGGING',
166                  'Enable stack logging',
167                  default=logging_default),
168     EnumVariable('LOG_LEVEL',
169                  'Enable stack logging level',
170                  default='DEBUG',
171                  allowed_values=('DEBUG', 'INFO', 'ERROR', 'WARNING', 'FATAL')),
172     EnumVariable('ROUTING',
173                  'Enable routing',
174                  default='EP',
175                  allowed_values=('GW', 'EP')),
176     EnumVariable('WITH_UPSTREAM_LIBCOAP',
177                  'Use latest stable version of LibCoAP downloaded from github',
178                  default=default_with_upstream_libcoap,
179                  allowed_values=('0', '1')),
180     EnumVariable('BUILD_SAMPLE',
181                  'Build with sample',
182                  default='ON',
183                  allowed_values=('ON', 'OFF')),
184 #    ANDROID_NDK set at end after default computed
185 #    ANDROID_HOME set at end after default computed
186 #    ANDROID_GRADLE set at end after default computed
187     BoolVariable('WITH_ENV',
188                  'Use compiler options from environment',
189                  default=False),
190     BoolVariable('AUTOMATIC_UPDATE',
191                  'Makes libcoap update automatically to the required versions if needed.',
192                  default=False),
193     BoolVariable('BUILD_JAVA',
194                  'Build Java bindings',
195                  default=False),
196     PathVariable('JAVA_HOME',
197                  'JDK directory',
198                  default=os.environ.get('JAVA_HOME'),
199                  validator=PathVariable.PathAccept),
200     EnumVariable('OIC_SUPPORT_TIZEN_TRACE',
201                  'Tizen Trace(T-trace) api availability',
202                  default=False,
203                  allowed_values=('True', 'False')),
204     BoolVariable('MANDATORY',
205                  'Enable/disable(default) mandatory',
206                  default=False)
207 )
208
209 ######################################################################
210 # Platform (build target) specific options
211 ######################################################################
212 if target_os in ['linux']:
213     # Build option to enable failing build if warnings encountered.
214     # May need to be off for developing with newer compilers which
215     # are stricter about emitting warnings. Defaults to true so
216     # developer builds and gerrit builds have all warnings examined.
217     help_vars.Add(
218         BoolVariable('ERROR_ON_WARN',
219                      'Make all compiler warnings into errors.',
220                       default=False))
221
222 targets_support_valgrind = ['linux', 'darwin']
223 if target_os in targets_support_valgrind:
224     # Build option to enable unit tests to be run under valgrind.
225     # May need to disable on small-memory platforms (e.g. Raspberry Pi)
226     # Checking for memory leak and usage errors is part of the
227     # acceptance criteria for project code, so this should default to on.
228     help_vars.Add(
229         BoolVariable('VALGRIND_CHECKS',
230                      'Build support for running code coverage checks',
231                       default=False))
232
233 targets_support_gcov = ['linux', 'darwin']
234 if target_os in targets_support_gcov:
235     # Build option to enable coverage checking using gcov.
236     # Requires gcc or clang family compilers.
237     # Actual compiler flags need to be set in target-specific script.
238     help_vars.Add(
239         BoolVariable('COVERAGE_CHECKS',
240                      'Build support for running code coverage checks',
241                       default=False))
242
243 if target_os == 'windows':
244     # Builds differ based on Visual Studio version
245     #   For VS2013, MSVC_VERSION is '12.0'.
246     #   For VS2015, MSVC_VERSION is '14.0'.
247     #   For VS2017, MSVC_VERSION is '14.1'.
248     # Default value is None, which means SCons will pick
249     help_vars.Add(
250         EnumVariable('MSVC_VERSION',
251                      'MSVC compiler version - Windows',
252                      default=None,
253                      allowed_values=('12.0', '14.0', '14.1')))
254     help_vars.Add(
255         EnumVariable('MSVC_UWP_APP',
256                      'Build a Universal Windows Platform (UWP) Application',
257                      default='0',
258                      allowed_values=('0', '1')))
259
260 AddOption(
261     '--prefix',
262     dest='prefix',
263     type='string',
264     nargs=1,
265     action='store',
266     metavar='DIR',
267     help='installation prefix')
268
269 ######################################################################
270 # Platform (build target) specific options: SDK/NDK & toolchain
271 ######################################################################
272 targets_support_cc = ['linux', 'tizen']
273
274 if target_os in targets_support_cc:
275     # Set cross compile toolchain
276     help_vars.Add('TC_PREFIX',
277                   "Toolchain prefix (Generally only required for cross-compiling)",
278                   default=None)
279     help_vars.Add(
280         PathVariable('TC_PATH',
281                      'Toolchain path (Generally only required for cross-compiling)',
282                      default=None,
283                      validator=PathVariable.PathAccept))
284
285 ######################################################################
286 # this is where the setup of the construction envionment begins
287 ######################################################################
288 if target_os in ['android']:
289     # Android always uses GNU compiler regardless of the host
290     env = Environment(
291         variables=help_vars,
292         tools=['gnulink', 'gcc', 'g++', 'ar', 'as', 'textfile'])
293 else:
294     env = Environment(
295         variables=help_vars,
296         tools=['default', 'textfile'],
297         TARGET_ARCH=target_arch,
298         TARGET_OS=target_os,
299         PREFIX=GetOption('prefix'),
300         LIB_INSTALL_DIR=ARGUMENTS.get('LIB_INSTALL_DIR')  #for 64bit build
301     )
302
303 if env.get('WITH_ENV'):
304     env['ENV'] = os.environ
305     if 'CC' in os.environ:
306         env['CC'] = Split(os.environ['CC'])
307         print("using CC from environment: %s" % env['CC'])
308     if 'CXX' in os.environ:
309         env['CXX'] = Split(os.environ['CXX'])
310         print("using CXX from environment: %s" % env['CXX'])
311     if 'CFLAGS' in os.environ:
312         env['CFLAGS'] = Split(os.environ['CFLAGS'])
313         print("using CFLAGS from environment: %s" % env['CFLAGS'])
314     if 'CXXFLAGS' in os.environ:
315         env['CXXFLAGS'] = Split(os.environ['CXXFLAGS'])
316         print("using CXXFLAGS from environment: %s" % env['CXXFLAGS'])
317     if 'CCFLAGS' in os.environ:
318         env['CCFLAGS'] = Split(os.environ['CCFLAGS'])
319         print("using CCFLAGS from environment: %s" % env['CCFLAGS'])
320     if 'CPPFLAGS' in os.environ:
321         env['CPPFLAGS'] = Split(os.environ['CPPFLAGS'])
322         print("using CPPFLAGS from environment: %s" % env['CPPFLAGS'])
323     if 'LDFLAGS' in os.environ:
324         env['LINKFLAGS'] = Split(os.environ['LDFLAGS'])
325         print("using LDFLAGS/LINKFLAGS from environment: %s" % env['LINKFLAGS'])
326
327 # set quieter build messages unless verbose mode was requested
328 if not env.get('VERBOSE'):
329     env['CCCOMSTR'] = "Compiling $TARGET"
330     env['SHCCCOMSTR'] = "Compiling $TARGET"
331     env['CXXCOMSTR'] = "Compiling $TARGET"
332     env['SHCXXCOMSTR'] = "Compiling $TARGET"
333     env['LINKCOMSTR'] = "Linking $TARGET"
334     env['SHLINKCOMSTR'] = "Linking shared object $TARGET"
335     env['ARCOMSTR'] = "Archiving $TARGET"
336     env['RANLIBCOMSTR'] = "Indexing Archive $TARGET"
337
338 if env.get('MANDATORY'):
339     env.AppendUnique(CPPDEFINES=['__MANDATORY__'])
340
341 tc_set_msg = '''
342 ************************************ Warning **********************************
343 * Warning: TC_PREFIX and/or TC_PATH is set in the environment.
344 * This means a non-default compilation toolchain will be used.
345 * If this is not what you expected you should unset, or it
346 * may lead to unexpected results.
347 *******************************************************************************
348 '''
349 if target_os in targets_support_cc:
350     prefix = env.get('TC_PREFIX')
351     tc_path = env.get('TC_PATH')
352     if prefix:
353         env.Replace(CC=prefix + env.get('CC', 'gcc'))
354         env.Replace(CXX=prefix + env.get('CXX', 'g++'))
355         env.Replace(AR=prefix + env.get('AR', 'ar'))
356         env.Replace(AS=prefix + env.get('AS', 'as'))
357         env.Replace(RANLIB=prefix + env.get('RANLIB', 'ranlib'))
358
359     if tc_path:
360         env.PrependENVPath('PATH', tc_path)
361         sys_root = os.path.abspath(tc_path + '/../')
362         env.AppendUnique(CCFLAGS=['--sysroot=' + sys_root])
363         env.AppendUnique(LINKFLAGS=['--sysroot=' + sys_root])
364
365     if prefix or tc_path:
366         print(tc_set_msg)
367
368 # Import env variables only if reproductibility is ensured
369 if target_os in ['yocto', 'webos']:
370     env['CONFIG_ENVIRONMENT_IMPORT'] = True
371 else:
372     env['CONFIG_ENVIRONMENT_IMPORT'] = False
373
374 if env['CONFIG_ENVIRONMENT_IMPORT']:
375     print("warning: importing some environment variables for OS: %s" % target_os)
376     for ev in [
377         'PATH',
378         'PKG_CONFIG',
379         'PKG_CONFIG_PATH',
380         'PKG_CONFIG_SYSROOT_DIR'
381     ]:
382         if os.environ.get(ev) is not None:
383             env['ENV'][ev] = os.environ.get(ev)
384     if os.environ['LDFLAGS'] != None:
385         env.AppendUnique(LINKFLAGS=Split(os.environ['LDFLAGS']))
386
387 if host in ['windows']:
388     # UnpackAll.py needs access to system PATH components that SCons
389     # does not include by default - e.g., the path to 7z.exe.
390     env.AppendUnique(PATH=os.environ['PATH'])
391
392 # Ensure scons is able to change its working directory
393 env.SConscriptChdir(1)
394
395 ######################################################################
396 # Convenience functions to "extend" SCons
397 ######################################################################
398
399
400 def __set_dir(env, dir):
401     #
402     # Set the source and build directories
403     #   Source directory: 'dir'
404     #   Build directory: 'dir'/out/<target_os>/<target_arch>/<release or debug>/
405     #   On windows, the build directory will be:
406     #     'dir'/out/windows/<win32 or uwp>/<target_arch>/<release or debug>/
407     #
408     # You can get the directory as following:
409     #   env.get('SRC_DIR')
410     #   env.get('BUILD_DIR')
411     #
412     if not os.path.exists(dir + '/SConstruct'):
413         msg = '''
414 *************************************** Error *********************************
415 * The directory (%s) seems not to be a buildable directory,
416 * no SConstruct file found.
417 *******************************************************************************
418 ''' % dir
419         Exit(msg)
420
421     build_dir = dir + '/out/' + target_os + '/'
422
423     if target_os == 'windows':
424         if env.get('MSVC_UWP_APP') == '1':
425             build_dir = build_dir + 'uwp/'
426         else:
427             build_dir = build_dir + 'win32/'
428
429     build_dir = build_dir + target_arch
430
431     if env.get('RELEASE'):
432         build_dir = build_dir + '/release/'
433     else:
434         build_dir = build_dir + '/debug/'
435
436     env.VariantDir(build_dir, dir, duplicate=0)
437
438     env.Replace(BUILD_DIR=build_dir)
439     env.Replace(SRC_DIR=dir)
440
441
442 def __src_to_obj(env, src, home=''):
443     '''
444     Make sure builds happen in BUILD_DIR (by default they
445     would happen in the directory of the source file)
446     Note this does not seem to be used, VariantDir is used instead
447     '''
448     obj = env.get('BUILD_DIR') + src.replace(home, '')
449     if env.get('OBJSUFFIX'):
450         obj += env.get('OBJSUFFIX')
451     return env.Object(obj, src)
452
453
454 def __install(ienv, targets, name=''):
455     '''
456     Copy files to internal place (not for install to system)
457     only use UserInstall() for copying files to system using "scons install"
458     '''
459     for filename in ienv.GetBuildPath(targets):
460         basename = os.path.basename(filename)
461         dst = env.get('BUILD_DIR') + basename
462         i_n = Command(dst, filename, Copy("$TARGET", "$SOURCE"))
463         if '' == name:
464             name = basename
465         ienv.Alias(name, i_n)
466         env.AppendUnique(TS=[name])
467
468
469 def __chrpath(target, source, env):
470     '''
471     Remove RPATH (if installed elsewhere)
472     '''
473     if target_os in ['linux', 'tizen']:
474         env.Command(None, target, 'chrpath -d $SOURCE')
475
476
477 def __installlib(ienv, targets, name=''):
478     '''
479     Install files to system, using "scons install" and remove rpath info if present
480     If prefix or lib install dir is not specified, for developer convenience
481     files are copied in relative "deploy" folder along executables (rpath is kept)
482     to avoid overlap with "internal place" above
483     '''
484     user_prefix = env.get('PREFIX')
485     if user_prefix:
486         user_lib = env.get('LIB_INSTALL_DIR')
487         if user_lib:
488             dst_dir  = user_lib
489         else:
490             dst_dir  = user_prefix + '/lib'
491     else:
492         dst_dir  = env.get('BUILD_DIR') + '/deploy'
493     action = ienv.Install(dst_dir, targets)
494     if not user_prefix and str(targets[0]).endswith(env['SHLIBSUFFIX']):
495         ienv.AddPostAction(action, __chrpath)
496     ienv.Alias("install", action)
497
498
499
500 def __installbin(ienv, targets, name=''):
501     '''
502     ' Install files to system, using "scons install"
503     ' If prefix is not specified, for developer convenience
504     ' files are copied in relative "deploy" folder along libraries
505     '''
506     user_prefix = env.get('PREFIX')
507     if user_prefix:
508         dst_dir  = user_prefix + '/bin'
509     else:
510         dst_dir  = env.get('BUILD_DIR') + '/deploy'
511     ienv.Alias("install", ienv.Install(dst_dir , targets))
512
513
514 def __installheader(ienv, targets, dir, name):
515     user_prefix = env.get('PREFIX')
516     if user_prefix:
517         i_n = ienv.Install(user_prefix + '/include/iotivity/' + dir, targets)
518     else:
519         i_n = ienv.Install(env.get('BUILD_DIR') + 'deploy/include/' + dir, targets)
520     ienv.Alias("install", i_n)
521
522
523 def __installpcfile(ienv, targets, name):
524     user_prefix = env.get('PREFIX')
525     if user_prefix:
526         user_lib = env.get('LIB_INSTALL_DIR')
527         if user_lib:
528             i_n = ienv.Install(user_lib + '/pkgconfig', targets)
529         else:
530             i_n = ienv.Install(user_prefix + '/lib/pkgconfig', targets)
531     else:
532         i_n = ienv.Install(env.get('BUILD_DIR') + 'deploy/pkgconfig', targets)
533     ienv.Alias("install", i_n)
534
535
536 def __installextra(ienv, targets, subdir="."):
537     '''
538     Install extra files, by default use file relative location as subdir
539     or use any other prefix of your choice, or in explicit "deploy" folder
540     '''
541     user_lib = env.get('LIB_INSTALL_DIR')
542     user_prefix = env.get('PREFIX')
543     for target in targets:
544         if "." == subdir:
545             dst = Dir('.').srcnode().path
546         else:
547             dst = subdir
548         if user_lib:
549             dst = user_lib + '/iotivity/' + dst
550         elif user_prefix:
551             dst = user_prefix + '/lib/iotivity/' + dst
552         else:
553             dst = env.get('BUILD_DIR') + '/deploy/extra/' + dst
554         i_n = ienv.Install(dst, target)
555         ienv.Alias('install', i_n)
556
557
558 def __append_target(ienv, name, targets=None):
559     if targets:
560         env.Alias(name, targets)
561     env.AppendUnique(TS=[name])
562
563
564 def __add_pthread_if_needed(ienv):
565     if 'gcc' == ienv.get('CC') and target_os not in ['android']:
566         ienv.AppendUnique(LINKFLAGS="-pthread")
567
568
569 def __print_targets(env):
570     Help('''
571 ===============================================================================
572 Targets:\n    ''')
573     for t in env.get('TS'):
574         Help(t + ' ')
575     Help('''
576
577 Default: all targets will be built. You can specify the target to build:
578
579     $ scons [options] [target]
580 ===============================================================================
581 ''')
582
583
584 env.AddMethod(__set_dir, 'SetDir')
585 env.AddMethod(__print_targets, 'PrintTargets')
586 env.AddMethod(__src_to_obj, 'SrcToObj')
587 env.AddMethod(__append_target, 'AppendTarget')
588 env.AddMethod(__add_pthread_if_needed, 'AddPthreadIfNeeded')
589 env.AddMethod(__install, 'InstallTarget')
590 env.AddMethod(__installlib, 'UserInstallTargetLib')
591 env.AddMethod(__installbin, 'UserInstallTargetBin')
592 env.AddMethod(__installheader, 'UserInstallTargetHeader')
593 env.AddMethod(__installpcfile, 'UserInstallTargetPCFile')
594 env.AddMethod(__installextra, 'UserInstallTargetExtra')
595 env.SetDir(env.GetLaunchDir())
596 env['ROOT_DIR'] = env.GetLaunchDir() + '/..'
597
598 # make 'env' available to all other build scripts to Import()
599 Export('env')
600
601 ####################################################################i#
602 # Generate the iotivity.pc file from iotivity.pc.in file
603 ######################################################################
604 pc_file = env.get('SRC_DIR') + '/iotivity.pc.in'
605
606 user_prefix = env.get('PREFIX')
607 user_lib = env.get('LIB_INSTALL_DIR')
608
609 if not user_prefix:
610     try:
611         user_prefix = env.get('BUILD_DIR').encode('string_escape')
612     except LookupError:
613         user_prefix = env.get('BUILD_DIR').encode('unicode_escape')
614
615 if not user_lib:
616     user_lib = '$${prefix}/lib'
617
618 defines = []
619 if env.get('LOGGING'):
620     defines.append('-DTB_LOG=1')
621
622 if env.get('ROUTING') == 'GW':
623     defines.append('-DROUTING_GATEWAY=1')
624 elif env.get('ROUTING') == 'EP':
625     defines.append('-DROUTING_EP=1')
626
627 libs = []
628 if env.get('WITH_TCP'):
629     defines.append('-DTCP_ADAPTER=1')
630     if env.get('SECURED') == '1':
631         defines.append('-D__WITH_TLS__=1')
632
633 if env.get('SECURED') == '1':
634     defines.append('-D__WITH_DTLS__=1')
635     if env.get('EXC_PROV_SUPPORT') == '0':
636         libs.append('-locpmapi')
637
638 pc_vars = {
639     '\@VERSION\@': project_version,
640     '\@PREFIX\@': user_prefix,
641     '\@EXEC_PREFIX\@': user_prefix,
642     '\@LIB_INSTALL_DIR\@': user_lib,
643     '\@DEFINES\@': " ".join(defines),
644     '\@LIBS\@': " ".join(libs)
645 }
646
647 env.Substfile(pc_file, SUBST_DICT=pc_vars)
648
649 ######################################################################
650 # Setting global compiler flags
651 ######################################################################
652 target_transport = env.get('TARGET_TRANSPORT')
653 with_mq = env.get('WITH_MQ')
654 with_ra = env.get('WITH_RA')
655 with_tcp = env.get('WITH_TCP')
656 rd_mode = env.get('RD_MODE')
657 with_ra_ibb = env.get('WITH_RA_IBB')
658
659 env.AppendUnique(LIBPATH = [env.get('BUILD_DIR')])
660
661 if not env.get('PREFIX') and not env.get('LIB_INSTALL_DIR'):
662    env.AppendUnique(LIBPATH = [env.get('BUILD_DIR') + '/deploy'])
663
664 if (env.get('WITH_UPSTREAM_LIBCOAP') == '1'):
665     env.AppendUnique(CPPDEFINES=['WITH_UPSTREAM_LIBCOAP'])
666
667 if (target_os not in ['windows']):
668     env.AppendUnique(CPPDEFINES=['WITH_POSIX'])
669
670 if (target_os in ['darwin', 'ios']):
671     env.AppendUnique(CPPDEFINES=['_DARWIN_C_SOURCE'])
672
673 if (env.get('SECURED') == '1'):
674     env.AppendUnique(CPPDEFINES=['SECURED'])
675     env.AppendUnique(CPPDEFINES=['__WITH_DTLS__'])
676
677 if ((env.get('SECURED') == '1') and with_tcp):
678     env.AppendUnique(CPPDEFINES=['__WITH_TLS__'])
679
680 if (env.get('MULTIPLE_OWNER') == '1'):
681     env.AppendUnique(CPPDEFINES=['MULTIPLE_OWNER'])
682
683 if (env.get('ROUTING') == 'GW'):
684     env.AppendUnique(CPPDEFINES=['ROUTING_GATEWAY'])
685 elif (env.get('ROUTING') == 'EP'):
686     env.AppendUnique(CPPDEFINES=['ROUTING_EP'])
687
688 if (('IP' in target_transport) or ('ALL' in target_transport)):
689     env.AppendUnique(CPPDEFINES=['WITH_BWT'])
690
691 if (target_os in ['linux', 'tizen', 'android', 'yocto'] and with_tcp):
692     env.AppendUnique(CPPDEFINES=['WITH_TCP'])
693
694 if (target_os in ['linux', 'tizen', 'android', 'ios', 'yocto']):
695     if (('BLE' in target_transport) or ('BT' in target_transport) or
696         ('ALL' in target_transport)):
697         env.AppendUnique(CPPDEFINES=['WITH_TCP'])
698
699 if 'ALL' in target_transport:
700     if with_ra:
701         env.AppendUnique(CPPDEFINES=['RA_ADAPTER'])
702     if with_tcp:
703         env.AppendUnique(CPPDEFINES=['TCP_ADAPTER'])
704     if (target_os in ['linux', 'yocto']):
705         env.AppendUnique(
706             CPPDEFINES=['IP_ADAPTER', 'NO_EDR_ADAPTER', 'LE_ADAPTER'])
707     elif (target_os == 'android'):
708         env.AppendUnique(CPPDEFINES=[
709             'IP_ADAPTER', 'EDR_ADAPTER', 'LE_ADAPTER', 'NFC_ADAPTER'
710         ])
711     elif (target_os in ['webos']):
712         env.AppendUnique(CPPDEFINES=[
713             'IP_ADAPTER', 'NO_EDR_ADAPTER', 'NO_LE_ADAPTER'])
714     elif (target_os in ['darwin', 'ios', 'msys_nt', 'windows']):
715         env.AppendUnique(
716             CPPDEFINES=['IP_ADAPTER', 'NO_EDR_ADAPTER', 'NO_LE_ADAPTER'])
717     else:
718         env.AppendUnique(
719             CPPDEFINES=['IP_ADAPTER', 'EDR_ADAPTER', 'LE_ADAPTER'])
720 else:
721     if ('BT' in target_transport):
722         if target_os in ('linux', 'yocto', 'webos'):
723             msg = "CA Transport BT is not supported "
724             Exit(msg)
725         else:
726             env.AppendUnique(CPPDEFINES=['EDR_ADAPTER'])
727     else:
728         env.AppendUnique(CPPDEFINES=['NO_EDR_ADAPTER'])
729
730     if ('BLE' in target_transport):
731         env.AppendUnique(CPPDEFINES=['LE_ADAPTER'])
732     else:
733         env.AppendUnique(CPPDEFINES=['NO_LE_ADAPTER'])
734
735     if ('IP' in target_transport):
736         env.AppendUnique(CPPDEFINES=['IP_ADAPTER'])
737     else:
738         env.AppendUnique(CPPDEFINES=['NO_IP_ADAPTER'])
739
740     if with_tcp:
741         if (target_os in [
742                 'linux', 'tizen', 'android', 'ios', 'windows', 'yocto', 'webos'
743         ]):
744             env.AppendUnique(CPPDEFINES=['TCP_ADAPTER', 'WITH_TCP'])
745         else:
746             msg = "CA Transport TCP is not supported "
747             Exit(msg)
748     else:
749         env.AppendUnique(CPPDEFINES=['NO_TCP_ADAPTER'])
750
751     if ('NFC' in target_transport):
752         if (target_os == 'android'):
753             env.AppendUnique(CPPDEFINES=['NFC_ADAPTER'])
754         else:
755             msg = "CA Transport NFC is not supported "
756             Exit(msg)
757     else:
758         env.AppendUnique(CPPDEFINES=['NO_NFC_ADAPTER'])
759
760 if ('SUB' in with_mq):
761     env.AppendUnique(CPPDEFINES=['MQ_SUBSCRIBER', 'WITH_MQ'])
762
763 if ('PUB' in with_mq):
764     env.AppendUnique(CPPDEFINES=['MQ_PUBLISHER', 'WITH_MQ'])
765
766 if ('BROKER' in with_mq):
767     env.AppendUnique(CPPDEFINES=['MQ_BROKER', 'WITH_MQ'])
768
769 env.AppendUnique(CPPDEFINES={'OC_LOG_LEVEL': env.get('LOG_LEVEL')})
770
771 if env.get('LOGGING'):
772     env.AppendUnique(CPPDEFINES=['TB_LOG'])
773
774 if env.get('WITH_CLOUD') and with_tcp:
775     env.AppendUnique(CPPDEFINES=['WITH_CLOUD'])
776
777 if 'CLIENT' in rd_mode:
778     env.AppendUnique(CPPDEFINES=['RD_CLIENT'])
779
780 if 'SERVER' in rd_mode:
781     env.AppendUnique(CPPDEFINES=['RD_SERVER'])
782
783 if with_ra_ibb:
784     env.AppendUnique(CPPDEFINES=['RA_ADAPTER_IBB'])
785
786 if env.get('RELEASE'):
787     env.AppendUnique(CPPDEFINES=['NDEBUG'])
788
789 env.SConscript('external_builders.scons')
790 ######################################################################
791 # Link scons to Yocto cross-toolchain ONLY when target_os is yocto
792 ######################################################################
793 if target_os in ['yocto', 'webos']:
794     '''
795     This code injects Yocto cross-compilation tools+flags into the scons
796     construction environment in order to invoke the relevant tools while
797     performing a build.
798     '''
799     import os.path
800     try:
801         CC = os.environ['CC']
802         target_prefix = CC.split()[0]
803         target_prefix = target_prefix[:-3]
804         tools = {
805             "CC": target_prefix + "gcc",
806             "CXX": target_prefix + "g++",
807             "AS": target_prefix + "as",
808             "LD": target_prefix + "ld",
809             "GDB": target_prefix + "gdb",
810             "STRIP": target_prefix + "strip",
811             "RANLIB": target_prefix + "ranlib",
812             "OBJCOPY": target_prefix + "objcopy",
813             "OBJDUMP": target_prefix + "objdump",
814             "AR": target_prefix + "ar",
815             "NM": target_prefix + "nm",
816             "M4": "m4",
817             "STRINGS": target_prefix + "strings"
818         }
819         PATH = os.environ['PATH'].split(os.pathsep)
820         for tool in tools:
821             if tool in os.environ:
822                 for path in PATH:
823                     if os.path.isfile(os.path.join(path, tools[tool])):
824                         env[tool] = os.path.join(path, os.environ[tool])
825                         break
826         env['CROSS_COMPILE'] = target_prefix[:-1]
827     except:
828         msg = "ERROR in Yocto cross-toolchain environment"
829         Exit(msg)
830     '''
831     Now reset TARGET_OS to linux so that all linux specific build configurations
832     hereupon apply for the entirety of the build process.
833     '''
834     env['TARGET_OS'] = 'linux'
835     '''
836     We want to preserve debug symbols to allow BitBake to generate both DEBUG and
837     RELEASE packages for OIC.
838     '''
839     env.AppendUnique(CCFLAGS=['-g'])
840     '''
841     Additional flags to pass to the Yocto toolchain.
842     '''
843     env.AppendUnique(CPPDEFINES=['__linux__', '_GNU_SOURCE'])
844     env.AppendUnique(CFLAGS=['-std=gnu99'])
845     env.AppendUnique(CCFLAGS=['-Wall', '-Wextra', '-fPIC'])
846     env.AppendUnique(LIBS=['dl', 'pthread', 'uuid'])
847 else:
848     '''
849     If target_os is not Yocto, continue with the regular build process
850     '''
851     # Load config of target os
852     env.SConscript(target_os + '/SConscript')
853
854 if env.get('CROSS_COMPILE'):
855     env.Append(RPATH=env.Literal('\\$$ORIGIN'))
856 else:
857     env.Append(RPATH=env.get('BUILD_DIR'))
858
859 # Delete the temp files of configuration
860 if env.GetOption('clean'):
861     dir = env.get('SRC_DIR')
862
863     if os.path.exists(dir + '/config.log'):
864         Execute(Delete(dir + '/config.log'))
865     if os.path.exists(dir + '/.sconsign.dblite'):
866         Execute(Delete(dir + '/.sconsign.dblite'))
867     if os.path.exists(dir + '/.sconf_temp'):
868         Execute(Delete(dir + '/.sconf_temp'))
869
870 ######################################################################
871 # Check for PThreads support
872 ######################################################################
873 import iotivityconfig
874 from iotivityconfig import *
875
876 conf = Configure(
877     env, custom_tests={'CheckPThreadsSupport': iotivityconfig.check_pthreads})
878
879 # Identify whether we have pthreads support, which is necessary for
880 # threading and mutexes.  This will set the environment variable
881 # POSIX_SUPPORTED, 1 if it is supported, 0 otherwise
882 conf.CheckPThreadsSupport()
883 env = conf.Finish()
884
885 ######################################################################
886 # Generate Cbor from json files
887 ######################################################################
888 json2cbor = env.get('BUILD_DIR') + 'resource/csdk/security/tool/json2cbor' + env.get('PROGSUFFIX')
889
890 def generate_actions(source, target, env, for_signature):
891     Depends(target, json2cbor)
892     return " %s %s %s" % (json2cbor, source[0], target[0])
893
894 builder = Builder(generator = generate_actions,
895                   suffix = '.dat',
896                   src_suffix = '.json')
897
898 env.Append(BUILDERS = {'Cbor' : builder})
899
900
901 def ScanJSON(env, directory=None):
902     targets = []
903     if not directory:
904         directory = Dir('.').srcnode().path
905     if env.GetOption('clean') or env.get('SECURED') != '1':
906         return targets
907     dst_dir = env.get('BUILD_DIR') + '/' + directory + '/'
908     src_dir = env.get('SRC_DIR') + '/' + directory + '/'
909     for json_file in Glob('*.json'):
910         filename = str(json_file.name)
911         src = src_dir + filename
912         dst = dst_dir + filename
913         targets += Command(dst, src, Copy("$TARGET", "$SOURCE"))
914         if env.get('CROSS_COMPILE') == None:
915             # Copy back compiled files to sources (to be used when compilation is not possible)
916             cbor_file = env.Cbor(json_file)
917             targets.append(cbor_file)
918             cbor_file = Flatten(cbor_file)[0].name
919             src = dst_dir + cbor_file
920             dst = src_dir + cbor_file
921             Command(dst, src, Copy("$TARGET", "$SOURCE"))
922         else:
923             # Can compile files at build time, so rely on previous generated files
924             cbor_file = re.sub('\.json$', '.dat', filename)
925             src = src_dir + cbor_file
926             dst = dst_dir + cbor_file
927             targets += Command(dst, src, Copy("$TARGET", "$SOURCE"))
928     return targets
929
930 AddMethod(env, ScanJSON)
931
932 ######################################################################
933 env.SConscript('external_libs.scons')
934
935 # these variables depend on a subsidiary script having set a path to
936 # use as the default. Such paths may include embedded version strings,
937 # for example, and we want to not embed those all over, so defer setting
938 # the help until we're back from those scripts. Then we can finally
939 # build the help message. However, it's also possible that we never
940 # needed to call those subsidary scripts, and then we come back with
941 # values unset, so deal with that as well.
942 if env.get('ANDROID_NDK'):
943     android_ndk = env['ANDROID_NDK']
944 else:
945     android_ndk = None
946 if env.get('ANDROID_GRADLE'):
947     android_gradle = env['ANDROID_GRADLE']
948 else:
949     android_gradle = None
950 if env.get('ANDROID_HOME'):
951     android_sdk = env['ANDROID_HOME']
952 else:
953     android_sdk = None
954 help_vars.AddVariables(
955     PathVariable('ANDROID_NDK',
956                  'Android NDK path',
957                  default=android_ndk,
958                  validator=PathVariable.PathAccept),
959     PathVariable('ANDROID_GRADLE',
960                  'Gradle executable location',
961                  default=android_gradle,
962                  validator=PathVariable.PathIsFile),
963     PathVariable('ANDROID_HOME',
964                  'Android SDK path',
965                  default=android_sdk,
966                  validator=PathVariable.PathAccept),
967 )
968 help_vars.Update(env)
969 Help(help_vars.GenerateHelpText(env, sort=True))
970 # Replicate change that occured after help_var initialisation from env
971 if target_os == "yocto":
972     env['TARGET_OS'] = 'linux'
973
974 Return('env')