*************** Advanced topics *************** This section describes some details of Jbuilder for advanced users. META file generation ==================== Jbuilder uses ``META`` files from the `findlib library manager `__ in order to interoperate with the rest of the world when installing libraries. It is able to generate them automatically. However, for the rare cases where you would need a specific ``META`` file, or to ease the transition of a project to Jbuilder, it is allowed to write/generate a specific one. In order to do that, write or setup a rule to generate a ``META..template`` file in the same directory as the ``.opam`` file. Jbuilder will generate a ``META.`` file from the ``META..template`` file by replacing lines of the form ``# JBUILDER_GEN`` by the contents of the ``META`` it would normally generate. For instance if you want to extend the ``META`` file generated by Jbuilder you can write the folliwing ``META.foo.template`` file: .. code:: # JBUILDER_GEN blah = "..." .. _custom-driver: Using a custom ppx driver ========================= You can use a custom ppx driver by putting it as the last library in ``(pps ...)`` forms. An example of alternative driver is `ppx_driver `__. To use it instead of ``ocaml-migrate-parsetree.driver-main``, simply write ``ppx_driver.runner`` as the last library: .. code:: scheme (preprocess (pps (ppx_sexp_conv ppx_bin_prot ppx_driver.runner))) Driver expectation ------------------ Jbuilder will invoke the executable resulting from linking the libraries given in the ``(pps ...)`` form as follows: .. code:: bash ppx.exe --dump-ast -o \ [--cookie library-name=""] [--impl|--intf] Where ```` is either an implementation (``.ml``) or interface (``.mli``) OCaml source file. The command is expected to write a binary OCaml AST in ````. Additionally, it is expected that if the executable is invoked with ``--as-ppx`` as its first argument, then it will behave as a standard ppx rewriter as passed to ``-ppx`` option of OCaml. This is for two reasons: - to improve interoperability with build systems other than Jbuilder - so that it can be used with merlin Findlib integration and limitations =================================== Jbuilder uses ``META`` files to support external libraries. However, it doesn't export the full power of findlib to the user, and especially it doesn't let the user specify *predicates*. The reason for this limitation is that so far they haven't been needed, and adding full support for them would complicate things quite a lot. In particular, complex ``META`` files are often hand-written and the various features they offer are only available once the package is installed, which goes against the root ideas jbuilder is built on. In practice, jbuilder interpret ``META`` files assuming the following set of predicates: - ``mt``: what this means is that using a library that can be used with or without threads with jbuilder will force the threaded version - ``mt_posix``: forces the use of posix threads rather than VM threads. VM threadws are deprecated and are likely to go away soon - ``ppx_driver``: when a library acts differently depending on whether it is linked as part of a driver or meant to add a ``-ppx`` argument to the compiler, choose the former behavior Cross Compilation ================= Jbuilder allows for cross compilation by defining build contexts with multiple targets. Targets are specified by adding a ``targets`` field to the definition of a build context. ``targets`` takes a list of target name. It can be either: - ``native`` which means using the native tools that can build binaries that run on the machine doing the build - the name of an alternative toolchain Note that at the moment, there is no official support for cross-compilation in OCaml. Jbuilder supports the opam-cross-x repositories from the `ocaml-cross organization on github `, such as: - `opam-cross-windows `_ - `opam-cross-android `_ - `opam-cross-ios `_ In particular: - to build Windows binaries using opam-cross-windows, write ``windows`` in the list of targets - to build Android binaries using opam-cross-android, write ``android`` in the list of targets - to build Android binaries using opam-cross-ios, write ``ios`` in the list of targets For example, the following workspace file defines three different targets for the ``default`` build context: .. code:: scheme (context (default (targets (native windows android)))) This configuration defines three build contexts: - ``default`` - ``default.windows`` - ``default.android`` Note that the ``native`` target is always implicitly added when not present. However, when implicitly added ``jbuilder build @install`` will skip this context, i.e. ``default`` will only be used for building executables needed by the other contexts. With such a setup, calling ``jbuilder build @install`` will build all the packages three times. Note that instead of writing a ``jbuild-workspace`` file, you can also use the ``-x`` command line option. Passing ``-x foo`` to ``jbuilder`` without having a ``jbuild-workspace`` file is the same as writing the following ``jbuild-workspace`` file: .. code:: scheme (context (default (targets (foo)))) If you have a ``jbuild-workspace`` and pass a ``-x foo`` option, ``foo`` will be added as target of all context stanzas. How does it work? ----------------- In such a setup, binaries that need to be built and executed in the ``default.windows`` or ``default.android`` contexts as part of the build, will no longer be executed. Instead, all the binaries that will be executed will come from the ``default`` context. One consequence of this is that all preprocessing (ppx or otherwise) will be done using binaries built in the ``default`` context. To clarify this with an example, let's assume that you have the following ``src/jbuild`` file: .. code:: scheme (executable ((name foo))) (rule (with-stdout-to blah (run ./foo.exe))) When building ``_build/default/src/blah``, jbuilder will resolve ``./foo.exe`` to ``_build/default/src/foo.exe`` as expected. However, for ``_build/default.windows/src/blah`` jbuilder will resolve ``./foo.exe`` to ``_build/default/src/foo.exe`` Assuming that the right packages are installed or that your workspace has no external dependencies, jbuilder will be able to cross-compile a given package without doing anything special. Some packages might still have to be updated to support cross-compilation. For instance if the ``foo.exe`` program in the previous example was using ``Sys.os_type``, it should instead take it as a command line argument: .. code:: scheme (rule (with-stdout-to blah (run ./foo.exe -os-type ${os_type}))) Classical ppx ============= *classical ppx* refers to running ppx using the -ppx compiler option, which is composed using Findlib. Even though this is useful to run some (usually old) ppx's which don't support drivers, Jbuilder does not support preprocessing with ppx this way. but a workaround exists using the `ppxfind `_ tool.