Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/markdown/snippets/embed_directories.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
## BuildTarget now has an `embed_directories` keyword argument

This provides an include_directories like path for the c23 and c++26 `#embed`
preprocessor directive.
8 changes: 8 additions & 0 deletions docs/yaml/functions/_build_target_base.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,14 @@ kwargs:

These may only be static sources.

embed_directories:
type: array[inc | str]
since: 1.13.0
description: |
one or more objects created with the [[include_directories]] function, or
strings, which will be implicitly convert to [[@inc]] objects, that is
used for the #embed preprocessor directive.

gui_app:
type: bool
deprecated: 0.56.0
Expand Down
6 changes: 6 additions & 0 deletions mesonbuild/backend/ninjabackend.py
Original file line number Diff line number Diff line change
Expand Up @@ -3181,6 +3181,12 @@ def _generate_single_compile_target_args(self, target: build.BuildTarget, compil
commands += bargs
for d in i.extra_build_dirs:
commands += compiler.get_include_args(d, i.is_system)

# Add any embed search dir arguments
for i in target.embed_dirs:
for incdir in i.rel_string_list(self.build_to_src, self.build_dir):
commands.extend(compiler.get_embed_args(incdir))

# Add per-target compile args, f.ex, `c_args : ['-DFOO']`. We set these
# near the end since these are supposed to override everything else.
commands += self.escape_extra_args(target.get_extra_args(compiler.get_language()))
Expand Down
4 changes: 4 additions & 0 deletions mesonbuild/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ class BuildTargetKeywordArguments(TypedDict, total=False):
d_unittest: bool
dependencies: T.List[dependencies.Dependency]
depend_files: T.List[File]
embed_directories: list[IncludeDirs]
extra_files: T.List[File]
gnu_symbol_visibility: Literal['default', 'internal', 'hidden', 'protected', 'inlineshidden', '']
implicit_include_directories: bool
Expand Down Expand Up @@ -841,6 +842,8 @@ def __init__(
self.structured_sources = structured_sources
self.external_deps: T.List[dependencies.Dependency] = []
self.include_dirs: T.List['IncludeDirs'] = []
# Use .get for embed_dirs because this is inherited in Java, which doesn't have embed_directories
self.embed_dirs = kwargs.get('embed_directories', []).copy()
self.link_language: T.Optional[Language] = kwargs.get('link_language')
self.link_targets: T.List[LinkableTargetTypes] = []
self.link_whole_targets: T.List[StaticTargetTypes] = []
Expand Down Expand Up @@ -1565,6 +1568,7 @@ def add_deps(self, deps: T.List[dependencies.Dependency]) -> None:
self.process_sourcelist(dep.sources)
self.extra_files.extend(f for f in dep.extra_files if f not in self.extra_files)
self.add_include_dirs(dep.get_include_dirs())
self.embed_dirs.extend(dep.embed_directories)
self.objects.extend(dep.objects)
self.link_targets.extend(dep.libraries)
self.link_whole_targets.extend(dep.whole_libraries)
Expand Down
4 changes: 4 additions & 0 deletions mesonbuild/compilers/c.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,10 @@ def get_option_link_args(self, target: 'BuildTarget', subproject: T.Optional[str
def get_pch_use_args(self, pch_dir: str, header: str) -> T.List[str]:
return ['-fpch-preprocess', '-include', os.path.basename(header)]

def get_embed_args(self, path: str) -> list[str]:
# Requires C23 or C++26 standard and GCC 15
return [f'--embed-dir={path}']


class PGICCompiler(PGICompiler, CCompiler):
def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice,
Expand Down
4 changes: 4 additions & 0 deletions mesonbuild/compilers/compilers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1717,3 +1717,7 @@ def get_target_libdir(self) -> str:
def get_show_dep_args(self) -> T.List[str]:
"""Arguments for printing depfile information in MSVC compatible format"""
return []

def get_embed_args(self, path: str) -> list[str]:
"""Format arguments for C and C++ #embed statements."""
raise EnvironmentException(f'{self.get_id()} does not support embed search paths')
4 changes: 4 additions & 0 deletions mesonbuild/compilers/cpp.py
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,10 @@ def get_pch_use_args(self, pch_dir: str, header: str) -> T.List[str]:
def get_cpp_modules_args(self) -> T.List[str]:
return ['-fmodules', '-fmodules-ts']

def get_embed_args(self, path: str) -> list[str]:
# Requires C23 or C++26 standard and GCC 15
return [f'--embed-dir={path}']


class PGICPPCompiler(PGICompiler, CPPCompiler):
def __init__(self, ccache: T.List[str], exelist: T.List[str], version: str, for_machine: MachineChoice,
Expand Down
5 changes: 5 additions & 0 deletions mesonbuild/compilers/mixins/clang.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,11 @@ def get_lto_link_args(self, *, target: T.Optional[BuildTarget] = None, threads:
args.append(f'-flto-jobs={threads}')
return args

def get_embed_args(self, path: str) -> list[str]:
# Requires C23 or C++26 standard and Clang 19
# Is not currently supported by AppleClang
return [f'--embed-dir={path}']


class ClangCStds(CompilerMixinBase):

Expand Down
5 changes: 4 additions & 1 deletion mesonbuild/dependencies/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@ class InternalDependency(Dependency):
type_name = DependencyTypeName('internal')

def __init__(self, version: str, incdirs: T.Optional[T.List['IncludeDirs']] = None,
embed_dirs: list[IncludeDirs] | None = None,
compile_args: T.Optional[T.List[str]] = None,
link_args: T.Optional[T.List[str]] = None,
libraries: T.Optional[T.List[LinkableTargetTypes]] = None,
Expand All @@ -322,6 +323,7 @@ def __init__(self, version: str, incdirs: T.Optional[T.List['IncludeDirs']] = No
self.version = version
self.is_found = True
self.include_directories = incdirs or []
self.embed_directories = embed_dirs or []
self.compile_args = compile_args or []
self.link_args = link_args or []
self.libraries = libraries or []
Expand Down Expand Up @@ -372,11 +374,12 @@ def get_partial_dependency(self, *, compile_args: bool = False,
final_sources = self.sources.copy() if sources else []
final_extra_files = self.extra_files.copy() if extra_files else []
final_includes = self.get_include_dirs().copy() if includes else []
final_embed = self.embed_directories.copy() if includes else []
final_deps = [d.get_partial_dependency(
compile_args=compile_args, link_args=link_args, links=links,
includes=includes, sources=sources) for d in self.ext_deps]
return type(self)(
self.version, final_includes, final_compile_args,
self.version, final_includes, final_embed, final_compile_args,
final_link_args, final_libraries, final_whole_libraries,
final_sources, final_extra_files, final_deps, self.variables, [], [], [], self.name)

Expand Down
6 changes: 5 additions & 1 deletion mesonbuild/interpreter/interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
ENV_KW,
ENV_METHOD_KW,
ENV_SEPARATOR_KW,
EMBED_DIRECTORIES,
INCLUDE_DIRECTORIES,
INSTALL_KW,
INSTALL_DIR_KW,
Expand Down Expand Up @@ -727,6 +728,7 @@ def func_files(self, node: mparser.FunctionNode, args: T.Tuple[T.List[str]], kwa
KwargInfo('compile_args', ContainerTypeInfo(list, str), listify=True, default=[]),
INCLUDE_DIRECTORIES.evolve(name='d_import_dirs', since='0.62.0'),
D_MODULE_VERSIONS_KW.evolve(since='0.62.0'),
EMBED_DIRECTORIES,
LINK_ARGS_KW,
DEPENDENCIES_KW,
INCLUDE_DIRECTORIES.evolve(since_values={ContainerTypeInfo(list, str): '0.50.0'}),
Expand All @@ -742,6 +744,7 @@ def func_declare_dependency(self, node: mparser.BaseNode, args: T.List[TYPE_var]
kwargs: kwtypes.FuncDeclareDependency) -> dependencies.Dependency:
deps = kwargs['dependencies']
incs = self.extract_incdirs(kwargs['include_directories'])
embed_directories = self.extract_incdirs(kwargs['embed_directories'])
libs = kwargs['link_with']
libs_whole = kwargs['link_whole']
objects = kwargs['objects']
Expand All @@ -768,7 +771,7 @@ def func_declare_dependency(self, node: mparser.BaseNode, args: T.List[TYPE_var]
and os.path.isdir(v):
variables[k] = P_OBJ.DependencyVariableString(v)

dep = dependencies.InternalDependency(version, incs, compile_args,
dep = dependencies.InternalDependency(version, incs, embed_directories, compile_args,
link_args, libs, libs_whole, sources, extra_files,
deps, variables, d_module_versions, d_import_dirs,
objects)
Expand Down Expand Up @@ -3690,6 +3693,7 @@ def __convert_build_target_base_kwargs(self, kwargs: kwtypes.BuildTarget, final:

# Convert into IncludeDirs objects
final['include_directories'] = self.extract_incdirs(kwargs['include_directories'])
final['embed_directories'] = self.extract_incdirs(kwargs['embed_directories'])
final['d_import_dirs'] = self.extract_incdirs(kwargs['d_import_dirs'], True)

# Convert language arguments
Expand Down
2 changes: 2 additions & 0 deletions mesonbuild/interpreter/kwargs.py
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,7 @@ class BuildTarget(BaseBuildTarget):
d_import_dirs: T.List[T.Union[str, build.IncludeDirs]]
d_module_versions: T.List[T.Union[str, int]]
d_unittest: bool
embed_directories: list[str | build.IncludeDirs]
install_dir: T.List[T.Union[str, bool]]
install_vala_header: T.Union[str, bool, None]
install_vala_vapi: T.Union[str, bool, None]
Expand Down Expand Up @@ -540,6 +541,7 @@ class FuncDeclareDependency(TypedDict):
d_import_dirs: T.List[T.Union[build.IncludeDirs, str]]
d_module_versions: T.List[T.Union[str, int]]
dependencies: T.List[Dependency]
embed_directories: list[str | build.IncludeDirs]
extra_files: T.List[FileOrString]
include_directories: T.List[T.Union[build.IncludeDirs, str]]
link_args: T.List[str]
Expand Down
6 changes: 6 additions & 0 deletions mesonbuild/interpreter/type_checking.py
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,11 @@ def _local_program_convertor(raw: T.List[T.Union[str, File, BuildTarget, Generat
default=[],
)

EMBED_DIRECTORIES = INCLUDE_DIRECTORIES.evolve(
name='embed_directories',
since='1.13.0',
)

def _default_options_convertor(raw: T.Union[str, T.List[str], T.Dict[str, ElementaryOptionValues]]) -> T.Dict[OptionKey, ElementaryOptionValues]:
d = _override_options_convertor(raw)
return {OptionKey.from_string(k): v for k, v in d.items()}
Expand Down Expand Up @@ -800,6 +805,7 @@ def _pch_convertor(args: T.List[str]) -> T.Optional[T.Tuple[str, T.Optional[str]
*_LANGUAGE_KWS,
BT_SOURCES_KW,
INCLUDE_DIRECTORIES.evolve(name='d_import_dirs'),
EMBED_DIRECTORIES,
LINK_ARGS_KW,
LINK_WHOLE_KW.evolve(
since='0.40.0',
Expand Down
2 changes: 1 addition & 1 deletion mesonbuild/modules/external_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ def dependency_method(self, state: 'ModuleState', args: T.Tuple[str], kwargs: 'D
compile_args = [f'-I{abs_includedir}']
link_args = [f'-L{abs_libdir}', f'-l{libname}']
sources = self.target
dep = InternalDependency(version, [], compile_args, link_args, [],
dep = InternalDependency(version, [], [], compile_args, link_args, [],
[], [sources], [], [], {}, [], [], [])
return dep

Expand Down
2 changes: 1 addition & 1 deletion mesonbuild/modules/gnome.py
Original file line number Diff line number Diff line change
Expand Up @@ -2333,7 +2333,7 @@ def generate_vapi(self, state: 'ModuleState', args: T.Tuple[str], kwargs: 'Gener
incs = [build.IncludeDirs(state.subdir, ['.'] + vapi_includes, False,
state.current_build_project)]
sources = [vapi_target] + vapi_depends
rv = InternalDependency(None, incs, [], [], link_with, [], sources, [], [], {}, [], [], [])
rv = InternalDependency(None, incs, [], [], [], link_with, [], sources, [], [], {}, [], [], [])
created_values.append(rv)
return ModuleReturnValue(rv, created_values)

Expand Down
35 changes: 35 additions & 0 deletions test cases/common/302 embed dirs/c/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright © 2026 Intel Corporation
*/

#include <stdio.h>

const char msg[] =
{
#embed "data.txt"
};

const char expected[] = {
'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', '\n',
};


int main(void) {
const int num_found = sizeof(msg) / sizeof(msg[0]);
const int num_expected = sizeof(expected) / sizeof(expected[0]);

if (num_found != num_expected) {
fprintf(stderr, "The number of found arguments (%d) does not match the expected(%d)\n", num_found, num_expected);
return 1;
}

for (unsigned i = 0; i < num_found; ++i) {
if (msg[i] != expected[i]) {
fprintf(stderr, "The items at index %d does not match: found: %c, expected: %c\n", i, msg[i], expected[i]);
return 1;
}
}

return 0;
}
39 changes: 39 additions & 0 deletions test cases/common/302 embed dirs/c/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright © 2026 Intel Corporation

if not add_languages('c', required : false, native : false)
debug('No C language support')
subdir_done()
endif

cc = meson.get_compiler('c')
if cc.get_id() == 'gcc'
if cc.version().version_compare('< 15')
debug('Skipping C test due to GCC being older than 15, and lacking support for #embed')
subdir_done()
endif
elif cc.get_id() == 'clang'
if cc.version().version_compare('< 19')
debug('Skipping C test due to Clang being older than 19, and lacking support for #embed')
subdir_done()
endif
else
debug('Skipping C test due to compiler @0@, which is not known to support #embed'.format(cc.get_id()))
subdir_done()
endif

exe = executable(
'c_prog',
'main.c',
embed_directories : embed_dir,
)

test('C embed', exe)

exe = executable(
'c_with_dep',
'main.c',
dependencies : dep,
)

test('From dependency object', exe)
35 changes: 35 additions & 0 deletions test cases/common/302 embed dirs/cpp/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright © 2026 Intel Corporation
*/

#include <iostream>

constexpr char msg[] =
{
#embed "data.txt"
};

constexpr char expected[] = {
'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!', '\n',
};


int main(void) {
constexpr int num_found = sizeof(msg) / sizeof(msg[0]);
constexpr int num_expected = sizeof(expected) / sizeof(expected[0]);

if (num_found != num_expected) {
std::cerr << "The number of found arguments (" << num_found << ") does not match the expected (" << num_expected << ")\n";
return 1;
}

for (unsigned i = 0; i < num_found; ++i) {
if (msg[i] != expected[i]) {
std::cerr << "The items at index " << i << "does not match: found: " << msg[i] << "expected: " << expected[i] << "\n";
return 1;
}
}

return 0;
}
31 changes: 31 additions & 0 deletions test cases/common/302 embed dirs/cpp/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright © 2026 Intel Corporation

if not add_languages('cpp', required : false, native : false)
debug('No C++ support')
subdir_done()
endif

cpp = meson.get_compiler('cpp')
if cpp.get_id() == 'gcc'
if cpp.version().version_compare('< 15')
debug('Skipping C++ test due to G++ being older than 15, and lacking support for #embed')
subdir_done()
endif
elif cpp.get_id() == 'clang'
if cpp.version().version_compare('< 19')
debug('Skipping C++ test due to Clang++ being older than 19, and lacking support for #embed')
subdir_done()
endif
else
debug('Skipping C++ test due to compiler @0@, which is not known to support #embed'.format(cpp.get_id()))
subdir_done()
endif

exe = executable(
'cpp_prog',
'main.cpp',
embed_directories : '../embed',
)

test('C++ embed', exe)
1 change: 1 addition & 0 deletions test cases/common/302 embed dirs/embed/data.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Hello, World!
17 changes: 17 additions & 0 deletions test cases/common/302 embed dirs/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# SPDX-License-Identifier: Apache-2.0
# Copyright © 2026 Intel Corporation

project(
'embed dirs',
meson_version : '>= 1.13.0',
default_options : {'c_std' : 'c23', 'cpp_std' : 'c++26'},
)

embed_dir = include_directories('embed')

dep = declare_dependency(
embed_directories : ['embed'],
)

subdir('c')
subdir('cpp')

This file was deleted.

This file was deleted.

This file was deleted.

Loading