How to embed HL/C programs

HL/C is the name of the hashlink -> C11 feature. Pulling it off is pretty easy if you follow the instructions on either the Hashlink homepage, or the Haxe manual:

1
2
haxe --main Main.hx --hl output/main.c
gcc -O3 -o hello -std=c11 -I out out/main.c -lhl

This will create a folder out which includes your main.c file, along with a ton of other auto-generated source files. These implement the classes from your program and the Haxe standard library. Here's a sample main.c file:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
// Generated by HLC 4.2.5 (HL v4)
#define HLC_BOOT
#include <hlc.h>
void fun$init(void);

#include <hlc_main.c>

#ifndef HL_MAKE
#  include <hl/hashes.c>
#  include <hl/functions.c>
#  include <hl/BaseType.c>
#  include <_std/String.c>
#  include <_std/Date.c>
#  include <hl/types/ArrayAccess.c>
#  include <hl/types/ArrayBase.c>
#  include <hl/types/ArrayBytes_Int.c>
#  include <hl/types/ArrayBytes_hl_UI16.c>
#  include <hl/types/ArrayBytes_hl_F32.c>
#  include <hl/types/ArrayBytes_Float.c>
#  include <haxe/Log.c>
#  include <hl/types/ArrayDyn.c>
#  include <_std/StringBuf.c>
#  include <_std/SysError.c>
#  include <_std/Sys.c>
#  include <hl/types/ArrayObj.c>
#  include <haxe/Exception.c>
#  include <haxe/ValueException.c>
#  include <haxe/exceptions/PosException.c>
#  include <haxe/exceptions/NotImplementedException.c>
#  include <haxe/iterators/ArrayIterator.c>
#  include <haxe/iterators/ArrayKeyValueIterator.c>
#  include <hl/NativeArrayIterator_Dynamic.c>
#  include <hl/NativeArrayIterator_Int.c>
#  include <hl/types/BytesIterator_Float.c>
#  include <hl/types/BytesKeyValueIterator_Float.c>
#  include <hl/types/BytesIterator_Int.c>
#  include <hl/types/BytesKeyValueIterator_Int.c>
#  include <hl/types/BytesIterator_hl_F32.c>
#  include <hl/types/BytesKeyValueIterator_hl_F32.c>
#  include <hl/types/BytesIterator_hl_UI16.c>
#  include <hl/types/BytesKeyValueIterator_hl_UI16.c>
#  include <hl/types/ArrayDynIterator.c>
#  include <hl/types/ArrayDynKeyValueIterator.c>
#  include <hl/types/ArrayObjIterator.c>
#  include <hl/types/ArrayObjKeyValueIterator.c>
#  include <_std/Std.c>
#  include <_std/Main.c>
#  include <hl/_Bytes/Bytes_Impl_.c>
#  include <_std/Type.c>
#  include <haxe/NativeStackTrace.c>
#  include <haxe/ds/ArraySort.c>
#  include <hl/init.c>
#  include <hl/reflect.c>
#  include <hl/types.c>
#  include <hl/globals.c>
#endif

void hl_init_hashes();
void hl_init_roots();
void hl_init_types( hl_module_context *ctx );
extern void *hl_functions_ptrs[];
extern hl_type *hl_functions_types[];

// Entry point
void hl_entry_point() {
    hl_module_context ctx;
    hl_alloc_init(&ctx.alloc);
    ctx.functions_ptrs = hl_functions_ptrs;
    ctx.functions_types = hl_functions_types;
    hl_init_types(&ctx);
    hl_init_hashes();
    hl_init_roots();
    fun$init();
}

The key thing here is the #include<hlc_main.c> directive. This file isn't in the output folder, but rather exists in the hashlink distribution/source folder. You need to make sure the compiler can find this file, otherwise it won't work. All of the other included files will exist in the auto-generated out folder, so they're not a concern.

Also, we can see that there's a HL_MAKE define wrapping all of the includes. This will come in handy later when adding a build system, so that we can compile those files individually and have much faster build times.

What is hlc_main.c?

This file is the real entrypoint of the program. If you notice, there's no main function above. Instead, hl_entry_point gets called by hlc_main. This is how you can compile a standalone program with hashlink; hlc_main implements everything you need to create a basic program.

Unfortunately, it's not very useful if we're trying to embed hashlink into an existing program. Instead, we'll want to implement that stuff ourselves.

Embedding as a library

We can toss the compiler a dummy hlc_main.c file, and compile the HL/C output into a standard library that we can link into our host program. If we want to use our Haxe code as a program, we can reimplement parts of hlc_main so that we can call hl_entry_point as usual. If instead we wish to do something more complicated, like having multiple entrypoints, or directly calling/instantiating classes, then we will need to familiarize ourselves with some of hashlink's APIs.