meson icon indicating copy to clipboard operation
meson copied to clipboard

Allow custom_target and generator to accept include_directories objects

Open dcbaker opened this issue 1 year ago • 2 comments

Recently, I've noticed a number of places where either a custom_target or a generator would benefit from directly understanding an include_directories object.

I considered adding a to_string() method to include_directories, but rejected it for a couple of reasons:

  1. In a generator that would require storing the strings as absolute paths, this would break the ability to move a meson build directory, since the include directories would break. This is required because a generator must be usable in a different directory than the one it is defined in.
  2. The same problem will exist for custom_targets if my work at adding a templating helper ever lands
  3. Meson generally prefers smart objects to strings, consider include_directories and files as examples of this.

As such, I have opted to add the include_directories field to custom_target, generator and generator.process. This formatted for the underlying program by a new custom_target_template parameter, which takes an array of strings which must include the @DIR@ formatter, and defaults to ['-I@DIR@']. This provides a way to tell Meson how the tools expects include_directories to be passed. Additionally, when using this functionality the command or arguments must include a @INCLUDE_DIRS@ formatter.

For example:

custom_target(
  command : [gcc, '@INPUT@', '-o', '@OUTPUT@', '@INCLUDE_DIRS@']
  include_directories : include_directories('include'),
  # include_directories_template : ['-I@DIR@'],  # just for demonstration
)

For generators include_directories can also be passed to process(), which will be placed before the include_directories passed to the generator() call.

dcbaker avatar Apr 04 '24 17:04 dcbaker

I understand how you came to this conclusion but it feels very worrisome to require three different kwargs working in tandem to get the minimal usecase to work.

I would also not really expect people to care about include_directories objects in the first place since that can be manually constructed -- it's known by the author of the meson.build -- whereas dependency objects have the same issue, but also have to handle link arguments, and need to be used in a variety of places including as input to configure_file

eli-schwartz avatar Apr 04 '24 17:04 eli-schwartz

I can put the include directories in the command directly if that's the problem. I did that initially but it ended up being really messy and I didn't like it.

This was spurred by the following pattern in several places in mesa:

global_includes = include_directoriers('../../../include', '../../../utils')  # actually defined in ../../../, but here for illistration
local_includes = include_directories('private', 'hardware')

generated = custom_target = (
   ...
   command : [
       ...
       '-I' + meson.current_source_dir() / 'private',
       '-I' + meson.current_source_dir() / 'hardware',
       '-I' + meson.current_source_dir() / '../../../include',
       '-I' + meson.current_source_dir() / '../../../utils',
       '-I' + meson.current_build_dir() / '../../../utils',
   ]
)

lib = static_library(
  'lib',
  'src.c', 'src.cpp' , generated,
  include_directories : [global_includes, local_includes,
)

So yeah, writing:

generated = custom_target = (
   ...
   command : [
       ..., '@INCLUDE_DIRS@',
   ],
   include_directories : [local_includes, global_includes],
)

is a huge win. if the include_directories field is the problem I can rewrite it to do:

generated = custom_target = (
   ...
   command : [
       ..., local_includes, global_includes,
   ],
)

but I also ran into this working with generators, where strings are a really big problem because you have to use strings that are absolute with generators, which is a thing we've (at least the in the past) tried very hard not to do for things that are relative to the build directory or source directory.

dcbaker avatar Apr 04 '24 20:04 dcbaker

I think I would rather see a .flags() method on include_directories. Similar to what we want to do with dependency.

Edit: dcbaker has shown me the potential pitfalls here.

tristan957 avatar May 02 '24 04:05 tristan957

@dcbaker

This was spurred by the following pattern in several places in mesa: ... '-I' + meson.current_source_dir() / 'hardware',

FWIW: After a fair bit of pain, I figured out that constructing include paths this way can lead to depfiles with different paths than when meson invokes the compiler. The problem is that meson.current_build_dir() and meson.current_source_dir() can return absolute paths, but meson uses relative paths when constructing -I from many uses of include_directories(). Which can lead to missing rebuilds and things like ninja -t missingdeps not working reliably.

While ninja does some canonicalization of paths, it doesn't turn absolute paths to relative ones or vice versa.

anarazel avatar May 02 '24 04:05 anarazel