1# 2# SPDX-License-Identifier: BSD-3-Clause 3# 4# Copyright © 2019 Keith Packard 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions 8# are met: 9# 10# 1. Redistributions of source code must retain the above copyright 11# notice, this list of conditions and the following disclaimer. 12# 13# 2. Redistributions in binary form must reproduce the above 14# copyright notice, this list of conditions and the following 15# disclaimer in the documentation and/or other materials provided 16# with the distribution. 17# 18# 3. Neither the name of the copyright holder nor the names of its 19# contributors may be used to endorse or promote products derived 20# from this software without specific prior written permission. 21# 22# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 31# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 33# OF THE POSSIBILITY OF SUCH DAMAGE. 34# 35project('picolibc', 'c', 36 default_options: [ 37 'buildtype=minsize', 38 'c_std=gnu99', 39 'b_staticpic=false', 40 ], 41 license : 'BSD', 42 meson_version : '>= 0.50', 43 version: '1.3' 44 ) 45 46targets = [] 47 48enable_multilib = get_option('multilib') 49enable_picolib = get_option('picolib') 50enable_tests = get_option('tests') 51enable_native_tests = get_option('native-tests') 52newlib_tinystdio = get_option('newlib-tinystdio') 53have_alias_attribute_option = get_option('have-alias-attribute') 54newlib_io_pos_args = get_option('newlib-io-pos-args') 55newlib_io_c99_formats = get_option('newlib-io-c99-formats') 56newlib_register_fini = get_option('newlib-register-fini') 57newlib_io_long_long = get_option('newlib-io-long-long') 58newlib_io_long_double = get_option('newlib-io-long-double') 59newlib_mb = get_option('newlib-mb') 60newlib_iconv_encodings = get_option('newlib-iconv-encodings') 61newlib_iconv_from_encodings = get_option('newlib-iconv-from-encodings') 62newlib_iconv_to_encodings = get_option('newlib-iconv-to-encodings') 63newlib_iconv_external_ccs = get_option('newlib-iconv-external-ccs') 64newlib_atexit_dynamic_alloc = get_option('newlib-atexit-dynamic-alloc') 65newlib_global_atexit = get_option('newlib-global-atexit') 66newlib_reent_small = get_option('newlib-reent-small') 67newlib_global_stdio_streams = get_option('newlib-global-stdio-streams') 68newlib_fvwrite_in_streamio = get_option('newlib-fvwrite-in-streamio') 69newlib_fseek_optimization = get_option('newlib-fseek-optimization') 70newlib_wide_orient = get_option('newlib-wide-orient') 71newlib_nano_malloc = get_option('newlib-nano-malloc') 72newlib_unbuf_stream_opt = get_option('newlib-unbuf-stream-opt') 73lite_exit = get_option('lite-exit') 74newlib_nano_formatted_io = get_option('newlib-nano-formatted-io') 75newlib_retargetable_locking = get_option('newlib-retargetable-locking') 76newlib_long_time_t = get_option('newlib-long-time_t') 77newlib_multithread = get_option('newlib-multithread') 78newlib_iconv = get_option('newlib-iconv') 79newlib_io_float = get_option('newlib-io-float') 80newlib_supplied_syscalls = get_option('newlib-supplied-syscalls') 81newlib_elix_level = get_option('newlib-elix-level') 82target_optspace = get_option('optimization') == 's' 83fast_strcmp = get_option('fast-strcmp') 84newlib_reentrant_syscalls_provided = get_option('newlib-reentrant-syscalls-provided') 85newlib_missing_syscall_names = get_option('newlib-missing-syscall-names') 86newlib_locale_info = get_option('newlib-locale-info') 87newlib_locale_info_extended = get_option('newlib-locale-info-extended') 88newlib_global_errno = get_option('newlib-global-errno') 89newlib_initfini_array = get_option('newlib-initfini-array') 90newlib_initfini = get_option('newlib-initfini') 91thread_local_storage_option = get_option('thread-local-storage') 92tls_model = get_option('tls-model') 93posix_io = get_option('posix-io') 94posix_console = posix_io and get_option('posix-console') 95sysroot_install = get_option('sysroot-install') 96newlib_obsolete_math = get_option('newlib-obsolete-math') 97 98host_cpu=host_machine.cpu() 99if host_cpu == '' 100 host_cmds = meson.get_compiler('c').cmd_array() + ['-dumpmachine'] 101 host_cc_machine=run_command(host_cmds).stdout().strip().split('-') 102 host_cpu=host_cc_machine[0] 103 message('Computed host_cpu as ' + host_cpu) 104endif 105 106specs_dir = get_option('specsdir') 107if specs_dir == '' 108 search_cmds = meson.get_compiler('c').cmd_array() + ['-print-search-dirs'] 109 install_dir=run_command(search_cmds).stdout().split('\n')[0] 110 specs_dir=install_dir.split(':')[1].strip() 111endif 112 113if have_alias_attribute_option == 'auto' 114 have_alias_attribute = meson.get_compiler('c').has_function_attribute('alias') 115else 116 have_alias_attribute = have_alias_attribute_option == 'true' 117endif 118 119if thread_local_storage_option == 'auto' 120 thread_local_storage = not meson.get_compiler('c').has_function('__emutls_get_address', args: ['-nostdlib', '-lgcc']) 121else 122 thread_local_storage = thread_local_storage_option == 'true' 123endif 124 125lib_dir = join_paths(get_option('prefix'), get_option('libdir')) 126 127specs_data = configuration_data() 128specs_data.set( 129 'INCLUDEDIR', 130 join_paths(sysroot_install? '%R' : get_option('prefix'), get_option('includedir')) 131) 132 133specs_data.set( 134 'LIBDIR', 135 sysroot_install? join_paths('%R', get_option('libdir')) : lib_dir 136) 137 138specs_data.set( 139 'TLSMODEL', 140 tls_model 141) 142 143configure_file(input: 'picolibc.specs.in', 144 output: '@BASENAME@', 145 configuration: specs_data, 146 install_dir: specs_dir, 147 install: true) 148 149install_data('picolibc.ld', 150 install_dir: lib_dir) 151 152long_double_code = ''' 153#include <float.h> 154#ifndef LDBL_MANT_DIG 155#error No long double support in float.h 156#endif 157long double test() 158{ 159 long double ld = 0.0L; 160 return ld; 161} 162''' 163have_long_double = meson.get_compiler('c').compiles(long_double_code, name : 'long double check') 164 165if enable_multilib 166 foreach target : run_command(meson.get_compiler('c'), '--print-multi-lib').stdout().strip().split('\n') 167 tmp = target.split(';') 168 flags = [] 169 if tmp.length() > 1 170 foreach flag : tmp[1].strip('@').split('@') 171 if flag != '' 172 flags += '-' + flag 173 endif 174 endforeach 175 if tmp[0] == '.' 176 name = '' 177 else 178 name = tmp[0].underscorify() 179 endif 180 else 181 name = '' 182 endif 183 targets += name 184 value = [tmp[0], flags] 185 set_variable('target_' + name, value) 186 endforeach 187else 188 targets = [''] 189 target_ = ['.', []] 190endif 191 192conf_data = configuration_data() 193 194NEWLIB_VERSION='2.10.0' 195NEWLIB_MAJOR_VERSION=2 196NEWLIB_MINOR_VERSION=10 197NEWLIB_PATCHLEVEL_VERSION=0 198 199have_cc_inhibit_loop_to_libcall=meson.get_compiler('c').has_argument('-fno-tree-loop-distribute-patterns') 200conf_data.set('_HAVE_CC_INHIBIT_LOOP_TO_LIBCALL', have_cc_inhibit_loop_to_libcall, 201 description: 'GCC flag to prevent detecting memcpy/memset patterns') 202conf_data.set('HAVE_LONG_DOUBLE', have_long_double, 203 description: 'Compiler has long double type') 204conf_data.set('HAVE_ALIAS_ATTRIBUTE', have_alias_attribute) 205conf_data.set('_WANT_IO_C99_FORMATS', newlib_io_c99_formats) 206conf_data.set('_WANT_REGISTER_FINI', newlib_register_fini) 207conf_data.set('_WANT_IO_LONG_LONG', newlib_io_long_long) 208conf_data.set('_WANT_IO_LONG_DOUBLE', newlib_io_long_double) 209conf_data.set('_WANT_IO_POS_ARGS', newlib_io_pos_args) 210conf_data.set('_WANT_REENT_SMALL', newlib_reent_small) 211conf_data.set('_WANT_REENT_GLOBAL_STDIO_STREAMS', newlib_global_stdio_streams) 212conf_data.set('_MB_CAPABLE', newlib_mb) 213conf_data.set('_MB_LEN_MAX', newlib_mb ? '8' : '1') 214conf_data.set('__SINGLE_THREAD__', newlib_multithread == false) 215conf_data.set('_ICONV_ENABLE_EXTERNAL_CCS', newlib_iconv_external_ccs) 216conf_data.set('_ICONV_ENABLED', newlib_iconv) 217conf_data.set('_ICONV_ENABLE_EXTERNAL_CCS', newlib_iconv_external_ccs) 218conf_data.set('_ATEXIT_DYNAMIC_ALLOC', newlib_atexit_dynamic_alloc) 219conf_data.set('_REENT_GLOBAL_ATEXIT', newlib_global_atexit) 220conf_data.set('_FVWRITE_IN_STREAMIO', newlib_fvwrite_in_streamio) 221conf_data.set('_FSEEK_OPTIMIZATION', newlib_fseek_optimization) 222conf_data.set('_WIDE_ORIENT', newlib_wide_orient) 223conf_data.set('_NANO_MALLOC', newlib_nano_malloc) 224conf_data.set('_UNBUF_STREAM_OPT', newlib_unbuf_stream_opt) 225conf_data.set('_LITE_EXIT', lite_exit) 226conf_data.set('_NANO_FORMATTED_IO', newlib_nano_formatted_io) 227conf_data.set('_RETARGETABLE_LOCKING', newlib_retargetable_locking) 228conf_data.set('_WANT_USE_LONG_TIME_T', newlib_long_time_t) 229conf_data.set('TINY_STDIO', newlib_tinystdio, description: 'Use tiny stdio from gcc avr') 230conf_data.set('_IEEE_LIBM', true, description: 'math library only offers ieee semantics') 231conf_data.set('PREFER_SIZE_OVER_SPEED', target_optspace, description: 'Optimize for space over speed') 232conf_data.set('FAST_STRCMP', fast_strcmp, description: 'Always optimize strcmp for performance') 233conf_data.set('REENTRANT_SYSCALLS_PROVIDED', newlib_reentrant_syscalls_provided, description: 'Reentrant syscalls provided for us') 234conf_data.set('MISSING_SYSCALL_NAMES', newlib_missing_syscall_names, description: 'use regular syscalls') 235conf_data.set('__HAVE_LOCALE_INFO__', newlib_locale_info, description: 'locale support') 236conf_data.set('__HAVE_LOCALE_INFO_EXTENDED__', newlib_locale_info_extended, description: 'extended locale support') 237conf_data.set('NEWLIB_GLOBAL_ERRNO', newlib_global_errno, description: 'use global errno variable') 238conf_data.set('HAVE_INITFINI_ARRAY', newlib_initfini_array, description: 'compiler supports INIT_ARRAY sections') 239conf_data.set('HAVE_INIT_FINI', newlib_initfini, description: 'Support _init() and _fini() functions') 240conf_data.set('NEWLIB_TLS', thread_local_storage, description: 'use thread local storage') 241conf_data.set('POSIX_IO', posix_io, description: 'Use open/close/read/write in tinystdio') 242conf_data.set('POSIX_CONSOLE', posix_console, description: 'Use POSIX I/O for stdin, stdout and stderr') 243 244if newlib_obsolete_math == 'auto' 245 obsolete_math_value = false 246elif newlib_obsolete_math == 'true' 247 obsolete_math_value = 1 248elif newlib_obsolete_math == 'false' 249 obsolete_math_value = 0 250endif 251 252conf_data.set('__OBSOLETE_MATH', obsolete_math_value, description: 'Use old math code (undef auto, 0 no, 1 yes)') 253 254version_array = meson.project_version().split('.') 255 256if version_array.length() > 2 257 picolibc_patch_level = version_array[2] 258else 259 picolibc_patch_level = 0 260endif 261 262conf_data.set('_PICOLIBC_VERSION', '"@0@"'.format(meson.project_version()), description: 'The Picolibc version in string format.') 263conf_data.set('_PICOLIBC__', version_array[0], description: 'The Picolibc major version number.') 264conf_data.set('_PICOLIBC_MINOR__', version_array[1], description: 'The Picolibc minor version number.') 265conf_data.set('__PICOLIBC_PATCHLEVEL__', picolibc_patch_level, description: 'The Picolibc patch level.') 266 267conf_data.set('_NEWLIB_VERSION', '"@0@"'.format(NEWLIB_VERSION), description: 'The newlib version in string format.') 268conf_data.set('_NEWLIB__', NEWLIB_MAJOR_VERSION, description: 'The newlib major version number.') 269conf_data.set('_NEWLIB_MINOR__', NEWLIB_MINOR_VERSION, description: 'The newlib minor version number.') 270conf_data.set('__NEWLIB_PATCHLEVEL__', NEWLIB_PATCHLEVEL_VERSION, description: 'The newlib patch level.') 271 272if newlib_tinystdio 273 stdio_inc_dir = 'newlib/libc/tinystdio' 274else 275 stdio_inc_dir = 'newlib/libc/stdio' 276endif 277 278inc_dirs = [stdio_inc_dir, '.', 'newlib/libc/include'] 279 280inc = include_directories(inc_dirs) 281 282includedir = join_paths(get_option('prefix'), get_option('includedir')) 283 284arguments = ['-g', '-ffunction-sections', '-fdata-sections'] 285 286if tls_model != '' 287 arguments += ['-ftls-model=' + tls_model] 288endif 289 290add_project_arguments(arguments, language: 'c') 291 292# semihost will adjust this if supported 293has_semihost = false 294 295if newlib_tinystdio 296 subdir('semihost') 297 subdir('dummyhost') 298endif 299 300conf_data.set('HAVE_SEMIHOST', has_semihost, description: 'Semihost APIs supported') 301 302# By default, tests don't require any special arguments 303 304test_c_args = [] 305test_link_args = [] 306test_link_depends = [] 307 308if has_semihost 309 310 # If we're using semihosting, we assume that there's a 311 # custom linker script that includes picolibc.specs 312 313 test_link_name = 'test-' + host_machine.cpu() + '.ld' 314 test_link_dep = files(test_link_name) 315 316 # Linker args must be strings (seems like a bug), so compute the 317 # full path by hand 318 319 test_link_path = '@0@/@1@'.format(meson.current_source_dir(), test_link_name) 320 321 test_c_args += ['--specs', 'picolibc.specs', '-nostartfiles'] 322 323 # Undefine _exit as that's in libsemihost and needs to replace the weak _exit 324 325 test_link_args += test_c_args + ['-L.', '-L' + meson.source_root(), '-T', test_link_path, '-Wl,--undefined=_exit', '-lgcc'] 326 327 # Make sure all of the tests get re-linked if the linker scripts change 328 329 test_link_depends += test_link_dep + files('picolibc.ld') 330endif 331 332subdir('picocrt') 333subdir('newlib') 334 335if enable_tests 336 subdir('test') 337endif 338 339configure_file(output : 'picolibc.h', 340 configuration: conf_data, 341 install_dir: includedir) 342 343# Usage as an embedded subproject: 344# If picolibc is embedded into the source as a subproject, 345# provide a dependency to be used by the main project: 346# dependency('libc', fallback: ['picolibc', 'libc_dep']) 347if not enable_multilib and meson.is_subproject() 348 picolibc_dep = declare_dependency(include_directories: inc, link_with: [lib_c, lib_m]) 349endif 350