Implement `preserve_path` for install_headers

The `install_headers` function now has an optional argument
`preserve_path` that allows installing multi-directory
headerfile structures that live alongside sourcecode with a
single command.

For example, the headerfile structure

headers = [
  'one.h',
  'two.h',
  'alpha/one.h',
  'alpha/two.h',
  'alpha/three.h'
  'beta/one.h'
]

can now be passed to `install_headers(headers, subdir: 'mylib', preserve_path: true)`
and the resulting directory tree will look like

{prefix}
└── include
    └── mylib
        ├── alpha
        │   ├── one.h
        │   ├── two.h
        │   └── three.h
        ├── beta
        │   └── one.h
        ├── one.h
        └── two.h

Fixes #3371
pull/7177/head
Florian "sp1rit"​ 3 years ago committed by Eli Schwartz
parent 37fea63033
commit ad8f24f232
  1. 35
      docs/markdown/snippets/install_headers_preserve_path_arg.md
  2. 16
      docs/yaml/functions/install_headers.yaml
  3. 22
      mesonbuild/interpreter/interpreter.py
  4. 3
      test cases/common/9 header install/child/childdir.h
  5. 7
      test cases/common/9 header install/meson.build
  6. 2
      test cases/common/9 header install/test.json

@ -0,0 +1,35 @@
## Added preserve_path arg to install_headers
The [[install_headers]] function now has an optional argument `preserve_path`
that allows installing multi-directory headerfile structures that live
alongside sourcecode with a single command.
For example, the headerfile structure
```meson
headers = [
'one.h',
'two.h',
'alpha/one.h',
'alpha/two.h',
'alpha/three.h'
'beta/one.h'
]
```
can now be passed to `install_headers(headers, subdir: 'mylib', preserve_path: true)`
and the resulting directory tree will look like
```
{prefix}
└── include
   └── mylib
      ├── alpha
        ├── one.h
        ├── two.h
        └── three.h
      ├── beta
        └── one.h
      ├── one.h
      └── two.h
```

@ -29,6 +29,13 @@ example: |
install_headers('common.h', 'proj/kola.h', install_dir : 'cust', subdir : 'myproj')
```
This will install `common.h` into `/{prefix}/include` and `kola.h`
into `/{prefix}/include/proj/`:
```meson
install_headers('common.h, 'proj/kola.h', preserve_path : true)
```
varargs:
name: file
type: file | str
@ -54,3 +61,12 @@ kwargs:
and optionally the owner/uid and group/gid for the installed files.
See the `install_mode` kwarg of [[install_data]] for more information.
preserve_path:
type: bool
since: 0.63.0
default: false
description: |
Disable stripping child-direcories from header files when installing.
This is equivalent to GNU Automake's `nobase` option.

@ -2091,6 +2091,7 @@ class Interpreter(InterpreterBase, HoldableObject):
@typed_kwargs(
'install_headers',
KwargInfo('install_dir', (str, NoneType)),
KwargInfo('preserve_path', bool, default=False, since='0.63.0'),
KwargInfo('subdir', (str, NoneType)),
INSTALL_MODE_KW.evolve(since='0.47.0'),
)
@ -2104,12 +2105,25 @@ class Interpreter(InterpreterBase, HoldableObject):
raise InterpreterException('install_headers: cannot specify both "install_dir" and "subdir". Use only "install_dir".')
if os.path.isabs(install_subdir):
mlog.deprecation('Subdir keyword must not be an absolute path. This will be a hard error in the next release.')
else:
install_subdir = ''
dirs = collections.defaultdict(list)
ret_headers = []
if kwargs['preserve_path']:
for file in source_files:
dirname = os.path.dirname(file.fname)
dirs[dirname].append(file)
else:
dirs[''].extend(source_files)
h = build.Headers(source_files, install_subdir, kwargs['install_dir'],
kwargs['install_mode'], self.subproject)
self.build.headers.append(h)
for childdir in dirs:
h = build.Headers(dirs[childdir], os.path.join(install_subdir, childdir), kwargs['install_dir'],
kwargs['install_mode'], self.subproject)
ret_headers.append(h)
self.build.headers.append(h)
return h
return ret_headers
@typed_pos_args('install_man', varargs=(str, mesonlib.File))
@typed_kwargs(

@ -0,0 +1,3 @@
/* This file goes, depending on the state of `preserve_path` into subdirectory of include root or into the `child` dir of the subdirectory of include root. */
int childdir_func();

@ -1,11 +1,12 @@
project('header install')
as_array = ['subdir.h']
as_array = ['subdir.h', 'child/childdir.h']
subdir('vanishing_subdir')
subdir('sub')
h1 = install_headers('rootdir.h')
h2 = install_headers(as_array, subdir : 'subdir')
h3 = install_headers(subheader)
h4 = install_headers(disabler())
h3 = install_headers(as_array, subdir : 'subdir', preserve_path : true)
h4 = install_headers(subheader)
h5 = install_headers(disabler())

@ -2,6 +2,8 @@
"installed": [
{ "type": "file", "file": "usr/include/rootdir.h" },
{ "type": "file", "file": "usr/include/subdir/subdir.h" },
{ "type": "file", "file": "usr/include/subdir/childdir.h" },
{ "type": "file", "file": "usr/include/subdir/child/childdir.h" },
{ "type": "file", "file": "usr/include/vanished.h" },
{ "type": "file", "file": "usr/include/fileheader.h" }
]

Loading…
Cancel
Save