mirror of
https://gitlab.com/qemu-project/meson.git
synced 2025-07-02 21:03:40 +08:00

This replaces all of the Apache blurbs at the start of each file with an `# SPDX-License-Identifier: Apache-2.0` string. It also fixes existing uses to be consistent in capitalization, and to be placed above any copyright notices. This removes nearly 3000 lines of boilerplate from the project (only python files), which no developer cares to look at. SPDX is in common use, particularly in the Linux kernel, and is the recommended format for Meson's own `project(license: )` field
289 lines
8.7 KiB
Python
Executable File
289 lines
8.7 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
# Copyright 2017 Niklas Claesson
|
|
|
|
"""This is two implementations for how to get module names from the boost
|
|
sources. One relies on json metadata files in the sources, the other relies on
|
|
the folder names.
|
|
|
|
Run the tool in the boost directory and append the stdout to the misc.py:
|
|
|
|
boost/$ path/to/meson/tools/boost_names.py >> path/to/meson/dependencies/misc.py
|
|
"""
|
|
|
|
import sys
|
|
import json
|
|
import re
|
|
import textwrap
|
|
import functools
|
|
import typing as T
|
|
from pathlib import Path
|
|
|
|
lib_dir = Path('libs')
|
|
jamroot = Path('Jamroot')
|
|
|
|
not_modules = ['config', 'disjoint_sets', 'headers']
|
|
|
|
export_modules = False
|
|
|
|
|
|
@functools.total_ordering
|
|
class BoostLibrary():
|
|
def __init__(self, name: str, shared: T.List[str], static: T.List[str], single: T.List[str], multi: T.List[str]):
|
|
self.name = name
|
|
self.shared = sorted(set(shared))
|
|
self.static = sorted(set(static))
|
|
self.single = sorted(set(single))
|
|
self.multi = sorted(set(multi))
|
|
|
|
def __lt__(self, other: object) -> bool:
|
|
if isinstance(other, BoostLibrary):
|
|
return self.name < other.name
|
|
return NotImplemented
|
|
|
|
def __eq__(self, other: object) -> bool:
|
|
if isinstance(other, BoostLibrary):
|
|
return self.name == other.name
|
|
elif isinstance(other, str):
|
|
return self.name == other
|
|
return NotImplemented
|
|
|
|
def __hash__(self) -> int:
|
|
return hash(self.name)
|
|
|
|
@functools.total_ordering
|
|
class BoostModule():
|
|
def __init__(self, name: str, key: str, desc: str, libs: T.List[BoostLibrary]):
|
|
self.name = name
|
|
self.key = key
|
|
self.desc = desc
|
|
self.libs = libs
|
|
|
|
def __lt__(self, other: object) -> bool:
|
|
if isinstance(other, BoostModule):
|
|
return self.key < other.key
|
|
return NotImplemented
|
|
|
|
|
|
def get_boost_version() -> T.Optional[str]:
|
|
raw = jamroot.read_text(encoding='utf-8')
|
|
m = re.search(r'BOOST_VERSION\s*:\s*([0-9\.]+)\s*;', raw)
|
|
if m:
|
|
return m.group(1)
|
|
return None
|
|
|
|
|
|
def get_libraries(jamfile: Path) -> T.List[BoostLibrary]:
|
|
# Extract libraries from the boost Jamfiles. This includes:
|
|
# - library name
|
|
# - compiler flags
|
|
|
|
libs: T.List[BoostLibrary] = []
|
|
raw = jamfile.read_text(encoding='utf-8')
|
|
raw = re.sub(r'#.*\n', '\n', raw) # Remove comments
|
|
raw = re.sub(r'\s+', ' ', raw) # Force single space
|
|
raw = re.sub(r'}', ';', raw) # Cheat code blocks by converting } to ;
|
|
|
|
cmds = raw.split(';') # Commands always terminate with a ; (I hope)
|
|
cmds = [x.strip() for x in cmds] # Some cleanup
|
|
|
|
project_usage_requirements: T.List[str] = []
|
|
|
|
# "Parse" the relevant sections
|
|
for i in cmds:
|
|
parts = i.split(' ')
|
|
parts = [x for x in parts if x not in ['']]
|
|
if not parts:
|
|
continue
|
|
|
|
# Parse project
|
|
if parts[0] in ['project']:
|
|
attributes: T.Dict[str, T.List[str]] = {}
|
|
curr: T.Optional[str] = None
|
|
|
|
for j in parts:
|
|
if j == ':':
|
|
curr = None
|
|
elif curr is None:
|
|
curr = j
|
|
else:
|
|
if curr not in attributes:
|
|
attributes[curr] = []
|
|
attributes[curr] += [j]
|
|
|
|
if 'usage-requirements' in attributes:
|
|
project_usage_requirements = attributes['usage-requirements']
|
|
|
|
# Parse libraries
|
|
elif parts[0] in ['lib', 'boost-lib']:
|
|
assert len(parts) >= 2
|
|
|
|
# Get and check the library name
|
|
lname = parts[1]
|
|
if parts[0] == 'boost-lib':
|
|
lname = f'boost_{lname}'
|
|
if not lname.startswith('boost_'):
|
|
continue
|
|
|
|
# Count `:` to only select the 'usage-requirements'
|
|
# See https://boostorg.github.io/build/manual/master/index.html#bbv2.main-target-rule-syntax
|
|
colon_counter = 0
|
|
usage_requirements: T.List[str] = []
|
|
for j in parts:
|
|
if j == ':':
|
|
colon_counter += 1
|
|
elif colon_counter >= 4:
|
|
usage_requirements += [j]
|
|
|
|
# Get shared / static defines
|
|
shared: T.List[str] = []
|
|
static: T.List[str] = []
|
|
single: T.List[str] = []
|
|
multi: T.List[str] = []
|
|
for j in usage_requirements + project_usage_requirements:
|
|
m1 = re.match(r'<link>shared:<define>(.*)', j)
|
|
m2 = re.match(r'<link>static:<define>(.*)', j)
|
|
m3 = re.match(r'<threading>single:<define>(.*)', j)
|
|
m4 = re.match(r'<threading>multi:<define>(.*)', j)
|
|
|
|
if m1:
|
|
shared += [f'-D{m1.group(1)}']
|
|
if m2:
|
|
static += [f'-D{m2.group(1)}']
|
|
if m3:
|
|
single +=[f'-D{m3.group(1)}']
|
|
if m4:
|
|
multi += [f'-D{m4.group(1)}']
|
|
|
|
libs += [BoostLibrary(lname, shared, static, single, multi)]
|
|
|
|
return libs
|
|
|
|
|
|
def process_lib_dir(ldir: Path) -> T.List[BoostModule]:
|
|
meta_file = ldir / 'meta' / 'libraries.json'
|
|
bjam_file = ldir / 'build' / 'Jamfile.v2'
|
|
if not meta_file.exists():
|
|
print(f'WARNING: Meta file {meta_file} does not exist')
|
|
return []
|
|
|
|
# Extract libs
|
|
libs: T.List[BoostLibrary] = []
|
|
if bjam_file.exists():
|
|
libs = get_libraries(bjam_file)
|
|
|
|
# Extract metadata
|
|
data = json.loads(meta_file.read_text(encoding='utf-8'))
|
|
if not isinstance(data, list):
|
|
data = [data]
|
|
|
|
modules: T.List[BoostModule] = []
|
|
for i in data:
|
|
modules += [BoostModule(i['name'], i['key'], i['description'], libs)]
|
|
|
|
return modules
|
|
|
|
|
|
def get_modules() -> T.List[BoostModule]:
|
|
modules: T.List[BoostModule] = []
|
|
for i in lib_dir.iterdir():
|
|
if not i.is_dir() or i.name in not_modules:
|
|
continue
|
|
|
|
# numeric has sub libs
|
|
subdirs = i / 'sublibs'
|
|
metadir = i / 'meta'
|
|
if subdirs.exists() and not metadir.exists():
|
|
for j in i.iterdir():
|
|
if not j.is_dir():
|
|
continue
|
|
modules += process_lib_dir(j)
|
|
else:
|
|
modules += process_lib_dir(i)
|
|
|
|
return modules
|
|
|
|
|
|
def main() -> int:
|
|
if not lib_dir.is_dir() or not jamroot.exists():
|
|
print("ERROR: script must be run in boost source directory")
|
|
return 1
|
|
|
|
vers = get_boost_version()
|
|
modules = get_modules()
|
|
modules = sorted(modules)
|
|
libraries = [x for y in modules for x in y.libs]
|
|
libraries = sorted(set(libraries))
|
|
|
|
print(textwrap.dedent(f'''\
|
|
#### ---- BEGIN GENERATED ---- ####
|
|
# #
|
|
# Generated with tools/boost_names.py:
|
|
# - boost version: {vers}
|
|
# - modules found: {len(modules)}
|
|
# - libraries found: {len(libraries)}
|
|
#
|
|
|
|
class BoostLibrary():
|
|
def __init__(self, name: str, shared: T.List[str], static: T.List[str], single: T.List[str], multi: T.List[str]):
|
|
self.name = name
|
|
self.shared = shared
|
|
self.static = static
|
|
self.single = single
|
|
self.multi = multi
|
|
|
|
class BoostModule():
|
|
def __init__(self, name: str, key: str, desc: str, libs: T.List[str]):
|
|
self.name = name
|
|
self.key = key
|
|
self.desc = desc
|
|
self.libs = libs
|
|
|
|
|
|
# dict of all know libraries with additional compile options
|
|
boost_libraries = {{\
|
|
'''))
|
|
|
|
for i in libraries:
|
|
print(textwrap.indent(textwrap.dedent(f"""\
|
|
'{i.name}': BoostLibrary(
|
|
name='{i.name}',
|
|
shared={i.shared},
|
|
static={i.static},
|
|
single={i.single},
|
|
multi={i.multi},
|
|
),\
|
|
"""), ' '))
|
|
|
|
if export_modules:
|
|
print(textwrap.dedent(f'''\
|
|
}}
|
|
|
|
|
|
# dict of all modules with metadata
|
|
boost_modules = {{\
|
|
'''))
|
|
|
|
for mod in modules:
|
|
desc_escaped = re.sub(r"'", "\\'", mod.desc)
|
|
print(textwrap.indent(textwrap.dedent(f"""\
|
|
'{mod.key}': BoostModule(
|
|
name='{mod.name}',
|
|
key='{mod.key}',
|
|
desc='{desc_escaped}',
|
|
libs={[x.name for x in mod.libs]},
|
|
),\
|
|
"""), ' '))
|
|
|
|
print(textwrap.dedent(f'''\
|
|
}}
|
|
|
|
# #
|
|
#### ---- END GENERATED ---- ####\
|
|
'''))
|
|
|
|
return 0
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main())
|