How do you use gcc's ar utility with ocaml's compiler? - ocaml

I can create a static library with ocaml object files using
ar rc ./lib/libprog.a ./_build/*.cmo
And I can display the contents of the libprog.a using
ar t ./lib/libprog.a
but I can't find any documentation that explains how to use this static library with ocaml's compilers.
Could someone please post an example(or provide a link) which demonstrates how to use a libprog.a file with ocaml's compilers. Please no examples with ocaml build utilities because I want to see how its done at the command line using ocaml's compilers. Thanks.

OCaml wants to use its own archive format.
$ cat a.ml
let x = 14
$ cat b.ml
let y = 17
$ cat main.ml
let () = Printf.printf "%d\n" (A.x + B.y)
$ ocamlc -c a.ml
$ ocamlc -c b.ml
$ ocamlc -a -o oclibab.cma a.cmo b.cmo
Now there is an OCaml archive (.cma file) named oclibab.cma that contains the modules A and B:
$ ocamlobjinfo oclibab.cma
File oclibab.cma
Force custom: no
Extra C object files:
Extra C options:
Extra dynamically-loaded libraries:
Unit name: A
Interfaces imported:
9b04ecdc97e5102c1d342892ef7ad9a2 Pervasives
79ae8c0eb753af6b441fe05456c7970b CamlinternalFormatBasics
b162d96cf09fcde9d245f96359c9178a A
Required globals:
Uses unsafe features: no
Force link: no
Unit name: B
Interfaces imported:
9b04ecdc97e5102c1d342892ef7ad9a2 Pervasives
79ae8c0eb753af6b441fe05456c7970b CamlinternalFormatBasics
bc583fd68fc2b0a4e44e3e640983c8dd B
Required globals:
Uses unsafe features: no
Force link: no
Note that this archive format contains digital signatures for the interfaces. This allows stronger checking at link time than is generally available through the stock toolchain of the OS (like ar).
$ ocamlc -o main oclibab.cma main.ml
$ ./main
31

Related

How to compile OCaml and C/C++ code that depend on each other

I'm having problems defining the signature of a C void function that accepts an uint64_t and a char*. I tried int64 -> string -> _.
I also don't know how to compile my C++ file (with C interface) together
events.ml
open Lwt.Infix
external call: int64 -> string -> _ = "function_pointer_caller"
let begin_event pointer =
Lwt_unix.sleep 5.0 >>= fun () ->
call pointer "message"
let () = Callback.register "begin_event" begin_event
interface.c:
#include <stdio.h>
#include <string.h>
#include <caml/mlvalues.h>
#include <caml/callback.h>
#include <caml/alloc.h>
#include <caml/bigarray.h>
extern void register_function_callback();
void print_from_event(char* message) {
printf("OCaml event: %s\n", message);
}
void function_pointer_caller(uint64_t pointer, char* message)
{
void (*f)(char *);
f = pointer;
}
void register_function_callback() {
static const value *begin_event_closure = NULL;
if (begin_event_closure == NULL)
{
begin_event_closure = caml_named_value("begin_event");
if (begin_event_closure == NULL)
{
printf("couldn't find OCaml function\n");
exit(1);
}
}
uint64_t pointer = (uint64_t) &function_pointer_caller;
caml_callback(*begin_event_closure, (int64_t) &pointer);
}
main.cc
#include <stdio.h>
#include <caml/callback.h>
extern "C" void register_function_callback();
int main(int argc, char **argv)
{
caml_startup(argv);
register_function_callback();
while (true)
{
}
return 0;
}
I think there's no way to compile a .cc together with a .ml, because a .cc does not necessairly have a C interface. Maybe it's possible to compile the .ml to a .so object and link it to the .cc with the C interface?
Anyways, I did change interface.cc to interface.c and added interface.c to the ocamlopt command:
ocamlfind ocamlopt -o s -linkpkg -package lwt.unix -thread event_emitter.ml interface.c
g++ -o event_emitter_program -I $(ocamlopt -where) \
s.o interface.o main.cc event_emitter.o $(ocamlopt -where)/libasmrun.a -ldl
The first command compiles ok, but g++ gives
event_emitter.o: In function `camlEvent_emitter__begin_event_90':
:(.text+0x3f): undefined reference to `camlLwt_unix__sleep_695'
:(.text+0x4c): undefined reference to `camlLwt__bind_1276'
collect2: error: ld returned 1 exit status
Notice that I plug the interface.o from the previous command (ocamlopt) and link in g++, because ocamlopt actually passes C files to a C compiler.
I don't know why it complains about Lwt_unix things, since I already compiled with them in ocamlopt.
The ocamlopt utility is doing a bit more than just linking the specified compilation units and libraries, it also embeds the architecture startup code, which is not included in the asmrun library. It is possible to obtain this code using the -output-obj, but I find it a little bit error-prone and hard to maintain as it is not really composable1.
So, it is better to rely on ocamlopt to build the final binary, which will consist of modules written in different languages. Each unit will be built with the appropriate to the language, in which it is written, tool. Let's build the events.ml compilation unit:
ocamlfind ocamlopt -c -package lwt.unix events.ml
Now, let's build the interface (we can use cc here, but using ocamlopt will save us a bit of hassle of providing the location of the includes)
ocamlfind ocamlopt -c interface.c
Now, let's build the C++ part (but first fix it and use caml_main instead of caml_startup since we want the native runtime).
g++ -c main.cc -o main.o -I `ocamlc -where`
Now, when we have all units we're ready for the final linking command:
ocamlfind ocamlopt events.cmx interface.o main.o -package lwt.unix -package lwt -thread -linkpkg -o emitter
Et voila, we can run our program with ./emitter.
1) using this option for more than one compilation unit may easily lead to symbol conflicts.
You should be more careful with “warning” messages and not rely on things that bind the building process to your configuration. Avoid usage of root console please!
[WARNING] Running as root is not recommended
In the root environment path to libraries can be complicated.
According to your pastebin I see that linker is unable to locate the lwt_unix_stubs library. And don't mix '.a' and '.so' libraries please (/root/.opam/4.10.0/lib/lwt/unix/liblwt_unix_stubs.a /root/.opam/4.10.0/lib/stublibs/dlllwt_unix_stubs.so)! '.a' is for static build while '.so' is for dynamic.
Example of build that works for me (Ubuntu Linux, ocaml 4.05.0):
ocamlfind ocamlopt -output-obj -dstartup -linkpkg -package lwt.unix -thread -o s.o event_emitter.ml
g++ -o event_emitter_program -I`ocamlfind c -where` -I $(ocamlopt -where) s.o interface.o main.cc -L `ocamlc -where` -L`ocamlfind query lwt.unix` -L`ocamlfind query threads` -lasmrun -llwt_unix_stubs -lunix -lbigarray -lcamlstr -lthreadsnat -lpthread -ldl
Usage of $(ocamlopt -where)/libasmrun.a is bad idea. It's more pedantic way to use -lasmrun and -L for path to libraries.
If you have problems with some undefined symbols, it's best to use readelf to find out which library is missing.

how to chose between two implementation code in OCaml

I have uploaded the very small exemple project on a github repository
I have a school project. The specifications say that we can enable or disable a component.
I came from the c world in which we can compile c to object and chose the object to link. I try this in OCaml.
I have two source file with the same function but their effect is different.
I have two folders called "on" with implementation and "off" folder with an empty body
For the test, I have a simple a.ml and a.mli file that only print hello world and b.mli b.ml that call the module a. (so I have on/a.ml and off/a.ml)
I compile the on version and the off with this command:
ocamlc -c -I on on/a.mli on/a.ml -o on/a.cmo
then I try to link the C-way
ocamlc on/a.cmo b.ml -o on_b.exe
but I get the error
File "b.ml", line 1, characters 9-15:
Error: Unbound module A
I have then read I should specify the folder to search in with -I.
ocamlc -I on -I off on/a.cmo b.ml -o on_b.exe
I was happy because of that work for the on version
but it will not work for the off version
ocamlc -I on -I off off/a.cmo b.ml -o off_b.exe
I get the error
Error: Files b.cmo and off/a.cmo
make inconsistent assumptions over interface A
I have inspected with ocamlobjinfo it seems to build B its searches for the first module called A
In this example, I have only A and B but in future, I will build with some version on and some off... but don't do it manually
A solution found but no really efficient is to clean all .cmo and .cmi files ...
thanks for your reading and your time
EDIT:
I have also test with -open but it seems to work only for standards modules.
As you can see, compiling your .mli files produces a .cmi file. This is the file that you indicate is there by using the -I dir option.
So, if I understand you correctly, you have a a.mli in both your on and your off directory.
Now, when you refer to the module A in your code, the compiler looks for it in the current directory, then in the linked directories in the order they are given. When you compile "on", the right .cmi is found (because -I on comes before -I off in your command line). In the case of "off", the "on" cmi is found, and the compiler sees that it doesn't correspond to the right cmo.
Your two compiling lines should be:
ocamlc -I on on/a.cmo b.ml -o on_b.exe
ocamlc -I off off/a.cmo b.ml -o off_b.exe

How to separate binary code from source in ocaml?

I have my source next to a build directory
ocamlc -c file1.ml
ocamlc -c file2.ml
…
ocamlc -o main.ml ….cmo
I have the source with the file generated by the compilation.
I would like an option of ocamlc that enable me to have this file in the build directory.
I know i can do ocamlc -o build/main.ml .....cmo but i would like to have to .cmo in the build directory too
Thank you for your help
The answer of your main question is very simple:
in order to put the main binary of your OCaml application in the build folder, you just need to run:
ocamlc -o build/main.exe main.ml ….cmo
Indeed as indicated in the documentation (man ocamlc):
-o exec-file
Specify the name of the output file produced by the linker. The
default output name is a.out, in keeping with the Unix tradition. […]
However, doing all the build steps by hand in the way you are suggesting in your question may not be very effective (in particular, all .cmo files will stay along with the sources in the same folder).
To avoid this and facilitate the build of your OCaml project, I suggest using a build management tool for OCaml, for example one of the four tools mentioned in the end of the tutorial Compiling OCaml Projects:
ocamlbuild
GNU make
OMake
Oasis
(ocamlbuild is probably the easiest tool to use among the four.)
But you may also consider using Dune (formerly known as JBuilder), which is the build system used by a majority of packages in opam.

Can a Crystal library be statically linked to from C?

I've read through the "C bindings" in the tutorial but I'm a novice at C stuff.
Could someone please let me know if a Crystal program can be built as a static library to link to, and if so could you please provide a simple example?
Yes, but it is not recommended to do so. Crystal depends on a GC which makes it less desirable to produce shared (or static) libraries. Thus there are also no syntax level constructs to aid in the creation of such nor a simple compiler invocation to do so. The C bindings section in the documentation is about making libraries written in C available to Crystal programs.
Here's a simple example anyhow:
logger.cr
fun init = crystal_init : Void
# We need to initialize the GC
GC.init
# We need to invoke Crystal's "main" function, the one that initializes
# all constants and runs the top-level code (none in this case, but without
# constants like STDOUT and others the last line will crash).
# We pass 0 and null to argc and argv.
LibCrystalMain.__crystal_main(0, Pointer(Pointer(UInt8)).null)
end
fun log = crystal_log(text: UInt8*): Void
puts String.new(text)
end
logger.h
#ifndef _CRYSTAL_LOGGER_H
#define _CRYSTAL_LOGGER_H
void crystal_init(void);
void crystal_log(char* text);
#endif
main.c
#include "logger.h"
int main(void) {
crystal_init();
crystal_log("Hello world!");
}
We can create a shared library with
crystal build --single-module --link-flags="-shared" -o liblogger.so
Or a static library with
crystal build logger.cr --single-module --emit obj
rm logger # we're not interested in the executable
strip -N main logger.o # Drop duplicated main from the object file
ar rcs liblogger.a logger.o
Let's confirm our functions got included
nm liblogger.so | grep crystal_
nm liblogger.a | grep crystal_
Alright, time to compile our C program
# Folder where we can store either liblogger.so or liblogger.a but
# not both at the same time, so we can sure to use the right one
rm -rf lib
mkdir lib
cp liblogger.so lib
gcc main.c -o dynamic_main -Llib -llogger
LD_LIBRARY_PATH="lib" ./dynamic_main
Or the static version
# Folder where we can store either liblogger.so or liblogger.a but
# not both at the same time, so we can sure to use the right one
rm -rf lib
mkdir lib
cp liblogger.a lib
gcc main.c -o static_main -Llib -levent -ldl -lpcl -lpcre -lgc -llogger
./static_main
With much inspiration from https://gist.github.com/3bd3aadd71db206e828f

Separate compilation of OCaml modules

I have read this question and others,
but my compile problem is unsolved.
I am testing separate compilation with these files:
testmoda.ml
module Testmoda = struct
let greeter () = print_endline "greetings from module a"
end
testmodb.ml
module Testmodb = struct
let dogreet () = print_endline "Modul B:"; Testmoda.greeter ()
end
testmod.ml
let main () =
print_endline "Calling modules now...";
Testmoda.greeter ();
Testmodb.dogreet ();
print_endline "End."
;;
let _ = main ()
Now I generate the .mli file
ocamlc -c -i testmoda.ml >testmoda.mli
and the testmoda.cmi is there.
Next I create the .cmo file without errors:
ocamlc -c testmoda.ml
Fine, so do the same with testmodb.ml:
strobel#s131-amd:~/Ocaml/ml/testmod> ocamlc -c -i testmodb.ml >testmodb.mli
File "testmodb.ml", line 3, characters 45-61:
Error: Unbound value Testmoda.greeter
Another try:
strobel#s131-amd:~/Ocaml/ml/testmod> ocamlc -c testmoda.cmo testmodb.ml
File "testmodb.ml", line 3, characters 45-61:
Error: Unbound value Testmoda.greeter
Other combinations failed as well.
How do I compile testmodb.ml and testmod.ml? This should be easy - without ocamlbuild / omake /
oasis, I think.
Syntax errors in the files are excluded,
if I cat them together to one file (with the required space between) it compiles
and executes perfectly.
OCaml gives you a module for free at the top level of each source file. So your first module is actually named Testmoda.Testmoda, the function is named Testmoda.Testmoda.greeter, and so on. Things will work better if your files just contain the function definitions.
As a side comment, if you're going to use the interface generated by ocamlc -i, you really don't need mli files. The interface in the absence of an mli file is the same as the one generated by ocamlc -i. If you don't want the default interface, using ocamlc -i gives a good starting point for your mli file. But for a simple example like this, it just makes things look a lot more complicated than they really are (IMHO).
If you modify your files as I describe (remove extra module declarations), you can compile and run from scratch as follows:
$ ls
testmod.ml testmoda.ml testmodb.ml
$ cat testmoda.ml
let greeter () = print_endline "greetings from module a"
$ cat testmodb.ml
let dogreet () = print_endline "Modul B:"; Testmoda.greeter ()
$ ocamlc -o testmod testmoda.ml testmodb.ml testmod.ml
$ ./testmod
Calling modules now...
greetings from module a
Modul B:
greetings from module a
End.
If you have already compiled a file (with ocamlc -c file.ml) you can replace .ml with .cmo in the above command. This works even if all the filenames are .cmo files; in that case ocamlc just links them together for you.