This commit is contained in:
swrup 2025-11-11 02:07:51 +01:00
parent aa2ff7b2f0
commit 2f3113f55d
11742 changed files with 1223940 additions and 0 deletions

View file

@ -0,0 +1,72 @@
# Test that .cmxs are installed with the executable bit set
$ cat >dune-project <<EOF
> (lang dune 2.8)
> (package (name foo))
> EOF
$ cat >dune <<EOF
> (library
> (public_name foo))
> EOF
$ cat >foo.ml <<EOF
> let x = "foo"
> EOF
$ dune build @install
$ test -x _build/install/default/lib/foo/foo.cmxs
$ dune install --prefix prefix --display short
Installing prefix/lib/foo/META
Installing prefix/lib/foo/dune-package
Installing prefix/lib/foo/foo.a
Installing prefix/lib/foo/foo.cma
Installing prefix/lib/foo/foo.cmi
Installing prefix/lib/foo/foo.cmt
Installing prefix/lib/foo/foo.cmx
Installing prefix/lib/foo/foo.cmxa
Installing prefix/lib/foo/foo.ml
Installing prefix/lib/foo/foo.cmxs
$ test -x prefix/lib/foo/foo.cmxs
Test that we can cope with the situation where a destination is an empty
directory instead of a file.
$ rm -rf prefix
$ mkdir -p prefix/lib/foo/foo.a
$ dune install --prefix prefix --display short
Installing prefix/lib/foo/META
Installing prefix/lib/foo/dune-package
Deleting empty directory prefix/lib/foo/foo.a
Installing prefix/lib/foo/foo.a
Installing prefix/lib/foo/foo.cma
Installing prefix/lib/foo/foo.cmi
Installing prefix/lib/foo/foo.cmt
Installing prefix/lib/foo/foo.cmx
Installing prefix/lib/foo/foo.cmxa
Installing prefix/lib/foo/foo.ml
Installing prefix/lib/foo/foo.cmxs
Test the error message if a destination is a non-empty directory instead of a file.
$ rm -rf prefix
$ mkdir -p prefix/lib/foo/foo.a
$ touch prefix/lib/foo/foo.a/file
$ dune install --prefix prefix --display short
Installing prefix/lib/foo/META
Installing prefix/lib/foo/dune-package
Error: Please delete non-empty directory prefix/lib/foo/foo.a manually.
[1]
Test the error message if a destination is a file instead of a directory.
$ rm -rf prefix
$ mkdir -p prefix/lib; touch prefix/lib/foo
$ dune install --prefix prefix --display short
Installing prefix/lib/foo/META
Error: Please delete file prefix/lib/foo manually.
[1]

View file

@ -0,0 +1,47 @@
# Test installation display output
$ cat >dune-project <<EOF
> (lang dune 3.7)
> (package (name foo))
> EOF
$ cat >dune <<EOF
> (library
> (public_name foo))
> EOF
$ cat >foo.ml <<EOF
> let x = "foo"
> EOF
$ dune build @install
dune install / uninstall should not output any messages by default:
$ dune install --prefix prefix -p foo
$ dune uninstall --prefix prefix -p foo
and for comparison here is the output with --display short:
$ dune install --prefix another_prefix -p foo --display short
Installing another_prefix/lib/foo/META
Installing another_prefix/lib/foo/dune-package
Installing another_prefix/lib/foo/foo.a
Installing another_prefix/lib/foo/foo.cma
Installing another_prefix/lib/foo/foo.cmi
Installing another_prefix/lib/foo/foo.cmt
Installing another_prefix/lib/foo/foo.cmx
Installing another_prefix/lib/foo/foo.cmxa
Installing another_prefix/lib/foo/foo.ml
Installing another_prefix/lib/foo/foo.cmxs
$ dune uninstall --prefix another_prefix -p foo --display short
Deleting another_prefix/lib/foo/META
Deleting another_prefix/lib/foo/dune-package
Deleting another_prefix/lib/foo/foo.a
Deleting another_prefix/lib/foo/foo.cma
Deleting another_prefix/lib/foo/foo.cmi
Deleting another_prefix/lib/foo/foo.cmt
Deleting another_prefix/lib/foo/foo.cmx
Deleting another_prefix/lib/foo/foo.cmxa
Deleting another_prefix/lib/foo/foo.ml
Deleting another_prefix/lib/foo/foo.cmxs
Deleting empty directory another_prefix/lib/foo

View file

@ -0,0 +1,103 @@
Test paths on public libraries with `.` are correct
$ mkdir a
$ cat > a/dune-project <<EOF
> (lang dune 3.7)
> (package (name a))
> EOF
$ cat > a/dune <<EOF
> (library
> (name a)
> (public_name a.sub))
> EOF
$ cat > a/foo.ml <<EOF
> let x = "foo"
> EOF
$ dune build a.install --root a
Entering directory 'a'
Leaving directory 'a'
$ cat a/_build/default/a.install
lib: [
"_build/install/default/lib/a/META"
"_build/install/default/lib/a/dune-package"
"_build/install/default/lib/a/sub/a.a" {"sub/a.a"}
"_build/install/default/lib/a/sub/a.cma" {"sub/a.cma"}
"_build/install/default/lib/a/sub/a.cmi" {"sub/a.cmi"}
"_build/install/default/lib/a/sub/a.cmt" {"sub/a.cmt"}
"_build/install/default/lib/a/sub/a.cmx" {"sub/a.cmx"}
"_build/install/default/lib/a/sub/a.cmxa" {"sub/a.cmxa"}
"_build/install/default/lib/a/sub/a.ml" {"sub/a.ml"}
"_build/install/default/lib/a/sub/a__Foo.cmi" {"sub/a__Foo.cmi"}
"_build/install/default/lib/a/sub/a__Foo.cmt" {"sub/a__Foo.cmt"}
"_build/install/default/lib/a/sub/a__Foo.cmx" {"sub/a__Foo.cmx"}
"_build/install/default/lib/a/sub/foo.ml" {"sub/foo.ml"}
]
libexec: [
"_build/install/default/lib/a/sub/a.cmxs" {"sub/a.cmxs"}
]
$ cat a/_build/install/default/lib/a/dune-package | grep path
(source (path A) (impl (path sub/a.ml-gen))))
(source (path Foo) (impl (path sub/foo.ml))))))
$ mkdir -p b/child
$ cat > b/dune-project <<EOF
> (lang dune 3.7)
> (package (name b))
> EOF
$ cat > b/dune <<EOF
> (include_subdirs qualified)
> (library
> (name b)
> (public_name b.sub))
> EOF
$ cat > b/foo.ml <<EOF
> let x = "foo"
> EOF
$ cat > b/child/bar.ml <<EOF
> let x = "bar"
> EOF
$ dune build b.install --root b
Entering directory 'b'
Leaving directory 'b'
$ cat b/_build/default/b.install
lib: [
"_build/install/default/lib/b/META"
"_build/install/default/lib/b/dune-package"
"_build/install/default/lib/b/sub/b.a" {"sub/b.a"}
"_build/install/default/lib/b/sub/b.cma" {"sub/b.cma"}
"_build/install/default/lib/b/sub/b.cmi" {"sub/b.cmi"}
"_build/install/default/lib/b/sub/b.cmt" {"sub/b.cmt"}
"_build/install/default/lib/b/sub/b.cmx" {"sub/b.cmx"}
"_build/install/default/lib/b/sub/b.cmxa" {"sub/b.cmxa"}
"_build/install/default/lib/b/sub/b.ml" {"sub/b.ml"}
"_build/install/default/lib/b/sub/b__Child.cmi" {"sub/b__Child.cmi"}
"_build/install/default/lib/b/sub/b__Child.cmt" {"sub/b__Child.cmt"}
"_build/install/default/lib/b/sub/b__Child.cmx" {"sub/b__Child.cmx"}
"_build/install/default/lib/b/sub/b__Child__Bar.cmi" {"sub/b__Child__Bar.cmi"}
"_build/install/default/lib/b/sub/b__Child__Bar.cmt" {"sub/b__Child__Bar.cmt"}
"_build/install/default/lib/b/sub/b__Child__Bar.cmx" {"sub/b__Child__Bar.cmx"}
"_build/install/default/lib/b/sub/b__Foo.cmi" {"sub/b__Foo.cmi"}
"_build/install/default/lib/b/sub/b__Foo.cmt" {"sub/b__Foo.cmt"}
"_build/install/default/lib/b/sub/b__Foo.cmx" {"sub/b__Foo.cmx"}
"_build/install/default/lib/b/sub/child/bar.ml" {"sub/child/bar.ml"}
"_build/install/default/lib/b/sub/child/child.ml" {"sub/child/child.ml"}
"_build/install/default/lib/b/sub/foo.ml" {"sub/foo.ml"}
]
libexec: [
"_build/install/default/lib/b/sub/b.cmxs" {"sub/b.cmxs"}
]
$ cat b/_build/install/default/lib/b/dune-package | grep path
(source (path B) (impl (path sub/b.ml-gen))))
(source (path Child Child) (impl (path sub/b__Child.ml-gen))))
(source (path Child Bar) (impl (path sub/child/bar.ml))))))
(source (path Foo) (impl (path sub/foo.ml))))))

View file

@ -0,0 +1,41 @@
Globs with absolute paths result in an error
$ cat >dune-project <<EOF
> (lang dune 3.6)
> (package (name foo))
> EOF
Put $PWD in a file that can be read with the %{read:...} pform, so that the underline
in the error message is of consisntent length on different systems.
$ printf $PWD > pwd
$ touch foo.txt bar.txt
Absolute paths work in non-recursive globs, but are not permitted in the install stanza.
$ cat >dune <<EOF
> (install
> (files (glob_files %{read:pwd}/*.txt))
> (section share))
> EOF
$ dune build @install
File "dune", line 2, characters 20-37:
2 | (files (glob_files %{read:pwd}/*.txt))
^^^^^^^^^^^^^^^^^
Error: Absolute paths are not allowed in the install stanza.
[1]
Absolute paths are not supported in recursive globs.
$ cat >dune <<EOF
> (install
> (files (glob_files_rec %{read:pwd}/*.txt))
> (section share))
> EOF
$ dune build @install
File "dune", line 2, characters 24-41:
2 | (files (glob_files_rec %{read:pwd}/*.txt))
^^^^^^^^^^^^^^^^^
Error: Absolute paths in recursive globs are not supported.
[1]

View file

@ -0,0 +1,33 @@
Test that the `glob_files` terms are only accepted in the `files` field and not in
the `dirs` field
$ cat >dune-project <<EOF
> (lang dune 3.6)
> (package (name foo))
> EOF
$ cat >dune <<EOF
> (install
> (dirs (glob_files *))
> (section share))
> EOF
$ dune build @install
File "dune", line 2, characters 7-21:
2 | (dirs (glob_files *))
^^^^^^^^^^^^^^
Error: Invalid format, <name> or (<name> as <install-as>) expected
[1]
$ cat >dune <<EOF
> (install
> (dirs (glob_files_rec *))
> (section share))
> EOF
$ dune build @install
File "dune", line 2, characters 7-25:
2 | (dirs (glob_files_rec *))
^^^^^^^^^^^^^^^^^^
Error: Invalid format, <name> or (<name> as <install-as>) expected
[1]

View file

@ -0,0 +1,69 @@
Test that `glob_files_rec` can recursively find files
$ cat >dune-project <<EOF
> (lang dune 3.5)
> (package (name foo))
> EOF
$ cat >dune <<EOF
> (install
> (files (glob_files_rec b/*.txt))
> (section share))
> EOF
Make a file outside of the "b" directory. This file should be skipped.
$ touch a.txt
Create a hierarchy of files and directories which should be included.
$ mkdir b
$ touch b/b.txt
$ mkdir b/c
$ touch b/c/c.txt
Make sure we don't crash on empty directories.
$ mkdir b/c/empty-dir
Add some files which don't match the glob.
$ touch b/b
$ touch b/txt
$ mkdir b/d
$ touch b/d/d
$ dune build
File "dune", line 2, characters 8-32:
2 | (files (glob_files_rec b/*.txt))
^^^^^^^^^^^^^^^^^^^^^^^^
Error: 'glob_files_rec' is only available since version 3.6 of the dune
language. Please update your dune-project file to have (lang dune 3.6).
[1]
$ cat >dune-project <<EOF
> (lang dune 3.6)
> (package (name foo))
> EOF
$ dune build
$ cat _build/default/foo.install
lib: [
"_build/install/default/lib/foo/META"
"_build/install/default/lib/foo/dune-package"
]
share: [
"_build/install/default/share/foo/b/b.txt" {"b/b.txt"}
"_build/install/default/share/foo/b/c/c.txt" {"b/c/c.txt"}
]
$ find _build/install | sort
_build/install
_build/install/default
_build/install/default/lib
_build/install/default/lib/foo
_build/install/default/lib/foo/META
_build/install/default/lib/foo/dune-package
_build/install/default/share
_build/install/default/share/foo
_build/install/default/share/foo/b
_build/install/default/share/foo/b/b.txt
_build/install/default/share/foo/b/c
_build/install/default/share/foo/b/c/c.txt

View file

@ -0,0 +1,78 @@
Install a glob pattern that uses a relative path.
Test that dune detects an error when we use a pattern such as ../foo/* in the
install stanza. The problem with this pattern is its destination refers to a
path outside the package's install directory.
$ cat >dune-project <<EOF
> (lang dune 3.11)
> (package (name foo))
> EOF
$ mkdir -p stanza stuff/xy
$ touch stuff/foo.txt stuff/xy/bar.txt
normal install stanza in the share directory of the package:
$ cat >dune <<EOF
> (install
> (section share)
> (files stuff/foo.txt))
> EOF
Incorrect install stanza that would place files outside the package's install directory
$ cat >stanza/dune <<EOF
> (install
> (files (glob_files_rec ../stuff/*.txt))
> (section share))
> EOF
$ dune build foo.install
File "stanza/dune", line 2, characters 24-38:
2 | (files (glob_files_rec ../stuff/*.txt))
^^^^^^^^^^^^^^
Warning: The destination path ../stuff/foo.txt begins with .. which will
become an error in a future version of Dune. Destinations of files in install
stanzas beginning with .. will be disallowed to prevent a package's installed
files from escaping that package's install directories.
Hint: To disable this warning, add the following to your dune-project file:
(warnings (escaping_paths_in_install_stanza disabled))
File "stanza/dune", line 2, characters 24-38:
2 | (files (glob_files_rec ../stuff/*.txt))
^^^^^^^^^^^^^^
Warning: The destination path ../stuff/xy/bar.txt begins with .. which will
become an error in a future version of Dune. Destinations of files in install
stanzas beginning with .. will be disallowed to prevent a package's installed
files from escaping that package's install directories.
Hint: To disable this warning, add the following to your dune-project file:
(warnings (escaping_paths_in_install_stanza disabled))
Test that we can disable the warning:
$ cat >>dune-project <<EOF
> (warnings (escaping_paths_in_install_stanza disabled))
> EOF
$ dune build foo.install
Now we remove disabling the warning
$ sed -i.bak '$d' dune-project
Correction to the above which uses `with_prefix` to change the install destination:
$ cat >stanza/dune <<EOF
> (install
> (files (glob_files_rec (../stuff/*.txt with_prefix stuff)))
> (section share))
> EOF
$ dune build foo.install
$ grep txt _build/default/foo.install
"_build/install/default/share/foo/foo.txt"
"_build/install/default/share/foo/stuff/foo.txt" {"stuff/foo.txt"}
"_build/install/default/share/foo/stuff/xy/bar.txt" {"stuff/xy/bar.txt"}
$ dune install foo --prefix _foo
$ find _foo | sort | grep txt
_foo/share/foo/foo.txt
_foo/share/foo/stuff/foo.txt
_foo/share/foo/stuff/xy/bar.txt

View file

@ -0,0 +1,32 @@
Make sure we can handle globs in dune files inside subdirectories
$ cat >dune-project <<EOF
> (lang dune 3.6)
> (package (name foo))
> EOF
$ mkdir -p sub-dir/x/y/z
$ cat >sub-dir/dune <<EOF
> (install
> (files a.txt (glob_files_rec x/*.txt))
> (section share))
> EOF
$ touch sub-dir/a.txt
$ touch sub-dir/b.txt
$ touch sub-dir/x/foo.txt
$ touch sub-dir/x/y/foo.txt
$ touch sub-dir/x/y/z/foo.txt
$ dune build @sub-dir/all
$ find _build/default/sub-dir | sort
_build/default/sub-dir
_build/default/sub-dir/a.txt
_build/default/sub-dir/x
_build/default/sub-dir/x/foo.txt
_build/default/sub-dir/x/y
_build/default/sub-dir/x/y/foo.txt
_build/default/sub-dir/x/y/z
_build/default/sub-dir/x/y/z/foo.txt

View file

@ -0,0 +1,5 @@
(install
(files
(glob_files style/*.css)
(glob_files_rec content/*.html))
(section share))

View file

@ -0,0 +1,2 @@
(lang dune 3.6)
(package (name blog))

View file

@ -0,0 +1,36 @@
Simple example of installing website files
$ dune build @install
$ cat _build/default/blog.install
lib: [
"_build/install/default/lib/blog/META"
"_build/install/default/lib/blog/dune-package"
]
share: [
"_build/install/default/share/blog/content/about.html" {"content/about.html"}
"_build/install/default/share/blog/content/posts/1.html" {"content/posts/1.html"}
"_build/install/default/share/blog/content/posts/2.html" {"content/posts/2.html"}
"_build/install/default/share/blog/content/posts/3.html" {"content/posts/3.html"}
"_build/install/default/share/blog/style/bar.css" {"style/bar.css"}
"_build/install/default/share/blog/style/foo.css" {"style/foo.css"}
]
$ find _build/install | sort
_build/install
_build/install/default
_build/install/default/lib
_build/install/default/lib/blog
_build/install/default/lib/blog/META
_build/install/default/lib/blog/dune-package
_build/install/default/share
_build/install/default/share/blog
_build/install/default/share/blog/content
_build/install/default/share/blog/content/about.html
_build/install/default/share/blog/content/posts
_build/install/default/share/blog/content/posts/1.html
_build/install/default/share/blog/content/posts/2.html
_build/install/default/share/blog/content/posts/3.html
_build/install/default/share/blog/style
_build/install/default/share/blog/style/bar.css
_build/install/default/share/blog/style/foo.css

View file

@ -0,0 +1,186 @@
Examples of the with-prefix feature
$ touch a.txt b.txt c.txt d.md e.md
$ cat >dune <<EOF
> (install
> (files (glob_files (*.txt with_prefix bar)))
> (section share))
> EOF
Test that the feature is unavailable before 3.11
$ cat >dune-project <<EOF
> (lang dune 3.10)
> (package
> (name foo))
> EOF
$ dune build foo.install && cat _build/default/foo.install
File "dune", line 2, characters 20-43:
2 | (files (glob_files (*.txt with_prefix bar)))
^^^^^^^^^^^^^^^^^^^^^^^
Error: This syntax is only available since version 3.11 of the dune language.
Please update your dune-project file to have (lang dune 3.11).
[1]
Basic example of using this feature:
$ cat >dune-project <<EOF
> (lang dune 3.11)
> (package
> (name foo))
> EOF
$ dune build foo.install && cat _build/default/foo.install
lib: [
"_build/install/default/lib/foo/META"
"_build/install/default/lib/foo/dune-package"
]
share: [
"_build/install/default/share/foo/bar/a.txt" {"bar/a.txt"}
"_build/install/default/share/foo/bar/b.txt" {"bar/b.txt"}
"_build/install/default/share/foo/bar/c.txt" {"bar/c.txt"}
]
Test with multiple with_prefix blocks in a single files entry:
$ cat >dune <<EOF
> (install
> (files
> (glob_files (*.txt with_prefix txt))
> (glob_files (*.md with_prefix md)))
> (section share))
> EOF
$ dune build foo.install && cat _build/default/foo.install
lib: [
"_build/install/default/lib/foo/META"
"_build/install/default/lib/foo/dune-package"
]
share: [
"_build/install/default/share/foo/md/d.md" {"md/d.md"}
"_build/install/default/share/foo/md/e.md" {"md/e.md"}
"_build/install/default/share/foo/txt/a.txt" {"txt/a.txt"}
"_build/install/default/share/foo/txt/b.txt" {"txt/b.txt"}
"_build/install/default/share/foo/txt/c.txt" {"txt/c.txt"}
]
Use "." as the prefix:
$ cat >dune <<EOF
> (install
> (files (glob_files (*.txt with_prefix .)))
> (section share))
> EOF
$ dune build foo.install && cat _build/default/foo.install
lib: [
"_build/install/default/lib/foo/META"
"_build/install/default/lib/foo/dune-package"
]
share: [
"_build/install/default/share/foo/a.txt" {"./a.txt"}
"_build/install/default/share/foo/b.txt" {"./b.txt"}
"_build/install/default/share/foo/c.txt" {"./c.txt"}
]
Use a pform in the prefix:
$ printf baz > prefix
$ cat >dune <<EOF
> (install
> (files (glob_files (*.txt with_prefix %{read:prefix})))
> (section share))
> EOF
$ dune build foo.install && cat _build/default/foo.install
lib: [
"_build/install/default/lib/foo/META"
"_build/install/default/lib/foo/dune-package"
]
share: [
"_build/install/default/share/foo/baz/a.txt" {"baz/a.txt"}
"_build/install/default/share/foo/baz/b.txt" {"baz/b.txt"}
"_build/install/default/share/foo/baz/c.txt" {"baz/c.txt"}
]
Use a prefix with a recursive glob:
$ mkdir -p a/b/c
$ touch a/x.txt a/b/y.txt a/b/c/z.txt
$ cat >dune <<EOF
> (install
> (files (glob_files_rec (*.txt with_prefix qux)))
> (section share))
> EOF
$ dune build foo.install && cat _build/default/foo.install
lib: [
"_build/install/default/lib/foo/META"
"_build/install/default/lib/foo/dune-package"
]
share: [
"_build/install/default/share/foo/qux/a.txt" {"qux/a.txt"}
"_build/install/default/share/foo/qux/a/b/c/z.txt" {"qux/a/b/c/z.txt"}
"_build/install/default/share/foo/qux/a/b/y.txt" {"qux/a/b/y.txt"}
"_build/install/default/share/foo/qux/a/x.txt" {"qux/a/x.txt"}
"_build/install/default/share/foo/qux/b.txt" {"qux/b.txt"}
"_build/install/default/share/foo/qux/c.txt" {"qux/c.txt"}
]
Demonstrating behaviour of `with_prefix` on globs with a prefix:
$ mkdir -p path/to/files
$ touch path/to/files/foo.txt path/to/files/bar.txt path/to/files/baz.txt
$ cat >dune <<EOF
> (install
> (files (glob_files (path/to/files/*.txt with_prefix some/new/path/)))
> (section share))
> EOF
$ dune build foo.install && cat _build/default/foo.install
lib: [
"_build/install/default/lib/foo/META"
"_build/install/default/lib/foo/dune-package"
]
share: [
"_build/install/default/share/foo/some/new/path/bar.txt" {"some/new/path/bar.txt"}
"_build/install/default/share/foo/some/new/path/baz.txt" {"some/new/path/baz.txt"}
"_build/install/default/share/foo/some/new/path/foo.txt" {"some/new/path/foo.txt"}
]
Replacing the prefix with the empty string works the same as with ".".
$ cat >dune <<EOF
> (install
> (files (glob_files_rec (*.txt with_prefix "")))
> (section share))
> EOF
$ dune build foo.install && cat _build/default/foo.install
lib: [
"_build/install/default/lib/foo/META"
"_build/install/default/lib/foo/dune-package"
]
share: [
"_build/install/default/share/foo/a.txt"
"_build/install/default/share/foo/a/b/c/z.txt" {"a/b/c/z.txt"}
"_build/install/default/share/foo/a/b/y.txt" {"a/b/y.txt"}
"_build/install/default/share/foo/a/x.txt" {"a/x.txt"}
"_build/install/default/share/foo/b.txt"
"_build/install/default/share/foo/c.txt"
"_build/install/default/share/foo/path/to/files/bar.txt" {"path/to/files/bar.txt"}
"_build/install/default/share/foo/path/to/files/baz.txt" {"path/to/files/baz.txt"}
"_build/install/default/share/foo/path/to/files/foo.txt" {"path/to/files/foo.txt"}
]
It's an error to use an absolute path as the prefix.
$ cat >dune <<EOF
> (install
> (files (glob_files_rec (*.txt with_prefix /some/absolute/path)))
> (section share))
> EOF
$ dune build foo.install && cat _build/default/foo.install
File "dune", line 2, characters 43-62:
2 | (files (glob_files_rec (*.txt with_prefix /some/absolute/path)))
^^^^^^^^^^^^^^^^^^^
Error: Absolute paths are not allowed in the install stanza.
[1]
The root directory is treated like an absolute path (ie. it's an error).
$ cat >dune <<EOF
> (install
> (files (glob_files_rec (*.txt with_prefix /)))
> (section share))
> EOF
$ dune build foo.install && cat _build/default/foo.install
File "dune", line 2, characters 43-44:
2 | (files (glob_files_rec (*.txt with_prefix /)))
^
Error: Absolute paths are not allowed in the install stanza.
[1]

View file

@ -0,0 +1,53 @@
Simple example of using a glob to specify files to install
$ cat >dune-project <<EOF
> (lang dune 3.5)
> (package (name foo))
> EOF
$ cat >dune <<EOF
> (install
> (files (glob_files *.txt))
> (section share))
> EOF
$ touch a.txt b.txt c.txt
$ dune build @install
File "dune", line 2, characters 8-26:
2 | (files (glob_files *.txt))
^^^^^^^^^^^^^^^^^^
Error: 'glob_files' is only available since version 3.6 of the dune language.
Please update your dune-project file to have (lang dune 3.6).
[1]
$ cat >dune-project <<EOF
> (lang dune 3.6)
> (package (name foo))
> EOF
$ dune build @install
$ cat _build/default/foo.install
lib: [
"_build/install/default/lib/foo/META"
"_build/install/default/lib/foo/dune-package"
]
share: [
"_build/install/default/share/foo/a.txt"
"_build/install/default/share/foo/b.txt"
"_build/install/default/share/foo/c.txt"
]
$ find _build/install | sort
_build/install
_build/install/default
_build/install/default/lib
_build/install/default/lib/foo
_build/install/default/lib/foo/META
_build/install/default/lib/foo/dune-package
_build/install/default/share
_build/install/default/share/foo
_build/install/default/share/foo/a.txt
_build/install/default/share/foo/b.txt
_build/install/default/share/foo/c.txt

View file

@ -0,0 +1,43 @@
Including a file in the install stanza which includes another file
$ cat >dune-project <<EOF
> (lang dune 3.5)
> (package (name hello))
> EOF
$ cat >dune <<EOF
> (executable
> (public_name hello))
>
> (install
> (files (include foo.sexp))
> (section share))
> EOF
$ cat >hello.ml <<EOF
> let () = print_endline "Hello, World!"
> EOF
$ cat >foo.sexp <<EOF
> ((include bar.sexp))
> EOF
$ cat >bar.sexp <<EOF
> (a.txt)
> EOF
$ touch a.txt
$ dune build @install
$ cat _build/default/hello.install
lib: [
"_build/install/default/lib/hello/META"
"_build/install/default/lib/hello/dune-package"
]
bin: [
"_build/install/default/bin/hello"
]
share: [
"_build/install/default/share/hello/a.txt"
]

View file

@ -0,0 +1,36 @@
Example of including a file in the dirs field of the install stanza
$ cat >dune-project <<EOF
> (lang dune 3.5)
> (package (name hello))
> (using directory-targets 0.1)
> EOF
$ cat >dune <<EOF
> (install
> (dirs (include baz.sexp))
> (section share))
> EOF
$ mkdir -p foo
$ cat >foo/dune <<EOF
> (rule
> (target (dir bar))
> (action (bash "mkdir %{target} && touch %{target}/a")))
> EOF
$ cat >baz.sexp <<EOF
> (foo/bar)
> EOF
$ dune build @install
$ cat _build/default/hello.install
lib: [
"_build/install/default/lib/hello/META"
"_build/install/default/lib/hello/dune-package"
]
share: [
"_build/install/default/share/hello/bar/a" {"bar/a"}
]

View file

@ -0,0 +1,39 @@
Include a file which contains the (foo as bar) syntax for renaming a file
$ cat >dune-project <<EOF
> (lang dune 3.5)
> (package (name hello))
> EOF
$ cat >dune <<EOF
> (executable
> (public_name hello))
>
> (install
> (files (include foo.sexp))
> (section share))
> EOF
$ cat >hello.ml <<EOF
> let () = print_endline "Hello, World!"
> EOF
$ cat >foo.sexp <<EOF
> ((a.txt as b/c.txt))
> EOF
$ touch a.txt
$ dune build @install
$ cat _build/default/hello.install
lib: [
"_build/install/default/lib/hello/META"
"_build/install/default/lib/hello/dune-package"
]
bin: [
"_build/install/default/bin/hello"
]
share: [
"_build/install/default/share/hello/b/c.txt" {"b/c.txt"}
]

View file

@ -0,0 +1,40 @@
Including a file in the install stanza which is generated by a rule
$ cat >dune-project <<EOF
> (lang dune 3.5)
> (package (name hello))
> EOF
$ cat >dune <<EOF
> (executable
> (public_name hello))
>
> (rule
> (target foo.sexp)
> (action
> (with-stdout-to foo.sexp (echo "(a.txt)"))))
>
> (install
> (files (include foo.sexp))
> (section share))
> EOF
$ cat >hello.ml <<EOF
> let () = print_endline "Hello, World!"
> EOF
$ touch a.txt
$ dune build @install
$ cat _build/default/hello.install
lib: [
"_build/install/default/lib/hello/META"
"_build/install/default/lib/hello/dune-package"
]
bin: [
"_build/install/default/bin/hello"
]
share: [
"_build/install/default/share/hello/a.txt"
]

View file

@ -0,0 +1,36 @@
Test that `(include ...)` composes with `(glob_files ...)`
$ cat >dune-project <<EOF
> (lang dune 3.6)
> (package (name foo))
> EOF
$ cat >dune <<EOF
> (install
> (files
> (include foo.sexp))
> (section share))
> EOF
$ cat >foo.sexp <<EOF
> ((glob_files dir1/*.txt)
> (glob_files_rec dir2/*.txt))
> EOF
$ mkdir -p dir1 dir2/foo/bar
$ touch dir1/a.txt dir1/b.txt dir2/c.txt dir2/foo/d.txt dir2/foo/bar/e.txt
$ dune build @install
$ cat _build/default/foo.install
lib: [
"_build/install/default/lib/foo/META"
"_build/install/default/lib/foo/dune-package"
]
share: [
"_build/install/default/share/foo/dir1/a.txt" {"dir1/a.txt"}
"_build/install/default/share/foo/dir1/b.txt" {"dir1/b.txt"}
"_build/install/default/share/foo/dir2/c.txt" {"dir2/c.txt"}
"_build/install/default/share/foo/dir2/foo/bar/e.txt" {"dir2/foo/bar/e.txt"}
"_build/install/default/share/foo/dir2/foo/d.txt" {"dir2/foo/d.txt"}
]

View file

@ -0,0 +1,32 @@
Including a file in the install stanza which does not contain a sexp list
$ cat >dune-project <<EOF
> (lang dune 3.5)
> (package (name hello))
> EOF
$ cat >dune <<EOF
> (executable
> (public_name hello))
>
> (install
> (files (include foo.sexp))
> (section share))
> EOF
$ cat >hello.ml <<EOF
> let () = print_endline "Hello, World!"
> EOF
$ cat >foo.sexp <<EOF
> a.txt
> EOF
$ dune build @install
File "_build/default/foo.sexp", line 1, characters 0-5:
1 | a.txt
^^^^^
Error: Expected list, got:
a.txt
[1]

View file

@ -0,0 +1,9 @@
(install
(files (include resources.sexp))
(section share))
(rule
(deps (source_tree resources) list_dir.ml)
(action
(with-stdout-to resources.sexp
(run ocaml list_dir.ml resources))))

View file

@ -0,0 +1,19 @@
(* Prints a sexp listing the contents of a given directory in the form:
((dir/foo as dir/foo)
(dir/bar as dir/bar)
(dir/baz as dir/baz)
...)
where foo, bar, baz, ... are files in the given directory. *)
let list_dir dir =
Sys.readdir dir
|> Array.to_list
|> List.map (fun f -> String.concat "/" [dir; f])
let () =
list_dir (Sys.argv.(1))
|> List.map (fun f -> Printf.sprintf "(%s as %s)" f f )
|> String.concat " "
|> Printf.printf "(%s)"

View file

@ -0,0 +1,21 @@
Include a file generated by listing the contents of a directory.
$ dune build @install
$ cat _build/default/foo.install
lib: [
"_build/install/default/lib/foo/META"
"_build/install/default/lib/foo/dune-package"
]
share: [
"_build/install/default/share/foo/resources/a.txt" {"resources/a.txt"}
"_build/install/default/share/foo/resources/b.txt" {"resources/b.txt"}
"_build/install/default/share/foo/resources/c.txt" {"resources/c.txt"}
]
$ find _build/install/default/share | sort
_build/install/default/share
_build/install/default/share/foo
_build/install/default/share/foo/resources
_build/install/default/share/foo/resources/a.txt
_build/install/default/share/foo/resources/b.txt
_build/install/default/share/foo/resources/c.txt

View file

@ -0,0 +1,34 @@
Detect include loops in files included in the install stanza
$ cat >dune-project <<EOF
> (lang dune 3.5)
> (package (name hello))
> EOF
$ cat >dune <<EOF
> (executable
> (public_name hello))
>
> (install
> (files (include foo.sexp))
> (section share))
> EOF
$ cat >hello.ml <<EOF
> let () = print_endline "Hello, World!"
> EOF
$ cat >foo.sexp <<EOF
> ((include bar.sexp))
> EOF
$ cat >bar.sexp <<EOF
> ((include foo.sexp))
> EOF
$ dune build @install
File "_build/default/bar.sexp", line 1, characters 10-18:
1 | ((include foo.sexp))
^^^^^^^^
Error: Include loop detected via: _build/default/foo.sexp
[1]

View file

@ -0,0 +1,70 @@
Simple example of including a file in the install stanza
$ cat >dune-project <<EOF
> (lang dune 3.4)
> (package (name hello))
> EOF
$ cat >dune <<EOF
> (executable
> (public_name hello))
>
> (install
> (files a.txt (include foo.sexp))
> (section share))
> EOF
$ cat >hello.ml <<EOF
> let () = print_endline "Hello, World!"
> EOF
$ touch a.txt
$ dune build @install
File "dune", line 5, characters 14-32:
5 | (files a.txt (include foo.sexp))
^^^^^^^^^^^^^^^^^^
Error: 'include' is only available since version 3.5 of the dune language.
Please update your dune-project file to have (lang dune 3.5).
[1]
$ cat >dune-project <<EOF
> (lang dune 3.5)
> (package (name hello))
> EOF
$ dune build @install
File "_unknown_", line 1, characters 0-0:
Error: No rule found for foo.sexp
[1]
$ cat >foo.sexp <<EOF
> (b.txt c.txt)
> EOF
$ touch b.txt
$ dune build @install
File "_build/default/foo.sexp", line 1, characters 7-12:
1 | (b.txt c.txt)
^^^^^
Error: No rule found for c.txt
[1]
$ touch c.txt
$ dune build @install
$ cat _build/default/hello.install
lib: [
"_build/install/default/lib/hello/META"
"_build/install/default/lib/hello/dune-package"
]
bin: [
"_build/install/default/bin/hello"
]
share: [
"_build/install/default/share/hello/a.txt"
"_build/install/default/share/hello/b.txt"
"_build/install/default/share/hello/c.txt"
]

View file

@ -0,0 +1,23 @@
Here we specify the behaviour of dune install when no install prefix is given.
$ cat > dune-project << EOF
> (lang dune 3.9)
> EOF
$ cat > dune << EOF
> (executable
> (public_name main))
> EOF
$ cat > main.ml
$ cat > proj.opam
$ dune build @install
We should suggest to the user here that they should use --prefix.
$ unset OPAM_SWITCH_PREFIX
$ dune install
Error: The mandir installation directory is unknown.
Hint: It can be specified with '--prefix' or by setting '--mandir'
[1]

View file

@ -0,0 +1,108 @@
Testing the source_trees field which is used to entire source_trees
$ cat >dune-project <<EOF
> (lang dune 3.11)
> (package
> (allow_empty)
> (name mypkg))
> EOF
$ test() {
> cat >dune <<EOF
> (install
> (section doc)
> (source_trees $1))
> EOF
> dune build mypkg.install && cat _build/default/mypkg.install
> }
Try to build a source directory that doesn't exist:
$ test "mydocs"
File "dune", line 3, characters 15-21:
3 | (source_trees mydocs))
^^^^^^
Error: This source directory does not exist
[1]
Create the source directory and fill it up with some dummy stuff for the test:
$ mkdir -p mydocs/foo
$ touch mydocs/foo.md mydocs/baz.md mydocs/foo/bar.md
$ test "mydocs"
lib: [
"_build/install/default/lib/mypkg/META"
"_build/install/default/lib/mypkg/dune-package"
]
doc: [
"_build/install/default/doc/mypkg/mydocs/baz.md" {"mydocs/baz.md"}
"_build/install/default/doc/mypkg/mydocs/foo.md" {"mydocs/foo.md"}
"_build/install/default/doc/mypkg/mydocs/foo/bar.md" {"mydocs/foo/bar.md"}
]
$ test "(mydocs as yourdocs)"
lib: [
"_build/install/default/lib/mypkg/META"
"_build/install/default/lib/mypkg/dune-package"
]
doc: [
"_build/install/default/doc/mypkg/yourdocs/baz.md" {"yourdocs/baz.md"}
"_build/install/default/doc/mypkg/yourdocs/foo.md" {"yourdocs/foo.md"}
"_build/install/default/doc/mypkg/yourdocs/foo/bar.md" {"yourdocs/foo/bar.md"}
]
$ test "(mydocs as your/docs)"
lib: [
"_build/install/default/lib/mypkg/META"
"_build/install/default/lib/mypkg/dune-package"
]
doc: [
"_build/install/default/doc/mypkg/your/docs/baz.md" {"your/docs/baz.md"}
"_build/install/default/doc/mypkg/your/docs/foo.md" {"your/docs/foo.md"}
"_build/install/default/doc/mypkg/your/docs/foo/bar.md" {"your/docs/foo/bar.md"}
]
Install docs directly into docs/<pkg>/:
$ test "(mydocs as .)"
lib: [
"_build/install/default/lib/mypkg/META"
"_build/install/default/lib/mypkg/dune-package"
]
doc: [
"_build/install/default/doc/mypkg/baz.md" {"./baz.md"}
"_build/install/default/doc/mypkg/foo.md" {"./foo.md"}
"_build/install/default/doc/mypkg/foo/bar.md" {"./foo/bar.md"}
]
Install multiple source trees at once:
$ mkdir otherdocs
$ touch otherdocs/help.txt
$ test "mydocs otherdocs"
lib: [
"_build/install/default/lib/mypkg/META"
"_build/install/default/lib/mypkg/dune-package"
]
doc: [
"_build/install/default/doc/mypkg/mydocs/baz.md" {"mydocs/baz.md"}
"_build/install/default/doc/mypkg/mydocs/foo.md" {"mydocs/foo.md"}
"_build/install/default/doc/mypkg/mydocs/foo/bar.md" {"mydocs/foo/bar.md"}
"_build/install/default/doc/mypkg/otherdocs/help.txt" {"otherdocs/help.txt"}
]
Install zero source trees:
$ test ""
lib: [
"_build/install/default/lib/mypkg/META"
"_build/install/default/lib/mypkg/dune-package"
]
It is an error for the destination path to start with "..".
$ test "(mydocs as ../)"
File "dune", line 3, characters 26-29:
3 | (source_trees (mydocs as ../)))
^^^
Error: The destination path ../ begins with .. which is not allowed.
Destinations in install stanzas may not begin with .. to prevent a package's
installed files from escaping that package's install directories.
[1]

View file

@ -0,0 +1,95 @@
This test shows that when libraries `libA` and `libB` containing both C stubs
are installed, and a bytecode executable `exeA` that depends on a local version
of `libA` and the installed version of `libB` is being built, then the C stubs
from the installed `libA` (on which `exeA` does not depend) are put in the load
path and take precendence over the local copy of `libA`.
See https://github.com/ocaml/dune/issues/9979.
Begin by installing libraries `libA` and `libB` with C stubs.
$ cat >dune-project <<EOF
> (lang dune 3.13)
> (package (name pkgA))
> EOF
$ cat >libA.ml <<EOF
> EOF
$ cat >libB.ml <<EOF
> EOF
$ cat >dune <<EOF
> (library
> (name libA)
> (public_name pkgA.libA)
> (foreign_stubs
> (language c)
> (names stubsA))
> (modules libA))
> (library
> (name libB)
> (public_name pkgA.libB)
> (foreign_stubs
> (language c)
> (names stubsB))
> (modules libB))
> EOF
$ cat >stubsA.c <<EOF
> int dummy0() { return 0; }
> EOF
$ cat >stubsB.c <<EOF
> int dummy1() { return 0; }
> EOF
$ dune build
$ dune install --prefix ./install --display short 2>&1 | grep \\.so
Installing install/lib/stublibs/dlllibA_stubs.so
Installing install/lib/stublibs/dlllibB_stubs.so
And we try to build an executable depending on the (local) `libA` and the (installed) `libB`:
$ mkdir -p libA
$ cat >libA/libA.ml <<EOF
> external f : int -> int = "dummy2"
> EOF
$ cat >libA/stubs.c <<EOF
> int dummy2() { return 0; }
> EOF
$ cat >exeA.ml <<EOF
> let _ = LibA.f
> EOF
$ cat >libA/dune <<EOF
> (library
> (name libA)
> (foreign_stubs
> (language c)
> (names stubs))
> (modules libA))
> EOF
$ cat >dune <<EOF
> (executable
> (name exeA)
> (modes byte)
> (libraries pkgA.libB libA)
> (modules exeA))
> EOF
$ OCAMLPATH=./install/lib dune build exeA.bc
File "_none_", line 1:
Error: Error while linking .exeA.eobjs/byte/dune__exe__ExeA.cmo:
The external function dummy2 is not available
[1]
The error comes from passing as flags `-I ./install/lib/pkgA/../stublibs -I
libA` so the `dlllibA_stubs.so` in `./install/lib/stublibs` takes precedence
over the one in `libA`.
If we list `libA` __before__ `pkgA.libB`, the build succeeds because the include
flags look like `-I libA -I ./install/lib/pkgA/../stublibs`:
$ cat >dune <<EOF
> (executable
> (name exeA)
> (modes byte)
> (libraries libA pkgA.libB)
> (modules exeA))
> EOF
$ OCAMLPATH=./install/lib dune build exeA.bc

View file

@ -0,0 +1,92 @@
Begin by installing a library with C stubs.
$ cat >dune-project <<EOF
> (lang dune 3.7)
> (package (name libA))
> EOF
$ cat >dune <<EOF
> (library
> (name libA)
> (public_name libA)
> (foreign_stubs
> (language c)
> (names stubs)))
> EOF
$ cat >stubs.c <<EOF
> int dummy() {
> return 0;
> }
> EOF
$ dune build
$ dune install --prefix ./install --display short
Installing install/lib/libA/META
Installing install/lib/libA/dune-package
Installing install/lib/libA/libA.a
Installing install/lib/libA/libA.cma
Installing install/lib/libA/libA.cmi
Installing install/lib/libA/libA.cmt
Installing install/lib/libA/libA.cmx
Installing install/lib/libA/libA.cmxa
Installing install/lib/libA/libA.ml
Installing install/lib/libA/liblibA_stubs.a
Installing install/lib/libA/libA.cmxs
Installing install/lib/stublibs/dlllibA_stubs.so
$ sed -E 's/lang dune [0-9.]+/lang dune XXX/' ./install/lib/libA/dune-package
(lang dune XXX)
(name libA)
(sections
(lib
$TESTCASE_ROOT/install/lib/libA)
(libexec
$TESTCASE_ROOT/install/lib/libA)
(stublibs
$TESTCASE_ROOT/install/lib/stublibs))
(files
(lib
(META
dune-package
libA.a
libA.cma
libA.cmi
libA.cmt
libA.cmx
libA.cmxa
libA.ml
liblibA_stubs.a))
(libexec (libA.cmxs))
(stublibs (dlllibA_stubs.so)))
(library
(name libA)
(kind normal)
(archives (byte libA.cma) (native libA.cmxa))
(plugins (byte libA.cma) (native libA.cmxs))
(foreign_objects stubs.o)
(foreign_archives (archives (for all) (files liblibA_stubs.a)))
(foreign_dll_files ../stublibs/dlllibA_stubs.so)
(native_archives libA.a)
(main_module_name LibA)
(modes byte native)
(modules
(wrapped
(group
(alias
(obj_name libA)
(visibility public)
(kind alias)
(source (path LibA) (impl (path libA.ml-gen))))
(name LibA))
(wrapped true))))
Now let us define an executable using that installed library.
$ cat >dune-project <<EOF
> (lang dune 3.7)
> EOF
$ cat >dune <<EOF
> (executable
> (name exeA)
> (libraries libA)
> (modes byte))
> EOF
$ touch exeA.ml
$ OCAMLPATH=./install/lib dune build

View file

@ -0,0 +1,19 @@
The misc install section isn't supported:
$ cat >dune-project <<EOF
> (lang dune 3.7)
> (package
> (name xxx))
> EOF
$ cat >dune <<EOF
> (install
> (section misc)
> (files foo))
> EOF
$ dune build xxx.install 2>&1 | awk '/Internal error/,/Raised/'
Internal error, please report upstream including the contents of _build/log.
Description:
("Install.Paths.get", {})
Raised at Stdune__Code_error.raise in file