|
@@ -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):
|