1

I have an OCaml project that is currently built using OCamlMake. I am not happy with the current build system since it leaves all build artefacts in the same directory as source files, plus it also requires to manually specify order of dependencies between modules. I would like to switch to a build system that does not suffer from these issues. I decided to give Oasis a try but have run into issues.

The problems arise from the fact that the project is built in a very specific way. It supports several different database backends (PostgreSQL, MySQL, SQLite). Currently, to compile a database backend user must install extra libraries required by that backend and enable it by setting an environment variable. This is how it looks in the Makefile:

ifdef MYSQL_LIBDIR
   DB_CODE    += mysql_database.ml
   DB_AUXLIBS += $(MYSQL_LIBDIR)
   DB_LIBS    += mysql
endif

Notice that this also adds extra module to the list of compiled modules. The important bit is that there is no dependency (in a sense of module import) between any module reachable from the applications entry point and database backend module. What happens rather is that each database backend module contains top-level code that runs when a module is initiated and registers itself, using side-effects, with the main application.

I cannot get this setup to work with Oasis. I declared each of the database backend modules as a separate library that can be enabled for compilation with a flag:

Library mysql-backend
  Path          : .
  Build        $: flag(mysql)
  Install       : false
  BuildTools    : ocamlbuild
  BuildDepends  : main, mysql
  Modules       : Mysql_backend

However, I cannot figure out a way to tell Oasis to link the optional modules into the executable. I tried to figure out a way of doing this by modifying myocamlbuild.ml file but failed. Can I achieve this with the rule function described here?

If what I describe cannot be achieved with ocamlbuild, is there any ither tool that would do the job and avoid problems of OCamlMake?

Jan Stolarek
  • 1,409
  • 1
  • 11
  • 21

3 Answers3

1

Well, I guess that answers it: https://github.com/links-lang/links/pull/77 :)

Drup
  • 3,679
  • 13
  • 14
  • I'm not sure how it solves the problem. The question was how to implement optional dependencies, the object section doesn't solve this, you still need to specify the dependency explicitly in the host program. Basically, the question was how to implement polymorphism on a compile level, when you can substitute libraries with the same interface but different implementations. – ivg Oct 01 '16 at 16:02
  • ah, ok I see, you have also implemented conditional linking in the myocamlbuild plugin. A little hardcodish, but should work. Ideally, we should contribute this back to the oasis. As your PR is a PoC that it may work :) – ivg Oct 01 '16 at 16:13
1

I saw the question and started working on it before I noticed Drup's answer above. Below is a self-contained ocamlbuild solution that is essentially the same as Drup's.

open Ocamlbuild_plugin

let enable_plugin () =
  let plugins = try string_list_of_file "plugin.config" with _ -> [] in
  dep ["ocaml"; "link_with_plugin"; "byte"]
    (List.map (fun p -> p^".cmo") plugins);
  dep ["ocaml"; "link_with_plugin"; "native"]
    (List.map (fun p -> p^".cmx") plugins);
  ()

let () = dispatch begin
    function
    | Before_rules -> enable_plugin ()
    | _ -> ()
end

Using the tag link_with_plugin on an ocamlbuild target will make it depend on any module whose path (without extension) is listed in the file plugin.config. For example if you have plugins pluga.ml, plugb.ml and a file main.ml, then writing pluga plugb in plugin.config and having <main.{cmo,cmx}>: link_with_plugin will link both plugin modules in the main executable.

gasche
  • 31,259
  • 3
  • 78
  • 100
0

Unfortunately, this is beyond oasis capabilities. This limitation has nothing to do with ocamlbuild, it just because oasis author tried to keep it simple, and didn't provide optional dependencies as a feature.

As always, an extra level of indirection may solve your problem. What you need, is a configuration script (configure) that will generate _oasis file for you, depending on parameters, provided by a user.

For example, in our project we have a similar setup, i.e., multiple different backends, that might be chosen by a user during the configuration phase, with --{enable,disable}-<feature>. We achieved this by writing our own ./configure script that generate _oasis file, depending on configuration. The configuration script just concatenates the resulting _oasis files from pieces, described in oasis folder.

An alternative solution would be to use m4 or just cpp, and have an _oasis.in file, that is preprocessed.

ivg
  • 34,431
  • 2
  • 35
  • 63
  • If the limitation has nothing to do with `ocamlbuild` can I somehow use `myocamlbuild.ml` to get what I want? – Jan Stolarek Sep 30 '16 at 19:24
  • I think you're confusing these two tools. `myocamlbuild.ml` is a plugin to ocamlbuild. `ocamlbuild` is a compilation driver, that knows how to build things, from the given recipes. In the plugin you can teach `ocamlbuild` how to build new things (e.g., latex, c++, preprocessing). `ocamlbuild` is not used to describe your project. You can describe your project manually, either in Makefile, or using `mlpack`. – ivg Sep 30 '16 at 19:30
  • ivg: preprocessing the oasis file is probably the worst way to do things: it makes your build system depend on oasis, which it shouldn't, and it's extremely heavy handed. See my answer for a better solution. – Drup Oct 01 '16 at 15:18
  • @Drup, I wouldn't say that is the worst. Not the cleanest one, but definitely not the worst. There are about 300 packages that depend on oasis in opam, and I myself, in company's repository maintain 60+ packages, that are also dependent on oasis. I never ever had any problems with it. This also follows in line with how cmake is used, and oasis, for me, is a cmake for OCaml. Finally, oasis has very few dependencies, so it really doesn't add anything to the build time. Speaking about the better solution, then it would be to add the feature to the oasis, or to implement another build system. – ivg Oct 01 '16 at 16:06