C3: Library packaging

Packaging libraries is fairly straight forward. A library package can be either “packed” or “unpacked” e.g. just a directory or an archive file named mylib.c3l. When distributing packages the latter option probably makes the most sense.

Let’s now look at how we can take the library from previous post and turn it into a package.

Creating a library project #

From the project root, navigate to lib directory and initialize a new library package.

cd lib
c3c init-lib mylib

this will create a directory mylib.c3l with the following contents.

/mylib.c3l
├── LICENSE
├── README.md
├── android-aarch64
├── freebsd-x64
├── linux-aarch64
├── linux-riscv32
├── linux-riscv64
├── linux-x64
├── linux-x86
├── macos-aarch64
├── macos-x64
├── manifest.json
├── mylib.c3i
├── netbsd-x64
├── openbsd-x64
├── scripts
├── wasm32
├── wasm64
├── windows-aarch64
└── windows-x64

Move or copy the static library from the previous post into to the directory of your target platform. In my case that’s freebsd-x64.

mv libmylib.a mylib.c3l/freebsd-x64/

Now we need edit the mylib.c3i file so that it contains our Point struct and add_point declaration from before.

module mylib;

struct Point
{
	int x;
	int y;
}

extern fn void point_add(Point* a, Point* b, Point* dest);

A .c3i file is essentially like a .h file from C.

Now we need to edit the manifest.json file. Find your target platform and edit the linked-libraries field to look like this.

"freebsd-x64" : {
  "link-args" : [],
  "dependencies" : [],
  "linked-libraries" : [ "mylib", "c" ]
},

You should now have roughly the following project structure. Where freebsd-x64 is replaced with whatever platform you are on.

myproject
├── LICENSE
├── README.md
├── docs
├── lib
│   └── mylib.c3l
│       ├── freebsd-x64
│       │   └── libmylib.a
│       ├── manifest.json
│       └── mylib.c3i
├── project.json
├── resources
├── scripts
└── src
    └── main.c3

Using the package #

Edit the project.json file and add "mylib" to the list of dependencies and remove the linked-libraries and linker-search-paths lines that we added previously.

{
  "langrev": "1",
  "warnings": [ "no-unused" ],
  "dependency-search-paths": [ "lib" ],
  "dependencies": [ "mylib" ],
  "authors": [ "John Doe <john.doe@example.com>" ],
  "version": "0.1.0",
  "sources": [ "src/**" ],
  "test-sources": [ "test/**" ],
  "output": "build",
  "targets": {
    "c3_cinterop": {
      "type": "executable",
    },
  },
  "cpu": "generic",
  "opt": "O0",
}

Import mylib in main.c3

import std;
import mylib;

fn int main()
{
	Point a = { 1, 1 };
	Point b = { 1, 2 };

	Point c = {};

	mylib::point_add(&a, &b, &c);

	io::printfn("x: %d, y: %d", c.x, c.y);

	return 0;
}

Let’s run it!

c3c run

If all goes well you should get the following output

x: 2, y: 3

From here you could improve the library by adding a c3 source-file with some wrapper functions if you wish. I’ll leave this as an exercise for the reader :^)

Getting existing C3 libraries #

A repository of libraries can found at github.com/c3lang/vendor, to install any of these libraries in your project simply run

c3c vendor-fetch <library-name>

Note: The vendor libraries may or may not be in sync with the latest version of the compiler.

Resources #

c3-lang.org: library packaging