Ocamlbuild override the default options - ocaml

My installation of OCaml does not recognize #!, therefore camlp4o cannot be ran standalone. It must be invoked as "ocamlrun camlp4o".
I try to add a flag in the plugin. But the new flag is simply added to the existing flag.
The result is that ocamlbuild will invoke the compiler with
"-pp camlp4o ocamlrun camlp4o".
A working workaround is to introduce a new tag 'my_camlp4o'. However, the documentation of ocamlbuild did mention the capability of 'overriding' defaults. It seems ocamlc, ocamlopt can be overridden. But can we override camlp4o? Can it be done in plugins?

There is support for changing defaults in Ocamlbuild, through the -ocamlc <command>, -ocamldep <command> etc. command-line options. Unfortunately, camlp4 is currently not part of the set of customizable commands. Could you please use the issue tracker to request this feature?
(In the meantime I recommend a workaround, eg. you replace the ocamlrun executable in your PATH by an executable script that does the right thing.)
Edit
Another workaround is to do all your compilation through ocamlfind, which has support for overriding the camlp4 command (see the documentation), and can be used as a basis for all ocamlbuild command with the -use-ocamlfind option. Unfortunately, ocamlfind itself only supports preprocessing at compile-time (when invoking the actual compiler), not stand-alone source-to-source processing, so that may not cover your own use case.

Related

Handling Meson build options with multiple buildtypes

Having read the Meson site pages (which are generally high quality), I'm still unsure about the intended best practice to handle different options for different buildtypes.
So to specify a debug build:
meson [srcdir] --buildtype=debug
Or to specify a release build:
meson [srcdir] --buildtype=release
However, if I want to add b_sanitize=address (or other arbitrary complex set of arguments) only for debug builds and b_ndebug=true only for release builds, I would do:
meson [srcdir] --buildtype=debug -Db_sanitize=address ...
meson [srcdir] --buildtype=release -Db_ndebug=true ...
However, it's more of a pain to add a bunch of custom arguments on the command line, and to me it seems neater to put that in the meson.build file.
So I know I can set some built in options thusly:
project('myproject', ['cpp'],
default_options : ['cpp_std=c++14',
'b_ndebug=true'])
But they are unconditionally set.
So a condition would look something like this:
if get_option('buildtype').startswith('release')
add_project_arguments('-DNDEBUG', language : ['cpp'])
endif
Which is one way to do it, however, it would seem the b_ndebug=true way would be preferred to add_project_arguments('-DNDEBUG'), because it is portable.
How would the portable-style build options be conditionally set within the Meson script?
Additionally, b_sanitize=address is set without any test whether the compiler supports it. I would prefer for it to check first if it is supported (because the library might be missing, for example):
if meson.get_compiler('cpp').has_link_argument('-fsanitize=address')
add_project_arguments('-fsanitize=address', language : ['cpp'])
add_project_link_arguments('-fsanitize=address', language : ['cpp'])
endif
Is it possible to have the built-in portable-style build options (such as b_sanitize) have a check if they are supported?
I'm still unsure about the intended best practice to handle different options for different buildtypes
The intended best practice is to use meson configure to set/change the "buildtype" options as you need it. You don't have to do it "all at once and forever". But, of course, you can still have several distinct build trees (say, "debug" and "release") to speed up the process.
How would the portable-style build options be conditionally set within the Meson script?
Talking of b_ndebug, you can use the special value: ['b_ndebug=if-release'], which does exactly what you want. Also, you should take into account, that several GNU-style command-line arguments in meson are always portable, due to the internal compiler-specific substitutions. If I remember correctly, these include: -D, -I, -L and -l.
However, in general, changing "buildtype" options inside a script (except default_options, which are meant to be overwritten by meson setup/configure), is discouraged, and meson intentionally lacks set_option() function.
Is it possible to have the built-in portable-style build options (such as b_sanitize) have a check if they are supported?
AFAIK, no, except has_argument() you've used above. However, if some build option, like b_sanitize, is not supported by the underlying compiler, then it will be automatically set to void, so using it shouldn't break anything.

Documentation generation for BuckleScript project

Is there any way to generate code documentation for BuckleScript or Reason? I've tried using ocamldoc, but I don't know how to include node package dependencies automatically.
There isn't an automatic resolution yet for node packages. You can manually specify each dependent package in the ocamldoc command, e.g.:
ocamldoc -html -d doc -I node_modules/bs-webapi/lib/ocaml -I node_modules/bs-fetch/lib/ocaml -I node_modules/bs-platform/lib/ocaml src/YourModule.re
The directory includes are fairly predictable, you just have to point at the lib/ocaml directories in each package, ocamldoc will find their compiled .cmi files and pull in the required type information from there.
This also means that you'll first need to have done bsb -make-world, to compile all those .cmis.
There’s a tool which, supposedly, automatically performs a lot of the orchestration of ocamldoc described by #Yawar, called BsDoc.
Note that I have not used this myself; but it it supposed to be the go-to for a lot of BuckleScript-specific projects (i.e. using bsb with npm-installed dependencies, not dune with opam-installed dependencies.)

Using Ocamlbuild plugins with Oasis

What is the proper way to integrate Ocamlbuild plugins like Ocamlbuild-protoc into a project managed by Oasis? I know how to manually edit myocamlbuild.ml to invoke the plugin, but that's not enough, because the proper tags have not been set. According to this particular plugin docs, it needs to be invoked with the following command, but I don't know how to do it in Oasis:
ocamlbuild -use-ocamlfind -plugin-tag "package(ocamlbuild_protoc)" target.native
Or is there maybe builtin support for Ocamlbuild plugins in Oasis that I missed?
Add to your _oasis file (outside any section) the line AlphaFeatures: ocamlbuild_more_args and XOCamlbuildExtraArgs: "-plugin-tag 'package(ocamlbuild_protoc)'".

How to compile a jocaml file with ocamlbuild and include a package?

How can I compile a jocaml source file which needs the cryptokit package (successfully compiled with the companion ocaml) with the ocamlbuild tool?
When I execute the command ocamlbuild -pkg cryptokit -use-jocaml a.native I get this error:
Warning: tag "package" does not expect a parameter, but is used with parameter "cryptokit"¬
+ jocamlopt -I /prefix/lib/ocaml -I /prefix/lib/ocaml/site-lib/cryptokit -I /prefix/lib/ocaml/site-lib/num /prefix/lib/ocaml/unix.cmxa /prefix/lib/ocaml/nums.cmxa /prefix/lib/ocaml/site-lib/cryptokit/cryptokit.cmxa a.cmx -o a.native¬
File "_none_", line 1:¬
Error: Files /prefix/lib/ocaml/unix.cmxa¬
and /prefix/lib/ocaml/unix.cmxa¬
both define a module named Unix¬
Command exited with code 2.¬
Compilation unsuccessful after building 4 targets (3 cached) in 00:00:00.
Essentially, the ocaml Unix module clashes with himself.
This error only pops when I include Cryptokit (with -pkg cryptokit) probably because Cryptokit requires Unix. a.ml can in fact be empty and still reproduce the error.
I tried to add the -use-ocamlfind flag but as it also uses ocamlfind to get the compiler, it selects the ocaml compiler instead of the jocaml one.
By executing sequentially the same commands as ocamlbuild (displayed by -verbose 1), I got that when I execute the last one without /.../unix.cmxa then there is no more clash, but the wrong Unix module is loaded: it's the one from ocaml and not from jocaml, so it it completely crashes when I use any jocaml feature in a.ml:
jocamlopt -I /prefix/lib/ocaml -I /prefix/lib/ocaml/site-lib/cryptokit -I /prefix/lib/ocaml/site-lib/num /prefix/lib/ocaml/nums.cmxa /prefix/lib/ocaml/site-lib/cryptokit/cryptokit.cmxa a.cmx -o a.native
However, when I also remove the -I /prefix/lib/ocaml part, then it compiles successfully:
jocamlopt -I /prefix/lib/ocaml/site-lib/cryptokit -I /prefix/lib/ocaml/site-lib/num /prefix/lib/ocaml/nums.cmxa /prefix/lib/ocaml/site-lib/cryptokit/cryptokit.cmxa a.cmx -o a.native
To summarize, I got it to work by executing manually a modification of the last command, but I would like to get ocamlbuild working.
I think this error has to do with the fact that Cryptokit requires the Unix module: as I compiled it with ocaml and not jocaml, at the linking stage it tries to link with the ocaml stdlib one (which needs to be included) and not the jocaml stdlib one (which is implicitly included as part of the stdlib).
I had no idea there were active users of the ocamlbuild+JOcaml combination! By curiosity, would you say a bit more about what you are using JOCaml+cryptokit for?
I don't know much about Cryptokit or JOCaml, but it looks like your main problem is not related to ocamlbuild. If I understand correctly, (1) Cryptokit needs Unix and (2) JOCaml needs to use its own variant of Unix. If this is correct, compiling Cryptokit against ocaml's Unix and expecting it to work when linked with a JOCaml program that itself requires JOCaml's Unix is bound to create a lot of trouble. If this work in your case, it must be because either the part of Cryptokit you use doesn't actually require Unix, or the JOCaml program you are testing with does not actually require JOCaml's Unix. In the long run, it would probably be best to compile Cryptokit with JOCaml directly (I don't know how comfortable you are with the OCaml ecosystem in general, but I would personally try to build an OPAM switch where ocaml{c,opt} are aliases for jocaml{c,opt} and build programs from that).
Regarding the ocamlbuild specific part, it's hard to give any accurate advice without a tarball to be able to reproduce your setup and experiment with it. But I would try one of the two following options:
You can use -use-ocamlfind and teach ocamlfind to use jocaml instead of ocaml by using the OCAMLFIND_COMMANDS environment variable (see man ocamlfind)
You can avoid -use-ocamlfind entirely and instead call ocamlfind as a command-line tool to get the location of the cryptokit library (ocamlfind query cryptokit). You would then not use -pkg cryptokit but pass the path yourself (with -lflags and -cflags or by modifying your myocamlbuild.ml configuration file).
Elaborating on the -use-ocamlfind option as suggested by gasche, I got it to work with the addition of a small nasty hack: removing "unix" from the requires field of the META file of the cryptokit package. It works because jocaml links everything with threads and unix by default (a real solution would have been to disable this behavior, but it seems a lot harder). So the working compilation command is:
ocamlbuild -use-ocamlfind -use-jocaml -pkg cryptokit a.ml
I think it is possible to generalize this to any package that uses either unix or threads when compiling with jocaml. A subsidiary question is whether it is possible to do this dynamically with a _tags or myocamlbuild.ml file (note: comment if this remark needs to be moved).

How to configure _oasis for OCaml to set 'Profile' flag

I have an existing project in OCaml and one _oasis file. I don't know where to enable the profiling flag for ocamlbuild.
I looked up Oasis manual and the code, and found there was a variable profile available in setup.data. I assume this was what Oasis auto generated.
Where and what should I include in _oasis to set profile to true ?
You can activate the ocamlbuild_more_args feature.
On top of your _oasis file:
AlphaFeatures: ocamlbuild_more_args
Then, in your Package:
XOCamlbuildExtraArgs: your_ocamlbuild_option
I can't find any -profile option in ocamlbuild though, so I'm not sure of what this is about. Also, this option is still quite unstable.
A better way to handle that would be to modify your _tags file accordingly. It is generated by oasis but you can modify it.
EDIT:
setup.data informs you of environment variables. As for profile, it shows if the -p option will be passed to ocamlopt. You can pass it using the NativeOpt field.
You can enable the oasis profile flag by adding the --enable-profile argument to the ./configure flag. But so far, I have only noticed any effect when I enabled native code compilation (CompiledObject: native in _oasis). Even then, the profiling generation is only done for gprof.
I suggest you to use _tags file as it is the easiest way. Just add the following to your _tags:
<true> : profile
You run this command:
echo "<true> : profile" >> _tags
in the folder where your _tags file is located.
If you still want to use _oasis file, then you can use NativeOpt field, to add options that will be passed to native compiler, i.e., ocamlopt.