307 lines
6.6 KiB
ReStructuredText
307 lines
6.6 KiB
ReStructuredText
**********
|
|
Quickstart
|
|
**********
|
|
|
|
This document gives simple usage examples of Jbuilder. You can also look at
|
|
`examples <https://github.com/ocaml/dune/tree/master/example>`__ for
|
|
complete examples of projects using Jbuilder.
|
|
|
|
Building a hello world program
|
|
==============================
|
|
|
|
In a directory of your choice, write this ``jbuild`` file:
|
|
|
|
.. code:: scheme
|
|
|
|
(jbuild_version 1)
|
|
|
|
;; This declare the hello_world executable implemented by hello_world.ml
|
|
(executable
|
|
((name hello_world)))
|
|
|
|
This ``hello_world.ml`` file:
|
|
|
|
.. code:: ocaml
|
|
|
|
print_endline "Hello, world!"
|
|
|
|
And build it with:
|
|
|
|
.. code:: bash
|
|
|
|
jbuilder build hello_world.exe
|
|
|
|
The executable will be built as ``_build/default/hello_world.exe``. Note that
|
|
native code executables will have the ``.exe`` extension on all platforms
|
|
(including non-Windows systems).
|
|
|
|
Building a hello world program using Lwt
|
|
========================================
|
|
|
|
In a directory of your choice, write this ``jbuild`` file:
|
|
|
|
.. code:: scheme
|
|
|
|
(jbuild_version 1)
|
|
|
|
(executable
|
|
((name hello_world)
|
|
(libraries (lwt.unix))))
|
|
|
|
This ``hello_world.ml`` file:
|
|
|
|
.. code:: ocaml
|
|
|
|
Lwt_main.run (Lwt_io.printf "Hello, world!\n")
|
|
|
|
And build it with:
|
|
|
|
.. code:: bash
|
|
|
|
jbuilder build hello_world.exe
|
|
|
|
The executable will be built as ``_build/default/hello_world.exe``
|
|
|
|
Building a hello world program using Core and Jane Street PPXs
|
|
==============================================================
|
|
|
|
Write this jbuild:
|
|
|
|
.. code:: scheme
|
|
|
|
(jbuild_version 1)
|
|
|
|
(executable
|
|
((name hello_world)
|
|
(libraries (core))
|
|
(preprocess (pps (ppx_jane)))
|
|
))
|
|
|
|
This ``hello_world.ml`` file:
|
|
|
|
.. code:: ocaml
|
|
|
|
open Core
|
|
|
|
let () =
|
|
Sexp.to_string_hum [%sexp ([3;4;5] : int list)]
|
|
|> print_endline
|
|
|
|
And build it with:
|
|
|
|
.. code:: bash
|
|
|
|
jbuilder build hello_world.exe
|
|
|
|
The executable will be built as ``_build/default/hello_world.exe``
|
|
|
|
Defining a library using Lwt and ocaml-re
|
|
=========================================
|
|
|
|
Write this jbuild:
|
|
|
|
.. code:: scheme
|
|
|
|
(jbuild_version 1)
|
|
|
|
(library
|
|
((name mylib)
|
|
(public_name mylib)
|
|
(libraries (re lwt))))
|
|
|
|
The library will be composed of all the modules in the same directory.
|
|
Outside of the library, module ``Foo`` will be accessible as
|
|
``Mylib.Foo``, unless you write an explicit ``mylib.ml`` file.
|
|
|
|
You can then use this library in any other directory by adding ``mylib``
|
|
to the ``(libraries ...)`` field.
|
|
|
|
Setting the OCaml compilation flags globally
|
|
============================================
|
|
|
|
Write this jbuild at the root of your project:
|
|
|
|
.. code:: scheme
|
|
|
|
(env
|
|
(dev
|
|
(flags (:standard -w +42)))
|
|
(release
|
|
(flags (:standard -O3))))
|
|
|
|
`dev` and `release` correspond to build profiles. The build profile
|
|
can be selected from the command line with `--profile foo` or from a
|
|
`dune-workspace` file by writing:
|
|
|
|
.. code:: scheme
|
|
|
|
(profile foo)
|
|
|
|
Using cppo
|
|
==========
|
|
|
|
Add this field to your ``library`` or ``executable`` stanzas:
|
|
|
|
.. code:: scheme
|
|
|
|
(preprocess (action (run ${bin:cppo} -V OCAML:${ocaml_version} ${<})))
|
|
|
|
Additionally, if you are include a ``config.h`` file, you need to
|
|
declare the dependency to this file via:
|
|
|
|
.. code:: scheme
|
|
|
|
(preprocessor_deps (config.h))
|
|
|
|
Using the .cppo.ml style like the ocamlbuild plugin
|
|
---------------------------------------------------
|
|
|
|
Write this in your jbuild:
|
|
|
|
.. code:: scheme
|
|
|
|
(rule
|
|
((targets (foo.ml))
|
|
(deps (foo.cppo.ml <other files that foo.ml includes>))
|
|
(action (run ${bin:cppo} ${<} -o ${@}))))
|
|
|
|
Defining a library with C stubs
|
|
===============================
|
|
|
|
Assuming you have a file called ``mystubs.c``, that you need to pass
|
|
``-I/blah/include`` to compile it and ``-lblah`` at link time, write
|
|
this jbuild:
|
|
|
|
.. code:: scheme
|
|
|
|
(jbuild_version 1)
|
|
|
|
(library
|
|
((name mylib)
|
|
(public_name mylib)
|
|
(libraries (re lwt))
|
|
(c_names (mystubs))
|
|
(c_flags (-I/blah/include))
|
|
(c_library_flags (-lblah))))
|
|
|
|
Defining a library with C stubs using pkg-config
|
|
================================================
|
|
|
|
Same context as before, but using ``pkg-config`` to query the
|
|
compilation and link flags. Write this jbuild:
|
|
|
|
.. code:: scheme
|
|
|
|
(jbuild_version 1)
|
|
|
|
(library
|
|
((name mylib)
|
|
(public_name mylib)
|
|
(libraries (re lwt))
|
|
(c_names (mystubs))
|
|
(c_flags (:include c_flags.sexp))
|
|
(c_library_flags (:include c_library_flags.sexp))))
|
|
|
|
(rule
|
|
((targets (c_flags.sexp
|
|
c_library_flags.sexp))
|
|
(deps (config/discover.exe))
|
|
(action (run ${<} -ocamlc ${OCAMLC}))))
|
|
|
|
Then create a ``config`` subdirectory and write this ``jbuild``:
|
|
|
|
.. code:: scheme
|
|
|
|
(jbuild_version 1)
|
|
|
|
(executable
|
|
((name discover)
|
|
(libraries (base stdio configurator))))
|
|
|
|
as well as this ``discover.ml`` file:
|
|
|
|
.. code:: ocaml
|
|
|
|
open Base
|
|
open Stdio
|
|
module C = Configurator
|
|
|
|
let write_sexp fn sexp =
|
|
Out_channel.write_all fn ~data:(Sexp.to_string sexp)
|
|
|
|
let () =
|
|
C.main ~name:"mylib" (fun c ->
|
|
let default : C.Pkg_config.package_conf =
|
|
{ libs = ["-lblah"]
|
|
; cflags = []
|
|
}
|
|
in
|
|
let conf =
|
|
match C.Pkg_config.get c with
|
|
| None -> default
|
|
| Some pc ->
|
|
Option.value (C.Pkg_config.query pc ~package:"blah") ~default
|
|
in
|
|
|
|
write_sexp "c_flags.sexp" (sexp_of_list sexp_of_string conf.cflags);
|
|
write_sexp "c_library_flags.sexp" (sexp_of_list sexp_of_string conf.libs))
|
|
|
|
Using a custom code generator
|
|
=============================
|
|
|
|
To generate a file ``foo.ml`` using a program from another directory:
|
|
|
|
.. code:: scheme
|
|
|
|
(jbuild_version 1)
|
|
|
|
(rule
|
|
((targets (foo.ml))
|
|
(deps (../generator/gen.exe))
|
|
(action (run ${<} -o ${@}))))
|
|
|
|
Defining tests
|
|
==============
|
|
|
|
Write this in your ``jbuild`` file:
|
|
|
|
.. code:: scheme
|
|
|
|
(jbuild_version 1)
|
|
|
|
(alias
|
|
((name runtest)
|
|
(deps (my-test-program.exe))
|
|
(action (run ${<}))))
|
|
|
|
And run the tests with:
|
|
|
|
.. code:: bash
|
|
|
|
jbuilder runtest
|
|
|
|
Building a custom toplevel
|
|
==========================
|
|
|
|
A toplevel is simply an executable calling ``Topmain.main ()`` and
|
|
linked with the compiler libraries and ``-linkall``. Moreover,
|
|
currently toplevels can only be built in bytecode.
|
|
|
|
As a result, write this in your ``jbuild`` file:
|
|
|
|
.. code:: scheme
|
|
|
|
(jbuild_version 1)
|
|
|
|
(executable
|
|
((name mytoplevel)
|
|
(libraries (compiler-libs.toplevel mylib))
|
|
(link_flags (-linkall))
|
|
(modes (byte))))
|
|
|
|
And write this in ``mytoplevel.ml``
|
|
|
|
.. code:: ocaml
|
|
|
|
let () = Topmain.main ()
|