The concept of merge_file intrinsically requires some GNU-specific
functionality, so let's emit a useful error message during
configuration, when we don't have that.
The relevant GNU gettext versions date back to around 2015 so *probably*
anyone has that too, but we may as well verify that while we are here.
There are a number of implementations for msgfmt, supporting various
options. The simplest, and most common, use case is to compile .po files
into .mo files, and this should be able to work on gettext
implementations other than the GNU one.
The problem is that we were passing some pretty portable arguments in an
unportable manner. The `-o` option-argument and its associated argument
came after the input file operand, which violates the POSIX Utility
Syntax Guidelines, and happens to not be supported by Solaris gettext.
The GNU gettext doesn't care; GNU invented GNU argument permutation.
Switch the order around so that our use respects the POSIX style.
At least, if you tried to use it when passing an install_dir. Because
T.Sequence is horrible and we should never use it, and the annotations
are a lie that produces bugs.
So, fix the annotations on CustomTarget to never allow this to happen
again, and also fix the function too. Move some definitions elsewhere
inline to satisfy the linter.
Fixes#11157
Gettext should search for input files relative to the (sub)project
source root, not the global source root.
This change exposes a root_subdir member in ModuleState.
Instead of using FeatureNew/FeatureDeprecated in the module.
The goal here is to be able to handle information about modules in a
single place, instead of having to handle it separately. Each module
simply defines some metadata, and then the interpreter handles the rest.
Logically, i18n.merge_file cannot ever take a MULTI_OUTPUT_KW, but it
does take a CT_OUTPUT_KW-like interface.
Actually trying to pass multiple merge_file outputs causes the
msgfmthelper script to be entirely malformed in the arguments it
accepts, and treat the broken one like a --flag, then exit with argparse
errors.
Even if we somehow assumed that somehow it was designed to actually
allow this, msgfmt doesn't support conceptually passing multiple outputs
so that would be a msgfmt error instead of an error inside the guts of
`meson --internal msgfmthelper`.
Same logic applies again for the itstool command and the itstool
internal helper.
Catch this error at configuration time by using the single-output kwarg
form.
Likewise, it's totally nonsense to accept multiple install_dir or
install_tags, and ever since commit 11f9638035
the CustomTarget itself won't even check this.
CT_OUTPUT_KW is the same OUTPUT_KW we use in lots of places. The most
distinctive thing about it is not that it's part of custom_target
(basically any other function that uses such a kwarg follows the same
rules due to using CustomTarget under the hood), but the fact that it
takes multiple outputs.
For maintainer targets, we need some more tools that gettext-tiny
doesn't implement. It's a shame to cause NLS to be completely disabled
in such environments, so instead just issue a warning and continue.
Before 0.62.0 these were never checked for, and would simply fail at
runtime, probably. In theory, the user might install the tools in
between configuring and building, and then the maintainer targets would
begin to work. Return to that behavior -- we still create the targets,
which will *probably* fail, but might not -- and for existing
integrations, failing at `ninja foo-update-po` with "error, program
msgmerge not found" is a bit more discoverable than ninja saying "what
do you mean, there's no such target".
We still have the 0.62.0 preferred behavior of trying to find the
programs, succeeding in all cases other than gettext-tiny, and
guaranteeing that their paths are set up in a machine-file-respecting
manner.
In the former case, the presence of tools is optional, but triggers a
warning and then no-ops the target. In the latter case, the presence of
the tools is mandatory. But if it was already looked up and discovered
to be missing, we did not actually check that it is found before trying
to use it.
In the case that it isn't found, check again, so that we explicitly
error out with a relevant error message due to setting the required
flag.
Fixes#10320
They are RunTargets because they are one-shot commands without outputs.
But we implement them purely via our internal wrapper for gettext, so
there is no reason to wrap them *again* in our internal wrapper for
meson_exe and set a bunch of environment variables we know we absolutely
do not need, use, or want.
This avoids the ugly "wrapped due to env" status, and allows users to
directly see the command being run without going into despair at obscure
pickled nonsense.
It also offers a tiny defense against upgrading Meson without
reconfiguring. People should not do that, and we error out about this in
a bunch of places, but `--internal gettext` has a perfectly stable
interface just like most build tools that aren't part of Meson
internals, since it uses command line arguments instead of pickling.
Disabling targets because the tools used to build them aren't available
is a pretty suspicious thing to do. Users who want this are probably, in
general, advised to check themselves whether it is possible to build
those targets with find_program(..., required: false)
The i18n.gettext() invocation is a bit unusual because the product of
running it is non-critical files, specifically, translation catalogs. If
users don't have the tools needed to build them, they may not be able to
use them either, because perhaps they have NLS disabled on their
platform or it's difficult to put it in the bootstrap path.
So, for this reason, it was made non-fatal and the message catalogs are
just not created, and the resulting build is still perfectly usable
*unless* you want to use it in another language, at which point it
"works" but the text is all inscrutable to the end user, and that's a
feature of the target platform.
That's an acceptable tradeoff for translation catalogs.
It is NOT an acceptable tradeoff for merge_file, which produces desktop
files or MIME database catalogs or other files which have crucial roles
to perform, without which the software in question simply doesn't work
at all. In such cases, this just fails to install crucial files, users
report bugs to the project in question, and the project adds
`find_program('xgettext')` to guarantee the hard error due to lack of
confidence in Meson.
Fixes#6165Fixes#8436
Use this instead of shutil.which to detect whether they will be
available, and pass the ExternalProgram object to CustomTarget
invocations, or else make use of the new functionality to specify the
correct program path in wrapper scripts.
Drop duplicate reporting for itstool missing. Since we use find_program
in required mode, its absence is already fatal, and already has a really
good error description.
Due to misuse of argparse in commit 82492f5d76
it was impossible to use both --datadirs and extra args passed directly
to msgfmt at the same time.
I'm not sure anyone actually knows how argparse works, so misusing it is
easy. What is definitely known is that argparse is NOT a POSIX compliant
parser and doesn't behave the way you'd expect a standards based parser
to handle options. Instead it caters to the easy use case, and hopes and
prays you don't need to do anything too complicated "with the wrong kind
of complicated".
Apparently, this particular type of complicated is when you have mixed
option_arguments and operands while simultaneously passing some operands
as nargs after a --.
It totally breaks, and interprets --datadirs, which is supposed to be an
option_argument, as an operand, eats it up as a msgfmt wrapped argument,
and breaks.
But if you don't pass additional arguments with -- then it interprets
--datadirs after operands as an option_argument. This is what we were
doing.
Instead pass option_arguments before all operands (including the ones
specified via `-- ...`). Add test case to pass meaningless datadirs (we
don't actually care if $GETTEXTDATADIRS is set to something that doesn't
contain gettext data).
Because we don't want to pass the Interpreter kwargs into the build
layer. This turned out to be a mega commit, as there's really on elegant
way to make this change in an incremental way. On the nice side, mypy
made this change super easy, as nearly all of the calls to
`CustomTarget` are fully type checked!
It also turns out that we're not handling install_tags in custom_target
correctly, since we're not converting the boolean values into Optional
values!
When input kwarg is missing in i18n.merge_file() it was crashing with a
backtrace because of kwargs['input'][0]. That code was useless anyway
because CustomTarget now uses first output as default name which is what
we need here.
The previous commit bd2fcb268b
accidentally used the wrong var so the param name was missing,
leading to an error of "unrecognized arguments" for the
datadirs parameter value.
There were two allowed kwargs that were unused, I've dropped them for
now, though I need to check if they were documented. If they are then we
need to deprecate them to remove them, otherwise we'll just leave them
removed.
And more accurate too, TBH. Currently it says it is building "lang.mo",
even though it is actually building "domain.mo" inside
lang/LC_MESSAGES/.
Since meson loudly complains if I try to name the display name
"lang/domain.mo", name it with a dash instead of a slash. The actual
name isn't a priority here IMO, and this is nicely readable.
Removed in commit 487d45c1e5 but perhaps
it should not have -- people may have been depending on ensuring those
are built somehow. Even though the internal implementation changed and
it is now built by the all target, let's keep the old target around too.
Now it just aliases the actual build rules, though.
Users may wish to make use of these files for their own purposes.
For example, the -pot and -update-po pseudo targets could be reused in
an alias_target(), and at least one person wanted to reuse the built .mo
files as custom_target input.
Fixes#6227
Don't just create a .PHONY target which runs a script that magically
generates files ninja doesn't know about. It results in untracked files,
and `meson install` has to run additional commands instead of copying
over files, and then cannot track them to uninstall them later.
I'm not even really sure why it was originally done via a proxy script,
most likely bad legacy design. This is after all one of the oldest
modules...
One side effect of this is that meson doesn't know how to rename
build.CustomTarget files on install (only data files are supported?),
and every file needs to be installed as "domainname.mo" so it must be
named that in-tree too. To prevent clashes, every locale gets its own
locale-specific subdirectory.
Once we are doing that anyway, we can output them to the actual
structure required by the gettext family of functions, and
bindtextdomain() can therefore point to this location if desired. This
might be useful for running localized programs from the build tree.
Re-implement it in backend using the same code path as for
custom_target(). This for example handle setting PATH on Windows when
command is an executable.
On Windows this would fail because of missing DLL:
```
mylib = library(...)
exe = executable(..., link_with: mylib)
meson.add_install_script(exe)
```
The reason is on Windows we cannot rely on rpath to find libraries from
build directory, they are searched in $PATH. We already have all that
mechanism in place for custom_target() using ExecutableSerialisation
class, so reuse it for install/dist/postconf scripts too.
This has bonus side effect to also use exe_wrapper for those scripts.
Fixes: #8187
This patches takes the options work to it's logical conclusion: A single
flat dictionary of OptionKey: UserOptions. This allows us to simplify a
large number of cases, as we don't need to check if an option is in this
dict or that one (or any of 5 or 6, actually).
D lang compilers have an option -release (or similar) which turns off
asserts, contracts, and other runtime type checking. This patch wires
that up to the b_ndebug flag.
Fixes#7082