1 ################################################################################
3 # Copyright 2016 Intel Corporation
7 # Licensed under the Apache License, Version 2.0 (the "License");
8 # you may not use this file except in compliance with the License.
9 # You may obtain a copy of the License at
11 # http://www.apache.org/licenses/LICENSE-2.0
13 # Unless required by applicable law or agreed to in writing, software
14 # distributed under the License is distributed on an "AS IS" BASIS,
15 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 # See the License for the specific language governing permissions and
17 # limitations under the License.
19 ################################################################################
22 # 'libcoap' script to make sure LibCoAP library is "installed"
31 libcoap_env = env.Clone()
32 target_os = libcoap_env.get('TARGET_OS')
33 src_dir = libcoap_env.get('SRC_DIR')
34 ca_transport = libcoap_env.get('TARGET_TRANSPORT')
35 with_tcp = libcoap_env.get('WITH_TCP')
36 with_upstream_libcoap = libcoap_env.get('WITH_UPSTREAM_LIBCOAP')
38 # Temporary LibCoAP URL is a fork of the original.
39 # Once a pull request is merged, change this back to the obgm original below.
40 libcoap_repo_url = 'https://github.com/dthaler/libcoap'
41 #libcoap_repo_url = 'https://github.com/obgm/libcoap'
43 ######################################################################
44 # Check for, and possibly update libcoap from git
45 ######################################################################
46 # The libcoap tag here must match the one in extlibs/libcoap/prep.sh.
47 libcoap_version = 'IoTivity-1.4'
48 libcoap_dir = os.path.join(src_dir, 'extlibs', 'libcoap', 'libcoap')
51 libcoap_checkout_cmd = 'git clone ' + libcoap_repo_url + '.git extlibs/libcoap/libcoap -b ' + libcoap_version
52 libcoap_update_cmd = 'git fetch --tags && git checkout -f ' + libcoap_version
53 libcoap_tag_cmd = 'git tag -l ' + libcoap_version
54 libcoap_sync_cmd = 'git checkout -f ' + libcoap_version
55 libcoap_chdir_cmd = 'cd ' + libcoap_dir
57 # define msg strings here so code sequence is readable
59 *********************************** Error: ************************************
60 * Please download libcoap using the following command:
62 *******************************************************************************
63 ''' % libcoap_checkout_cmd
66 ******************************* Info: *****************************************
67 * Your libCoAP repo is not up to date with the latest version we require (%s).
68 *******************************************************************************
71 info_updatingcoap = '''
72 ******************************* Info: *****************************************
73 * Automatically updating libcoap to version %s.
74 *******************************************************************************
78 ******************************* Info: *****************************************
79 * Please update using the following commands:
82 *******************************************************************************
83 ''' % (libcoap_chdir_cmd, libcoap_update_cmd)
86 ******************************* Info: *****************************************
87 * Using FORKED copy of libCoap located in:
88 * resource/csdk/connectivity/lib/libcoap-4.1.1
89 *******************************************************************************
92 if with_upstream_libcoap == '0':
93 print(info_forkedcoap)
95 # If using the github libcoap, check for correct version
96 # Right now this script assumes the revision is a tag, not a branch or
97 # an arbitrary commit. If this changes, update the check below, or else
98 # the script will always conclude the repo is not up to date because a tag
99 # with that name does not exist.
100 print('*** Checking for installation of libCoAP %s ***' % libcoap_version)
101 if not os.path.exists(libcoap_dir):
104 # Tizen uses its own process to prepare the libcoap repo in gbsbuild.sh
105 # and cannot use git during the build. That process removes .git.
106 # Do the git checks only if .git is present.
107 if os.path.exists(libcoap_dir + '/.git/HEAD'):
108 start_dir = os.getcwd()
109 os.chdir(libcoap_dir)
110 out = subprocess.check_output(libcoap_tag_cmd, shell=True).rstrip()
111 if libcoap_version not in SCons.Util.to_String(out):
113 if libcoap_env.get('AUTOMATIC_UPDATE'):
114 print(info_updatingcoap)
116 retcode = subprocess.call(libcoap_update_cmd, shell=True)
118 Exit("libcoap: update failed: " + str(retcode))
120 Exit("libcoap: execution failed: " + e)
122 Exit(info_updatecoap)
123 # to be pedantic, always checkout to the tag
124 retcode = subprocess.call(libcoap_sync_cmd, shell=True)
126 Exit("libcoap: checkout failed: " + str(retcode))
129 ######################################################################
131 ######################################################################
133 if target_os not in ['windows', 'winrt', 'msys_nt']:
134 # libcoap uses ipv6 features from <netinet/in.h> which only
135 # turn on if __GNU_SOURCE is defined
136 libcoap_env.AppendUnique(CPPDEFINES=['WITH_POSIX', '_GNU_SOURCE'])
137 libcoap_env.AppendUnique(CFLAGS=['-std=gnu99','-fPIC'])
139 if target_os not in ['windows', 'winrt']:
140 libcoap_env.AppendUnique(CFLAGS=['-Wall', '-ffunction-sections',
141 '-fdata-sections', '-fno-exceptions'])
143 if target_os == 'msys_nt':
144 libcoap_env.AppendUnique(CPPDEFINES=['_DEFAULT_SOURCE'])
145 libcoap_env.AppendUnique(CFLAGS=['-std=c99'])
147 if target_os in ['linux', 'tizen', 'android', 'ios', 'windows']:
149 libcoap_env.AppendUnique(CPPDEFINES=['WITH_TCP', 'WITH_WS'])
151 if target_os in ['linux', 'tizen', 'android']:
152 libcoap_env.AppendUnique(LIBS=['log'])
153 if 'BLE' in ca_transport or 'BT' in ca_transport or 'ALL' in ca_transport:
154 libcoap_env.AppendUnique(CPPDEFINES=['WITH_TCP'])
156 # Remove -Werror build flag when building the 'coap' library it
157 # is external code. see IOT-2539
158 while '-Werror' in libcoap_env['CCFLAGS']: libcoap_env['CCFLAGS'].remove('-Werror')
159 if env['CC'] == 'cl':
160 # In external code, don't fail on warnings:
161 # - warning C4267: conversion from size_t to unsigned short, possible loss of data
162 # - warning C4244: '=' : conversion from 'size_t' to 'unsigned short', possible loss of data
163 # TODO: fix libcoap fork, we introduced this error, it isn't from upstream
164 libcoap_env.AppendUnique(CCFLAGS=['/wd4267', '/wd4244'])
166 ######################################################################
167 # Source files and Target(s)
168 ######################################################################
169 if with_upstream_libcoap == '0':
170 # For bring up purposes only, the forked version will live here.
171 libcoap_src_root = '#/resource/csdk/connectivity/lib/libcoap-4.1.1/'
172 libcoap_src = Glob(libcoap_src_root + '*.c')
174 # We need to generate a pair of headers to describe our config
175 coap_h_pc_file = os.path.join(libcoap_dir, 'include', 'coap', 'coap.h.in')
176 config_h_file = os.path.join(libcoap_dir, 'include', 'coap', 'coap_config.h')
177 libcoap_env.PrependUnique(CPPPATH=['libcoap/include/coap'])
178 libcoap_env.AppendUnique(CPPDEFINES=['WITH_UPSTREAM_LIBCOAP'])
180 # Generate coap_config.h
181 target_arch = env.get('TARGET_ARCH')
182 lib_prefix = '' + str(libcoap_env.get('LIBPREFIX'))
184 if not os.path.isfile(config_h_file) and env.GetOption not in ('clean', 'help'):
185 conf = Configure(libcoap_env.Clone(LIBS=[]))
187 config_h_header = '''
188 /* ****************************************************************************
189 * coap_config.h - libcoap platform-specific configuration header.
191 * Auto-generated code for the %s %s platform. Do not edit.
193 *************************************************************************** */
195 #ifndef _COAP_CONFIG_H_
196 #define _COAP_CONFIG_H_
198 ''' % (str(target_os), str(target_arch))
200 config_h_footer = '''
202 /* Define to the full name of this package. */
203 #define PACKAGE_NAME "%s"
205 /* Define to the full name and version of this package. */
206 #define PACKAGE_STRING "%s"
208 #ifndef COAP_STATIC_INLINE
209 # if defined(__cplusplus)
210 # define COAP_STATIC_INLINE inline
213 # define COAP_STATIC_INLINE static __inline
215 # define COAP_STATIC_INLINE static inline
220 #endif // _COAP_CONFIG_H_
222 ''' % (str(lib_prefix + 'coap'), str(lib_prefix + 'coap ' + libcoap_version))
226 if ((target_os == 'windows') and (libcoap_env.get('MSVC_UWP_APP') == '1')):
227 # Workaround for libcoap config [Investigation in IOT-2234]:
228 # libcoap builds its config file by trying to create a small program to see if an API is
229 # available. However, when building with store libraries on windows, it doesn't seem
230 # to find malloc or strnlen APIs. On Windows, those APIs are guaranteed to be there,
231 # therefore, create the libcoap config_h_body with what is needed and expected to be
234 #define HAVE_ASSERT_H 1
236 #define HAVE_LIMITS_H 1
238 #define HAVE_STDIO_H 1
240 #define HAVE_SYS_TYPES_H 1
242 #define HAVE_TIME_H 1
244 #define HAVE_WINSOCK2_H 1
246 #define HAVE_WS2TCPIP_H 1
248 #define HAVE_MALLOC 1
250 #define HAVE_STRNLEN 1
252 #define ssize_t SSIZE_T
254 #define in_port_t uint16_t
286 def get_define_from_string(string_):
287 string_converted = string_.replace("/", "_").replace(".", "_").upper()
288 return "HAVE_" + string_converted
290 for header_file_name in cxx_headers:
291 if conf.CheckCXXHeader(header_file_name):
292 config_h_body += "#define %s 1\n\n" % get_define_from_string(
295 for function_name in cxx_functions:
296 if conf.CheckFunc(function_name):
297 config_h_body += "#define %s 1\n\n" % get_define_from_string(
300 if conf.CheckCXXHeader('windows.h'):
301 config_h_body += "#define ssize_t SSIZE_T\n\n"
302 config_h_body += "#define in_port_t uint16_t\n\n"
306 with open(config_h_file, "w") as configfile:
307 configfile.write(config_h_header + config_h_body + config_h_footer)
309 # Sanity check to ensure that the above block created the file.
310 if not os.path.exists(config_h_file) and not env.GetOption('clean'):
311 msg = "Error: coap_config.h file not created!"
314 # Generate coap.h from coap.h.in by substitution
316 '@PACKAGE_NAME@': lib_prefix + 'coap',
317 '@PACKAGE_STRING@': lib_prefix + 'coap-' + libcoap_version,
318 '@PACKAGE_URL@': libcoap_repo_url,
319 '@PACKAGE_BUGREPORT@': libcoap_repo_url + '/issues',
320 '@PACKAGE_VERSION@': libcoap_version
322 libcoap_env.Substfile(coap_h_pc_file, SUBST_DICT=pc_vars)
324 libcoap_src_root = 'libcoap/src/'
326 libcoap_src = Glob(libcoap_src_root + '*.c',
327 exclude=libcoap_src_root + 'coap_io_lwip.c')
328 except TypeError: # very old SCons doesn't have 'exclude' in Glob
329 libcoap_src = Glob(libcoap_src_root + '*.c')
330 libcoap_src = [src for src in libcoap_src if 'coap_io_lwip.c' not in src.path]
332 # finally ready to build:
333 libcoap = libcoap_env.StaticLibrary('coap', libcoap_src, OBJPREFIX='libcoap_')
335 # set for use by other scripts:
336 if with_upstream_libcoap == '1':
337 env.AppendUnique(LIBCOAP_INC='#/extlibs/libcoap/libcoap/include')
339 env.AppendUnique(LIBCOAP_INC='#/resource/csdk/connectivity/lib/libcoap-4.1.1/include')
341 libcoap_env.InstallTarget([libcoap], 'coap')
342 libcoap_env.UserInstallTargetLib(libcoap)