Meson targets that depend on subdir siblings
Asked Answered
B

3

8

Here is my project structure:

.
├── include
├── src
│   ├── abc
│   │   ├── include
│   │   └── src
│   ├── def
│   │   ├── include
│   │   └── src
│   └── ghi
│       ├── include
│       └── src
└── vendor
    ├── bar
    │   ├── include
    │   └── src
    └── foo

16 directories

I would like to port my build to Meson. However, I'm not sure how to link targets defined in sibling folders.

My dependency graph looks like this:

  • src/abc/meson.build defines a static library abc
  • src/def/meson.build defines a static library def that depends on abc and foo
  • src/ghi/meson.build defines a static library ghi that depends on bar
  • vendor/bar/meson.build defines a static library bar
  • vendor/foo/meson.build defines a static library foo
  • The top-level meson.build defines an executable app that depends on abc, def and ghi

In the documentation, there seem to be two mechanisms:

  • subdir
  • subproject

It is not clear to me which is best here. I do not have any dependencies outside of my source-code.

What should I write in my meson.build files to link these targets together?

Byerly answered 11/3, 2019 at 17:33 Comment(0)
B
6

You can use subdir from the top-level meson.build file down. All variables you declare in the subdir meson.build files are available to later meson.build files. As long as you get the order of subdir calls correct, it will work.

Byerly answered 11/3, 2019 at 18:9 Comment(2)
Not quite, paths must be relative in meson, but they are specified relative to each meson.build so paths defined in one subdir are inherently broken in another.Dalesman
@Makogan: To avoid this, you have to use the file() command.Kathlenekathlin
B
9

Besides @sdgfsdh's (correct) answer, another approach I like is to define libraries and executables only in the top-level meson file, and use subdir calls to define a sets of source files and "local" include paths. Done this way, the subdir files don't implicitly depend on each other; the entire dependency tree lives in the top-level meson file.

The advantages of this approach are:

  • subdirs don't need to know their own path (files() and include_directories() will track this for you)
  • The top-level file only needs to know subdir paths to call the subdir meson files. After that, you can define everything in terms of variables created in the subdirs
  • subdir files don't directly depend on any other meson files

Disadvantages:

  • The top-level file is more cluttered
  • Variable names in subdir files need to be globally unique, since everything is ultimately defined in the top-level scope

An example for your case:

# Top-level meson.build
subdir('src/abc')
subdir('src/def')
subdir('src/ghi')
subdir('vendor/foo')
subdir('vendor/bar')

libabc = static_library('abc', abc_files, include_directories: abc_includes)

libabc_dep = declare_dependency(include_directories: abc_includes, link_with : libabc)

libfoo = static_library('foo', foo_files, include_directories: foo_includes)

libfoo_dep = declare_dependency(include_directories: foo_includes, link_with : libfoo)

libdef = library('def', def_files, include_directories: def_includes, dependencies : [ libabc_dep, libfoo_dep])
# src/abc/meson.build (others would be similar)
abc_files = files(['1.c','2.c',...])
abc_includes = include_directories('include')
Buckskins answered 15/4, 2019 at 14:21 Comment(2)
With libdef = library(... link_with: [libabc, libfoo] ...), can libabc_dep and libfoo_dep be omitted?Saccharoid
The one problem with this approach is that when referring to e.g. abc_files from the top-level meson.build, filenames need to be prefixed with the directory that they live in; otherwise they cannot be found when the call to library() etc is made.Hangdog
B
6

You can use subdir from the top-level meson.build file down. All variables you declare in the subdir meson.build files are available to later meson.build files. As long as you get the order of subdir calls correct, it will work.

Byerly answered 11/3, 2019 at 18:9 Comment(2)
Not quite, paths must be relative in meson, but they are specified relative to each meson.build so paths defined in one subdir are inherently broken in another.Dalesman
@Makogan: To avoid this, you have to use the file() command.Kathlenekathlin
E
0

In addition to the answers already proposed there is the special case of a target in which you have a dependency on a file that is not used as a source file nor an include file and it also needs some customization during this process.

An example is a linker script that is required in a target in the top level meson.build file. The linker script is used passing it via the -T flag to the compiler. If the linker script depends on a subdirectory you cannot easily propagate the dependency to the top as you would do with objects returned by include_files() for instance.

This can be resolved via the configure_file function. In the simplest case, it can be used in copy mode directly from the subdirectories' meson.build file to keep the file unchanged:

linker_script = configure_file( 
     copy: true, 
     input: 'linker.ld', 
     output: 'linker.ld' 
 )

Other modes of this function can be used to customize the file furtherly. See this manual page in Meson's documentation.

This places the linker script in the build directory with the same relative path and so it is usable as a parameter to the compiler in the top level Meson file.

It also returns a configured file object usable in upper directories, so in the top level Meson file, in the target that uses this file:

executable( 
     'MyTarget',  
     src, 
     include_directories : [...], 
     link_args : ['-T', '@0@'.format(linker_script)], 
     link_depends : linker_script
 ) 

Where '@0@'.format(file object) is a trick to extract the file path from a file object, the linker script file in this case.

Plus we use link_depends to ensure the file is considered a dependency for this target, so if the file changes, Meson re-links the target (but does not recompile src and headers that have not changed). This is necessary as Meson will not recognize the file as an implicit dependency if used in this way.

Espalier answered 17/10, 2023 at 20:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.