1383 lines
47 KiB
Python
1383 lines
47 KiB
Python
"""
|
|
Copyright 2024 Google LLC
|
|
SPDX-License-Identifier: MIT
|
|
"""
|
|
|
|
import os
|
|
import meson_impl as impl
|
|
import tomllib
|
|
import re
|
|
|
|
from jinja2 import Environment, FileSystemLoader
|
|
from pathlib import Path
|
|
|
|
from meson_build_state import *
|
|
|
|
jinja_env = Environment(
|
|
loader=FileSystemLoader(Path(__file__).parent.resolve() / 'templates/')
|
|
)
|
|
|
|
# A map that holds the build-system to build file
|
|
# Keep the keys lower-case for non-case sensitivity
|
|
OUTPUT_FILES = {'soong': r'Android_res.bp', 'bazel': r'BUILD.bazel'}
|
|
|
|
|
|
def generate_build_file(translator, build_type: str):
|
|
defaults_gen = jinja_env.get_template('defaults/all_defaults.txt')
|
|
defaults = defaults_gen.render()
|
|
# Write our manually defined defaults
|
|
with open(OUTPUT_FILES[build_type], 'w') as file:
|
|
if build_type == 'soong':
|
|
file.write(defaults)
|
|
path = build_type + '/'
|
|
# Render all static libraries
|
|
static_libs_template = jinja_env.get_template(path + 'static_library.txt')
|
|
for static_lib in translator.meson_state.static_libraries:
|
|
if static_lib.library_type is LibraryType.LibraryShared:
|
|
static_libs_template = jinja_env.get_template(
|
|
path + 'shared_library.txt'
|
|
)
|
|
cc_lib = static_libs_template.render(
|
|
name=static_lib.name,
|
|
host_supported='false', # TODO(bpnguyen): Fix hardcoded host_supported
|
|
srcs=static_lib.srcs,
|
|
hdrs=static_lib.generated_headers,
|
|
generated_headers=static_lib.generated_headers,
|
|
generated_sources=static_lib.generated_sources,
|
|
copts=static_lib.copts,
|
|
c_std_val=static_lib.cstd,
|
|
cpp_std_val=static_lib.cpp_std,
|
|
cflags=static_lib.conlyflags,
|
|
cppflags=static_lib.cppflags,
|
|
include_directories=static_lib.local_include_dirs,
|
|
system_include_directories=static_lib.system_include_dirs,
|
|
static_libs=static_lib.static_libs,
|
|
whole_static_libs=static_lib.whole_static_libs,
|
|
shared_libs=static_lib.shared_libs,
|
|
header_libs=static_lib.header_libs,
|
|
target_compatible_with=static_lib.target_compatible_with,
|
|
deps=static_lib.deps,
|
|
)
|
|
# Set the template back to static by default
|
|
if static_lib.library_type is LibraryType.LibraryShared:
|
|
static_libs_template = jinja_env.get_template(
|
|
path + 'static_library.txt'
|
|
)
|
|
file.write(cc_lib)
|
|
|
|
# Render genrules / custom targets
|
|
custom_target_template = jinja_env.get_template(path + 'genrule.txt')
|
|
for custom_target in translator.meson_state.custom_targets:
|
|
genrule = custom_target_template.render(
|
|
name=custom_target.name,
|
|
srcs=custom_target.srcs,
|
|
outs=custom_target.out,
|
|
tools=custom_target.tools,
|
|
export=len(custom_target.export_include_dirs) > 0,
|
|
export_include_dirs=custom_target.export_include_dirs,
|
|
cmd=custom_target.cmd,
|
|
)
|
|
file.write(genrule)
|
|
|
|
# python binary hosts
|
|
py_binary_host_template = jinja_env.get_template(path + 'py_binary.txt')
|
|
for py_binary in translator.meson_state.custom_py_targets:
|
|
py_binary_render = py_binary_host_template.render(
|
|
name=py_binary.name,
|
|
main=py_binary.main,
|
|
srcs=py_binary.srcs,
|
|
imports=py_binary.imports,
|
|
)
|
|
file.write(py_binary_render)
|
|
|
|
include_dir_template = jinja_env.get_template(path + 'include_directories.txt')
|
|
for include_dir in translator.meson_state.include_dirs:
|
|
include_dir_render = include_dir_template.render(
|
|
name=include_dir.name,
|
|
hdrs=include_dir.dirs,
|
|
)
|
|
file.write(include_dir_render)
|
|
|
|
|
|
class SoongGenerator(impl.Compiler):
|
|
def has_header_symbol(
|
|
self,
|
|
header: str,
|
|
symbol: str,
|
|
args=[],
|
|
dependencies=[],
|
|
include_directories=[],
|
|
no_builtin_args=False,
|
|
prefix=[],
|
|
required=False,
|
|
):
|
|
# Exclude what is currently not working.
|
|
result = self.is_symbol_supported(header, symbol)
|
|
print("has_header_symbol '%s', '%s': %s" % (header, symbol, str(result)))
|
|
return result
|
|
|
|
def check_header(self, header, prefix=''):
|
|
result = self.is_header_supported(header)
|
|
print("check_header '%s': %s" % (header, str(result)))
|
|
return result
|
|
|
|
def has_function(self, function, args=[], prefix='', dependencies=''):
|
|
# Exclude what is currently not working.
|
|
result = self.is_function_supported(function)
|
|
print("has_function '%s': %s" % (function, str(result)))
|
|
return result
|
|
|
|
def links(self, snippet, name, args=[], dependencies=[]):
|
|
# Exclude what is currently not working.
|
|
result = self.is_link_supported(name)
|
|
print("links '%s': %s" % (name, str(result)))
|
|
return result
|
|
|
|
def generate(self, translator):
|
|
"""
|
|
Generates a Soong valid build file
|
|
:return: None
|
|
"""
|
|
# Render all the defaults to the file first.
|
|
generate_build_file(translator, 'soong')
|
|
|
|
|
|
class BazelGenerator(impl.Compiler):
|
|
def is_symbol_supported(self, header: str, symbol: str):
|
|
if header in meson_translator.config.headers_not_supported:
|
|
return False
|
|
if symbol in meson_translator.config.symbols_not_supported:
|
|
return False
|
|
return super().is_symbol_supported(header, symbol)
|
|
|
|
def is_function_supported(self, function):
|
|
if function in meson_translator.config.functions_not_supported:
|
|
return False
|
|
return super().is_function_supported(function)
|
|
|
|
def is_link_supported(self, name):
|
|
if name in meson_translator.config.links_not_supported:
|
|
return False
|
|
return super().is_link_supported(name)
|
|
|
|
def has_header_symbol(
|
|
self,
|
|
header: str,
|
|
symbol: str,
|
|
args=None,
|
|
dependencies=None,
|
|
include_directories=None,
|
|
no_builtin_args=False,
|
|
prefix=None,
|
|
required=False,
|
|
):
|
|
if args is None:
|
|
args = []
|
|
if dependencies is None:
|
|
dependencies = []
|
|
if include_directories is None:
|
|
include_directories = []
|
|
if prefix is None:
|
|
prefix = []
|
|
# Exclude what is currently not working.
|
|
result = self.is_symbol_supported(header, symbol)
|
|
print("has_header_symbol '%s', '%s': %s" % (header, symbol, str(result)))
|
|
return result
|
|
|
|
def check_header(self, header, prefix=''):
|
|
result = self.is_header_supported(header)
|
|
print(f"check_header '{header}': {result}")
|
|
return result
|
|
|
|
def has_function(self, function, args=[], prefix='', dependencies='') -> bool:
|
|
# Exclude what is currently not working.
|
|
result = self.is_function_supported(function)
|
|
print(f"has_function '{function}': {result}")
|
|
return result
|
|
|
|
def links(self, snippet, name, args=[], dependencies=[]):
|
|
# Exclude what is currently not working.
|
|
result = self.is_link_supported(name)
|
|
print(f"links '{name}': {result}")
|
|
return result
|
|
|
|
def generate(self, translator):
|
|
generate_build_file(translator, 'bazel')
|
|
|
|
|
|
class BazelPkgConfigModule(impl.PkgConfigModule):
|
|
def generate(
|
|
self,
|
|
lib,
|
|
name='',
|
|
description='',
|
|
extra_cflags=None,
|
|
filebase='',
|
|
version='',
|
|
libraries=None,
|
|
libraries_private=None,
|
|
):
|
|
assert type(lib) is impl.StaticLibrary
|
|
sl = StaticLibrary()
|
|
sl.name = name
|
|
sl.deps = lib.target_name
|
|
sl.system_include_dirs.append(".")
|
|
sl.visibility.append('//visibility:public')
|
|
meson_translator.meson_state.static_libraries.append(sl)
|
|
|
|
|
|
|
|
class MesonTranslator:
|
|
"""
|
|
Abstract class that defines all common attributes
|
|
between different build systems (Soong, Bazel, etc...)
|
|
"""
|
|
|
|
def __init__(self):
|
|
self._generator = None
|
|
self._config_file = None
|
|
self._build = ''
|
|
# configs and meson_project_states are ordered with each other.
|
|
self._configs: list[ProjectConfig] = []
|
|
self._meson_project_states: list[MesonProjectState] = []
|
|
# TODO(357080225): Fix the use hardcoded state 0
|
|
self._state = 0 # index of self._configs
|
|
|
|
def init_data(self, config_file: str):
|
|
self._config_file: str = config_file
|
|
print('CONFIG:', self._config_file)
|
|
self._init_metadata()
|
|
_generator = (
|
|
SoongGenerator(self.config.cpu_family)
|
|
if self._build.lower() == 'soong'
|
|
else BazelGenerator(self.config.cpu_family)
|
|
)
|
|
self._generator: impl.Compiler = _generator
|
|
return self
|
|
|
|
@property
|
|
def config_file(self) -> Path:
|
|
return self._config_file
|
|
|
|
@property
|
|
def host_machine(self) -> str:
|
|
return self._configs[self._state].host_machine
|
|
|
|
@property
|
|
def build_machine(self) -> str:
|
|
return self._configs[self._state].build_machine
|
|
|
|
@property
|
|
def generator(self) -> impl.Compiler:
|
|
return self._generator
|
|
|
|
@property
|
|
def build(self) -> str:
|
|
return self._build
|
|
|
|
@property
|
|
def config(self) -> ProjectConfig:
|
|
return self._configs[self._state]
|
|
|
|
@property
|
|
def meson_state(self):
|
|
return self._meson_project_states[self._state]
|
|
|
|
def is_soong(self):
|
|
return self._build.lower() == 'soong'
|
|
|
|
def is_bazel(self):
|
|
return self._build.lower() == 'bazel'
|
|
|
|
def get_output_filename(self) -> str:
|
|
return OUTPUT_FILES[self._build.lower()]
|
|
|
|
def _init_metadata(self):
|
|
"""
|
|
To be called after self._config_file has alredy been assigned.
|
|
Parses the given config files for common build attributes
|
|
Fills the list of all project configs
|
|
:return: None
|
|
"""
|
|
with open(self._config_file, 'rb') as f:
|
|
data = tomllib.load(f)
|
|
self._build = data.get('build')
|
|
base_config = data.get('base_project_config')
|
|
|
|
configs = data.get('project_config')
|
|
for config in configs:
|
|
proj_config = ProjectConfig.create_project_config(self._build, **config)
|
|
self._configs.append(
|
|
proj_config
|
|
)
|
|
self._meson_project_states.append(MesonProjectState())
|
|
|
|
new_configs = []
|
|
# Handle Inheritance
|
|
for config in self._configs:
|
|
# Parent config, that contains shared attributes
|
|
base_proj_config = ProjectConfig.create_project_config(self._build, **base_config)
|
|
if not config.inherits_from:
|
|
new_configs.append(config)
|
|
continue
|
|
if config.inherits_from == 'base_project_config':
|
|
new_configs.append(
|
|
base_proj_config.extend(config).deepcopy()
|
|
)
|
|
else:
|
|
for proj_config in self._configs:
|
|
if config.inherits_from == proj_config.name:
|
|
new_configs.append(
|
|
proj_config.extend(config).deepcopy()
|
|
)
|
|
self._configs = new_configs
|
|
|
|
|
|
# Declares an empty attribute data class
|
|
# metadata is allocated during Generators-runtime (I.E. generate_<host>_build.py)
|
|
meson_translator = MesonTranslator()
|
|
|
|
_gIncludeDirectories = {}
|
|
|
|
|
|
def load_meson_data(config_file: str):
|
|
meson_translator.init_data(config_file)
|
|
|
|
|
|
def open_output_file():
|
|
impl.open_output_file(meson_translator.get_output_filename())
|
|
|
|
|
|
def close_output_file():
|
|
impl.close_output_file()
|
|
|
|
|
|
def add_subdirs_to_set(dir_, dir_set):
|
|
subdirs = os.listdir(dir_)
|
|
for subdir in subdirs:
|
|
subdir = os.path.join(dir_, subdir)
|
|
if os.path.isdir(subdir):
|
|
dir_set.add(subdir)
|
|
|
|
|
|
def include_directories(*paths, is_system=False):
|
|
if meson_translator.host_machine == 'android':
|
|
return impl.IncludeDirectories('', impl.get_include_dirs(paths))
|
|
# elif host_machine == 'fuchsia'
|
|
dirs = impl.get_include_dirs(paths)
|
|
name = dirs[0].replace('/', '_')
|
|
if is_system:
|
|
name += '_sys'
|
|
|
|
global _gIncludeDirectories
|
|
if name not in _gIncludeDirectories:
|
|
# Mesa likes to include files at a level down from the include path,
|
|
# so ensure Bazel allows this by including all of the possibilities.
|
|
# Can't repeat entries so use a set.
|
|
dir_set = set()
|
|
for dir_ in dirs:
|
|
dir_ = os.path.normpath(dir_)
|
|
dir_set.add(dir_)
|
|
add_subdirs_to_set(dir_, dir_set)
|
|
|
|
# HACK: For special cases we go down two levels:
|
|
# - Mesa vulkan runtime does #include "vulkan/wsi/..."
|
|
paths_needing_two_levels = ['src/vulkan']
|
|
for dir_ in list(dir_set):
|
|
if dir_ in paths_needing_two_levels:
|
|
add_subdirs_to_set(dir_, dir_set)
|
|
|
|
include_dir = IncludeDirectories()
|
|
include_dir.name = name
|
|
|
|
for dir_ in dir_set:
|
|
include_dir.dirs.append(os.path.normpath(os.path.join(dir_, '*.h')))
|
|
include_dir.dirs.append(os.path.normpath(os.path.join(dir_, '*.c')))
|
|
include_dir.visibility.append('//visibility:public')
|
|
_gIncludeDirectories[name] = impl.IncludeDirectories(name, dirs)
|
|
meson_translator.meson_state.include_dirs.append(include_dir)
|
|
return _gIncludeDirectories[name]
|
|
|
|
|
|
def module_import(name: str):
|
|
if name == 'python':
|
|
return impl.PythonModule()
|
|
if name == 'pkgconfig' and meson_translator.host_machine.lower() == 'fuchsia':
|
|
return BazelPkgConfigModule()
|
|
if name == 'pkgconfig' and meson_translator.host_machine.lower() == 'android':
|
|
return impl.PkgConfigModule()
|
|
if name == 'pkgconfig' and meson_translator.host_machine.lower() == 'linux':
|
|
return impl.PkgConfigModule()
|
|
exit(
|
|
f'Unhandled module: "{name}" for host machine: "{meson_translator.host_machine}"'
|
|
)
|
|
|
|
|
|
def load_dependencies():
|
|
impl.load_dependencies(meson_translator.config_file)
|
|
|
|
|
|
def dependency(
|
|
*names,
|
|
required=True,
|
|
version='',
|
|
allow_fallback=False,
|
|
method='',
|
|
modules=[],
|
|
optional_modules=[],
|
|
static=True,
|
|
fallback=[],
|
|
include_type='',
|
|
native=False,
|
|
):
|
|
return impl.dependency(*names, required=required, version=version)
|
|
|
|
|
|
def static_library(
|
|
target_name,
|
|
*source_files,
|
|
c_args=[],
|
|
cpp_args=[],
|
|
c_pch='',
|
|
build_by_default=False,
|
|
build_rpath='',
|
|
d_debug=[],
|
|
d_import_dirs=[],
|
|
d_module_versions=[],
|
|
d_unittest=False,
|
|
dependencies=[],
|
|
extra_files='',
|
|
gnu_symbol_visibility='',
|
|
gui_app=False,
|
|
implicit_include_directories=False,
|
|
include_directories=[],
|
|
install=False,
|
|
install_dir='',
|
|
install_mode=[],
|
|
install_rpath='',
|
|
install_tag='',
|
|
link_args=[],
|
|
link_depends='',
|
|
link_language='',
|
|
link_whole=[],
|
|
link_with=[],
|
|
name_prefix='',
|
|
name_suffix='',
|
|
native=False,
|
|
objects=[],
|
|
override_options=[],
|
|
pic=False,
|
|
prelink=False,
|
|
rust_abi='',
|
|
rust_crate_type='',
|
|
rust_dependency_map={},
|
|
sources='',
|
|
vala_args=[],
|
|
win_subsystem='',
|
|
):
|
|
print('static_library: ' + target_name)
|
|
|
|
link_with = impl.get_linear_list(link_with)
|
|
link_whole = impl.get_linear_list(link_whole)
|
|
|
|
# Emitting link_with/link_whole into a static library isn't useful for building,
|
|
# shared libraries must specify the whole chain of dependencies.
|
|
# Leaving them here for traceability though maybe it's less confusing to remove them?
|
|
_emit_builtin_target(
|
|
target_name,
|
|
*source_files,
|
|
c_args=c_args,
|
|
cpp_args=cpp_args,
|
|
dependencies=dependencies,
|
|
include_directories=include_directories,
|
|
link_with=link_with,
|
|
link_whole=link_whole,
|
|
builtin_type_name='cc_library_static',
|
|
static=meson_translator.is_bazel(),
|
|
library_type=LibraryType.LibraryStatic,
|
|
)
|
|
|
|
return impl.StaticLibrary(target_name, link_with=link_with, link_whole=link_whole)
|
|
|
|
|
|
def _get_sources(input_sources, sources, generated_sources, generated_headers):
|
|
def generate_sources_fuchsia(source_):
|
|
if type(source_) is impl.CustomTarget:
|
|
generated_sources.add(source_.target_name())
|
|
for out in source_.outputs:
|
|
sources.add(out)
|
|
elif type(source_) is impl.CustomTargetItem:
|
|
target = source_.target
|
|
generated_sources.add(target.target_name())
|
|
sources.add(target.outputs[source_.index])
|
|
|
|
def generate_sources_android(source_):
|
|
if type(source_) is impl.CustomTarget:
|
|
if source_.generates_h():
|
|
generated_headers.add(source_.target_name_h())
|
|
if source_.generates_c():
|
|
generated_sources.add(source_.target_name_c())
|
|
elif type(source_) is impl.CustomTargetItem:
|
|
source_ = source_.target
|
|
if source_.generates_h():
|
|
generated_headers.add(source_.target_name_h())
|
|
if source_.generates_c():
|
|
generated_sources.add(source_.target_name_c())
|
|
|
|
for source in input_sources:
|
|
if type(source) is list:
|
|
_get_sources(source, sources, generated_sources, generated_headers)
|
|
elif type(source) is impl.CustomTarget or type(source) is impl.CustomTargetItem:
|
|
if meson_translator.is_bazel():
|
|
generate_sources_fuchsia(source)
|
|
else: # is_soong
|
|
generate_sources_android(source)
|
|
elif type(source) is impl.File:
|
|
sources.add(source.name)
|
|
elif type(source) is str:
|
|
sources.add(impl.get_relative_dir(source))
|
|
else:
|
|
exit(f'source type not handled: {type(source)}')
|
|
|
|
|
|
# TODO(bpnguyen): Implement some bazel/soong parser that would merge
|
|
# logic from this function to _emit_builtin_target_android
|
|
def _emit_builtin_target_fuchsia(
|
|
target_name,
|
|
*source,
|
|
static=False,
|
|
c_args=[],
|
|
cpp_args=[],
|
|
dependencies=[],
|
|
include_directories=[],
|
|
link_with=[],
|
|
link_whole=[],
|
|
library_type=LibraryType.Library,
|
|
):
|
|
sl = StaticLibrary()
|
|
target_name_so = target_name
|
|
target_name = target_name if static else '_' + target_name
|
|
sl.name = target_name
|
|
sl.library_type = library_type
|
|
|
|
srcs = set()
|
|
generated_sources = set()
|
|
generated_headers = set()
|
|
generated_header_files = []
|
|
for source_arg in source:
|
|
assert type(source_arg) is list
|
|
_get_sources(source_arg, srcs, generated_sources, generated_headers)
|
|
|
|
deps = impl.get_set_of_deps(dependencies)
|
|
include_directories = impl.get_include_directories(include_directories)
|
|
static_libs = []
|
|
whole_static_libs = []
|
|
shared_libs = []
|
|
for dep in deps:
|
|
print(' dep: ' + dep.name)
|
|
for src in impl.get_linear_list([dep.sources]):
|
|
if type(src) is impl.CustomTargetItem:
|
|
generated_headers.add(src.target.target_name_h())
|
|
generated_header_files.extend(src.target.header_outputs())
|
|
elif type(src) is impl.CustomTarget:
|
|
generated_headers.add(src.target_name_h())
|
|
generated_header_files.extend(src.header_outputs())
|
|
else:
|
|
exit('Unhandled source dependency: ' + str(type(src)))
|
|
include_directories.extend(
|
|
impl.get_include_directories(dep.include_directories)
|
|
)
|
|
for target in impl.get_static_libs([dep.link_with]):
|
|
assert type(target) is impl.StaticLibrary
|
|
static_libs.append(target.target_name)
|
|
for target in impl.get_linear_list([dep.link_whole]):
|
|
assert type(target) is impl.StaticLibrary
|
|
whole_static_libs.append(target.target_name)
|
|
for target in dep.targets:
|
|
if target.target_type == impl.DependencyTargetType.SHARED_LIBRARY:
|
|
shared_libs.append(target.target_name)
|
|
elif target.target_type == impl.DependencyTargetType.STATIC_LIBRARY:
|
|
static_libs.append(target.target_name)
|
|
elif target.target_type == impl.DependencyTargetType.HEADER_LIBRARY:
|
|
exit('Header library not supported')
|
|
c_args.append(dep.compile_args)
|
|
cpp_args.append(dep.compile_args)
|
|
|
|
for target in impl.get_static_libs(link_with):
|
|
if type(target) is impl.StaticLibrary:
|
|
static_libs.append(target.target_name)
|
|
else:
|
|
exit('Unhandled link_with type: ' + str(type(target)))
|
|
|
|
for target in impl.get_whole_static_libs(link_whole):
|
|
if type(target) is impl.StaticLibrary:
|
|
whole_static_libs.append(target.target_name())
|
|
else:
|
|
exit('Unhandled link_whole type: ' + str(type(target)))
|
|
|
|
# Android turns all warnings into errors but thirdparty projects typically can't handle that
|
|
cflags = ['-Wno-error'] + impl.get_linear_list(impl.get_project_cflags() + c_args)
|
|
cppflags = ['-Wno-error'] + impl.get_linear_list(
|
|
impl.get_project_cppflags() + cpp_args
|
|
)
|
|
|
|
has_c_files = False
|
|
for src in srcs:
|
|
if src.endswith('.c'):
|
|
has_c_files = True
|
|
sl.srcs.append(src)
|
|
|
|
# For Bazel to find headers in the "current area", we have to include
|
|
# not just the headers in the relative dir, but also relative subdirs
|
|
# that aren't themselves areas (containing meson.build).
|
|
# We only look one level deep.
|
|
local_include_dirs = [impl.get_relative_dir()]
|
|
local_entries = (
|
|
[] if impl.get_relative_dir() == '' else os.listdir(impl.get_relative_dir())
|
|
)
|
|
for entry in local_entries:
|
|
entry = os.path.join(impl.get_relative_dir(), entry)
|
|
if os.path.isdir(entry):
|
|
subdir_entries = os.listdir(entry)
|
|
if 'meson.build' not in subdir_entries:
|
|
local_include_dirs.append(entry)
|
|
|
|
for hdr in set(generated_header_files):
|
|
sl.generated_headers.append(hdr)
|
|
for hdr in local_include_dirs:
|
|
sl.local_include_dirs.append(os.path.normpath(os.path.join(hdr, '*.h')))
|
|
# Needed for subdir sources
|
|
sl.copts.append(f'-I {impl.get_relative_dir()}')
|
|
sl.copts.append(f'-I $(GENDIR)/{impl.get_relative_dir()}')
|
|
for inc in include_directories:
|
|
for dir in inc.dirs:
|
|
sl.copts.append(f'-I {dir}')
|
|
sl.copts.append(f'-I $(GENDIR)/{dir}')
|
|
|
|
if has_c_files:
|
|
for arg in cflags:
|
|
# Double escape double quotations
|
|
arg = re.sub(r'"', '\\\\\\"', arg)
|
|
sl.copts.append(arg)
|
|
else:
|
|
for arg in cppflags:
|
|
# Double escape double quotations
|
|
arg = re.sub(r'"', '\\\\\\"', arg)
|
|
sl.copts.append(arg)
|
|
|
|
# Ensure bazel deps are unique
|
|
bazel_deps = set()
|
|
for lib in static_libs:
|
|
bazel_deps.add(lib)
|
|
for lib in whole_static_libs:
|
|
bazel_deps.add(lib)
|
|
for inc in include_directories:
|
|
bazel_deps.add(inc.name)
|
|
for target in generated_headers:
|
|
bazel_deps.add(target)
|
|
for target in generated_sources:
|
|
bazel_deps.add(target)
|
|
|
|
for bdep in bazel_deps:
|
|
sl.deps.append(bdep)
|
|
|
|
sl.target_compatible_with.append('@platforms//os:fuchsia')
|
|
sl.visibility.append('//visibility:public')
|
|
|
|
meson_translator.meson_state.static_libraries.append(sl)
|
|
|
|
if not static:
|
|
shared_sl = StaticLibrary()
|
|
shared_sl.library_type = LibraryType.LibraryShared
|
|
shared_sl.name = target_name_so
|
|
shared_sl.deps.append(target_name)
|
|
meson_translator.meson_state.static_libraries.append(shared_sl)
|
|
|
|
|
|
# TODO(bpnguyen): Implement some bazel/soong parser that would merge
|
|
# logic from this function to _emit_builtin_target_fuchsia
|
|
def _emit_builtin_target_android(
|
|
target_name,
|
|
*source,
|
|
c_args=[],
|
|
cpp_args=[],
|
|
dependencies=[],
|
|
include_directories=[],
|
|
link_with=[],
|
|
link_whole=[],
|
|
builtin_type_name='',
|
|
static=False,
|
|
library_type=LibraryType.Library,
|
|
):
|
|
static_lib = StaticLibrary()
|
|
static_lib.name = target_name
|
|
static_lib.library_type = library_type
|
|
|
|
srcs = set()
|
|
generated_sources = set()
|
|
generated_headers = set()
|
|
for source_arg in source:
|
|
assert type(source_arg) is list
|
|
_get_sources(source_arg, srcs, generated_sources, generated_headers)
|
|
|
|
deps = impl.get_set_of_deps(dependencies)
|
|
include_directories = [impl.get_relative_dir()] + impl.get_include_dirs(
|
|
include_directories
|
|
)
|
|
static_libs = []
|
|
whole_static_libs = []
|
|
shared_libs = []
|
|
header_libs = []
|
|
for dep in deps:
|
|
print(' dep: ' + dep.name)
|
|
for src in impl.get_linear_list([dep.sources]):
|
|
if type(src) is impl.CustomTargetItem:
|
|
generated_headers.add(src.target.target_name_h())
|
|
elif type(src) is impl.CustomTarget:
|
|
generated_headers.add(src.target_name_h())
|
|
else:
|
|
exit('Unhandled source dependency: ' + str(type(src)))
|
|
include_directories.extend(impl.get_include_dirs(dep.include_directories))
|
|
for target in impl.get_static_libs([dep.link_with]):
|
|
assert type(target) is impl.StaticLibrary
|
|
static_libs.append(target.target_name)
|
|
for target in impl.get_linear_list([dep.link_whole]):
|
|
assert type(target) is impl.StaticLibrary
|
|
whole_static_libs.append(target.target_name)
|
|
for target in dep.targets:
|
|
if target.target_type is impl.DependencyTargetType.SHARED_LIBRARY:
|
|
shared_libs.append(target.target_name)
|
|
elif target.target_type is impl.DependencyTargetType.STATIC_LIBRARY:
|
|
static_libs.append(target.target_name)
|
|
elif target.target_type is impl.DependencyTargetType.HEADER_LIBRARY:
|
|
header_libs.append(target.target_name)
|
|
c_args.append(dep.compile_args)
|
|
cpp_args.append(dep.compile_args)
|
|
|
|
for target in impl.get_static_libs(link_with):
|
|
if type(target) is impl.StaticLibrary:
|
|
static_libs.append(target.target_name)
|
|
else:
|
|
exit(f'Unhandled link_with type: {type(target)}')
|
|
|
|
for target in impl.get_whole_static_libs(link_whole):
|
|
if type(target) is impl.StaticLibrary:
|
|
whole_static_libs.append(target.target_name())
|
|
else:
|
|
exit(f'Unhandled link_whole type: {type(target)}')
|
|
|
|
# Android turns all warnings into errors but thirdparty projects typically can't handle that
|
|
cflags = ['-Wno-error'] + impl.get_linear_list(impl.get_project_cflags() + c_args)
|
|
cppflags = ['-Wno-error'] + impl.get_linear_list(
|
|
impl.get_project_cppflags() + cpp_args
|
|
)
|
|
|
|
for src in srcs:
|
|
# Filter out header files
|
|
if not src.endswith('.h'):
|
|
static_lib.srcs.append(src)
|
|
for generated in generated_headers:
|
|
static_lib.generated_headers.append(generated)
|
|
for generated in generated_sources:
|
|
static_lib.generated_sources.append(generated)
|
|
|
|
for arg in impl.get_project_options():
|
|
if arg.name == 'c_std':
|
|
static_lib.cstd = arg.value
|
|
elif arg.name == 'cpp_std':
|
|
static_lib.cpp_std = arg.value
|
|
|
|
for arg in cflags:
|
|
# Escape double quotations
|
|
arg = re.sub(r'"', '\\"', arg)
|
|
static_lib.conlyflags.append(arg)
|
|
for arg in cppflags:
|
|
# Escape double quotations
|
|
arg = re.sub(r'"', '\\"', arg)
|
|
static_lib.cppflags.append(arg)
|
|
|
|
for inc in include_directories:
|
|
static_lib.local_include_dirs.append(inc)
|
|
|
|
for lib in static_libs:
|
|
static_lib.static_libs.append(lib)
|
|
|
|
for lib in whole_static_libs:
|
|
static_lib.whole_static_libs.append(lib)
|
|
|
|
for lib in shared_libs:
|
|
static_lib.shared_libs.append(lib)
|
|
|
|
for lib in header_libs:
|
|
static_lib.header_libs.append(lib)
|
|
|
|
meson_translator.meson_state.static_libraries.append(static_lib)
|
|
|
|
|
|
def _emit_builtin_target(
|
|
target_name,
|
|
*source,
|
|
c_args=[],
|
|
cpp_args=[],
|
|
dependencies=[],
|
|
include_directories=[],
|
|
link_with=[],
|
|
link_whole=[],
|
|
builtin_type_name='',
|
|
static=False,
|
|
library_type=LibraryType.Library,
|
|
):
|
|
if meson_translator.is_bazel():
|
|
_emit_builtin_target_fuchsia(
|
|
target_name,
|
|
*source,
|
|
c_args=c_args,
|
|
cpp_args=cpp_args,
|
|
dependencies=dependencies,
|
|
include_directories=include_directories,
|
|
link_with=link_with,
|
|
link_whole=link_whole,
|
|
static=static,
|
|
library_type=library_type,
|
|
)
|
|
else: # meson_translator.is_soong()
|
|
_emit_builtin_target_android(
|
|
target_name,
|
|
*source,
|
|
c_args=c_args,
|
|
cpp_args=cpp_args,
|
|
dependencies=dependencies,
|
|
include_directories=include_directories,
|
|
link_with=link_with,
|
|
link_whole=link_whole,
|
|
builtin_type_name=builtin_type_name,
|
|
library_type=library_type,
|
|
)
|
|
|
|
|
|
def shared_library(
|
|
target_name,
|
|
*source,
|
|
c_args=[],
|
|
cpp_args=[],
|
|
c_pch='',
|
|
build_by_default=False,
|
|
build_rpath='',
|
|
d_debug=[],
|
|
d_import_dirs=[],
|
|
d_module_versions=[],
|
|
d_unittest=False,
|
|
darwin_versions='',
|
|
dependencies=[],
|
|
extra_files='',
|
|
gnu_symbol_visibility='',
|
|
gui_app=False,
|
|
implicit_include_directories=False,
|
|
include_directories=[],
|
|
install=False,
|
|
install_dir='',
|
|
install_mode=[],
|
|
install_rpath='',
|
|
install_tag='',
|
|
link_args=[],
|
|
link_depends=[],
|
|
link_language='',
|
|
link_whole=[],
|
|
link_with=[],
|
|
name_prefix='',
|
|
name_suffix='',
|
|
native=False,
|
|
objects=[],
|
|
override_options=[],
|
|
rust_abi='',
|
|
rust_crate_type='',
|
|
rust_dependency_map={},
|
|
sources=[],
|
|
soversion='',
|
|
vala_args=[],
|
|
version='',
|
|
vs_module_defs='',
|
|
win_subsystem='',
|
|
):
|
|
print('shared_library: ' + target_name)
|
|
|
|
link_with = impl.get_linear_list([link_with])
|
|
link_whole = impl.get_linear_list([link_whole])
|
|
|
|
_emit_builtin_target(
|
|
target_name,
|
|
*source,
|
|
c_args=c_args,
|
|
static=False,
|
|
cpp_args=cpp_args,
|
|
dependencies=dependencies,
|
|
include_directories=include_directories,
|
|
link_with=link_with,
|
|
link_whole=link_whole,
|
|
builtin_type_name='cc_library_shared',
|
|
library_type=LibraryType.LibraryStatic,
|
|
)
|
|
return impl.SharedLibrary(target_name)
|
|
|
|
|
|
def _process_target_name(name):
|
|
name = re.sub(r'[\[\]]', '', name)
|
|
return name
|
|
|
|
|
|
def _location_wrapper(name_or_list) -> str | list[str]:
|
|
if isinstance(name_or_list, list):
|
|
ret = []
|
|
for i in name_or_list:
|
|
ret.append(f'$(location {i})')
|
|
return ret
|
|
|
|
assert isinstance(name_or_list, str)
|
|
return f'$(location {name_or_list})'
|
|
|
|
|
|
def _is_header(name):
|
|
return re.search(r'\.h[xx|pp]?$', name) is not None
|
|
|
|
|
|
def _is_source(name):
|
|
return re.search(r'\.c[c|xx|pp]?$', name) is not None
|
|
|
|
|
|
def _get_command_args(
|
|
command,
|
|
input,
|
|
output,
|
|
deps,
|
|
location_wrap=False,
|
|
obfuscate_output_c=False,
|
|
obfuscate_output_h=False,
|
|
obfuscate_suffix='',
|
|
):
|
|
args = []
|
|
gendir = 'GENDIR' if meson_translator.is_bazel() else 'genDir'
|
|
for command_item in command[1:]:
|
|
if isinstance(command_item, list):
|
|
for item in command_item:
|
|
if type(item) is impl.File:
|
|
args.append(
|
|
_location_wrapper(item.name) if location_wrap else item.name
|
|
)
|
|
elif type(item) is str:
|
|
args.append(item)
|
|
continue
|
|
|
|
assert type(command_item) is str
|
|
match = re.match(r'@INPUT([0-9])?@', command_item)
|
|
if match is not None:
|
|
if match.group(1) is not None:
|
|
input_index = int(match.group(1))
|
|
input_list = impl.get_list_of_relative_inputs(input[input_index])
|
|
else:
|
|
input_list = impl.get_list_of_relative_inputs(input)
|
|
args.extend(_location_wrapper(input_list) if location_wrap else input_list)
|
|
continue
|
|
|
|
match = re.match(r'(.*?)@OUTPUT([0-9])?@', command_item)
|
|
if match is not None:
|
|
output_list = []
|
|
if match.group(2) is not None:
|
|
output_index = int(match.group(2))
|
|
selected_output = (
|
|
output[output_index] if isinstance(output, list) else output
|
|
)
|
|
output_list.append(impl.get_relative_gen_dir(selected_output))
|
|
elif isinstance(output, list):
|
|
for out in output:
|
|
output_list.append(impl.get_relative_gen_dir(out))
|
|
else:
|
|
output_list.append(impl.get_relative_gen_dir(output))
|
|
for out in output_list:
|
|
if _is_header(out) and obfuscate_output_h:
|
|
args.append(
|
|
match.group(1) + f'$({gendir})/{out}' if location_wrap else out
|
|
)
|
|
else:
|
|
if _is_source(out) and obfuscate_output_c:
|
|
out += obfuscate_suffix
|
|
args.append(
|
|
match.group(1) + _location_wrapper(out)
|
|
if location_wrap
|
|
else out
|
|
)
|
|
continue
|
|
|
|
# Assume used to locate generated outputs
|
|
match = re.match(r'(.*?)@CURRENT_BUILD_DIR@', command_item)
|
|
if match is not None:
|
|
args.append(f'$({gendir})' + '/' + impl.get_relative_dir())
|
|
continue
|
|
|
|
if meson_translator.is_bazel():
|
|
match = re.match(r'@PROJECT_BUILD_ROOT@(.*)', command_item)
|
|
if match is not None:
|
|
args.append(f'$({gendir}){match.group(1)}')
|
|
continue
|
|
|
|
# A plain arg
|
|
if ' ' in command_item:
|
|
args.append(f"'{command_item}'")
|
|
else:
|
|
args.append(command_item)
|
|
|
|
return args
|
|
|
|
|
|
def library(
|
|
target_name,
|
|
*sources,
|
|
c_args=[],
|
|
install=False,
|
|
link_args=[],
|
|
vs_module_defs='',
|
|
version='',
|
|
):
|
|
print('library: ' + target_name)
|
|
|
|
return static_library(
|
|
target_name,
|
|
*sources,
|
|
c_args=c_args,
|
|
install=install,
|
|
link_args=link_args,
|
|
sources=sources,
|
|
)
|
|
|
|
|
|
# Assume dependencies of custom targets are custom targets that are generating
|
|
# python scripts; build a python path of their locations.
|
|
def _get_python_path(deps):
|
|
python_path = ''
|
|
for index, dep in enumerate(deps):
|
|
assert type(dep) is impl.CustomTarget
|
|
if index > 0:
|
|
python_path += ':'
|
|
python_path += '`dirname %s`' % _location_wrapper(':%s' % dep.target_name())
|
|
return python_path
|
|
|
|
|
|
def _get_export_include_dirs():
|
|
dirs = [impl.get_relative_dir()]
|
|
# HACK for source files that expect that include generated files like:
|
|
# include "vulkan/runtime/...h"
|
|
if impl.get_relative_dir().startswith('src'):
|
|
dirs.append('src')
|
|
return dirs
|
|
|
|
|
|
def _process_wrapped_args_for_python(
|
|
wrapped_args, python_script, python_script_target_name, deps
|
|
):
|
|
# The python script arg should be replaced with the python binary target name
|
|
args = impl.replace_wrapped_input_with_target(
|
|
wrapped_args, python_script, python_script_target_name
|
|
)
|
|
if meson_translator.is_bazel():
|
|
return args
|
|
# else is_soong():
|
|
python_path = 'PYTHONPATH='
|
|
# Python scripts expect to be able to import other scripts from the same directory, but this
|
|
# doesn't work in the soong execution environment, so we have to explicitly add the script
|
|
# dir. We can't use $(location python_binary) because that is missing the relative path;
|
|
# instead we can use $(location python_script), which happens to work, and we're careful to
|
|
# ensure the script is in the list of sources even when it's used as the command directly.
|
|
python_path += '`dirname $(location %s)`' % python_script
|
|
# Also ensure that scripts generated by dependent custom targets can be imported.
|
|
if type(deps) is impl.CustomTarget:
|
|
python_path += ':' + _get_python_path([deps])
|
|
if type(deps) is list:
|
|
python_path += ':' + _get_python_path(deps)
|
|
args.insert(0, python_path)
|
|
return args
|
|
|
|
|
|
# TODO(bpnguyen): merge custom_target
|
|
def custom_target(
|
|
target_name: str,
|
|
build_always=False,
|
|
build_always_stale=False,
|
|
build_by_default=False,
|
|
capture=False,
|
|
command=[],
|
|
console=False,
|
|
depend_files=[],
|
|
depends=[],
|
|
depfile='',
|
|
env=[],
|
|
feed=False,
|
|
input=[],
|
|
install=False,
|
|
install_dir='',
|
|
install_mode=[],
|
|
install_tag=[],
|
|
output=[],
|
|
):
|
|
target_name = _process_target_name(target_name)
|
|
print('Custom target: ' + target_name)
|
|
assert type(command) is list
|
|
program = command[0]
|
|
program_args = []
|
|
|
|
# The program can be an array that includes arguments
|
|
if isinstance(program, list):
|
|
for arg in program[1:]:
|
|
assert type(arg) is str
|
|
program_args.append(arg)
|
|
program = program[0]
|
|
|
|
assert isinstance(program, impl.Program)
|
|
assert program.found()
|
|
|
|
args = program_args + _get_command_args(command, input, output, depends)
|
|
|
|
# Python scripts need special handling to find mako library
|
|
python_script = ''
|
|
python_script_target_name = ''
|
|
if program.command.endswith('.py'):
|
|
python_script = program.command
|
|
else:
|
|
for index, arg in enumerate(args):
|
|
if arg.endswith('.py'):
|
|
python_script = arg
|
|
break
|
|
if python_script != '':
|
|
python_script_target_name = target_name + '_' + os.path.basename(python_script)
|
|
srcs = [python_script] + impl.get_list_of_relative_inputs(depend_files)
|
|
python_custom_target = PythonCustomTarget()
|
|
python_custom_target.name = python_script_target_name
|
|
python_custom_target.main = python_script
|
|
for src in set(srcs):
|
|
if src.endswith('.py'):
|
|
python_custom_target.srcs.append(src)
|
|
for src in set(srcs):
|
|
if src.endswith('.py'):
|
|
python_custom_target.imports.append(os.path.dirname(src))
|
|
|
|
meson_translator.meson_state.custom_py_targets.append(python_custom_target)
|
|
|
|
relative_inputs = impl.get_list_of_relative_inputs(input)
|
|
# We use python_host_binary instead of calling python scripts directly;
|
|
# however there's an issue with python locating modules in the same directory
|
|
# as the script; to workaround that (see _process_wrapped_args_for_python) we
|
|
# ensure the script is listed in the genrule targets.
|
|
if python_script != '' and python_script not in relative_inputs:
|
|
relative_inputs.append(python_script)
|
|
relative_inputs.extend(impl.get_list_of_relative_inputs(depend_files))
|
|
|
|
relative_inputs_set = set()
|
|
if meson_translator.is_soong():
|
|
for src in relative_inputs:
|
|
relative_inputs_set.add(src)
|
|
|
|
relative_outputs = []
|
|
if isinstance(output, list):
|
|
for file in output:
|
|
relative_outputs.append(impl.get_relative_gen_dir(file))
|
|
else:
|
|
assert type(output) is str
|
|
relative_outputs.append(impl.get_relative_gen_dir(output))
|
|
|
|
generates_h = False
|
|
generates_c = False
|
|
custom_target_ = None
|
|
if meson_translator.is_soong():
|
|
# Soong requires genrule to generate only headers OR non-headers
|
|
for out in relative_outputs:
|
|
if _is_header(out):
|
|
generates_h = True
|
|
if _is_source(out):
|
|
generates_c = True
|
|
custom_target_ = impl.CustomTarget(
|
|
target_name, relative_outputs, generates_h, generates_c
|
|
)
|
|
else: # is_bazel:
|
|
custom_target_ = impl.CustomTarget(target_name, relative_outputs)
|
|
|
|
program_command = program.command
|
|
if meson_translator.is_soong():
|
|
if program_command == 'bison':
|
|
program_command_arg = 'M4=$(location m4) $(location bison)'
|
|
elif program_command == 'flex':
|
|
program_command_arg = 'M4=$(location m4) $(location flex)'
|
|
elif program_command.endswith('.py'):
|
|
program_command_arg = _location_wrapper(program_command)
|
|
else:
|
|
program_command_arg = program_command
|
|
|
|
program_args = [program_command_arg] + program_args
|
|
|
|
if custom_target_.generates_h() and custom_target_.generates_c():
|
|
# Make a rule for only the headers
|
|
obfuscate_suffix = '.dummy.h'
|
|
wrapped_args = program_args + _get_command_args(
|
|
command,
|
|
input,
|
|
output,
|
|
depends,
|
|
location_wrap=True,
|
|
obfuscate_output_c=True,
|
|
obfuscate_suffix=obfuscate_suffix,
|
|
)
|
|
if python_script:
|
|
wrapped_args = _process_wrapped_args_for_python(
|
|
wrapped_args, python_script, python_script_target_name, depends
|
|
)
|
|
|
|
command_line = impl.get_command_line_from_args(wrapped_args)
|
|
if capture:
|
|
command_line += ' > %s' % _location_wrapper(
|
|
impl.get_relative_gen_dir(output)
|
|
)
|
|
ct = CustomTarget()
|
|
ct.name = custom_target_.target_name_h()
|
|
for src in relative_inputs_set:
|
|
ct.srcs.append(src)
|
|
for dep in depends:
|
|
assert type(dep) is impl.CustomTarget
|
|
ct.srcs.append(':' + dep.target_name())
|
|
for out in relative_outputs:
|
|
if _is_source(out):
|
|
out += obfuscate_suffix
|
|
# The scripts may still write to the assumed .c file, ensure the obfuscated
|
|
# file exists
|
|
command_line += (
|
|
"; echo '//nothing to see here' > " + _location_wrapper(out)
|
|
)
|
|
ct.out.append(out)
|
|
if python_script_target_name != '':
|
|
ct.tools.append(python_script_target_name)
|
|
|
|
if program_command == 'bison' or program_command == 'flex':
|
|
ct.tools.append('m4')
|
|
ct.tools.append(program_command)
|
|
|
|
for dir in _get_export_include_dirs():
|
|
ct.export_include_dirs.append(dir)
|
|
|
|
ct.cmd = command_line
|
|
meson_translator.meson_state.custom_targets.append(ct)
|
|
# Make a rule for only the sources
|
|
obfuscate_suffix = '.dummy.c'
|
|
wrapped_args = program_args + _get_command_args(
|
|
command,
|
|
input,
|
|
output,
|
|
depends,
|
|
location_wrap=True,
|
|
obfuscate_output_h=True,
|
|
obfuscate_suffix=obfuscate_suffix,
|
|
)
|
|
if python_script:
|
|
wrapped_args = _process_wrapped_args_for_python(
|
|
wrapped_args, python_script, python_script_target_name, depends
|
|
)
|
|
|
|
command_line = impl.get_command_line_from_args(wrapped_args)
|
|
if capture:
|
|
command_line += ' > %s' % _location_wrapper(
|
|
impl.get_relative_gen_dir(output)
|
|
)
|
|
|
|
# We keep the header as an output with an obfuscated name because some scripts insist
|
|
# on having --out-h (like vk_entrypoints_gen.py). When Soong depends on this genrule
|
|
# it'll insist on compiling all the outputs, so we replace the content of all header
|
|
# outputs.
|
|
ct_ = CustomTarget()
|
|
ct_.name = custom_target_.target_name_c()
|
|
|
|
for src in relative_inputs_set:
|
|
ct_.srcs.append(src)
|
|
for dep in depends:
|
|
assert type(dep) is impl.CustomTarget
|
|
ct_.srcs.append(':' + dep.target_name())
|
|
for out in relative_outputs:
|
|
if _is_header(out):
|
|
out += obfuscate_suffix
|
|
ct_.out.append(out)
|
|
# Remove the content because Soong will compile this dummy source file
|
|
command_line += (
|
|
"; echo '//nothing to see here' > " + _location_wrapper(out)
|
|
)
|
|
ct_.out.append(out)
|
|
if python_script_target_name != '':
|
|
ct_.tools.append(python_script_target_name)
|
|
if program_command == 'bison' or program_command == 'flex':
|
|
ct.tools.append('m4')
|
|
ct.tools.append(program_command)
|
|
ct_.cmd = command_line
|
|
meson_translator.meson_state.custom_targets.append(ct_)
|
|
return custom_target_
|
|
else:
|
|
wrapped_args = program_args + _get_command_args(
|
|
command, input, output, depends, location_wrap=True
|
|
)
|
|
if python_script:
|
|
wrapped_args = _process_wrapped_args_for_python(
|
|
wrapped_args, python_script, python_script_target_name, depends
|
|
)
|
|
|
|
command_line = impl.get_command_line_from_args(wrapped_args)
|
|
if capture:
|
|
command_line += ' > %s' % _location_wrapper(
|
|
impl.get_relative_gen_dir(output)
|
|
)
|
|
ct = CustomTarget()
|
|
ct.name = custom_target_.target_name()
|
|
for src in relative_inputs_set:
|
|
ct.srcs.append(src)
|
|
for dep in depends:
|
|
assert type(dep) is impl.CustomTarget
|
|
ct.srcs.append(':' + dep.target_name())
|
|
for out in relative_outputs:
|
|
ct.out.append(out)
|
|
if python_script_target_name != '':
|
|
ct.tools.append(python_script_target_name)
|
|
if program_command == 'bison' or program_command == 'flex':
|
|
ct.tools.append('m4')
|
|
ct.tools.append(program_command)
|
|
for dir_ in _get_export_include_dirs():
|
|
ct.export_include_dirs.append(dir_)
|
|
ct.cmd = command_line
|
|
meson_translator.meson_state.custom_targets.append(ct)
|
|
else: # is_bazel
|
|
if program_command.endswith('.py'):
|
|
program_command_arg = _location_wrapper(program_command)
|
|
else:
|
|
program_command_arg = program_command
|
|
|
|
program_args = [program_command_arg] + program_args
|
|
|
|
wrapped_args = program_args + _get_command_args(
|
|
command, input, output, depends, location_wrap=True
|
|
)
|
|
if python_script:
|
|
wrapped_args = _process_wrapped_args_for_python(
|
|
wrapped_args, python_script, python_script_target_name, depends
|
|
)
|
|
|
|
command_line = impl.get_command_line_from_args(wrapped_args)
|
|
if capture:
|
|
command_line += ' > %s' % _location_wrapper(
|
|
impl.get_relative_gen_dir(output)
|
|
)
|
|
|
|
ct = CustomTarget()
|
|
ct.name = custom_target_.target_name()
|
|
for src in set(relative_inputs):
|
|
ct.srcs.append(src)
|
|
for dep in depends:
|
|
assert type(dep) is impl.CustomTarget
|
|
ct.srcs.append(dep.target_name())
|
|
for out in set(relative_outputs):
|
|
ct.out.append(out)
|
|
if python_script_target_name != '':
|
|
ct.tools.append(python_script_target_name)
|
|
ct.cmd = command_line
|
|
meson_translator.meson_state.custom_targets.append(ct)
|
|
|
|
return custom_target_
|