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

Add a file_argument function #12287

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

dcbaker
Copy link
Member

@dcbaker dcbaker commented Sep 25, 2023

A common problem we run into is passing arguments to compilers that need to have a file included in the argument, and cannot be split. Take for example the classic gnu linker script -Wl,--linker-script,<path>. if <path> is a File object, this can't be easily represented. A workaround was to use str.format, however, that as never meant to work and has been marked as deprecated (broken, actually).

There are a number of ways this could be fixed:

  1. We could special case the addition (+) operator for str and file, but that feels a little gross, and is likely to backfire in spectacular ways.
  2. We could add a method to convert files to strings, but that has some caveats as well, since file objects can be built, and therefore not always available. This would break the ordering guarantees that Meson can create by using files
  3. we can add a new function for handling this

I've taken route 3, which allows both getting the correct string value, but also creating the correct ordering guarantees. It works like this

build_target(
  ...,
  link_args : file_argument('-Wl,--version-script,', files('file.map')),
)

This returns an opaque argument that Meson reduces to a string argument, which is passed to the compiler/linker, and a correct dependency on the file object being passed.

This is built on top of the first three patches of #11981

Fixes: #12259

@medhefgo
Copy link
Contributor

Looks like this only supports two args in a fixed order? That seems overly restrictive to me. It would be nicer if it supported any number of strings and files in any order. And maybe even lists of those and some separator/joiner kwarg.

@dcbaker
Copy link
Member Author

dcbaker commented Sep 25, 2023

What is the use case for more than one file Do you have an example of an argument that works like that? The only uses I've run into or seen submited are things like --arg=<path> or -Wl,--arg,<path>. Generally, we try to be conservative and not address issues that we don't have a current use case for.

@dcbaker dcbaker force-pushed the submit/file-argument branch from 23e83e2 to ac12f54 Compare September 25, 2023 19:50
@tristan957
Copy link
Contributor

tristan957 commented Sep 25, 2023

what about a .to_list() method on a files object that creates a list of filenames?

@dcbaker
Copy link
Member Author

dcbaker commented Sep 25, 2023

what about a .to_list() method on a files object that creates a list of filenames?

files() has a signature like files(...str) -> array[file]. So we wouldn't have any place to attach a to_list method to.

And with to_str on file itself you're still left having to write:

mapfile = files('foo.map)
build_target(
  link_args : ['-Wl,--linker-script,' + mapfile[0].to_str()],
  link_depends : mapfile,
)

Which is easier to get wrong than using the file_argument() approach, where Meson can ensure the dependency is correctly inserted in a DRY manner

@tristan957
Copy link
Contributor

In the past, someone has discussed adding better support for linker scripts. Maybe @eli-schwartz

@dcbaker dcbaker force-pushed the submit/file-argument branch from ac12f54 to 27e3c1d Compare September 25, 2023 20:01
@dcbaker dcbaker requested a review from mensinda as a code owner September 25, 2023 20:01
@dcbaker dcbaker force-pushed the submit/file-argument branch from 27e3c1d to e5b931c Compare September 25, 2023 20:03
@medhefgo
Copy link
Contributor

Do you have an example of an argument that works like that?

I don't have a concrete use-case. But I've seen several meson functions in the docs become variadic when they would've clearly been sensible to be so from the start. This one strikes me as one.

Btw, yes, in systemd we use format to string for linker scripts (and already set a link dependency for it). And I just tested this PR and it seems to works.

Now if only meson --fatal-meson-warnings wouldn't make it a fatal deprecation warning unless you actually target >= 1.3.0 (since there would literally be nothing you can do about it until then)… sigh

@dcbaker
Copy link
Member Author

dcbaker commented Sep 25, 2023

Now if only meson --fatal-meson-warnings wouldn't make it a fatal deprecation warning unless you actually target >= 1.3.0 (since there would literally be nothing you can do about it until then)… sigh

hmmmm... normally that's how deprecations work. Let me see...

@dcbaker dcbaker force-pushed the submit/file-argument branch from e5b931c to de05fee Compare September 25, 2023 21:02
@antonysigma
Copy link
Contributor

antonysigma commented Sep 25, 2023

I can add another use case of the file_argument function: functional testing of user code with binary test vectors.

For example, the following meson build rule scans the project for a raw data file, decode its absolute path, then add it to the compiler flags. In the unit-test file, we invoke fopen to read the binary data from disk for data validations.

unit_test_exe = executable('test-main',
  sources: 'test-main.cpp',
  cpp_args: file_argument('-DRAW_DATA_PATH="@0@"', files('data/raw-data.bin')),
)

test('Raw data validation test with hardcoded binary datafile path', unit_test_exe)

And, the pseudo-code of a typical unit test file:

#ifndef RAW_DATA_PATH
#error preprocessor flag "RAW_DATA_PATH" not yet defined
#endif
TEST_CASE("Can decode the raw binary file") {
    constexpr char file_path[] { RAW_DATA_PATH };
    const std::vector<byte> raw_data = my_fopen(file_path);
    
    assert(raw_data.size > 0);
    assert(std::equal(raw_data, my_simulated_data));
}

@eli-schwartz
Copy link
Member

For example, the following meson build rule scans the project for a raw data file, decode its absolute path, then add it to the compiler flags. In the unit-test file, we invoke fopen to read the binary data from disk for data validations.

This seems like a bad use case, actually... adding a build ordering rule here that forces the executable to be recompiled every time the test data file is updated would be somewhat wasteful unless the executable actually used #embed (which itself seems odd for a test-time executable). And the design of this PR assumes that the correct thing to do is to helpfully add that rebuild dependency for you.

Way back in Meson 0.25, support was added to `vala_args` for Files.
Strangely, this was never added to any other language, though it's been
discussed before. For type safety, it makes more sense to handle this in
the interpreter level, and pass only strings into the build IR.

This is accomplished by adding a `depend_files` field to the
`BuildTarget` class (which is not exposed to the user), and adding the
depend files into that field, while converting the arguments to relative
string paths. This ensures both the proper build dependencies happen, as
well as that the arguments are always strings.
This also moves the repacking into the interpreter, making the build
implementation simpler and removing a layering violation. This also
makes use a defaultdict to remove the need to call `.get()`
@dcbaker dcbaker force-pushed the submit/file-argument branch from de05fee to 6bd3f7e Compare September 26, 2023 17:58
`java_args` is only valid for `jar()` (and `build_target()`, but that's
deprecated), while all other language args are invalid for `jar()`. This
deprecates all of those arguments, that shouldn't be allowed, and
provides useful error messages. As an advantage, this avoids generating
useless `java_static_args` and `java_shared_args`.

In order to get useful error messages for both build_target and
executable + *library, we need to separate LIBRARY and BUILD_TARGET a
bit.
@dcbaker dcbaker force-pushed the submit/file-argument branch from 6bd3f7e to 35c6660 Compare September 26, 2023 18:01
@eli-schwartz
Copy link
Member

eli-schwartz commented Sep 26, 2023

Now if only meson --fatal-meson-warnings wouldn't make it a fatal deprecation warning unless you actually target >= 1.3.0 (since there would literally be nothing you can do about it until then)… sigh

It very much depends on what sort of deprecation we are talking about.

The general rule of thumb is that most deprecations are "XXX was supported but we have changed our mind and would like to remove it. We promised you the ability to use XXX and we are not going to retract that". In such cases we do not issue a warning at all unless you're targeting a high enough minimum. There's a final summary at "notice" level for things which will become deprecated in the future but this does not trigger fatal-meson-warnings since it's not actionable.

The other case of deprecation warnings is when something is asserted by meson developers to be "always wrong" regardless of version. Maybe we never promised you it would work. Maybe it's just "so darned buggy" that we regard it as an ecosystem hazard if we allow it to be used even on ancient versions of meson that had no choice.

In this case we are warning about something that was never guaranteed to work, does not work reliably, and has no guidance other than "have you considered manually constructing your raw strings with meson.current_source_dir()".

The fact that an unrelated PR proposes to provide ergonomics around one limited use case for the deprecated functionality, doesn't have any bearing on the timeline for deprecation (it is deprecated for a vast number of scenarios, most of which don't involve compiler arguments).

@dcbaker dcbaker force-pushed the submit/file-argument branch from 35c6660 to e535713 Compare September 26, 2023 18:58
This allows for handling special arguments like
`--version-script=<path>`, where the `=` is required and may not be
passed as two separate arguments. A new dsl function `file_argument` is
added, and is used like this:
```meson
executable(
  ...,
  c_args : [file_argument('--file-arg=', files('foo.arg'))]
)
```
This returns an opaque object, which meson will correctly add to either
the build or link depends (depending on whether it was passed to a
compile argument or to a link argument), and will convert the argument
into `--file-arg=relative/path/to/foo.arg`
@dcbaker dcbaker force-pushed the submit/file-argument branch from e535713 to 11f3e31 Compare September 26, 2023 19:00
@mon
Copy link
Contributor

mon commented Oct 12, 2023

We could special case the addition (+) operator for str and file, but that feels a little gross, and is likely to backfire in spectacular ways.

It would be nice to special case str+file anyway to throw an error saying "you probably want to use file_argument", as that's the first approach anyone is going to try when adding a linker script.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Cannot convert file objects to string since cec3edc08a6cd6a89761c49292ba6a3bace8b3c1
6 participants