See the basics.
The installation description generates an OPAM install file
which is simply a description of file moves (in the
from the build or source directory to standard install
directories. Describing these moves in a given build
configuration effectively determines what needs to built by the
package build command.
Note. Always use
"/" as a directory seperator for paths, even
val nothing :
nothingis an empty set of install moves.
val flatten :
install list -> install
flatten installsis the union of all the install moves in
?exts:Topkg.Exts.t -> ?dst:Topkg.fpath -> Topkg.fpath -> install
field srcsimply moves the file
srcat the root of the install directory of the field.
field ~force ~built ~cond ~exts ~dst src generates install
move as follows:
dstis the path were the source is written to. Expressed relative to the install directory of the field. Defaults to
Fpath.basename src, i.e. at the root of the install directory. If
dstis a directory path, the destination is
(dst ^ Fpath.basename src).
extsis present and non empty, generates the list of paths
List.map (fun e -> src ^ e)and a move for each of these. For example
"src/m"would generate a move for the files
true) no file move is generated. This provides a convenient way to conditionalize installation based on the build configuration for example:
let jsoo = Conf.value jsoo in Pkg.mllib ~cond:jsoo "src/mylib_jsoo.mllib"
srcis expressed relative to the build directory of the distribution and the path
srcis be given to build system invocation for construction. If
srcis relative to the root of the distribution and is excluded from the build system invocation; this can be used for installing files that don't need to be built.
false) it disables the automatic
srcfiltering performed by the library. When
false, the library automatically disable certain build artefact depending on OCaml's configuration, one such example is filtering native code build artefact if the OCaml install doesn't support native code compilation
?auto:bool -> field
Topkg.Pkg.fieldexcept for the additional
field src dstautomatically adds the
".byte"suffix otherwise. Besides it automatically adds
dst, which handles things correctly on the various Windows ports.
falseyou have full control according to
val bin :
binis a field that installs to a common
val doc :
docis a field that installs to a package specific
val etc :
etcis a field that installs to a package specific
val lib :
libis a field that installs to a package specific
val libexec :
libexecis a field that installs to a package specific
lib/directory but with the executable bit set.
val man :
manis a field that installs to a common
man/directory. See the OPAM manual for details.
val misc :
miscis a field that installs to an arbitrary absolute path, the user is prompted for authorization, see the OPAM manual for details.
val sbin :
sbinis a field that installs to a common
shareis a field that installs to a package specific
share_rootis a field that installs to a common
val stublibs :
stublibsis a field that install to a common
lib/stublibs/directory. Used for OCaml C stub directory.
val toplevel :
toplevelis a field that installs to a common
val test :
?run:bool -> ?dir:Topkg.fpath -> ?args:Topkg.Cmd.t -> exec_field
testis a special executable field: it doesn't install the described executable (as such the
dstargument is ignored at the moment). If
true(default) executes the test with
ocaml pkg/pkg.ml testis run; this will notably run to test the distribution tarball. If
falsethe test needs to be invoked explicitely.
dirspecifies the current working directory for the test, expressed relative to the root directory of the package (defaults to
The following functions are OCamlbuild specific higher level
installs that generate moves by reading OCamlbuild specification
files. They also automatically handle the
configuration key by building and installing the build artefacts
needed by debuggers whenever its value is
val mllib :
?api:string list -> ?dst_dir:Topkg.fpath -> Topkg.fpath -> install
mllib ~field ~cond ~api ~dst_dir mllibinstalls an OCaml library described by the OCamlbuild .mllib file
fieldis the field where it gets installed (defaults to
true), no move is generated.
apiis the list of modules that defines the public interface of the library, if
Noneall the modules mentioned in
mllibare part of the public interface.
dst_diris the destination directory of the library in the field. If unspecified this is the root of the field's directory.
val clib :
?cond:bool -> ?lib_dst_dir:Topkg.fpath -> Topkg.fpath -> install
clib clibinstalls C stubs described by the OCamlbuild .clib file
dllfieldis the field where the C DLL archive gets installed, (defaults to
libfieldis the field where the C static archive gets installed (defaults to
true), no move is generated.
lib_dst_diris the destination directory of the library in the
libfieldfield. If unspecified this is the root of the field's directory. This does not affect the
dllfield, DLLs are always installed at the root directory of the
val build :
?pre:(Topkg.Conf.t -> unit Topkg.result) ->
?cmd:(Topkg.Conf.t -> Topkg.Conf.os -> Topkg.fpath list -> unit Topkg.result) ->
?post:(Topkg.Conf.t -> unit Topkg.result) ->
?clean:(Topkg.Conf.os -> build_dir:Topkg.fpath -> unit Topkg.result) ->
unit -> build
build ~prepare_on_pin ~dir ~cmd ~pre ~postdescribes the package build procedure.
true(default) distribution preparation is performed if a
`Pinbuild context is detected. This means that the checkout is watermarked and the massage hook is invoked, see step 2. of distribution creation.
diris the directory where build artefacts are generated, (defaults to
"_build"). Note that his value can be overriden from the command line.
preis a hook that is invoked with the build context, after distribution preparation if applicable, but before the build command. It can be used to adapt the build setup according to the build configuration. Default is a nop.
cmdinvokes the build system to build the files determined by install moves. It is given the build configuration, an OS specification, the list of files to build relative to the build directory, and build the given files in the build directory. The default is:
fun c os files -> OS.Cmd.run @@ Cmd.(Pkg.build_cmd c os %% of_list files)
postis a hook that is invoked with the build context after the build command returned sucessfully. Default is a nop.
cleanis invoked to clean a build. It is given an OS specification and a build directory to clean. The default is:
let clean os ~build_dir = OS.Cmd.run @@ Pkg.clean_cmd os ~build_dir
Topkg.Conf.toolto look them up it helps for cross-compilation.
If you are using
ocamlbuild, the following functions
help to customize the build system invocation according to the
val build_cmd :
Topkg.Conf.t -> Topkg.Conf.os -> Topkg.Cmd.t
build_cmd c osis the default build command to which files to build are given. Its value is defined by:
fun c os -> let ocamlbuild = Conf.tool "ocamlbuild" os in let build_dir = Conf.build_dir c in let debug = Cmd.(on (Conf.debug c) (v "-tag" % "debug")) in let profile = Cmd.(on (Conf.profile c) (v "-tag" % "profile")) in Cmd.(ocamlbuild % "-use-ocamlfind" % "-classic-display" %% debug %% profile % "-build-dir" % build_dir)
val clean_cmd :
Topkg.Conf.os -> build_dir:Topkg.fpath -> Topkg.Cmd.t
clean_cmd os ~build_diris the default clean command. Its value is defined by:
fun os ~build_dir -> let ocamlbuild = Conf.tool "ocamlbuild" os in Cmd.(ocamlbuild % "-use-ocamlfind" % "-classic-display" % "-build-dir" % build_dir % "-clean")
val ocb_tag :
Topkg.Conf.t -> 'a Topkg.Conf.key -> string -> Topkg.Cmd.t
ocb_tag c key nameis a command fragment adding the
key's value to the default set of tags. The key value is converted to a string using the printer of the key value converter.
For example with a key
k : bool Conf.key whose value is
ocb_tag c k "foo" adds the tag
foo(true) to the
default tags. A sample build command for
this key would be:
let cmd c os files = OS.Cmd.run Cmd.(build_cmd c os %% ocb_tag c k "foo" %% of_list files)
val ocb_bool_tag :
Topkg.Conf.t -> bool Topkg.Conf.key -> string -> Topkg.Cmd.t
ocb_bool_tag c key nameis a command fragment adding the
nameto the default set of tags iff
key's value is
Topkg.Conf.t -> (bool Topkg.Conf.key * string) list -> Topkg.Cmd.t
ocb_bool_tags c associs the concatenation of
Topkg.Pkg.ocb_bool_tagfor all pairs in
| `Opam of Topkg.fpath option * string * string
| `String of string
| `Vcs of [ `Commit_id ]
| `Version_num ]
"ID"and its definition:
sis the definition.
`Name, is the name of package.
`Version, is the version of the distribution.
`Version_num, is the version of the distribution with a potential leading
`Vcs `Commit_id, is the commit identifier (hash) of the distribution. May be post-fixed by
"dirty"in pin builds.
`Opam (file, field, sep), is the values of the field
fieldconcatenated with separator
sepof the OPAM file
file, expressed relative to the distribution root directory, if
Nonethis is the package's default OPAM file, see
Topkg.Pkg.describe. Not all fields are supported see the value of
Topkg_care.Opam.File.field_names. Warning. In pin builds,
`Opamwatermarks are only substituted if the package
When a file is watermarked with an identifier
"ID", any occurence of
%%ID%% in its content is substituted by its definition.
val distrib :
?watermarks:watermark list ->
?files_to_watermark:(unit -> Topkg.fpath list Topkg.result) ->
?massage:(unit -> unit Topkg.result) ->
?exclude_paths:(unit -> Topkg.fpath list Topkg.result) ->
?uri:string -> unit -> distrib
distrib ~watermarks ~files_to_watermark ~massage ~exclude_paths ~uri ()influences the distribution creation process performed by the
topkgtool. See the full details about distribution creation.
In the following the distribution build directory is a
private clone of the package's source repository's
topkg distrib is invoked.
watermarksdefines the source watermarks for the distribution, defaults to
files_to_watermarkis invoked in the distribution build directory to determine the files to watermark, defaults to
massageis invoked in the distribution build directory, after watermarking, but before archiving. It can be used to generate distribution time build artefacts. Defaults to
exclude_paths ()is invoked in the distribution build directory, after massaging, to determine the paths that are excluded from being added to the distribution archive. Defaults to
uriis an URI pattern that specifies the location of the distribution on the WWW. In this string any sub-string
"$(NAME)"is replaced by the package name,
"$(VERSION)"is replaced by the distribution version string and
"$(VERSION_NUM)"by the distribution version string, chopping an initial
'V'character if present. This argument is used to generate the
urlfile of an OPAM package for the distribution; it will be deprecated in the future in favour of a
x-distrib-urifield in the OPAM file. If the value is unspecified it defaults to:
where PKG_HOMEPAGE is the package's OPAM file
homepagefield. As a special case if the hostname of PKG_HOMEPAGE is
githubthe following is used:
where PKG_DEV_REPO is the package's OPAM file
dev-repofield without the
val watermarks :
watermarksis the default list of watermarks. It has the following elements:
("VCS_COMMIT_ID", `Vcs [`Commit_id])
("PKG_MAINTAINER", `Opam (None, "maintainer", ", "))
("PKG_AUTHORS", `Opam (None, "authors", ", ")
("PKG_HOMEPAGE", `Opam (None, "homepage", " ")
("PKG_ISSUES", `Opam (None, "bug-reports", " ")
("PKG_DOC", `Opam (None, "doc", " "))
("PKG_LICENSE", `Opam (None, "license", ", ")
("PKG_REPO", `Opam (None, "dev-repo", " "))
val files_to_watermark :
unit -> Topkg.fpath list Topkg.result
files_to_watermark ()is the default list of files to watermark. It is invoked in the distribution build directory and gets the set of tracked files of this directory from which it removes the files that end with
val massage :
unit -> unit Topkg.result
massageis the default distribution massaging function. It is invoked in the distribution build directory and does nothing.
val exclude_paths :
unit -> Topkg.fpath list Topkg.result
exclude_paths ()is the default list of paths to exclude from the distribution archive. It is invoked in the distribution build directory and returns the following static set of files.
fun () -> Ok [".git"; ".gitignore"; ".gitattributes"; ".hg"; ".hgignore"; "build"; "Makefile"; "_build"]
val publish :
?artefacts:[ `Alt of string | `Distrib | `Doc ] list ->
unit -> publish
publish ~artefacts ()influences the distribution publication process performed by the
artefactsdefines which artefacts are published by an invocation of
topkg publishwithout arguments (defaults to
val std_file :
?install:bool -> Topkg.fpath -> std_file
std_file ~install pis a standard file
pexpressed relative to the distribution root directory. The file is automatically installed if
val meta_file :
?lint:bool -> ?install:bool -> Topkg.fpath -> meta_file
meta_file ~lint ~install pis a META file
pexpressed relative to the distribution root directory. The file is automatically installed in the
true(default), it is OCamlfind linted.
val opam_file :
?lint_deps_excluding:string list option ->
?install:bool -> Topkg.fpath -> opam_file
opam_file ~lint ~lint_deps_excluding ~install pis an OPAM file
pexpressd relative to the distribution root directory such that:
true(default), it is automatically installed in the
true(default), it is OPAM linted.
topkgchecks that each of the OPAM package dependencies is mentioned as a root package in the OCamlbuild
_tagsfile and vice-versa. The following package names are excluded from this test:
Nonethe dependency check is disabled.
val describe :
?readmes:std_file list ->
?licenses:std_file list ->
?change_logs:std_file list ->
?metas:meta_file list ->
?opams:opam_file list ->
?lint_files:Topkg.fpath list option ->
?lint_custom:(unit -> Topkg.R.msg Topkg.result list) ->
string -> (Topkg.Conf.t -> install list Topkg.result) -> unit
describe name installdescribes a package named
delegate, the package delegate command to use. If unspecfied determined by the delegate lookup procedure, see
topkg help delegatefor more information.
readmesare readme files, defaults to
[std_file "README.md"]. Automatic install is in the
licensesare license files, defaults to
[std_file "LICENSE.md"]. Automatic install is in the
change_logsare change logs, defaults to
[std_file "CHANGES.md"]. The first file of the list is the one that is acted upon by the
topkg logcommand. Automatic install is in the
metasthe package's ocamlfind META files, defaults to
[ meta_file "pkg/META" ].
opamsthe package's OPAM package files, defaults to
[opam_file "opam"]. The default OPAM file used by a package description depends on the package
name(which can be overriden from the command line). The OPAM file lookup procedure selects the first path in
opamswhose filename is
(name ^ ".opam")and, failing to do so, it fallbacks to an
"opam"file at the root of the distribution.
Some files, ensures that all files mentioned in
filesare present in the distribution. Defaults to
Some . If
Nonedisables the file existence tests (including readme, change_log, license, metas, opams, metas.)
lint_customdefines a custom linting process run with the current directory set at the root of the distribution. Successes and errors in the returned list are reported as such and any error in the list makes the lint fail. Defaults to
distrib, specifies the distribution process, defaults to
publish, specifies the publication process, defaults to
build, specifies the build process, defaults to
installgiven a build configuration specifies the install moves. Note that some of standard files are automatically installed and don't need to be specified, see
The following describes the exact steps performed by
distrib to create the distribution archive. Note that
allows to override or disable part of the process via command
line arguments, e.g. to specify the version string manually or
skip linting. See
topkg distrib --help for more information.
The distribution process assumes that the source repository working directory is clean so that its definitions are consistent with those of the distribution build directory. A warning is generated if this is not the case as it may end up in inconsistent distribution archives (but which may be fine to only publish a documentation update).
$NAME be the name of the package,
$BUILD be its
$VERSION be the VCS tag description
git-describe(1) if you are using
git) of the source
repository HEAD commit and
distrib the distribution
description found in the source's repository
HEADas the distribution build directory
distribin the distribution build directory to determine the files to watermark with
watermarksand perform the watermarking process.
$VERSIONto the OPAM files mentioned by
distribin the distribution build directory. This can be used to create distribution time build artefacts.
distribin the distribution build directory to determine the paths to exclude from the archive.
$BUILD/$NAME-$VERSION.tbzwith the file hierarchy in
$BUILD/$NAME-$VERSION.build, excluding the paths determined at the preceeding point and delete the clone
$BUILD/$NAME-$VERSION.build. File modifications times in the archive are set to
HEAD's commit time and file permissions are preserved. Any other form of file metadata is discarded in the archive.
$BUILD/$NAME-$VERSION, lint the distribution, build the package in the current build environment with its tests, run the tests, on success delete
$BUILD/$NAME-$VERSION. Note that this uses the archive's
pkg/pkg.mlfile, which should not be different from the source's repository file if the latter was clean when
topkg distribwas invoked.
It is right to doubt the beauty and be concerned about the watermarking process. However experience shows that alternatives like having an OCaml module generated with the appropriate information doesn't work well in practice. Version numbers do not only show up in OCaml source code. They also appear in documentation comments, metadata files, textual data files and non-OCaml source files.
Watermarking by default all the non binary files of the distribution allows one to write %%VERSION%% in any context and be sure it is be substituted with the right version number in pin and distribution build contexts (this occurence was not subsituted because a ZERO WIDTH NON-JOINER U+200C was introduced between the first two percent characters).
If this scheme poses a problem for certain files or you remain
unconvinced, simply filter the result of
replace it by the exact files you would like to watermark.