Foreign Sources, Archives, and Objects¶
Dune provides basic support for including foreign source files as well
as archives of foreign object files into OCaml projects via the
foreign_stubs and foreign_archives fields. Individual object
files can also be included via the extra_objects field.
Foreign Stubs¶
You can specify foreign sources using the foreign_stubs field of the
library and executable stanzas. For example:
(library
(name lib)
(foreign_stubs (language c) (names src1 src2))
(foreign_stubs (language cxx) (names src3) (flags -O2)))
Here we declare an OCaml library lib, which contains two C sources
src1 and src2, and one C++ source, src3, which need to be
compiled with -O2. These source files will be compiled and packaged
with the library, along with the link-time flags to be used when
linking the final executables. When matching names to source files,
Dune treats *.c files as C sources, and *.cpp, *.cc, and
*.cxx files as C++ sources.
Here is a complete list of supported subfields:
languagespecifies the source language, wherecmeans C andcxxmeans C++. In the future, more languages may be supported.namesspecifies the names of source files. When specifying a source file, omit the extension and any relative parts of the path; Dune will scan all library directories to find all matching files and raise an error if multiple source files map to the same object name. If you need to have multiple object files with the same name, you can package them into different Foreign Archives via theforeign_archivesfield. This field uses the Ordered Set Language where the:standardvalue corresponds to the set of names of all source files whose extensions match the specifiedlanguage.flagsare passed when compiling source files. This field is specified using the Ordered Set Language, where the:standardvalue comes from the environment settingsc_flagsandcxx_flags, respectively. Note that, for C stubs, Dune unconditionally adds the flags present in the OCaml config fieldsocamlc_cflagsandocamlc_cppflagsto the compiler command line. This behavior can be disabled since Dune 2.8 via thedune-projectoption use_standard_c_and_cxx_flags.include_dirsare tracked as dependencies and passed to the compiler via the-Iflag. You can use Variables in this field and refer to a library source directory using the(lib library-name)syntax. Additionally, the syntax(include filename)can be used to specify a file containing additional arguments to(include_dirs ...). The named file can either contain a single path to be added to this list of include directories, or an S-expression listing additional(include_dirs ...)arguments (the(lib ...)and(include ...)syntax is also supported in files included in this way). For example,(include_dirs dir1 (lib lib1) (lib lib2) (include inc1) dir2)specifies the directorydir1, the source directories oflib1, andlib2, the list of directories contained in the fileinc1, and the directorydir2, in this order. Some examples of possible contents of the fileinc1are:dir3which would adddir3to the list of include directories((lib lib3) dir4 (include inc2))which would add the source directory of the librarylib3, the directorydir4, and the result of recursively including the contents of the fileinc2. The contents of included directories are tracked recursively, e.g., if you use(include_dir dir)and have headersdir/base.handdir/lib/lib.h, they both will be tracked as dependencies.extra_depsspecifies any other dependencies that should be tracked. This is useful when dealing with#includestatements that escape into a parent directory like#include "../a.h".
Mode-Dependent Stubs¶
Since Dune 3.5, it is possible to use different foreign stubs when building in
native or byte mode. This feature needs to be activated by adding (using
mode_specific_stubs 0.1) in the dune-project file.
Then it is allowed to use the mode field when describing foreign_stubs.
If the same stub is defined twice, Dune will automatically chose the correct one.
This allows the use of different sets of flags or even different source files
from which the stubs are built.
(executable
(name main)
(modes native byte_complete)
(foreign_stubs
(language c)
(mode byte)
(names c_stubs))
(foreign_stubs
(language c)
(mode native)
(flags :standard -DNATIVE_CODE) ; A flag specific to native builds
(names c_stubs))) ; This could be the name of an implementation
; specific to native builds
Note that, as of version 0.1 of this extension, this mechanism does not work for foreign_archives.
Foreign Archives¶
You can also specify archives of separately compiled foreign object files
that need to be packaged with an OCaml library or linked into an OCaml
executable. To do that, use the foreign_archives field of the
corresponding library or executable stanza. For example:
(library
(name lib)
(foreign_stubs (language c) (names src1 src2))
(foreign_stubs (language cxx) (names src3) (flags -O2))
(foreign_archives arch1 some/dir/arch2))
Here, in addition to Foreign Stubs, we also specify foreign archives
arch1 and arch2, where the latter is stored in a subdirectory
some/dir.
You can build a foreign archive manually, e.g., using a custom rule as
described in Foreign Build Sandboxing, or ask Dune to build it via the
foreign_library stanza:
(foreign_library
(archive_name arch1)
(language c)
(names src4 src5)
(include_dir headers))
This asks Dune to compile C source files src4 and src5 with
headers tracked in the headers directory and put the resulting
object files into an archive arch1, whose full name is typically
libarch1.a for static linking and dllarch1.so for dynamic
linking.
The foreign_library stanza supports all Foreign Stubs fields plus
the archive_name field, which specifies the archive’s name. You can refer
to the same archive name from multiple OCaml libraries and executables, so a
foreign archive is a bit like a foreign library, hence the name of the stanza.
Foreign archives are particularly useful when embedding a library written in a foreign language and/or built with another build system. See Foreign Build Sandboxing for more details.
Extra Objects¶
It’s possible to specify native object files to be packaged with OCaml
libraries or linked into OCaml executables. Do this by using the
extra_objects field of the library or executable stanzas.
For example:
(executable
(public_name main)
(extra_objects foo bar))
(rule
(targets foo.o bar.o)
(deps foo.c bar.c)
(action (run ocamlopt %{deps})))
This example builds an executable which is linked against a pair of native
object files, foo.o and bar.o. The extra_objects field takes a
list of object names, which correspond to the object file names with their path
and extension omitted.
In this example, the sources corresponding to the objects (foo.c and
bar.c) are assumed to be present in the same directory as the OCaml source
code, and a custom rule is used to compile the C source code into object
files using ocamlopt. This is not necessary; one can instead compile foreign
object files manually and place them next to the OCaml source code.
Flags¶
Depending on the use_standard_c_and_cxx_flags option, the base :standard set of
flags for C will contain only ocamlc_cflags or both ocamlc_cflags and
ocamlc_cppflags.
There are multiple levels where one can declare custom flags (using the Ordered Set Language), and each level inherits the flags of the previous one in its :standard set:
In the global
envdefinition of adune-workspacefileIn the per-context env definitions in a dune-workspace file
In the env definition of a dune file
In a foreign_ field of an executable or a library
The %{cc} variable will contain the flags
from the first three levels only.