ocamlbuild: build plugin with options - ocaml

I'm trying to write an ocamlbuild plugin (myocamlbuild.ml) that will use definitions from another file. I have a lot of definitions that I'd like to be used across several build plugins and I wanted put them in their own file. I tried running ocamlbuild twice, once with -no-plugin just to build the plugin, e.g.
ocamlbuild -no-plugin myocamlbuild.cmo
and then again afterwards
ocamlbuild actual-targets.otarget
but when I run the second one it tries to rebuild the plugin and complains that it can't find the included library (even though it exists in the _build directory). So, is there any way that I can convince ocamlbuild to include '-I _build _build/coq_paths.cmx' on the command line? From 'ocamlbuild -help' it looks like there is a '-plugin-option' flag, but I can't find any way to use it.
Thanks.

Since 4.01, ocamlbuild supports a new (experimental) option -plugin-tag that allows to specify (built-in) ocamlbuild tags to use when compiling myocamlbuild.ml. If you package "coq-paths" using findlib, you can then use
ocamlbuild -use-ocamlfind -plugin-tag "package(coq-path)" ...

Related

Is it possible to compile OCaml codes using Core without corebuild?

I'm using Ubuntu 18.04. I have OCaml 4.05 installed (via apt-get) as well as utop and Core (via opam). And this is the content of my ~/.ocamlinit:
(* Added by OPAM. *)
let () =
try Topdirs.dir_directory (Sys.getenv "OCAML_TOPLEVEL_PATH")
with Not_found -> ()
;;
#use "topfind";;
#thread;;
#camlp4o;;
#require "core.top";;
#require "core.syntax";;
Compiling OCaml codes which use Core works fine with corebuild. It doesn't work with plain ocamlc or ocamlopt though. They complain:
Error: Unbound module Core
And I found corebuild to be pretty picky. It doesn't like any existing non-OCaml codes in the same directory:
SANITIZE: a total of 12 files that should probably not be in your source tree
has been found. A script shell file "/home/anta40/Codes/_build/sanitize.sh"
is being created. Check this script and run it to remove unwanted files or
use other options (such as defining hygiene exceptions or using the
-no-hygiene option).
IMPORTANT: I cannot work with leftover compiled files.
ERROR: Leftover object files:
File hellod.o in . has suffix .o
File helloscheme_.o in . has suffix .o
File nqueens.o in . has suffix .o
File helloscheme.o in . has suffix .o
File HelloHS.o in . has suffix .o
File helloml.o in . has suffix .o
ERROR: Leftover OCaml compilation files:
File nqueens.cmo in . has suffix .cmo
File helloml.cmo in . has suffix .cmo
File helloml.cmi in . has suffix .cmi
File nqueens.cmi in . has suffix .cmi
File nqueens.cmx in . has suffix .cmx
File helloml.cmx in . has suffix .cmx
Exiting due to hygiene violations.
Compilation unsuccessful after building 0 targets (0 cached) in 00:00:00.
Using the -no-hygiene option, e.g corebuild sum.ml -no-hygiene doesn't produce any native executable. Is there any workaround?
`
The OPAM package manager can support multiple OCaml instances, where each groups an OCaml installation (ocaml, ocamlc, ocamlopt, etc.) with installed packages. Each instance is called a switch.
Type ocaml switch to see a list of instances. In terms of switches, the installation of OCaml using packages (apt-get) is called system.
It may be better to avoid mixing the system and OPAM installations. I suggest that you create a new switch, ensure that the OPAM settings are properly sourced, and install Core into it the new switch :
opam switch 4.06.1
eval $(opam config env)
opam install core
The automatic build tools assume that they control the entire build process and complain when they find other compilation results. Normally, running the suggested shell script and retrying side-steps the problem, even if only to uncover another one. Your second problem (with -no-hygeine) may be related to the installation issues.
Your installation is dated.
I imagine that you followed instructions in Real World OCaml but OCaml ecosystem has moved since the first edition of RWO. To get a modern installation you should follow the dev version of Real World OCaml https://dev.realworldocaml.org/install.html .
To answer your question, corebuild is a fine wrapper around ocamlbuild. To build an executable from a sum.ml with corebuild, you should use
corebuild sum.native
for native executable or
corebuild sum.byte
for bytecode compilation
Otherwise, you can invoke ocamlopt through ocamlfind:
ocamlfind ocamlopt -package core sum.ml
Finally, if you intend to build larger project, you ought to have a look to dune https://jbuilder.readthedocs.io/en/latest/overview.html .

How to let a new compiled ocamlc to compile a simple ocaml program?

I build ocaml from source,first ./configure,then make world
so i have a ocamlc program under the source folder
I write a simple program a.ml:
let a=1
then ./ocamlc a.ml
but got error:Unbound mudule Pervasives
I tried to use
./ocamlc -I +compiler-libs ./stdlib/stdlib.cma a.ml
and
./ocamlc -I +compiler-libs ./compilerlibs/*.cma a.ml
but got this error too
so how to build a.ml use the new compiled ocamlc?Thanks
Usually OCaml compiler is supposed to be installed by make install before using it.
Having said that, there is a way to use the compiler without installing it:
$ boot/ocamlrun ./ocamlc -nostdlib -I stdlib -c a.ml
boot/ocamlrun is required to use the correct bytecode interpreter. It may work without it, but it may be just by luck: the interpreter specified in your new ./ocamlc shebang may pre-exists and may be compatible with your new compiler.
-nostdlib is required not to use the standard library already installed.
-I stdlib is required to load the correct standard library compiled with your new ocamlc compiler.
If you need to use other libraries add appropriate include and linking options.
Everything is explained in http://caml.inria.fr/pub/docs/manual-ocaml/comp.html , so please read it.
If you want to use compiler libraries without installing them, you have to not only link with one or several *.cma files under ./compilerlibs, but also add -I options of directories of compiler sources: -I parsing -I utils -I typing ..., so that ./ocamlc can find the required *.cmi files. (If you want to play with the compiler libs, you should be familiar with how OCaml compiler finds modules first of all...)

ocamlbuild specify output location/name

Can I specify the build location and file name with the ocamlbuild tool? I would like to be able to say (in pseudocode):
ocamlbuild myapp.ml -b native -o bin/myapp
There is no such option, but ocamlbuild is extensible and allows you to add your own options with Options.add. Of course, you will also need to add some implementation. Basically, hijacking the rule for native and extending it with installation procedure may work. To extend ocamlbuild you should write a plugin (other option is to create your own standalone executable, and use it instead of ocamlbuild, that is what we're doing in our project).
But for most purposes it is enough to use standard tools like ocamlfind, oasis. I would suggest to look at the latter, as it is more high-level.
Oasis
With oasis you need to write a simple _oasis file (or use oasis quickstart to write it interactively). The minimum file would look something like this:
OASISFormat: 0.4
Name: myapp
Version: 0.0.1
Synopsis: My first application in oasis
Authors: Authors list
Maintainers: Maintainer Name
License: MIT
Copyrights: (C) Copyright Holder
Plugins: META (0.4), DevFiles (0.4)
BuildTools: ocamlbuild
Executable "myapp"
Path: .
MainIs: myapp.ml
Install: true
CompiledObject: best
After the file is finished, run
oasis setup
that will generate Makefile and configure script. Run
./configure
as usual to check and setup your environment. E.g., ./configure --prefix=$HOME will setup your build system to install into your home folder (i.e., to executables to ~/bin, etc). I usually prefer to install onto opam stack, and use ./configure --prefix=$(opam config var env)
And finally, usual pair of
make && make install
Will do the work.
OCamlfind
ocamlfind will still require your to write META file. Usually they write them by just copy-pasting and editing the META file from some existing project. But it is not hard to write one, as it is very well documented.
After the meta is written, you can use ocamlfind install subcommand which has a -destdir option.
But ocamlfind doesn't handle executables, only libraries. So this may not suit you.
With entering ocamlbuild --help, I cannot find a such option.
One solution is to write a script doing this :
#!/bin/bash
ocalmbuild myapp.native // build your executable
mv myapp.native bin/myapp // rename it
EDIT:
Following suggestion of ivg, you should replace the line mv myapp.native bin/myapp by cp -L myapp.native bin/myapp.
Maybe someone can give this option, which I found interesting but in the user manual, there is not. So one solution is to use script.

OCamlfind local library unbound module

I am trying to use ocamlfind to install a library. I am using OCamlMakeFile. Here is my Makefile:
OCAMLMAKEFILE = OCamlMakeFile
RESULT = owebl
SOURCES = src/utils.ml src/verb.ml src/request.ml src/template.ml src/response.ml src/rule.ml src/handler.ml src/server.ml
PACKS = unix str
all: native-code-library byte-code-library
install: libinstall
uninstall: libuninstall
include $(OCAMLMAKEFILE)
So basically the library is a collection of modules that I want to distribute. A basic usage of the library is (main.ml):
open Response
open Rule
open Verb
open Server
let handler =
Handler.create
(StaticRouteRule.create "/" [GET])
(FileResponse.create
~static_file:(FileResponse.StaticFile "/index.html")
())
let server = Server.create "0.0.0.0" 8080 [handler];;
server#serve
I compile the library just by running "make". It generates three files: "owebl.a, owebl.cma, owebl.cmxa". Then I install the library using ocamlfind:
ocamlfind install owebl META owebl.a owebl.cma owebl.cmxa
Oh, the META file is:
version = "0.1"
name = "OWebl"
description = "A Web Framework for OCaml"
archive(byte) = "owebl.cma"
archive(native) = "owebl.cmxa"
requires = "unix,str"
Everything works until I try to compile the above example that uses the library. I run:
ocamlbuild -use-ocamlfind -pkgs owebl main.native
And I get:
ocamlbuild -use-ocamlfind -pkgs owebl main.native
+ ocamlfind ocamlc -c -package owebl -o main.cmo main.ml
File "main.ml", line 1, characters 5-10:
Error: Unbound module Owebl
Command exited with code 2.
Hint: Recursive traversal of subdirectories was not enabled for this build,
as the working directory does not look like an ocamlbuild project (no
'_tags' or 'myocamlbuild.ml' file). If you have modules in subdirectories,
you should add the option "-r" or create an empty '_tags' file.
To enable recursive traversal for some subdirectories only, you can use the
following '_tags' file:
true: -traverse
<dir1> or <dir2>: traverse
Compilation unsuccessful after building 2 targets (1 cached) in 00:00:00.
make: *** [fileserver] Error 10
I tried adding open Owebl to the beginning of main.ml but I just got "unbound module Owebl" similarly. I'm pretty lost as to why these modules are all unbound. What am I missing?
You should use LIB_PACK_NAME variable if you want to pack your modules under umbrella namespace, like OWebl, otherwise they will be available just as it is, e.g. Response, Rule, etc. Also, you should specify the mli files as well as ml files in SOURCES variable. And finally, you shouldn't forget to install cmi files, as well as .a files. Installing mli files is also considered a good tradition, although is not strictly required. Also, consider using OCamlMakefile installation facilities instead of custom installation script.
I am no longer using OCamlMakefile therefore am not sure, but assuming OCamlMakefile compiles things with -for-pack OWebl option and properly builds a packaged module owebl.cmo, you also need to install owebl.cmi.
OCaml compiler seeks cmi files to check the existence of modules and to get their type information. If not installed, the compiler cannot find it. cma and cmxa files are collections of objects and do not provide type information.

Using "ocamlfind" to make the OCaml compiler and toplevel find (project specific) libraries

I'm trying to use ocamlfind with both the OCaml compiler and toplevel. From what I understood, I need to place the required libraries in the _tags file at the root of my project, so that the ocamlfind tool will take care of loading them - allowing me to open them in my modules like so :
open Sdl
open Sdlvideo
open Str
Currently, my _tags file looks like this :
<*>: pkg_sdl,pkg_str
I can apparently launch the ocamlfind command with the ocamlc or ocamlopt argument, provided I wan't to compile my project, but I did not see an option to launch the toplevel in the same manner. Is there any way to do this (something like "ocamlfind ocaml")?
I also don't know how to place my project specific modules in the _tags file : imagine I have a module name Land. I am currently using the #use "land.ml" directive to open the file and load the module, but it has been suggested that this is not good practice. What syntax should I use in _tags to specify it should be loaded by ocamlfind (considering land.ml is not in the ocamlfind search path) ?
Thank you,
Charlie P.
Edit : According to the first answer of this post, the _tags file is not to be used with ocamlfind. The questions above still stand, there is just a new one to the list : what is the correct way to specify the libraries to ocamlfind ?
try this:
$ cat >> .ocamlinit
#use "topfind";;
#require "sdl";;
#require "sdlvideo";;
open Sdl
open Sdlvideo;;
open Str;;
.ocamlinit is sourced from the current directory, falling back to /home/user/.ocamlinit. you can explicitly override it via ocaml -init <filename>
One should distinguish ocamlfind packages, module names and file names. Source code references only module names. Modules are provided by .cma .cmo .cmx (and .cmi) files. Ocamlfind packages are named collections of such files (binaries built from some ocaml library sources). Ocamlfind is not strictly necessary to build a project - just specify the paths to all used libraries via -I. But if the project is distributed in source form - another people will have troubles building it cause used libraries are placed in different places. Then one seeks the way to specify the names of used "third party code pieces" and some external tool to resolve those names to actual paths. This tool is ocamlfind.
First find the ocamlfind package that provides the modules you need (in this case Sdl and Sdlvideo - just run ocamlfind list, most probably the package is named sdl.
Compile with ocamlfind ocamlc -package <package name> -linkpkg source.ml -o program
Alternatively use ocamlfind to extract the path to the .cma file (and others) provided by the package (ocamlfind query <package name>) and use this path with your build tool (plain Makefile, ocamlbuild, etc).
Moreover ocamlfind (is intended to) take away the burden of remembering how the actual .cma files are named and what matching compiler options are required and in what order the packages are depending on each other. One just needs to specify the package name.
Keep in mind that there is no one-to-one strict formal relationship between library name (purely human-targeted name e.g. ocaml-extlib), module names (ExtLib, Enum, IO, etc), file names (extLib.cma) and ocamlfind package name (extlib), though for convenience package maintainers and library authors usually choose guessable names :)
The _tags file is not for ocamlfind, but for ocamlbuild.
Exemple :
ocamlbuild land.native