OCaml - Parsing command-line options with arguments using Arg - ocaml

I want to parse command line options with arguments in OCaml.
The module Arg of the standard library seems to do everything I need and there are some tutorials which explain how to use this module.
My problem is, that they all seem to share the same strange behavior when the argument of an option is missing. For example, executing the program from this example with ./a.out -d produces the following output:
./a.out: option '-d' needs an argument.
usage: ./a.out [-b] [-s string] [-d int]
-b : set somebool to true
-s : what follows -s sets some string
-d : some int parameter
-help Display this list of options
--help Display this list of options
./a.out: ./a.out: option '-d' needs an argument.
usage: ./a.out [-b] [-s string] [-d int]
-b : set somebool to true
-s : what follows -s sets some string
-d : some int parameter
-help Display this list of options
--help Display this list of options
.
usage: ./a.out [-b] [-s string] [-d int]
-b : set somebool to true
-s : what follows -s sets some string
-d : some int parameter
-help Display this list of options
--help Display this list of options
I was not able to find out why the error/usage message is printed three times. This also happens to all the other code examples I found online. Is this a problem in the Arg module or is it somehow not used correctly in these examples?

I have managed to reproduce the bug with OCaml 4.04.2, but not with 4.02.3, so it would seem that there is some sort of regression going on there.
So, one thing you could do is sticking to an older version of OCaml, but I wouldn't recommend that.
Instead, you could use an alternative standard library, such as Jane Street's Core. It has a module named Command which allows you to write command-line interfaces just like the one you're trying to run.
An extensive tutorial for this module is available here.
As an example, here is the CLI from Rosetta using Command:
open Core
let spec =
let open Command.Spec in
empty
+> flag "-b" (no_arg) ~doc:"Sets some flag"
+> flag "-s" (optional_with_default "" string) ~doc:"STRING Some string parameter"
+> flag "-d" (optional_with_default 0 int) ~doc:"INTEGER Some int parameter"
let command =
Command.basic
~summary:"My awesome CLI"
spec
(fun some_flag some_string some_int () ->
printf " %b '%s' %d\n" some_flag some_string some_int
)
let () =
Command.run command
EDIT : This bug was known and is going to be fixed in OCaml 4.05.

Related

/bin/sh: 1: Syntax error: "(" unexpected after running Makefile [duplicate]

I often find Bash syntax very helpful, e.g. process substitution like in diff <(sort file1) <(sort file2).
Is it possible to use such Bash commands in a Makefile? I'm thinking of something like this:
file-differences:
diff <(sort file1) <(sort file2) > $#
In my GNU Make 3.80 this will give an error since it uses the shell instead of bash to execute the commands.
From the GNU Make documentation,
5.3.2 Choosing the Shell
------------------------
The program used as the shell is taken from the variable `SHELL'. If
this variable is not set in your makefile, the program `/bin/sh' is
used as the shell.
So put SHELL := /bin/bash at the top of your makefile, and you should be good to go.
BTW: You can also do this for one target, at least for GNU Make. Each target can have its own variable assignments, like this:
all: a b
a:
#echo "a is $$0"
b: SHELL:=/bin/bash # HERE: this is setting the shell for b only
b:
#echo "b is $$0"
That'll print:
a is /bin/sh
b is /bin/bash
See "Target-specific Variable Values" in the documentation for more details. That line can go anywhere in the Makefile, it doesn't have to be immediately before the target.
You can call bash directly, use the -c flag:
bash -c "diff <(sort file1) <(sort file2) > $#"
Of course, you may not be able to redirect to the variable $#, but when I tried to do this, I got -bash: $#: ambiguous redirect as an error message, so you may want to look into that before you get too into this (though I'm using bash 3.2.something, so maybe yours works differently).
One way that also works is putting it this way in the first line of the your target:
your-target: $(eval SHELL:=/bin/bash)
#echo "here shell is $$0"
If portability is important you may not want to depend on a specific shell in your Makefile. Not all environments have bash available.
You can call bash directly within your Makefile instead of using the default shell:
bash -c "ls -al"
instead of:
ls -al
There is a way to do this without explicitly setting your SHELL variable to point to bash. This can be useful if you have many makefiles since SHELL isn't inherited by subsequent makefiles or taken from the environment. You also need to be sure that anyone who compiles your code configures their system this way.
If you run sudo dpkg-reconfigure dash and answer 'no' to the prompt, your system will not use dash as the default shell. It will then point to bash (at least in Ubuntu). Note that using dash as your system shell is a bit more efficient though.
It's not a direct answer to the question, makeit is limited Makefile replacement with bash syntax and it can be useful in some cases (I'm the author)
rules can be defined as bash-functions
auto-completion feature
Basic idea is to have while loop in the end of the script:
while [ $# != 0 ]; do
if [ "$(type -t $1)" == 'function' ]; then
$1
else
exit 1
fi
shift
done
https://asciinema.org/a/435159

sumo-launchd.py sumo checking

when I execute the command :
sumo-launchd.py -vv-c /.../sumo-gui.exe
I receive error:
Usage: sumo-launchd.py (options)
sumo-launchd.py: error: no such option: --
sorry but I'm not very good with these installations
some help?
Most likely you wanted to use arguments -vv -c ... instead of -vv-c .... Many argument parsers treat a sequence of individual characters as multiple single-letter arguments (in your case: -v, -v, --, and -c), which is why the argument parser gives this weird error.

Z3 bindings on ocaml

I am currently using ocaml 4.06.0 and I am trying to use the Z3 sat solver. I am using opam's oasis to compile the files (which is building everything successfully). However, when I run the native code produced I am getting the following error: error while loading shared libraries: libz3.so. I tried reinstalling the z3 package but the error still persists. Can anyone help me solve this please because I have no idea what else to try?
Here is what I did just now to install z3 under Ubuntu 18.04.1:
$ opam depext conf-gmp.1
$ opam depext conf-m4.1
These installed gmp and m4 outside of opam. Pretty impressive.
$ opam install z3
Now the z3 library is installed so you can use it from OCaml code. But there are no executables installed (that I can find).
$ export LD_LIBRARY_PATH=~/.opam/4.06.0/lib/z3
$ ocaml -I ~/.opam/4.06.0/lib/z3
OCaml version 4.06.0
# #load "nums.cma";;
# #load "z3ml.cma";;
# let ctx = Z3.mk_context [];;
val ctx : Z3.context = <abstr>
The setting of LD_LIBRARY_PATH is what makes it possible to find libz3.so.
This is as far as I got for now. Maybe this will be helpful.
Update
Here is how I compiled and linked a test program.
$ export LD_LIBRARY_PATH=~/.opam/4.06.0/lib/z3
$ cat tz3.ml
let context = Z3.mk_context []
let solver = Z3.Solver.mk_solver context None
let xsy = Z3.Symbol.mk_string context "x"
let x = Z3.Boolean.mk_const context xsy
let () = Z3.Solver.add solver [x]
let main () =
match Z3.Solver.check solver [] with
| UNSATISFIABLE -> Printf.printf "unsat\n"
| UNKNOWN -> Printf.printf "unknown"
| SATISFIABLE ->
match Z3.Solver.get_model solver with
| None -> ()
| Some model ->
Printf.printf "%s\n"
(Z3.Model.to_string model)
let () = main ()
$ ocamlopt -I ~/.opam/4.06.0/lib/z3 -o tz3 \
nums.cmxa z3ml.cmxa tz3.ml
$ ./tz3
(define-fun x () Bool
true)
$ unset LD_LIBRARY_PATH
$ ./tz3
./tz3: error while loading shared libraries: libz3.so:
cannot open shared object file: No such file or directory
It works--i.e., it says that the trivial formula x can be satisfied by making x be true.
Note: initially I thought the setting of LD_LIBRARY_PATH wasn't necessary here. But in later testing I've found that it is necessary. So that is probably the key to your problem.
It's a little cumbersome and error prone to set LD_LIBRARY_PATH for running your programs. It's good enough for personal testing, but probably not for any kind of wider deployment. There are ways to set the search path for shared libraries at link time.
I hope this helps.

Determine place of segmentation error CMake

I am trying to figure out where a segmentation error is made. Thesame issue has been solved below for a different compiler. I am using CMake and am wondering if this compiler also has this function. CMake has no -g build option so I have no idea where to look.
Determine the line of code that causes a segmentation fault?
Here is also some info on what build options there are available for the debugger, maybe this points out what debugger I use since I have no idea.
/usr/bin/make: invalid option -- 'g'
Usage: make [options] [target] ...
Options:
-b, -m Ignored for compatibility.
-B, --always-make Unconditionally make all targets.
-C DIRECTORY, --directory=DIRECTORY
Change to DIRECTORY before doing anything.
-d Print lots of debugging information.
--debug[=FLAGS] Print various types of debugging information.
-e, --environment-overrides
Environment variables override makefiles.
--eval=STRING Evaluate STRING as a makefile statement.
-f FILE, --file=FILE, --makefile=FILE
Read FILE as a makefile.
-h, --help Print this message and exit.
-i, --ignore-errors Ignore errors from recipes.
-I DIRECTORY, --include-dir=DIRECTORY
Search DIRECTORY for included makefiles.
-j [N], --jobs[=N] Allow N jobs at once; infinite jobs with no arg.
-k, --keep-going Keep going when some targets can't be made.
-l [N], --load-average[=N], --max-load[=N]
Don't start multiple jobs unless load is below N.
-L, --check-symlink-times Use the latest mtime between symlinks and target.
-n, --just-print, --dry-run, --recon
Don't actually run any recipe; just print them.
-o FILE, --old-file=FILE, --assume-old=FILE
Consider FILE to be very old and don't remake it.
-O[TYPE], --output-sync[=TYPE]
Synchronize output of parallel jobs by TYPE.
-p, --print-data-base Print make's internal database.
-q, --question Run no recipe; exit status says if up to date.
-r, --no-builtin-rules Disable the built-in implicit rules.
-R, --no-builtin-variables Disable the built-in variable settings.
-s, --silent, --quiet Don't echo recipes.
-S, --no-keep-going, --stop
Turns off -k.
-t, --touch Touch targets instead of remaking them.
--trace Print tracing information.
-v, --version Print the version number of make and exit.
-w, --print-directory Print the current directory.
--no-print-directory Turn off -w, even if it was turned on implicitly.
-W FILE, --what-if=FILE, --new-file=FILE, --assume-new=FILE
Consider FILE to be infinitely new.
--warn-undefined-variables Warn when an undefined variable is referenced.
This program built for x86_64-pc-linux-gnu
Report bugs to <bug-make#gnu.org>

How to pass -S flag to ocamlopt with ocamlbuild?

I'd like to pass the -S flag to ocamlopt when building with the ocamlbuild and corebuild commands.
I understand doing ocamlbuild -cflag -S ... won't work since -S flag does only exist for ocamlopt and not ocamlc.
How can I do this using _tags files?
Here's one way to do it using myocamlbuild.ml and _tags.
In myocamlbuild.ml, add a flag instruction to let ocamlbuild recognize a new tag - here keep_asm - which will enable -S for selected files when compiling to native:
flag ["ocaml";"compile";"native";"keep_asm"] (S [A "-S"]);
Without the "native" string in the list passed to flag, the flag would be enabled for any compilation stage using ocaml (as indicated by the strings "ocaml" and "compile"), and would trigger when ocamlc is invoked, which you don't want.
So, for a complete stand alone myocamlbuild.ml doing only the above, this would turn out as:
open Ocamlbuild_plugin;;
open Command;;
dispatch begin function
| Before_rules ->
begin
end
| After_rules ->
begin
flag ["ocaml";"compile";"native";"keep_asm"] (S [ A "-S"]);
end
| _ -> ()
end
Once, you've got that new tag defined, you may use it in your _tags file as with any other tag, for instance:
<myfile.ml>: use_bigarray, keep_asm