Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor option getting v2 #13441

Open
wants to merge 104 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
104 commits
Select commit Hold shift + click to select a range
569536a
Refactor getting target options to a dedicated method.
jpakkane Apr 14, 2024
7f8ba9b
Move option querying to coredata so it can be shared.
jpakkane Apr 20, 2024
a8fa34c
Refactor code to use per-target option methods.
jpakkane Apr 20, 2024
d2a3f91
Convert more usages to per-target methods.
jpakkane Apr 20, 2024
39c4129
Convert more usages to per-target methods.
jpakkane Apr 22, 2024
bd96bfb
Convert more usages to per-target methods.
jpakkane Apr 23, 2024
6045f22
Convert more usages to per-target methods.
jpakkane Apr 24, 2024
d176894
Convert more usages to per-target methods.
jpakkane Apr 25, 2024
32a7b6d
Refactor getting option value to its own method.
jpakkane Apr 26, 2024
3b693ad
Refactor option overriding code.
jpakkane Apr 28, 2024
c1fc3e4
Fix std lookup in subprojects.
jpakkane Apr 28, 2024
84ce0f9
Can specify per-subproject options from the command line.
jpakkane Apr 9, 2024
cdf8b2e
Add enough override functionality to pass override unit tests.
jpakkane May 6, 2024
e9257c2
Update tests and find new roadblock.
jpakkane May 7, 2024
1d1a5fd
Pass original strings to setter method.
jpakkane May 15, 2024
2a8ba99
Rebasing fix.
jpakkane May 19, 2024
21586c0
Persp override test works. Other tests do not.
jpakkane May 20, 2024
4cd8d9e
Start working on an option store class.
jpakkane May 24, 2024
fe34853
Write more tests.
jpakkane May 24, 2024
8d5b189
Implement augments in OptionStore.
jpakkane May 24, 2024
a7ce0e6
Add some more tests and functionality to OptionStore.
jpakkane May 25, 2024
ca35970
Hook up new option store to the old code. Can compile simple projects.
jpakkane May 26, 2024
2e3382a
Preserve default options in the original string form.
jpakkane May 28, 2024
8dca103
Fix things, 73 failing common tests remaining.
jpakkane May 28, 2024
551211e
Fix all visible tracebacks from accessing coredata.options for common…
jpakkane May 29, 2024
ed65bac
Preserve command line options as strings all the way until OptionStore.
jpakkane May 30, 2024
486b2ac
Fix option object usage.
jpakkane May 31, 2024
9cddcad
Fix more option code paths.
jpakkane May 31, 2024
dfd1406
More option fixes.
jpakkane May 31, 2024
ff4ed1d
More option fixing.
jpakkane Jun 1, 2024
efbdd74
Fix configure command enough to print values and augments.
jpakkane Jun 2, 2024
2e21f8a
Start getting option data from optstore.
jpakkane Jun 2, 2024
b15ccb1
Keep the new optionstore around.
jpakkane Jun 4, 2024
3213b5d
Fix a few more files.
jpakkane Jun 4, 2024
0e63815
Fix some options.
jpakkane Jun 5, 2024
ce772b5
Fix errors of mega rebase enough to compile trivial test project.
jpakkane Jul 19, 2024
1cc1a1e
More fixes.
jpakkane Jul 19, 2024
95426e0
Fix option unit tests. But break everything else.
jpakkane Jul 20, 2024
45eb7c2
Fix a bunch of failing common project tests.
jpakkane Jul 21, 2024
137c9b4
Always initialize compilers in the same order.
jpakkane Jul 22, 2024
e069a11
Fix CMake project tests.
jpakkane Jul 23, 2024
8aee56d
Fix pending options.
jpakkane Jul 23, 2024
00668ce
Fix options in project() call.
jpakkane Jul 28, 2024
24aeb65
Use set_value method rather than poking the dict directly.
jpakkane Jul 28, 2024
a92a602
Move deprecation handling in OptionStore.
jpakkane Jul 28, 2024
fd010ef
Fix options so that all common tests now pass.
jpakkane Jul 28, 2024
a05481d
Temporary fix for failing test.
jpakkane Jul 30, 2024
7b04d91
Made build options fall back to regular ones when not cross compiling.
jpakkane Jul 31, 2024
1443791
Fix project tests.
jpakkane Jul 31, 2024
3f6d7cb
Fix some unit tests.
jpakkane Aug 1, 2024
5d4c834
Fix unit tests.
jpakkane Aug 1, 2024
0e66574
Fix unit tests.
jpakkane Aug 2, 2024
9c3bb68
Fix unit tests.
jpakkane Aug 4, 2024
070c19e
Fix unit tests.
jpakkane Aug 5, 2024
090ce81
Fix unit tests.
jpakkane Aug 7, 2024
b69d95f
Convert named options to corresponding -D options.
jpakkane Aug 7, 2024
a7f4186
Fix unit tests.
jpakkane Aug 7, 2024
60734d0
Fix unit tests.
jpakkane Aug 8, 2024
7beadc1
Fix unit tests.
jpakkane Aug 9, 2024
caf5947
Fix unit tests.
jpakkane Aug 9, 2024
4157e87
Fix unit tests.
jpakkane Aug 10, 2024
0050d68
Fix unit tests.
jpakkane Aug 10, 2024
745ad65
Fix unit tests.
jpakkane Aug 11, 2024
6e0e998
Fewer than 20 failing unit tests remaining.
jpakkane Aug 11, 2024
a5d1dc1
Fix unit tests.
jpakkane Aug 12, 2024
db4a992
Fix unit tests.
jpakkane Aug 12, 2024
f5e4476
Disable test that is no longer meaningful.
jpakkane Aug 13, 2024
61ca065
Handle machine type correctly.
jpakkane Aug 13, 2024
94aabdf
Fix initializing prefix dependent options.
jpakkane Aug 13, 2024
cdff21d
Fix a few unit tests and more fail than before.
jpakkane Aug 15, 2024
7e5e1b0
Fix unit tests.
jpakkane Aug 16, 2024
27acdca
Use OptionKey instead of strings.
jpakkane Aug 16, 2024
df00872
Add per-subproject options in machine files to augments.
jpakkane Aug 17, 2024
ba346ed
Disable and alter some failing tests.
jpakkane Aug 18, 2024
3d862fc
ALL TESTS PASS! On this machine.
jpakkane Aug 18, 2024
91a4eca
Fix some failing CI tests.
jpakkane Aug 19, 2024
35cad78
Vala fix.
jpakkane Aug 19, 2024
82ce69e
Fix some Clang tests.
jpakkane Aug 19, 2024
79aa83c
Fix VS code.
jpakkane Aug 19, 2024
46753dc
Fix the VS backend a bit.
jpakkane Aug 19, 2024
5c02f72
Fix Objective C/C++.
jpakkane Aug 21, 2024
eb855f1
Fix some Windows issues.
jpakkane Aug 22, 2024
49ee948
Fix unity issues.
jpakkane Aug 23, 2024
498e7f7
Fix Cuda options.
jpakkane Aug 23, 2024
aa91c02
Fix Windows things.
jpakkane Aug 23, 2024
7c523e6
Fix Mac bitcode warning.
jpakkane Aug 23, 2024
2aae29a
Fix vslite generation.
jpakkane Aug 24, 2024
128bf39
Windows fixes.
jpakkane Aug 24, 2024
fab5a01
Fix cross compilation.
jpakkane Aug 25, 2024
25b1005
Fortran fixes.
jpakkane Aug 26, 2024
2002cdb
Set debug and opt based on buildtype changes.
jpakkane Aug 26, 2024
4c481c4
Fix typing.
jpakkane Aug 27, 2024
8caafa4
Fix annotations for C compilers.
jpakkane Aug 27, 2024
6ab4d31
Fix annotations for C++ compilers.
jpakkane Aug 27, 2024
b011005
Add more annotations.
jpakkane Aug 27, 2024
2613d7c
Add more annotations.
jpakkane Aug 27, 2024
34fe03d
Add more annotations.
jpakkane Aug 27, 2024
8211f75
Fix annotations.
jpakkane Aug 28, 2024
cd64e53
Fix pylint issues.
jpakkane Aug 28, 2024
518a1d9
Fix flake8 issues.
jpakkane Aug 28, 2024
134e70a
Refactor option evaluation to a single method.
jpakkane Sep 2, 2024
3a139b5
Group getter and setter methods together.
jpakkane Sep 15, 2024
0fe1254
Move configure option -A functionality to -D.
jpakkane Sep 5, 2024
9d5594c
Add documentation for per-subproject options.
jpakkane Aug 14, 2024
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
37 changes: 37 additions & 0 deletions docs/markdown/Configuring-a-build-directory.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,40 @@ by invoking [`meson configure`](Commands.md#configure) with the
project source directory or the path to the root `meson.build`. In
this case, Meson will print the default values of all options similar
to the example output from above.

## Per project subproject options rewrite (Since 1.7)

A common requirement when building large projects with many
subprojects is to build some (or all) subprojects with project options
that are different from the "main project". This has been sort of
possible in a limited way but is now possible in a general way. These
additions can be added, changed and removed at runtime using the
command line or, in other words, without editing existing
`meson.build` files.

Starting with version 1.7 you can specify per-project option settings.
These can be specified for every top level (i.e. not project) options.
Suppose you have a project that has a single subproject called
`numbercruncher` that does heavy computation. During development you
want to build that subproject with optimizations enabled but your main
project without optimizations. This can be done by specifying an
augment to the given subproject:

meson configure -Dnumbercruncher:optimization=3

Another case might be that you want to build with errors as warnings,
but some subproject does not support it. It would be set up like this:

meson configure -Dwerror=true -Anaughty:werror=false

You can also specify an augment on the top level project. A more
general version of enabling optimizations on all subprojects but not
the top project would be done like this:

meson configure -Doptimization=2 -D:optimization=0

Note the colon after the second `D`.

Subproject specific values can be removed with -U

meson configure -Usubproject:optionnname
19 changes: 19 additions & 0 deletions docs/markdown/snippets/optionrefactor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
## Per project subproject options rewrite

You can now define per-subproject values for all shared configuration
options. As an example you might want to enable optimizations on only
one subproject:

meson configure -Dnumbercruncher:optimization=3

Subproject specific values can be removed with -U

meson configure -Unumbercruncher:optimization

This is a major change in how options are handled. Current
per-subproject options are converted to augments on the fly. It is
expected that the logic might be changed in the next few releases as
logic errors are discovered.

We have tried to keep backwards compatibility as much as possible, but
this may lead to some build breakage.
2 changes: 1 addition & 1 deletion mesonbuild/ast/introspection.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ def _str_list(node: T.Any) -> T.Optional[T.List[str]]:
def_opts = self.flatten_args(kwargs.get('default_options', []))
_project_default_options = mesonlib.stringlistify(def_opts)
self.project_default_options = cdata.create_options_dict(_project_default_options, self.subproject)
self.default_options.update(self.project_default_options)
self.default_options.update(self.project_default_options) # type: ignore [arg-type]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the type warning being ignored?

self.coredata.set_default_options(self.default_options, self.subproject, self.environment)

if not self.is_subproject() and 'subproject_dir' in kwargs:
Expand Down
43 changes: 32 additions & 11 deletions mesonbuild/backend/backends.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@
from .._typing import ImmutableListProtocol
from ..arglist import CompilerArgs
from ..compilers import Compiler
from ..environment import Environment

Check failure

Code scanning / CodeQL

Module-level cyclic import Error

'Environment' may not be defined if module
mesonbuild.environment
is imported before module
mesonbuild.backend.backends
, as the
definition
of Environment occurs after the cyclic
import
of mesonbuild.backend.backends.
'Environment' may not be defined if module
mesonbuild.environment
is imported before module
mesonbuild.backend.backends
, as the
definition
of Environment occurs after the cyclic
import
of mesonbuild.backend.backends.
'Environment' may not be defined if module
mesonbuild.environment
is imported before module
mesonbuild.backend.backends
, as the
definition
of Environment occurs after the cyclic
import
of mesonbuild.backend.backends.
'Environment' may not be defined if module
mesonbuild.environment
is imported before module
mesonbuild.backend.backends
, as the
definition
of Environment occurs after the cyclic
import
of mesonbuild.backend.backends.
'Environment' may not be defined if module
mesonbuild.environment
is imported before module
mesonbuild.backend.backends
, as the
definition
of Environment occurs after the cyclic
import
of mesonbuild.backend.backends.
'Environment' may not be defined if module
mesonbuild.environment
is imported before module
mesonbuild.backend.backends
, as the
definition
of Environment occurs after the cyclic
import
of mesonbuild.backend.backends.
'Environment' may not be defined if module
mesonbuild.environment
is imported before module
mesonbuild.backend.backends
, as the
definition
of Environment occurs after the cyclic
import
of mesonbuild.backend.backends.
'Environment' may not be defined if module
mesonbuild.environment
is imported before module
mesonbuild.backend.backends
, as the
definition
of Environment occurs after the cyclic
import
of mesonbuild.backend.backends.
'Environment' may not be defined if module
mesonbuild.environment
is imported before module
mesonbuild.backend.backends
, as the
definition
of Environment occurs after the cyclic
import
of mesonbuild.backend.backends.
'Environment' may not be defined if module
mesonbuild.environment
is imported before module
mesonbuild.backend.backends
, as the
definition
of Environment occurs after the cyclic
import
of mesonbuild.backend.backends.
'Environment' may not be defined if module
mesonbuild.environment
is imported before module
mesonbuild.backend.backends
, as the
definition
of Environment occurs after the cyclic
import
of mesonbuild.backend.backends.
from ..interpreter import Interpreter, Test
from ..linkers.linkers import StaticLinker

Check failure

Code scanning / CodeQL

Module-level cyclic import Error

'StaticLinker' may not be defined if module
mesonbuild.linkers.linkers
is imported before module
mesonbuild.backend.backends
, as the
definition
of StaticLinker occurs after the cyclic
import
of mesonbuild.backend.backends.
'StaticLinker' may not be defined if module
mesonbuild.linkers.linkers
is imported before module
mesonbuild.backend.backends
, as the
definition
of StaticLinker occurs after the cyclic
import
of mesonbuild.backend.backends.
'StaticLinker' may not be defined if module
mesonbuild.linkers.linkers
is imported before module
mesonbuild.backend.backends
, as the
definition
of StaticLinker occurs after the cyclic
import
of mesonbuild.backend.backends.
'StaticLinker' may not be defined if module
mesonbuild.linkers.linkers
is imported before module
mesonbuild.backend.backends
, as the
definition
of StaticLinker occurs after the cyclic
import
of mesonbuild.backend.backends.
'StaticLinker' may not be defined if module
mesonbuild.linkers.linkers
is imported before module
mesonbuild.backend.backends
, as the
definition
of StaticLinker occurs after the cyclic
import
of mesonbuild.backend.backends.
'StaticLinker' may not be defined if module
mesonbuild.linkers.linkers
is imported before module
mesonbuild.backend.backends
, as the
definition
of StaticLinker occurs after the cyclic
import
of mesonbuild.backend.backends.
from ..mesonlib import FileMode, FileOrString

from typing_extensions import TypedDict
Expand Down Expand Up @@ -422,7 +422,7 @@
abs_files: T.List[str] = []
result: T.List[mesonlib.File] = []
compsrcs = classify_unity_sources(target.compilers.values(), unity_src)
unity_size = target.get_option(OptionKey('unity_size'))
unity_size = self.get_target_option(target, 'unity_size')
assert isinstance(unity_size, int), 'for mypy'

def init_language_file(suffix: str, unity_file_number: int) -> T.TextIO:
Expand Down Expand Up @@ -908,10 +908,10 @@
# With unity builds, sources don't map directly to objects,
# we only support extracting all the objects in this mode,
# so just return all object files.
if extobj.target.is_unity:
if self.is_unity(extobj.target):
compsrcs = classify_unity_sources(extobj.target.compilers.values(), sources)
sources = []
unity_size = extobj.target.get_option(OptionKey('unity_size'))
unity_size = self.get_target_option(extobj.target, 'unity_size')
assert isinstance(unity_size, int), 'for mypy'

for comp, srcs in compsrcs.items():
Expand Down Expand Up @@ -964,7 +964,7 @@

def target_uses_pch(self, target: build.BuildTarget) -> bool:
try:
return T.cast('bool', target.get_option(OptionKey('b_pch')))
return T.cast('bool', self.get_target_option(target, 'b_pch'))
except (KeyError, AttributeError):
return False

Expand All @@ -990,30 +990,29 @@
# starting from hard-coded defaults followed by build options and so on.
commands = compiler.compiler_args()

copt_proxy = target.get_options()
# First, the trivial ones that are impossible to override.
#
# Add -nostdinc/-nostdinc++ if needed; can't be overridden
commands += self.get_no_stdlib_args(target, compiler)
# Add things like /NOLOGO or -pipe; usually can't be overridden
commands += compiler.get_always_args()
# warning_level is a string, but mypy can't determine that
commands += compiler.get_warn_args(T.cast('str', target.get_option(OptionKey('warning_level'))))
commands += compiler.get_warn_args(T.cast('str', self.get_target_option(target, 'warning_level')))
# Add -Werror if werror=true is set in the build options set on the
# command-line or default_options inside project(). This only sets the
# action to be done for warnings if/when they are emitted, so it's ok
# to set it after or get_warn_args().
if target.get_option(OptionKey('werror')):
if self.get_target_option(target, 'werror'):
commands += compiler.get_werror_args()
# Add compile args for c_* or cpp_* build options set on the
# command-line or default_options inside project().
commands += compiler.get_option_compile_args(copt_proxy)
commands += compiler.get_option_compile_args(target, self.environment, target.subproject)

optimization = target.get_option(OptionKey('optimization'))
optimization = self.get_target_option(target, 'optimization')
assert isinstance(optimization, str), 'for mypy'
commands += compiler.get_optimization_args(optimization)

debug = target.get_option(OptionKey('debug'))
debug = self.get_target_option(target, 'debug')
assert isinstance(debug, bool), 'for mypy'
commands += compiler.get_debug_args(debug)

Expand Down Expand Up @@ -1738,7 +1737,7 @@
# TODO: Create GNUStrip/AppleStrip/etc. hierarchy for more
# fine-grained stripping of static archives.
can_strip = not isinstance(t, build.StaticLibrary)
should_strip = can_strip and t.get_option(OptionKey('strip'))
should_strip = can_strip and self.get_target_option(t, 'strip')
assert isinstance(should_strip, bool), 'for mypy'
# Install primary build output (library/executable/jar, etc)
# Done separately because of strip/aliases/rpath
Expand Down Expand Up @@ -2062,3 +2061,25 @@
all_sources = T.cast('_ALL_SOURCES_TYPE', target.sources) + T.cast('_ALL_SOURCES_TYPE', target.generated)
return self.compiler_to_generator(target, target.compiler, all_sources,
target.output_templ, target.depends)

def is_unity(self, target: build.BuildTarget) -> bool:
if isinstance(target, build.CompileTarget):
return False
val = self.get_target_option(target, 'unity')
if val == 'on':
return True
if val == 'off':
return False
if val == 'subprojects':
return target.subproject != ''
Comment on lines +2068 to +2074
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the business logic coming out of the Target and into the Backend? This means that we later have to pass the unity information back into the Target for extract_objects. Wouldn't it be cleaner for Targets to have a reference to the OptionStore?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change I have consistently gone to was to separate "data storage" from "evaluation code". Before this the logic of how option values were evaluated was all over the place. Not to mention that some of the data transformations were silently lossy. This made it hard to answer questions like "where exactly does the value of option X for Y come from".

Because of this all data containers like build targets only store the original data they were given as close to the original form as possible. They do not have logic. They do not do transformations. All that is computed in one place and if you ever need to debug issues with it you know exactly the one place where you should set your debugger breakpoint.

This is a bit unfortunate for Unity since it has the "for subprojects" value. If we had had this functionality already it would never have been needed. But it's there now, so we have to deal with it and eventually deprecate and remove the "for subprojects only" value from it.

raise MesonException(f'Internal error: invalid option type for "unity": {val}')

def get_target_option(self, target: build.BuildTarget, name: T.Union[str, OptionKey]) -> T.Union[str, int, bool, T.List[str]]:
if isinstance(name, str):
key = OptionKey(name, subproject=target.subproject)
elif isinstance(name, OptionKey):
key = name
else:
import sys
sys.exit('Internal error: invalid option type.')
return self.environment.coredata.get_option_for_target(target, key)
Loading
Loading