How do I include tesseract (a cpp lib)

I want to make a project where I am using GitHub - tesseract-ocr/tesseract: Tesseract Open Source OCR Engine (main repository). The problem is, that the project is written in cpp. My question: How can I include this in my project?

First you need to build the library and find a simple working C example.

In your build.zig file add exe.linkSystemLibrary("tesseract");
You might also need to add where are the libraries and include files:

exe.addIncludePath(.{.cwd_relative = "/path/to/tesseract/include"});
exe.addLibraryPath(.{.cwd_relative = "/path/to/lib"});

In your zig source file add:

const tesseract = @cImport({
    // add all the include files required for the C API
    @cInclude("capi.h");
});

pub fn main() void {
    const handle = tesseract.TessBaseAPICreate();
    defer tesseract.TessBaseAPIDelete(handle);
}

Translate the C API example to zig calls like the calls to TessBaseAPICreate.

Wait so ideally I need to find an example of someone who managed to do this in c and then just replicate it, so first statically compile the library and then include and statically link it?

There are examples in the User Guide.
Search for “Example using the C-API in a C program”.

2 Likes

I just found em too, I’ll give them a try probably tomorrow

I have tried this, but baseapi.h is a hpp in disguise

Zig cannot call/include C++ code but you can use the C API since the library have both a C and C++ API.

1 Like

Im a bit lost here, I dont know what I’m doing wrong.

My build file:

const std = @import("std");

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    const exe = b.addExecutable(.{
        .name = "document-sorter",
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });
    exe.linkLibC();
    exe.linkSystemLibrary("tesseract");
    // exe.addIncludePath(b.path("include/tesseract/include/tesseract/"));
    b.installArtifact(exe);

    const run_cmd = b.addRunArtifact(exe);
    run_cmd.step.dependOn(b.getInstallStep());
    if (b.args) |args|
        run_cmd.addArgs(args);
    const run_step = b.step("run", "Run the app");
    run_step.dependOn(&run_cmd.step);

    const exe_unit_tests = b.addTest(.{
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });
    const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);
    const test_step = b.step("test", "Run unit tests");
    test_step.dependOn(&run_exe_unit_tests.step);
}

My main file:

const std = @import("std");
const c = @cImport({
    @cInclude("tesseract/baseapi.h");
    // @cInclude("baseapi.h");
});

pub fn main() !void {
    _ = c;
    unreachable;
}

The commented out lines are there because I also have the repo cloned and tried to include it that way. In both cases I got the exact same error:

install
└─ install document-sorter
   └─ zig build-exe document-sorter Debug native 6 errors
src/main.zig:2:11: error: C import failed
const c = @cImport({
          ^~~~~~~~
referenced by:
    main: src/main.zig:8:9
    callMain: /home/segfault-enjoyer/.bin/lib/std/start.zig:524:32
    remaining reference traces hidden; use '-freference-trace' to see all reference traces
/usr/include/tesseract/publictypes.h:20:1: error: unknown type name 'namespace'
namespace tesseract {
^
/usr/include/tesseract/publictypes.h:20:20: error: expected ';' after top level declarator
namespace tesseract {
                   ^
/usr/include/tesseract/pageiterator.h:27:1: error: unknown type name 'namespace'
namespace tesseract {
^
/usr/include/tesseract/pageiterator.h:27:20: error: expected ';' after top level declarator
namespace tesseract {
                   ^
/usr/include/tesseract/unichar.h:23:10: error: 'cstring' file not found
#include <cstring>
         ^

which is clearly just the zig compiler having a stroke upon seeing cpp (very understandable ngl)

Zig cannot parse baseapi.h because it is C++.
include the capi.h file.

const std = @import("std");
const c = @cImport({
    @cInclude("tesseract/capi.h");
});

pub fn main() !void {
    _ = c;
    unreachable;
}
2 Likes

Oh lol you’re right. I though that capi.h was just something left from a copy paste of sorts and didn’t know it actually existed. I appreciate your help and persistence despite my misunderstandings!

1 Like

Hehe one more question: How could I link this statically?

linkSystemLibrary2 have LinkSystemLibraryOptions

exe.linkSystemLibrary2("tesseract", .{ .preferred_link_mode = .static });

Is it possible to do this via the cloned project too? I would find it very nice if I can just copy this to any of my machines and instantly compile it without having to rely on the repos having tesseract.

Also, does preferred_link_mode enforce static linking here or “politely ask”?