ocamlopt: option to control where to put cmx and cmi - build

Is there a command line option or argument to ocamlopt (and ocamlc) to tell there it where to put the produced .cmx (and similar) files?
The documentation mentions -o, but that only works for me when there's no .mli file.
Similar for .cmi files.

The -o option works for me:
$ ocamlopt -version
4.03.0
$ ls
t.ml
$ ocamlopt -c -o zed.cmx t.ml
$ ls
t.ml
zed.cmi
zed.cmx
zed.o

Related

How to link object file produced by ocamlopt to create executable?

I can take the following ocaml module test.ml and compile it with ocamlopt
(* test.ml *)
Printf.printf "hi\n"
By doing
$ ocamlopt -o test.native test.ml
$ ./test.native
hi
I can also compile it without linking.
$ ocamlopt -o test.o -c test.ml
$ ls
test.cmi test.cmx test.ml test.o
However, if I then try to link the object I just created with the OCaml runtime to get an executable, no files are created (even though ocamlopt exits normally)
$ ocamlopt -o test.native test.o
$ ls
test.cmi test.cmx test.ml test.o
How do I direct ocamlopt to link in the OCaml runtime and produce an executable "as if" I had run ocamlopt -o test.native test.ml?
You need to give the .cmx file to the compiler, not the .o file.
$ ocamlopt -o test.native test.cmx
$ ./test.native
hi

Using ocamlc to compile libraries independently

I have three files:
$ ls
lib.ml desk.ml test.ml
$ cat lib.ml
let myfunction () = print_endline "Hello world"
$ cat desk.ml
module Liberty = Lib
$ cat test.ml
Desk.Liberty.myfunction ()
I want to compile a desk.cma that does not expose the module Lib, but is able to make use of it. For example, I've tried:
$ ocamlc -a lib.ml -o lib.cma
$ ocamlc -a lib.cma desk.ml -o desk.cma
$ ocamlc desk.cma test.ml -o test.byte
Unfortunately, if you change test.ml to be Lib.myfunction (), the same compilation steps work just fine. I want it so that Lib is not exposed to test.ml and only exposed to desk.ml. Does anyone know how to do this? Thanks very much!
It looks like you're looking for the -pack mechanism of OCaml. This allows you to create a pack.cmo (or pack.cmx for native compilation) from several compilation units, like a pack.cma library, but with the added advantage that you can have a corresponding pack.mli interface with which you can hide the parts that should be internal to your pack. In your example, you could for instance have:
-- lib.ml --
let myfunction () = print_endline "Hello world"
-- liberty.ml --
include Lib
-- desk.mli --
(* No module Lib: Lib will not be seen outside of the pack. *)
module Liberty: sig
val myfunction: unit -> unit
end
Then you can compile that with
ocamlc -for-pack Desk -c lib.ml
ocamlc -for-pack Desk -c liberty.ml
ocamlc desk.mli
ocamlc -pack -o desk.cmo lib.cmo liberty.cmo
This will give you a module Desk, that contains only Liberty a sub-module. Of course, desk.mli can be used to get more fine-grained restriction, e.g. with
module Lib: sig end
module Liberty: sig val myfunction: unit -> unit end
you export Lib with an empty signature, thus hiding a single (albeit the only one in the example ;-P) function from Lib.
You're asking that Lib be a module of desk.cma that Desk can use, but no other modules. I'm pretty sure the structure of a cma file doesn't offer this kind of control.
If you define Lib inside Desk you can make it a hidden detail.
$ ls
desk.ml desk.mli test1.ml test2.ml test3.ml
$ cat desk.ml
module Lib = struct
let myfunction () = print_endline "Hello world"
end
module Liberty = Lib
$ cat desk.mli
module Liberty : sig
val myfunction : unit -> unit
end
$ cat test1.ml
Desk.Liberty.myfunction ()
$ cat test2.ml
Lib.myfunction ()
$ cat test3.ml
Desk.Lib.myfunction ()
The Liberty module is visible to the test programs, but the Lib module isn't:
$ ocamlc -c desk.mli
$ ocamlc -a desk.ml -o desk.cma
$ ocamlc desk.cma test1.ml -o test1.byte
$ ./test1.byte
Hello world
$ ocamlc desk.cma test2.ml -o test2.byte
File "test2.ml", line 1, characters 0-14:
Error: Unbound module Lib
$ ocamlc desk.cma test3.ml -o test3.byte
File "test3.ml", line 1, characters 0-19:
Error: Unbound module Desk.Lib
You can implement Lib in a separate file, then include it into the definition of the Desk.Lib module.
I suspect this isn't a fully satisfying answer, but I hope it's helpful.

Difference between .cma, .cmo, .cmx files and how to use them correctly in compilation?

I am new to the OCaml and I'm confused with the file of .cma, .cmo and .cmx. Sometimes I have to include a .cma file in the compile command but sometimes I have to include a .cmo file.
Why is there a such difference for library? Is it the same concept in C++ as library and include path?
Example: ocamlc -o executable str.cma extstring.cmo mycode.ml
Thanks
You may think that .cmo is library, but it's not.
.cmo is bytecode object file. It's like .class in Java.
.cma is bytecode library. It's produce by archiving some .cmo into .cma
.cmx is produced by ocamlopt (the native-code compiler). Main output files of ocamlopt is .o but ocamlopt also produce it.
To create executable files, we arrange .cmo and .cma like ocamlc -o executable lib.cma a.cmo b.cmo ... to link them.
You can write .ml here instead of .cmo but it's the same as compiling .ml with -c and link the .cmo and other files.
For your deep undestanding, it's better to check how each files (related to ocaml) are produced.
Let's see what files are produce by ocamlc and ocamlopt.
[/tmp/test] ls
test.ml
[/tmp/test] cat ./test.ml
let id x = x
[/tmp/test] ocamlc -c /tmp/test/test.ml
[/tmp/test] ls
test.cmi test.cmo test.ml
[/tmp/test]
Now I compiled test.ml file and compile it with ocamlc with -c option
(the content of test.ml is not matter here).
You see ocamlc outputs two files:
test.cmi: Compiled interface file. This file includes type information of functions, variables in test.ml for separate compilation.
test.cmo: Bytecode object file: It's like .class file in Java.
We use .cmo files to create executable files.
[/tmp/test] ocamlc -c test.ml
[/tmp/test] ocamlc -o a.out test.cmo
[/tmp/test] ls
a.out test.cmi test.cmo test.ml
You see a.out file are produced via the .cmo file.
.cma are library files. These are produced by composing multiple .cmo files.
[/tmp/test] ls
test.ml lib.ml
[/tmp/test] cat lib.ml
let i = Test.id 1
let j = Test.id 2
[/tmp/test] ocamlc -c test.ml; ocamlc -c lib.ml
[/tmp/test] ls
lib.cmi lib.cmo lib.ml test.cmi test.cmo test.ml
[/tmp/test] ocamlc -a -o testlib.cma ./test.cmo lib.cmo
[/tmp/test] ls
lib.cmi lib.cmo lib.ml test.cmi test.cmo test.ml testlib.cma
Now I create lib.ml (which use id function in test.ml) and compile test.ml and lib.ml, then link them to create testlib.cma (option -a means creating a library).
You can see .cma is just packed with .cmo files.
To use the library, we just arrange it with other object files.
[/tmp/test] cat user.ml
let _ = print_int (Lib.i + Lib.j)
[/tmp/test] ocamlc -c user.ml
[/tmp/test] ocamlc -o a.out testlib.cma user.cmo
Finally, let's check what files are produce by ocamlopt.
[/tmp/test] ocamlopt -c ./test.ml
[/tmp/test] ls
test.cmi test.cmx test.ml test.o
ocamlopt produces
test.o: Native object file
test.cmi: Compiled interaface file
test.cmx: Also native object file, but it is mainly used for inlining functions across files!!!
So, the difference is here (when there's a x in the file extension, it means it's a native-code compiled object so that it runs faster. The cmx files are obtained with ocamlopt and the cmo files with ocamlc) :
.cma / .cmxa -> libraries that are already available for the programmer (standard libraries and libraries you installed)
.cmo / .cmx -> object files corresponding to your .ml files
TL;DR : .cm(x)a files were not created by you, .cm(o|x) files were.

Trouble compiling a program using an archive (.a)

When I try to compile my file using a library (.a), I get 'fatal error: URLInputStream.h: No such file or directory
compilation terminated.
'. I'm still pretty new to C++, and this seems so simple but I can't get it to work.
Compilation commands I've tried:
g++ inc/Downloader.h lib/libcs240utils.a
g++ inc/Downloader.h -L lib -l cs240utils
g++ inc/Downloader.h -Llib -lcs240utils
g++ src/Downloader.cpp -I inc -L lib -l cs240utils
g++ -c src/Downloader.cpp -I inc -L lib -l cs240utils
How I compile my archive:
make lib
g++ -c -o utils/obj/CommandRunner.o utils/src/CommandRunner.cpp -I utils/inc
g++ -c -o utils/obj/FileInputStream.o utils/src/FileInputStream.cpp -I utils/inc
g++ -c -o utils/obj/FileSystem.o utils/src/FileSystem.cpp -I utils/inc
g++ -c -o utils/obj/HTMLToken.o utils/src/HTMLToken.cpp -I utils/inc
g++ -c -o utils/obj/HTMLTokenizer.o utils/src/HTMLTokenizer.cpp -I utils/inc
g++ -c -o utils/obj/HTTPInputStream.o utils/src/HTTPInputStream.cpp -I utils/inc
g++ -c -o utils/obj/StringUtil.o utils/src/StringUtil.cpp -I utils/inc
g++ -c -o utils/obj/URLInputStream.o utils/src/URLInputStream.cpp -I utils/inc
ar cr lib/libcs240utils.a utils/obj/*.o
The archive seems to be built correctly:
ar t lib/libcs240utils.a
CommandRunner.o
FileInputStream.o
FileSystem.o
HTMLToken.o
HTMLTokenizer.o
HTTPInputStream.o
StringUtil.o
URLInputStream.o
I've also tried various options in ar. If I specify an include path -I utils/inc then it will compile and work properly, so the file I want does work properly. I've read numerous articles and questions here on StackOverflow, and I can't seem to see what I'm doing incorrectly. Any ideas or suggestions?
Note: I'm compiling a header which seems weird. It was originally split into .cpp and .h, but to simplify problem solving I merged them. This same error happened when they were split as well: g++ src/Downloader.cpp -I inc -L lib -l cs240utils
If Downloader.h still likely needs header files to talk to types/classes/etc. in your static library.
The fact that you mention that "-I utils/inc" makes it work would lead me to think that Downloader.h references stuff in that header. You still need the header for compilation even when you have a static lib as part of the link step.

How to change default output file of g++ in ubuntu?

Trivially
g++ sample.c
generates a.out
Can g++ be configured to output to a different default name for output file ?
You need to use the -o option of g++
g++ -o output_file_name source.cpp
Use the g++ -o switch: g++ sample.cc -o myoutfile
See a man page for g++
-o file
Place output in file file.
If you want to change the default output name to test for example, all you need to do is go to .bashrc, and put in:
alias g++='g++ -o test'
But you need to reopen a new terminal for it to work.
Man pages are your friends:
$ man g++ (and just do a search for "out" and you're done ;)