The Meson Build System
http://mesonbuild.com/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
637 lines
21 KiB
637 lines
21 KiB
--- |
|
short-description: Dependencies for external libraries and frameworks |
|
... |
|
|
|
# Dependencies |
|
|
|
Very few applications are fully self-contained, but rather they use |
|
external libraries and frameworks to do their work. Meson makes it |
|
very easy to find and use external dependencies. Here is how one would |
|
use the zlib compression library. |
|
|
|
```meson |
|
zdep = dependency('zlib', version : '>=1.2.8') |
|
exe = executable('zlibprog', 'prog.c', dependencies : zdep) |
|
``` |
|
|
|
First Meson is told to find the external library `zlib` and error out |
|
if it is not found. The `version` keyword is optional and specifies a |
|
version requirement for the dependency. Then an executable is built |
|
using the specified dependency. Note how the user does not need to |
|
manually handle compiler or linker flags or deal with any other |
|
minutiae. |
|
|
|
If you have multiple dependencies, pass them as an array: |
|
|
|
```meson |
|
executable('manydeps', 'file.c', dependencies : [dep1, dep2, dep3, dep4]) |
|
``` |
|
|
|
If the dependency is optional, you can tell Meson not to error out if |
|
the dependency is not found and then do further configuration. |
|
|
|
```meson |
|
opt_dep = dependency('somedep', required : false) |
|
if opt_dep.found() |
|
# Do something. |
|
else |
|
# Do something else. |
|
endif |
|
``` |
|
|
|
You can pass the `opt_dep` variable to target construction functions |
|
whether the actual dependency was found or not. Meson will ignore |
|
non-found dependencies. |
|
|
|
Meson also allows to get variables that are defined in the |
|
`pkg-config` file. This can be done by using the |
|
`get_pkgconfig_variable` function. |
|
|
|
```meson |
|
zdep_prefix = zdep.get_pkgconfig_variable('prefix') |
|
``` |
|
|
|
These variables can also be redefined by passing the `define_variable` |
|
parameter, which might be useful in certain situations: |
|
|
|
```meson |
|
zdep_prefix = zdep.get_pkgconfig_variable('libdir', define_variable: ['prefix', '/tmp']) |
|
``` |
|
|
|
The dependency detector works with all libraries that provide a |
|
`pkg-config` file. Unfortunately several packages don't provide |
|
pkg-config files. Meson has autodetection support for some of these, |
|
and they are described [later in this |
|
page](#dependencies-with-custom-lookup-functionality). |
|
|
|
# Arbitrary variables from dependencies that can be found multiple ways |
|
|
|
*Note* new in 0.51.0 |
|
*new in 0.54.0, the `internal` keyword* |
|
|
|
When you need to get an arbitrary variables from a dependency that can be |
|
found multiple ways and you don't want to constrain the type you can use |
|
the generic `get_variable` method. This currently supports cmake, pkg-config, |
|
and config-tool based variables. |
|
|
|
```meson |
|
foo_dep = dependency('foo') |
|
var = foo_dep.get_variable(cmake : 'CMAKE_VAR', pkgconfig : 'pkg-config-var', configtool : 'get-var', default_value : 'default') |
|
``` |
|
|
|
It accepts the keywords 'cmake', 'pkgconfig', 'pkgconfig_define', |
|
'configtool', 'internal', and 'default_value'. 'pkgconfig_define' works just |
|
like the 'define_variable' argument to `get_pkgconfig_variable`. When this |
|
method is invoked the keyword corresponding to the underlying type of the |
|
dependency will be used to look for a variable. If that variable cannot be |
|
found or if the caller does not provide an argument for the type of |
|
dependency, one of the following will happen: If 'default_value' was provided |
|
that value will be returned, if 'default_value' was not provided then an |
|
error will be raised. |
|
|
|
# Declaring your own |
|
|
|
You can declare your own dependency objects that can be used |
|
interchangeably with dependency objects obtained from the system. The |
|
syntax is straightforward: |
|
|
|
```meson |
|
my_inc = include_directories(...) |
|
my_lib = static_library(...) |
|
my_dep = declare_dependency(link_with : my_lib, |
|
include_directories : my_inc) |
|
``` |
|
|
|
This declares a dependency that adds the given include directories and |
|
static library to any target you use it in. |
|
|
|
# Building dependencies as subprojects |
|
|
|
Many platforms do not provide a system package manager. On these |
|
systems dependencies must be compiled from source. Meson's subprojects |
|
make it simple to use system dependencies when they are available and |
|
to build dependencies manually when they are not. |
|
|
|
To make this work, the dependency must have Meson build definitions |
|
and it must declare its own dependency like this: |
|
|
|
```meson |
|
foo_dep = declare_dependency(...) |
|
``` |
|
|
|
Then any project that wants to use it can write out the following |
|
declaration in their main `meson.build` file. |
|
|
|
```meson |
|
foo_dep = dependency('foo', fallback : ['foo', 'foo_dep']) |
|
``` |
|
|
|
What this declaration means is that first Meson tries to look up the |
|
dependency from the system (such as by using pkg-config). If it is not |
|
available, then it builds subproject named `foo` and from that |
|
extracts a variable `foo_dep`. That means that the return value of |
|
this function is either an external or an internal dependency |
|
object. Since they can be used interchangeably, the rest of the build |
|
definitions do not need to care which one it is. Meson will take care |
|
of all the work behind the scenes to make this work. |
|
|
|
# Dependency method |
|
|
|
You can use the keyword `method` to let meson know what method to use |
|
when searching for the dependency. The default value is `auto`. |
|
Additional dependencies methods are `pkg-config`, `config-tool`, `cmake`, |
|
`system`, `sysconfig`, `qmake`, `extraframework` and `dub`. |
|
|
|
```meson |
|
cups_dep = dependency('cups', method : 'pkg-config') |
|
``` |
|
|
|
The dependency method order for `auto` is: |
|
|
|
1. `pkg-config` |
|
2. `cmake` |
|
3. `extraframework` (OSX only) |
|
|
|
## CMake |
|
|
|
Meson can use the CMake `find_package()` function to detect |
|
dependencies with the builtin `Find<NAME>.cmake` modules and exported |
|
project configurations (usually in `/usr/lib/cmake`). Meson is able |
|
to use both the old-style `<NAME>_LIBRARIES` variables as well as |
|
imported targets. |
|
|
|
It is possible to manually specify a list of CMake targets that should |
|
be used with the `modules` property. However, this step is optional |
|
since meson tries to automatically guess the correct target based on the |
|
name of the dependency. |
|
|
|
Depending on the dependency it may be necessary to explicitly specify |
|
a CMake target with the `modules` property if meson is unable to guess |
|
it automatically. |
|
|
|
```meson |
|
cmake_dep = dependency('ZLIB', method : 'cmake', modules : ['ZLIB::ZLIB']) |
|
``` |
|
|
|
Support for adding additional `COMPONENTS` for the CMake `find_package` lookup |
|
is provided with the `components` kwarg (*introduced in 0.54.0*). All specified |
|
componets will be passed directly to `find_package(COMPONENTS)`. |
|
|
|
Support for packages which require a specified version for CMake |
|
`find_package` to succeed is provided with the `cmake_package_version` kwarg |
|
(*introduced in 0.57.0*). The specified `cmake_package_version` will be |
|
passed directly as the second parameter to `find_package`. |
|
|
|
It is also possible to reuse existing `Find<name>.cmake` files with the |
|
`cmake_module_path` property. Using this property is equivalent to setting the |
|
`CMAKE_MODULE_PATH` variable in CMake. The path(s) given to `cmake_module_path` |
|
should all be relative to the project source directory. Absolute paths |
|
should only be used if the CMake files are not stored in the project itself. |
|
|
|
Additional CMake parameters can be specified with the `cmake_args` property. |
|
|
|
## Dub |
|
|
|
Please understand that meson is only able to find dependencies that |
|
exist in the local Dub repository. You need to manually fetch and |
|
build the target dependencies. |
|
|
|
For `urld`. |
|
``` |
|
dub fetch urld |
|
dub build urld |
|
``` |
|
|
|
Other thing you need to keep in mind is that both meson and Dub need |
|
to be using the same compiler. This can be achieved using Dub's |
|
`-compiler` argument and/or manually setting the `DC` environment |
|
variable when running meson. |
|
``` |
|
dub build urld --compiler=dmd |
|
DC="dmd" meson builddir |
|
``` |
|
|
|
# Dependencies with custom lookup functionality |
|
|
|
Some dependencies have specific detection logic. |
|
|
|
Generic dependency names are case-sensitive<sup>[1](#footnote1)</sup>, |
|
but these dependency names are matched case-insensitively. The |
|
recommended style is to write them in all lower-case. |
|
|
|
In some cases, more than one detection method exists, and the `method` keyword |
|
may be used to select a detection method to use. The `auto` method uses any |
|
checking mechanisms in whatever order meson thinks is best. |
|
|
|
e.g. libwmf and CUPS provide both pkg-config and config-tool support. You can |
|
force one or another via the `method` keyword: |
|
|
|
```meson |
|
cups_dep = dependency('cups', method : 'pkg-config') |
|
wmf_dep = dependency('libwmf', method : 'config-tool') |
|
``` |
|
|
|
## Dependencies using config tools |
|
|
|
[CUPS](#cups), [LLVM](#llvm), [pcap](#pcap), [WxWidgets](#wxwidgets), |
|
[libwmf](#libwmf), [GCrypt](#libgcrypt), [GPGME](#gpgme), and GnuStep either do not provide pkg-config |
|
modules or additionally can be detected via a config tool |
|
(cups-config, llvm-config, libgcrypt-config, etc). Meson has native support for these |
|
tools, and they can be found like other dependencies: |
|
|
|
```meson |
|
pcap_dep = dependency('pcap', version : '>=1.0') |
|
cups_dep = dependency('cups', version : '>=1.4') |
|
llvm_dep = dependency('llvm', version : '>=4.0') |
|
libgcrypt_dep = dependency('libgcrypt', version: '>= 1.8') |
|
gpgme_dep = dependency('gpgme', version: '>= 1.0') |
|
``` |
|
|
|
*Since 0.55.0* Meson won't search $PATH any more for a config tool binary when |
|
cross compiling if the config tool did not have an entry in the cross file. |
|
|
|
## AppleFrameworks |
|
|
|
Use the `modules` keyword to list frameworks required, e.g. |
|
|
|
```meson |
|
dep = dependency('appleframeworks', modules : 'foundation') |
|
``` |
|
|
|
These dependencies can never be found for non-OSX hosts. |
|
|
|
## Blocks |
|
|
|
Enable support for Clang's blocks extension. |
|
|
|
```meson |
|
dep = dependency('blocks') |
|
``` |
|
|
|
*(added 0.52.0)* |
|
|
|
## Boost |
|
|
|
Boost is not a single dependency but rather a group of different |
|
libraries. To use Boost headers-only libraries, simply add Boost as a |
|
dependency. |
|
|
|
```meson |
|
boost_dep = dependency('boost') |
|
exe = executable('myprog', 'file.cc', dependencies : boost_dep) |
|
``` |
|
|
|
To link against boost with Meson, simply list which libraries you |
|
would like to use. |
|
|
|
```meson |
|
boost_dep = dependency('boost', modules : ['thread', 'utility']) |
|
exe = executable('myprog', 'file.cc', dependencies : boost_dep) |
|
``` |
|
|
|
You can call `dependency` multiple times with different modules and |
|
use those to link against your targets. |
|
|
|
If your boost headers or libraries are in non-standard locations you |
|
can set the `BOOST_ROOT`, or the `BOOST_INCLUDEDIR` and `BOOST_LIBRARYDIR` |
|
environment variables. *(added in 0.56.0)* You can also set these |
|
parameters as `boost_root`, `boost_include`, and `boost_librarydir` in your |
|
native or cross machine file. Note that machine file variables are |
|
preferred to environment variables, and that specifying any of these |
|
disables system-wide search for boost. |
|
|
|
You can set the argument `threading` to `single` to use boost |
|
libraries that have been compiled for single-threaded use instead. |
|
|
|
## CUDA |
|
|
|
*(added 0.53.0)* |
|
|
|
Enables compiling and linking against the CUDA Toolkit. The `version` |
|
and `modules` keywords may be passed to request the use of a specific |
|
CUDA Toolkit version and/or additional CUDA libraries, correspondingly: |
|
|
|
```meson |
|
dep = dependency('cuda', version : '>=10', modules : ['cublas']) |
|
``` |
|
|
|
Note that explicitly adding this dependency is only necessary if you are |
|
using CUDA Toolkit from a C/C++ file or project, or if you are utilizing |
|
additional toolkit libraries that need to be explicitly linked to. |
|
|
|
## CUPS |
|
|
|
`method` may be `auto`, `config-tool`, `pkg-config`, `cmake` or `extraframework`. |
|
|
|
## Fortran Coarrays |
|
|
|
*(added 0.50.0)* |
|
|
|
Coarrays are a Fortran language intrinsic feature, enabled by |
|
`dependency('coarray')`. |
|
|
|
GCC will use OpenCoarrays if present to implement coarrays, while Intel and NAG |
|
use internal coarray support. |
|
|
|
## GL |
|
|
|
This finds the OpenGL library in a way appropriate to the platform. |
|
|
|
`method` may be `auto`, `pkg-config` or `system`. |
|
|
|
## GTest and GMock |
|
|
|
GTest and GMock come as sources that must be compiled as part of your |
|
project. With Meson you don't have to care about the details, just |
|
pass `gtest` or `gmock` to `dependency` and it will do everything for |
|
you. If you want to use GMock, it is recommended to use GTest as well, |
|
as getting it to work standalone is tricky. |
|
|
|
You can set the `main` keyword argument to `true` to use the `main()` |
|
function provided by GTest: |
|
|
|
```meson |
|
gtest_dep = dependency('gtest', main : true, required : false) |
|
e = executable('testprog', 'test.cc', dependencies : gtest_dep) |
|
test('gtest test', e) |
|
``` |
|
|
|
## HDF5 |
|
|
|
*(added 0.50.0)* |
|
|
|
HDF5 is supported for C, C++ and Fortran. Because dependencies are |
|
language-specific, you must specify the requested language using the |
|
`language` keyword argument, i.e., |
|
* `dependency('hdf5', language: 'c')` for the C HDF5 headers and libraries |
|
* `dependency('hdf5', language: 'cpp')` for the C++ HDF5 headers and libraries |
|
* `dependency('hdf5', language: 'fortran')` for the Fortran HDF5 headers and libraries |
|
|
|
Meson uses pkg-config to find HDF5. The standard low-level HDF5 function and the `HL` high-level HDF5 functions are linked for each language. |
|
|
|
`method` may be `auto`, `config-tool` or `pkg-config`. |
|
|
|
*New in 0.56.0* the `config-tool` method. |
|
*New in 0.56.0* the dependencies now return proper dependency types and `get_variable` and similar methods should work as expected. |
|
|
|
## libwmf |
|
|
|
*(added 0.44.0)* |
|
|
|
`method` may be `auto`, `config-tool` or `pkg-config`. |
|
|
|
## LLVM |
|
|
|
Meson has native support for LLVM going back to version LLVM version 3.5. |
|
It supports a few additional features compared to other config-tool based |
|
dependencies. |
|
|
|
As of 0.44.0 Meson supports the `static` keyword argument for |
|
LLVM. Before this LLVM >= 3.9 would always dynamically link, while |
|
older versions would statically link, due to a quirk in `llvm-config`. |
|
|
|
`method` may be `auto`, `config-tool`, or `cmake`. |
|
|
|
### Modules, a.k.a. Components |
|
|
|
Meson wraps LLVM's concept of components in it's own modules concept. |
|
When you need specific components you add them as modules as meson |
|
will do the right thing: |
|
|
|
```meson |
|
llvm_dep = dependency('llvm', version : '>= 4.0', modules : ['amdgpu']) |
|
``` |
|
|
|
As of 0.44.0 it can also take optional modules (these will affect the arguments |
|
generated for a static link): |
|
|
|
```meson |
|
llvm_dep = dependency( |
|
'llvm', version : '>= 4.0', modules : ['amdgpu'], optional_modules : ['inteljitevents'], |
|
) |
|
``` |
|
|
|
### Using LLVM tools |
|
When using LLVM as library but also needing its tools, it is often beneficial to use the same version. |
|
This can partially be achieved with the `version` argument of `find_program()`. |
|
However, distributions tend to package different LLVM versions in rather different ways. |
|
Therefore, it is often better to use the llvm dependency directly to retrieve the tools: |
|
|
|
```meson |
|
llvm_dep = dependency('llvm', version : ['>= 8', '< 9']) |
|
llvm_link = find_program(llvm_dep.get_variable(configtool: 'bindir') / 'llvm-link') |
|
``` |
|
|
|
## MPI |
|
|
|
*(added 0.42.0)* |
|
|
|
MPI is supported for C, C++ and Fortran. Because dependencies are |
|
language-specific, you must specify the requested language using the |
|
`language` keyword argument, i.e., |
|
* `dependency('mpi', language: 'c')` for the C MPI headers and libraries |
|
* `dependency('mpi', language: 'cpp')` for the C++ MPI headers and libraries |
|
* `dependency('mpi', language: 'fortran')` for the Fortran MPI headers and libraries |
|
|
|
Meson prefers pkg-config for MPI, but if your MPI implementation does |
|
not provide them, it will search for the standard wrapper executables, |
|
`mpic`, `mpicxx`, `mpic++`, `mpifort`, `mpif90`, `mpif77`. If these |
|
are not in your path, they can be specified by setting the standard |
|
environment variables `MPICC`, `MPICXX`, `MPIFC`, `MPIF90`, or |
|
`MPIF77`, during configuration. It will also try to use the Microsoft |
|
implementation on windows via the `system` method. |
|
|
|
`method` may be `auto`, `config-tool`, `pkg-config` or `system`. |
|
|
|
*New in 0.54.0* The `config-tool` and `system` method values. Previous |
|
versions would always try `pkg-config`, then `config-tool`, then `system`. |
|
|
|
## NetCDF |
|
|
|
*(added 0.50.0)* |
|
|
|
NetCDF is supported for C, C++ and Fortran. Because NetCDF dependencies are |
|
language-specific, you must specify the requested language using the |
|
`language` keyword argument, i.e., |
|
* `dependency('netcdf', language: 'c')` for the C NetCDF headers and libraries |
|
* `dependency('netcdf', language: 'cpp')` for the C++ NetCDF headers and libraries |
|
* `dependency('netcdf', language: 'fortran')` for the Fortran NetCDF headers and libraries |
|
|
|
Meson uses pkg-config to find NetCDF. |
|
|
|
|
|
## OpenMP |
|
|
|
*(added 0.46.0)* |
|
|
|
This dependency selects the appropriate compiler flags and/or libraries to use |
|
for OpenMP support. |
|
|
|
The `language` keyword may used. |
|
|
|
## pcap |
|
|
|
*(added 0.42.0)* |
|
|
|
`method` may be `auto`, `config-tool` or `pkg-config`. |
|
|
|
## libgcrypt |
|
|
|
*(added 0.49.0)* |
|
|
|
`method` may be `auto`, `config-tool` or `pkg-config`. |
|
|
|
## GPGME |
|
|
|
*(added 0.51.0)* |
|
|
|
`method` may be `auto`, `config-tool` or `pkg-config`. |
|
|
|
## Python3 |
|
|
|
Python3 is handled specially by meson: |
|
1. Meson tries to use `pkg-config`. |
|
2. If `pkg-config` fails meson uses a fallback: |
|
- On Windows the fallback is the current `python3` interpreter. |
|
- On OSX the fallback is a framework dependency from `/Library/Frameworks`. |
|
|
|
Note that `python3` found by this dependency might differ from the one used in |
|
`python3` module because modules uses the current interpreter, but dependency tries |
|
`pkg-config` first. |
|
|
|
`method` may be `auto`, `extraframework`, `pkg-config` or `sysconfig` |
|
|
|
## Qt4 & Qt5 |
|
|
|
Meson has native Qt support. Its usage is best demonstrated with an |
|
example. |
|
|
|
```meson |
|
qt5_mod = import('qt5') |
|
qt5widgets = dependency('qt5', modules : 'Widgets') |
|
|
|
processed = qt5_mod.preprocess( |
|
moc_headers : 'mainWindow.h', # Only headers that need moc should be put here |
|
moc_sources : 'helperFile.cpp', # must have #include"moc_helperFile.cpp" |
|
ui_files : 'mainWindow.ui', |
|
qresources : 'resources.qrc', |
|
) |
|
|
|
q5exe = executable('qt5test', |
|
sources : ['main.cpp', |
|
'mainWindow.cpp', |
|
processed], |
|
dependencies: qt5widgets) |
|
``` |
|
|
|
Here we have an UI file created with Qt Designer and one source and |
|
header file each that require preprocessing with the `moc` tool. We |
|
also define a resource file to be compiled with `rcc`. We just have to |
|
tell Meson which files are which and it will take care of invoking all |
|
the necessary tools in the correct order, which is done with the |
|
`preprocess` method of the `qt5` module. Its output is simply put in |
|
the list of sources for the target. The `modules` keyword of |
|
`dependency` works just like it does with Boost. It tells which |
|
subparts of Qt the program uses. |
|
|
|
You can set the `main` keyword argument to `true` to use the `WinMain()` |
|
function provided by qtmain static library (this argument does nothing on platforms |
|
other than Windows). |
|
|
|
Setting the optional `private_headers` keyword to true adds the private header |
|
include path of the given module(s) to the compiler flags. (since v0.47.0) |
|
|
|
**Note** using private headers in your project is a bad idea, do so at your own |
|
risk. |
|
|
|
`method` may be `auto`, `pkg-config` or `qmake`. |
|
|
|
## SDL2 |
|
|
|
SDL2 can be located using `pkg-confg`, the `sdl2-config` config tool, or as an |
|
OSX framework. |
|
|
|
`method` may be `auto`, `config-tool`, `extraframework` or `pkg-config`. |
|
|
|
## Threads |
|
|
|
This dependency selects the appropriate compiler flags and/or libraries to use |
|
for thread support. |
|
|
|
See [threads](Threads.md). |
|
|
|
## Valgrind |
|
|
|
Meson will find valgrind using `pkg-config`, but only uses the compilation flags |
|
and avoids trying to link with it's non-PIC static libs. |
|
|
|
## Vulkan |
|
|
|
*(added 0.42.0)* |
|
|
|
Vulkan can be located using `pkg-config`, or the `VULKAN_SDK` environment variable. |
|
|
|
`method` may be `auto`, `pkg-config` or `system`. |
|
|
|
## WxWidgets |
|
|
|
Similar to [Boost](#boost), WxWidgets is not a single library but rather |
|
a collection of modules. WxWidgets is supported via `wx-config`. |
|
Meson substitutes `modules` to `wx-config` invocation, it generates |
|
- `compile_args` using `wx-config --cxxflags $modules...` |
|
- `link_args` using `wx-config --libs $modules...` |
|
|
|
### Example |
|
|
|
```meson |
|
wx_dep = dependency( |
|
'wxwidgets', version : '>=3.0.0', modules : ['std', 'stc'], |
|
) |
|
``` |
|
|
|
```shell |
|
# compile_args: |
|
$ wx-config --cxxflags std stc |
|
|
|
# link_args: |
|
$ wx-config --libs std stc |
|
``` |
|
|
|
## Shaderc |
|
|
|
*(added 0.51.0)* |
|
|
|
Shaderc currently does not ship with any means of detection. Nevertheless, Meson |
|
can try to detect it using `pkg-config`, but will default to looking for the |
|
appropriate library manually. If the `static` keyword argument is `true`, |
|
`shaderc_combined` is preferred. Otherwise, `shaderc_shared` is preferred. Note |
|
that it is not possible to obtain the shaderc version using this method. |
|
|
|
`method` may be `auto`, `pkg-config` or `system`. |
|
|
|
## Zlib |
|
|
|
Zlib ships with pkg-config and cmake support, but on some operating systems |
|
(windows, macOs, FreeBSD, dragonflybsd), it is provided as part of the base |
|
operating system without pkg-config support. The new System finder can be used |
|
on these OSes to link with the bundled version. |
|
|
|
`method` may be `auto`, `pkg-config`, `cmake`, or `system`. |
|
|
|
*New in 0.54.0* the `system` method. |
|
|
|
## Curses |
|
|
|
*(Since 0.54.0)* |
|
|
|
Curses (and ncurses) are a cross platform pain in the butt. Meson wraps up |
|
these dependencies in the `curses` dependency. This covers both `ncurses` |
|
(preferred) and other curses implementations. |
|
|
|
`method` may be `auto`, `pkg-config`, `config-tool`, or `system`. |
|
|
|
*New in 0.56.0* The `config-tool` and `system` methods. |
|
|
|
<hr> |
|
<a name="footnote1">1</a>: They may appear to be case-insensitive, if the |
|
underlying file system happens to be case-insensitive.
|
|
|