summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXiang.Lin <[email protected]>2023-11-08 15:09:09 +0800
committerGitHub <[email protected]>2023-11-08 02:09:09 -0500
commitda55491608e19c53d5260309a4fb2ccad930cc51 (patch)
tree7f9c65b785c4850e314b60268ba11e8e33ad11ea
parent063c8f7bec57ba63a038c1bad2fa9056fb0c5ac0 (diff)
[libc][picolibc] improve gcc picolibc support
-rw-r--r--components/libc/compilers/picolibc/SConscript8
-rw-r--r--components/libc/compilers/picolibc/exit.c19
-rw-r--r--components/libc/compilers/picolibc/fcntl.h36
-rw-r--r--components/libc/compilers/picolibc/iob.c73
-rw-r--r--tools/gcc.py120
5 files changed, 235 insertions, 21 deletions
diff --git a/components/libc/compilers/picolibc/SConscript b/components/libc/compilers/picolibc/SConscript
index 999f7cca56..c0de465a2f 100644
--- a/components/libc/compilers/picolibc/SConscript
+++ b/components/libc/compilers/picolibc/SConscript
@@ -1,10 +1,16 @@
import os
from building import *
-from llvm_arm import *
Import('rtconfig')
group = []
+if rtconfig.PLATFORM == 'gcc':
+ from gcc import *
+elif rtconfig.PLATFORM == 'llvm-arm':
+ from llvm_arm import *
+else:
+ Return('group')
+
picolibc_version = GetPicoLibcVersion(rtconfig)
if picolibc_version and not GetDepend('RT_USING_EXTERNAL_LIBC'):
diff --git a/components/libc/compilers/picolibc/exit.c b/components/libc/compilers/picolibc/exit.c
new file mode 100644
index 0000000000..f3f3ce831a
--- /dev/null
+++ b/components/libc/compilers/picolibc/exit.c
@@ -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);
+}
diff --git a/components/libc/compilers/picolibc/fcntl.h b/components/libc/compilers/picolibc/fcntl.h
new file mode 100644
index 0000000000..ce8b621125
--- /dev/null
+++ b/components/libc/compilers/picolibc/fcntl.h
@@ -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
diff --git a/components/libc/compilers/picolibc/iob.c b/components/libc/compilers/picolibc/iob.c
new file mode 100644
index 0000000000..a13eb3a0e4
--- /dev/null
+++ b/components/libc/compilers/picolibc/iob.c
@@ -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
diff --git a/tools/gcc.py b/tools/gcc.py
index 556ede8f23..356842a8e8 100644
--- a/tools/gcc.py
+++ b/tools/gcc.py
@@ -20,10 +20,12 @@
# Change Logs:
# Date Author Notes
# 2018-05-22 Bernard The first version
+# 2023-11-03 idings return file path in GetHeader
import os
import re
import platform
+import subprocess
def GetGCCRoot(rtconfig):
exec_path = rtconfig.EXEC_PATH
@@ -39,12 +41,68 @@ def GetGCCRoot(rtconfig):
return root_path
-def CheckHeader(rtconfig, filename):
- root = GetGCCRoot(rtconfig)
+# https://stackoverflow.com/questions/4980819/what-are-the-gcc-default-include-directories
+# 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)
if os.path.isfile(fn):
- return True
+ return fn
# Usually the cross compiling gcc toolchain has directory as:
#
@@ -62,37 +120,61 @@ def CheckHeader(rtconfig, filename):
fn = os.path.join(root, prefix, 'include', filename)
if os.path.isfile(fn):
- return True
+ return fn
- return False
+ return None
# GCC like means the toolchains which are compatible with GCC
def GetGCCLikePLATFORM():
return ['gcc', 'armclang', 'llvm-arm']
-def GetNewLibVersion(rtconfig):
+def GetPicoLibcVersion(rtconfig):
version = None
-
try:
rtconfig.PREFIX
except:
return version
- root = GetGCCRoot(rtconfig)
- if CheckHeader(rtconfig, '_newlib_version.h'): # get version from _newlib_version.h file
- f = open(os.path.join(root, 'include', '_newlib_version.h'), 'r')
- if f:
- for line in f:
- if line.find('_NEWLIB_VERSION') != -1 and line.find('"') != -1:
- version = re.search(r'\"([^"]+)\"', line).groups()[0]
- f.close()
- elif CheckHeader(rtconfig, 'newlib.h'): # get version from newlib.h
- f = open(os.path.join(root, 'include', 'newlib.h'), 'r')
+ # 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('_NEWLIB_VERSION') != -1 and line.find('"') != -1:
+ if line.find('__PICOLIBC_VERSION__') != -1 and line.find('"') != -1:
version = re.search(r'\"([^"]+)\"', line).groups()[0]
f.close()
+
+ return version
+
+def GetNewLibVersion(rtconfig):
+ version = None
+
+ try:
+ rtconfig.PREFIX
+ except:
+ return version
+
+ # if find picolibc.h, use picolibc
+ fn = GetHeader(rtconfig, 'picolibc.h')
+ if fn:
+ return version
+
+ # get version from _newlib_version.h file
+ fn = GetHeader(rtconfig, '_newlib_version.h')
+
+ # get version from newlib.h
+ if not fn:
+ fn = GetHeader(rtconfig, 'newlib.h')
+
+ if fn:
+ f = open(fn, 'r')
+ for line in f:
+ if line.find('_NEWLIB_VERSION') != -1 and line.find('"') != -1:
+ version = re.search(r'\"([^"]+)\"', line).groups()[0]
+ f.close()
+
return version
# FIXME: there is no musl version or musl macros can be found officially
@@ -109,8 +191,6 @@ def GetMuslVersion(rtconfig):
return version
def GCCResult(rtconfig, str):
- import subprocess
-
result = ''
def checkAndGetResult(pattern, string):