Installation¶
Install on Windows:
winget install -e --id Diskuv.dkor Apple/Silicon:
sudo curl -o /usr/local/bin/dk https://diskuv.com/a/dk-exe/2.4.202506160116-signed/dk-darwin_arm64
sudo chmod +x /usr/local/bin/dkor Apple/Intel:
sudo curl -o /usr/local/bin/dk https://diskuv.com/a/dk-exe/2.4.202506160116-signed/dk-darwin_x86_64
sudo chmod +x /usr/local/bin/dkor Linux with glibc and libstdc++ (Debian, Ubuntu, etc. but not Alpine):
sudo curl -o /usr/local/bin/dk https://diskuv.com/a/dk-exe/2.4.202506160116-signed/dk-linux_x86_64
sudo chmod +x /usr/local/bin/dk
[ -x /usr/bin/dnf ] && sudo dnf install -y libstdc++ Say: Make it so¶
Copy and paste in your Terminal (PowerShell on Windows) and wait for a minute until you see Make it so.:
dk -g dune -U "Tr1Stdlib_V414Io.StdIo.print_endline {|Make it so.|}" RunRun it again and it will be fairly quick:
dk -g dune -U "Tr1Stdlib_V414Io.StdIo.print_endline {|Make it so.|}" RunCongratulations, you have run your first script!
Let's breakdown exactly what happened ...
The -g dune was the build generator option. dk is technically a meta-build system like CMake, where build files are generated for a specific build system. Within the broader OCaml ecosystem, "Dune" is the conventional build system that compiles OCaml source code into executables. With -g dune, dk will create build files for Dune. The "Dune" build tool will then be invoked automatically to compile your scripts.
The -U <expression> introduces the unit expression: Tr1Stdlib_V414Io.StdIo.print_endline {|Make it so.|}. Expressions are the basic OCaml language construct where we can call functions. If you are unfamiliar with expressions, the chapter OCaml Programming: Correct + Efficient + Beautiful: Expressions is a great introduction. The "unit" in "unit expression" is the type of the expression. The "unit" type corresponds closely to the "void" return type in Java, C# and C. We'll be returning to the expression shortly.
The Run command line argument is the name of the tool to invoke. The Run tool naturally runs whatever you said on the command line. There are other tools which we'll see in the next section.
Let's get back to the unit expression: Tr1Stdlib_V414Io.StdIo.print_endline {|Make it so.|}. You may be asking why would we have an expression that returns "unit" ... that is, it doesn't return anything? The answer is that the expression produces useful results (in this example, we'll be printing to the console screen), even without returning a value.
Tr1Stdlib_V414Io.StdIo.print_endline {|Make it so.|} is a function call expression [¹]. We had to add double-quotes around the function call so that your Unix shell, Windows PowerShell or Command Prompt knows that the whole Tr1Stdlib_V414Io.StdIo.print_endline {|Make it so.|} is the command line argument to -U.
Let's compare the OCaml function call expression to the equivalent function call statement in Java:
System.out.println ("Make it so.");OCaml is unusual among other languages in that you don't use parentheses separate the function reference from the function argument. In OCaml, we separate each function arguments from the function reference using whitespace.
Let's start with the function arguments. The first and only argument to Tr1Stdlib_V414Io.StdIo.print_endline was {|Make it so.|}. The {|Make it so.|} is a string. The unusual {| begin and |} end tokens tell OCaml to interpret the intervening characters Make it so. as a "literal" string: that is, a string that has no escape characters. Normally we would use double-quotes like "Make it so." which is interpreted as a regular string. However, because we already used double-quotes to support Unix shell / Windows PowerShell / Command Prompt, we use the literal string syntax instead.
Now let's move back to the function reference. The Java function reference System.out.println has the same behavior as Tr1Stdlib_V414Io.StdIo.print_endline does in dk: It prints a string and ends it with a newline.
The first dot-separated term of the function reference Tr1Stdlib_V414Io.StdIo.print_endline was Tr1Stdlib_V414Io. That is called the library id. You can find a description of all the dk libraries at dkcoder-libraries(7).
The next term is StdIo, which is a module defined in the Tr1Stdlib_V414Io library. A module, at least for our purposes in this section, is a namespace for functions. There can be many modules, and the modules may be nested with a dot separator (.) just like Java packages.
The last term, the last term is print_endline, which is the function we want to call. Unfortunately at this time the dk documentation is not rendering a description of the function, but when it does it will be here.
Cross-compiling¶
Now copy and paste and wait for several minutes (the first time only!):
dk -g dune -S "
module Http = DkNet_Std.Http
module Uri = Tr1Uri_Std.Uri
let print_endline = Tr1Stdlib_V414Io.StdIo.print_endline
" -U "
print_endline @@
Lwt_main.run @@
Http.fetch_url ~max_sz:4096 @@
Uri.of_string {|https://jigsaw.w3.org/HTTP/h-content-md5.html|}
" -O ReleaseSmall ExeWhat happened? You created standalone executables for Linux and Windows and Android, all with one command, and if you are on macOS you also created standalone macOS executables.
Go ahead and find the standalone executable for your machine, and then run it:
target/ZzZz_Zz.Adhoc-android_arm32v7atarget/ZzZz_Zz.Adhoc-android_arm64v8atarget/ZzZz_Zz.Adhoc-android_x86_64target/ZzZz_Zz.Adhoc-darwin_arm64target/ZzZz_Zz.Adhoc-darwin_x86_64target/ZzZz_Zz.Adhoc-linux_x86target/ZzZz_Zz.Adhoc-linux_x86_64target/ZzZz_Zz.Adhoc-windows_x86_64.exetarget/ZzZz_Zz.Adhoc-windows_x86.exe
In this section we introduced a few more command line options and arguments.
The last argument Exe is the tool. In the last section we had used the Run tool, but in this section we used the Exe tool because we wanted to generate executables for different operating systems.
The -O ReleaseSmall option tells dk that we want to optimize the generated executable for a small file size and to exclude most debug information.
The -S <structure> option introduces the structure (aka. contents) of a module. Before we had mentioned to consider a "module" as just a namespace for functions. Certainly the module can have functions, but it can also have what are called "module aliases".
Let consider the first module alias: module Http = DkNet_Std.Http. What that alias does is let us use Http instead of the longer DkNet_Std.Http for the remainder of the module (which includes the unit expression -U <expression>).
But the normal use of a module is to define values, especially functions. In our example above the function print_endline was defined using the module binding:
let print_endline = Tr1Stdlib_V414Io.StdIo.print_endlineBindings are very similar to module aliases, except they operate on values (including functions) rather than modules. So print_endline can be used instead of the fully-qualifed function reference Tr1Stdlib_V414Io.StdIo.print_endline for the remainder of the module.
The only thing we haven't explained is what are all those @@ doing in the function calls? @@ is an operator that places the terms on the right hand side of the expression in parentheses.
So:
print_endline @@
Lwt_main.run @@
Http.fetch_url ~max_sz:4096 @@
Uri.of_string {|https://jigsaw.w3.org/HTTP/h-content-md5.html|}is really:
print_endline (
Lwt_main.run (
Http.fetch_url ~max_sz:4096 (
Uri.of_string {|https://jigsaw.w3.org/HTTP/h-content-md5.html|}))) Using a script file¶
Let's save the last script to a file. Copy and paste the following (notice we use Run rather than -O ReleaseSmall Exe):
dk -g dune -S "
module Http = DkNet_Std.Http
module Uri = Tr1Uri_Std.Uri
let print_endline = Tr1Stdlib_V414Io.StdIo.print_endline
" -U "
print_endline @@
Lwt_main.run @@
Http.fetch_url ~max_sz:4096 @@
Uri.of_string {|https://jigsaw.w3.org/HTTP/h-content-md5.html|}
" RunYou will see that it prints the contents for you (scroll up a bit):
module Http = DkNet_Std.Http
module Uri = Tr1Uri_Std.Uri
let print_endline = Tr1Stdlib_V414Io.StdIo.print_endline
let () =
print_endline @@ Lwt_main.run
@@ Http.fetch_url ~max_sz:4096
@@ Uri.of_string {|https://jigsaw.w3.org/HTTP/h-content-md5.html|}Put that into a file; let's name it myfirstscript.ml.
Then run it with:
dk -g dune -s myfirstscript.ml RunCongratulations, you saved and ran your first script.
In the last section we had described how the -S <structure> option introduce the structure (contents) of a module. Here we use -s <structure-file> option instead, which just reads the module from the file rather than using command line option as-is.
Next Steps¶
You can:
- start the extended walk-through -or-
- browse the documentation

