[libc][picolibc] improve gcc picolibc support
This commit is contained in:
parent
063c8f7bec
commit
da55491608
|
@ -1,10 +1,16 @@
|
||||||
import os
|
import os
|
||||||
from building import *
|
from building import *
|
||||||
from llvm_arm import *
|
|
||||||
Import('rtconfig')
|
Import('rtconfig')
|
||||||
|
|
||||||
group = []
|
group = []
|
||||||
|
|
||||||
|
if rtconfig.PLATFORM == 'gcc':
|
||||||
|
from gcc import *
|
||||||
|
elif rtconfig.PLATFORM == 'llvm-arm':
|
||||||
|
from llvm_arm import *
|
||||||
|
else:
|
||||||
|
Return('group')
|
||||||
|
|
||||||
picolibc_version = GetPicoLibcVersion(rtconfig)
|
picolibc_version = GetPicoLibcVersion(rtconfig)
|
||||||
|
|
||||||
if picolibc_version and not GetDepend('RT_USING_EXTERNAL_LIBC'):
|
if picolibc_version and not GetDepend('RT_USING_EXTERNAL_LIBC'):
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <rtthread.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
/* for exit() and abort() */
|
||||||
|
rt_noreturn void _exit (int status)
|
||||||
|
{
|
||||||
|
extern void __rt_libc_exit(int status);
|
||||||
|
__rt_libc_exit(status);
|
||||||
|
while(1);
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
* 2021-09-02 Meco Man First version
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __FCNTL_H__
|
||||||
|
#define __FCNTL_H__
|
||||||
|
|
||||||
|
#include <sys/_default_fcntl.h>
|
||||||
|
|
||||||
|
#ifndef O_EXEC
|
||||||
|
#define O_EXEC 0x400000
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef O_TMPFILE
|
||||||
|
#define O_TMPFILE 0x800000
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef O_BINARY
|
||||||
|
#define O_BINARY 0x10000
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef O_NOFOLLOW
|
||||||
|
#define O_NOFOLLOW 0x100000
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef O_DIRECTORY
|
||||||
|
#define O_DIRECTORY 0x200000
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2006-2023, RT-Thread Development Team
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <rtthread.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#ifdef RT_USING_POSIX_STDIO
|
||||||
|
#include <posix/stdio.h>
|
||||||
|
#endif /* RT_USING_POSIX_STDIO */
|
||||||
|
#define DBG_TAG "picolibc.iob"
|
||||||
|
#define DBG_LVL DBG_INFO
|
||||||
|
#include <rtdbg.h>
|
||||||
|
|
||||||
|
#ifdef TINY_STDIO
|
||||||
|
|
||||||
|
static int __fputc(char c, FILE *file);
|
||||||
|
static int __fgetc(FILE *file);
|
||||||
|
|
||||||
|
static FILE __stdio_in = FDEV_SETUP_STREAM(NULL, __fgetc, NULL, _FDEV_SETUP_READ);
|
||||||
|
static FILE __stdio_out = FDEV_SETUP_STREAM(__fputc, NULL, NULL, _FDEV_SETUP_WRITE);
|
||||||
|
|
||||||
|
#ifdef __strong_reference
|
||||||
|
#define STDIO_ALIAS(x) __strong_reference(stdout, x);
|
||||||
|
#else
|
||||||
|
#define STDIO_ALIAS(x) FILE *const x = &__stdio_out;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
FILE *const stdin = &__stdio_in;
|
||||||
|
FILE *const stdout = &__stdio_out;
|
||||||
|
STDIO_ALIAS(stderr);
|
||||||
|
|
||||||
|
static int __fputc(char c, FILE *file)
|
||||||
|
{
|
||||||
|
if (file == &__stdio_out)
|
||||||
|
{
|
||||||
|
#if defined(RT_USING_CONSOLE) && defined(RT_USING_DEVICE)
|
||||||
|
rt_device_t console = rt_console_get_device();
|
||||||
|
if (console)
|
||||||
|
{
|
||||||
|
rt_ssize_t rc = rt_device_write(console, -1, &c, 1);
|
||||||
|
return rc > 0 ? rc : -1;
|
||||||
|
}
|
||||||
|
#endif /* defined(RT_USING_CONSOLE) && defined(RT_USING_DEVICE) */
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __fgetc(FILE *file)
|
||||||
|
{
|
||||||
|
if (file == &__stdio_in)
|
||||||
|
{
|
||||||
|
#ifdef RT_USING_POSIX_STDIO
|
||||||
|
if (rt_posix_stdio_get_console() >= 0)
|
||||||
|
{
|
||||||
|
char c;
|
||||||
|
int rc = read(STDIN_FILENO, &c, 1);
|
||||||
|
return rc == 1 ? c : EOF;
|
||||||
|
}
|
||||||
|
#endif /* RT_USING_POSIX_STDIO */
|
||||||
|
}
|
||||||
|
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
116
tools/gcc.py
116
tools/gcc.py
|
@ -20,10 +20,12 @@
|
||||||
# Change Logs:
|
# Change Logs:
|
||||||
# Date Author Notes
|
# Date Author Notes
|
||||||
# 2018-05-22 Bernard The first version
|
# 2018-05-22 Bernard The first version
|
||||||
|
# 2023-11-03 idings return file path in GetHeader
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import platform
|
import platform
|
||||||
|
import subprocess
|
||||||
|
|
||||||
def GetGCCRoot(rtconfig):
|
def GetGCCRoot(rtconfig):
|
||||||
exec_path = rtconfig.EXEC_PATH
|
exec_path = rtconfig.EXEC_PATH
|
||||||
|
@ -39,12 +41,68 @@ def GetGCCRoot(rtconfig):
|
||||||
|
|
||||||
return root_path
|
return root_path
|
||||||
|
|
||||||
def CheckHeader(rtconfig, filename):
|
# https://stackoverflow.com/questions/4980819/what-are-the-gcc-default-include-directories
|
||||||
root = GetGCCRoot(rtconfig)
|
# https://stackoverflow.com/questions/53937211/how-can-i-parse-gcc-output-by-regex-to-get-default-include-paths
|
||||||
|
def match_pattern(pattern, input, start = 0, stop = -1, flags = 0):
|
||||||
|
length = len(input)
|
||||||
|
|
||||||
|
if length == 0:
|
||||||
|
return None
|
||||||
|
|
||||||
|
end_it = max(0, length - 1)
|
||||||
|
|
||||||
|
if start >= end_it:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if stop<0:
|
||||||
|
stop = length
|
||||||
|
|
||||||
|
if stop <= start:
|
||||||
|
return None
|
||||||
|
|
||||||
|
for it in range(max(0, start), min(stop, length)):
|
||||||
|
elem = input[it]
|
||||||
|
match = re.match(pattern, elem, flags)
|
||||||
|
if match:
|
||||||
|
return it
|
||||||
|
|
||||||
|
def GetGccDefaultSearchDirs(rtconfig):
|
||||||
|
start_pattern = r' *#include <\.\.\.> search starts here: *'
|
||||||
|
end_pattern = r' *End of search list\. *'
|
||||||
|
|
||||||
|
gcc_cmd = os.path.join(rtconfig.EXEC_PATH, rtconfig.CC)
|
||||||
|
device_flags = rtconfig.DEVICE.split()
|
||||||
|
args = [gcc_cmd] + device_flags + ['-xc', '-E', '-v', os.devnull]
|
||||||
|
|
||||||
|
proc = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
|
||||||
|
lines = proc.stdout.splitlines()
|
||||||
|
|
||||||
|
start_it = match_pattern(start_pattern, lines)
|
||||||
|
if start_it == None:
|
||||||
|
return []
|
||||||
|
|
||||||
|
end_it = match_pattern(end_pattern, lines, start_it)
|
||||||
|
if end_it == None:
|
||||||
|
return []
|
||||||
|
|
||||||
|
# theres no paths between them
|
||||||
|
if (end_it - start_it) == 1:
|
||||||
|
return []
|
||||||
|
|
||||||
|
return lines[start_it + 1 : end_it]
|
||||||
|
|
||||||
|
def GetHeader(rtconfig, filename):
|
||||||
|
include_dirs = GetGccDefaultSearchDirs(rtconfig)
|
||||||
|
for directory in include_dirs:
|
||||||
|
fn = os.path.join(directory, filename).strip()
|
||||||
|
if os.path.isfile(fn):
|
||||||
|
return fn
|
||||||
|
|
||||||
|
# fallback to use fixed method if can't autodetect
|
||||||
|
root = GetGCCRoot(rtconfig)
|
||||||
fn = os.path.join(root, 'include', filename)
|
fn = os.path.join(root, 'include', filename)
|
||||||
if os.path.isfile(fn):
|
if os.path.isfile(fn):
|
||||||
return True
|
return fn
|
||||||
|
|
||||||
# Usually the cross compiling gcc toolchain has directory as:
|
# Usually the cross compiling gcc toolchain has directory as:
|
||||||
#
|
#
|
||||||
|
@ -62,14 +120,34 @@ def CheckHeader(rtconfig, filename):
|
||||||
|
|
||||||
fn = os.path.join(root, prefix, 'include', filename)
|
fn = os.path.join(root, prefix, 'include', filename)
|
||||||
if os.path.isfile(fn):
|
if os.path.isfile(fn):
|
||||||
return True
|
return fn
|
||||||
|
|
||||||
return False
|
return None
|
||||||
|
|
||||||
# GCC like means the toolchains which are compatible with GCC
|
# GCC like means the toolchains which are compatible with GCC
|
||||||
def GetGCCLikePLATFORM():
|
def GetGCCLikePLATFORM():
|
||||||
return ['gcc', 'armclang', 'llvm-arm']
|
return ['gcc', 'armclang', 'llvm-arm']
|
||||||
|
|
||||||
|
def GetPicoLibcVersion(rtconfig):
|
||||||
|
version = None
|
||||||
|
try:
|
||||||
|
rtconfig.PREFIX
|
||||||
|
except:
|
||||||
|
return version
|
||||||
|
|
||||||
|
# get version from picolibc.h
|
||||||
|
fn = GetHeader(rtconfig, 'picolibc.h')
|
||||||
|
|
||||||
|
if fn:
|
||||||
|
f = open(fn, 'r')
|
||||||
|
if f:
|
||||||
|
for line in f:
|
||||||
|
if line.find('__PICOLIBC_VERSION__') != -1 and line.find('"') != -1:
|
||||||
|
version = re.search(r'\"([^"]+)\"', line).groups()[0]
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
return version
|
||||||
|
|
||||||
def GetNewLibVersion(rtconfig):
|
def GetNewLibVersion(rtconfig):
|
||||||
version = None
|
version = None
|
||||||
|
|
||||||
|
@ -78,21 +156,25 @@ def GetNewLibVersion(rtconfig):
|
||||||
except:
|
except:
|
||||||
return version
|
return version
|
||||||
|
|
||||||
root = GetGCCRoot(rtconfig)
|
# if find picolibc.h, use picolibc
|
||||||
if CheckHeader(rtconfig, '_newlib_version.h'): # get version from _newlib_version.h file
|
fn = GetHeader(rtconfig, 'picolibc.h')
|
||||||
f = open(os.path.join(root, 'include', '_newlib_version.h'), 'r')
|
if fn:
|
||||||
if f:
|
return version
|
||||||
for line in f:
|
|
||||||
if line.find('_NEWLIB_VERSION') != -1 and line.find('"') != -1:
|
# get version from _newlib_version.h file
|
||||||
version = re.search(r'\"([^"]+)\"', line).groups()[0]
|
fn = GetHeader(rtconfig, '_newlib_version.h')
|
||||||
f.close()
|
|
||||||
elif CheckHeader(rtconfig, 'newlib.h'): # get version from newlib.h
|
# get version from newlib.h
|
||||||
f = open(os.path.join(root, 'include', 'newlib.h'), 'r')
|
if not fn:
|
||||||
if f:
|
fn = GetHeader(rtconfig, 'newlib.h')
|
||||||
|
|
||||||
|
if fn:
|
||||||
|
f = open(fn, 'r')
|
||||||
for line in f:
|
for line in f:
|
||||||
if line.find('_NEWLIB_VERSION') != -1 and line.find('"') != -1:
|
if line.find('_NEWLIB_VERSION') != -1 and line.find('"') != -1:
|
||||||
version = re.search(r'\"([^"]+)\"', line).groups()[0]
|
version = re.search(r'\"([^"]+)\"', line).groups()[0]
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
return version
|
return version
|
||||||
|
|
||||||
# FIXME: there is no musl version or musl macros can be found officially
|
# FIXME: there is no musl version or musl macros can be found officially
|
||||||
|
@ -109,8 +191,6 @@ def GetMuslVersion(rtconfig):
|
||||||
return version
|
return version
|
||||||
|
|
||||||
def GCCResult(rtconfig, str):
|
def GCCResult(rtconfig, str):
|
||||||
import subprocess
|
|
||||||
|
|
||||||
result = ''
|
result = ''
|
||||||
|
|
||||||
def checkAndGetResult(pattern, string):
|
def checkAndGetResult(pattern, string):
|
||||||
|
|
Loading…
Reference in New Issue