# Generate a library and load it

**URL:** <https://forum.crystal-lang.org/t/generate-a-library-and-load-it/7570>\
**Category:** Help & Support\
**Created:** [January 4, 2025, 9:47pm UTC](https://forum.crystal-lang.org/t/generate-a-library-and-load-it/7570 "2025-01-04T21:47:49Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![Fulgurance](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/fulgurance/32/1463_2.png) [@Fulgurance](https://forum.crystal-lang.org/u/Fulgurance)\
**Post date:** [January 4, 2025, 9:47pm UTC](https://forum.crystal-lang.org/t/generate-a-library-and-load-it/7570/1 "2025-01-04T21:47:49Z")

</div>

Hi guys, I have a question (for Linux).

How can I build a crystal library I wrote as a library (.so), and then load it from another crystal program ?

Because I start seriously to think to split my project in libraries, because I am starting to write too an init system (in Crystal as well)

---

<div class="post-metadata">

**Author:** ![kojix2](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/kojix2/32/1583_2.png) [@kojix2](https://forum.crystal-lang.org/u/kojix2)\
**Post date:** [January 5, 2025, 2:16am UTC](https://forum.crystal-lang.org/t/generate-a-library-and-load-it/7570/2 "2025-01-05T02:16:08Z")

</div>

To the best of my knowledge, the best documentation on this topic is here.  
Please read Asterite’s comments and the replies to them.

> [@Embeddable / Interoperable with ruby](https://forum.crystal-lang.org/t/embeddable-interoperable-with-ruby/4894/35):
>
> Let’s take this code: def foo(x) if x.is\_a?(Int32) 1 else 2 end end foo(1 || 'a') foo('a' || 1) We can compile it like this: crystal build --prelude=empty --emit llvm-ir foo.cr That will give us the LLVM IR for that file, and specifically for what the generated foo function is. How does the generated code check if x.is\_a?(Int32)? The answer is that Crystal gives each type a unique ID: an integer. Here’s the LLVM IR code for the generated foo function: define internal i32 @"…

---

<div class="post-metadata">

**Author:** ![kojix2](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/kojix2/32/1583_2.png) [@kojix2](https://forum.crystal-lang.org/u/kojix2)\
**Post date:** [January 5, 2025, 2:36am UTC](https://forum.crystal-lang.org/t/generate-a-library-and-load-it/7570/3 "2025-01-05T02:36:38Z")

</div>

### Creating a C-ABI Shared Library in Crystal

```sh
crystal build sum.cr --single-module --link-flags="-shared" -o libsum.so

```

```cr
fun crystal_init : Void
  GC.init

  LibCrystalMain.__crystal_main(0, Pointer(Pointer(UInt8)).null)
end

fun sum(a : Int32, b : Int32): Int32
  puts "Calculate sum"
  a + b
end

```

This only works when there is only one shared library; with two or more, there will be a segmentation fault.

One approach would be to use a single `libgc` across all libraries while thoroughly mangling other symbols, but this is highly complex. Another idea—related to Ruby’s “external type definitions”—involves generating a type and ID translation table at compile time, though Crystal’s open classes and abstract types complicate things. Finally, there is a possibility that a dedicated shared library format for Crystal, rather than relying on the C ABI, could be devised (though exporting to WebAssembly might become more prevalent).

Since this issue is often discussed, I have written what I have heard so far and what can be inferred from it. Comments from those who know a little more about the issue are expected.

---

<div class="post-metadata">

**Author:** ![ysbaddaden](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/ysbaddaden/32/2252_2.png) [@ysbaddaden](https://forum.crystal-lang.org/u/ysbaddaden)\
**Post date:** [January 6, 2025, 11:19am UTC](https://forum.crystal-lang.org/t/generate-a-library-and-load-it/7570/4 "2025-01-06T11:19:04Z")

</div>

This is currently impossible.

It’s technically possible to create a library from crystal code, but every compilation of a Crystal program will generate the same symbols that will conflict with each other.

We don’t have the means to create a public _external_ API while hiding the _internal_ private symbols.

---

<div class="post-metadata">

**Author:** ![Fulgurance](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/fulgurance/32/1463_2.png) [@Fulgurance](https://forum.crystal-lang.org/u/Fulgurance)\
**Post date:** [October 30, 2025, 9:51am UTC](https://forum.crystal-lang.org/t/generate-a-library-and-load-it/7570/5 "2025-10-30T09:51:07Z")

</div>

I think it’s really sad for crystal :X

---

<div class="post-metadata">

**Author:** ![ysbaddaden](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/ysbaddaden/32/2252_2.png) [@ysbaddaden](https://forum.crystal-lang.org/u/ysbaddaden)\
**Post date:** [October 30, 2025, 3:47pm UTC](https://forum.crystal-lang.org/t/generate-a-library-and-load-it/7570/6 "2025-10-30T15:47:46Z")

</div>

\*\*Crystal was never meant to compile individual modules, and will likely never be. This is by design.\*\*

Now, my previous comment is kinda outdated today. I then investigated and fixed a couple issues:

- [Add the ability to create a dynamic library · Issue #921 · crystal-lang/crystal · GitHub](https://github.com/crystal-lang/crystal/issues/921#issuecomment-2631673180) (and follow up comments)
- [Set linkage of `__crystal_*` funs to internal by ysbaddaden · Pull Request #15439 · crystal-lang/crystal · GitHub](https://github.com/crystal-lang/crystal/pull/15439)
- [Fix: don't set external linkage when `@[NoInline]` is specified by ysbaddaden · Pull Request #15424 · crystal-lang/crystal · GitHub](https://github.com/crystal-lang/crystal/pull/15424)

But it’s still not possible to compile multiple crystal libraries and link these together unless you give up the stdlib.

---

<div class="post-metadata">

**Author:** ![paulocoghi](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/paulocoghi/32/1429_2.png) [@paulocoghi](https://forum.crystal-lang.org/u/paulocoghi)\
**Post date:** [October 31, 2025, 7:39am UTC](https://forum.crystal-lang.org/t/generate-a-library-and-load-it/7570/7 "2025-10-31T07:39:18Z")

</div>

Since the OP context is about one Crystal library to be used on another Crystal program, why not just use them as simple shards (in case just separated files in the same project doesn’t solve the problem)?

Why we would need to first compile the Crystal library, since the second program is also in Crystal?

---

<div class="post-metadata">

**Author:** ![ralsina](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/ralsina/32/2139_2.png) [@ralsina](https://forum.crystal-lang.org/u/ralsina)\
**Post date:** [October 31, 2025, 2:44pm UTC](https://forum.crystal-lang.org/t/generate-a-library-and-load-it/7570/8 "2025-10-31T14:44:04Z")

</div>

I have now started to use a pattern where I create shards in the same repo. So repo/src is the main code and repo/thing is a shard. I then just use shard.yml to coordinate the dependency.

If in the future the shard is generally useful I can spin it off to its own repo

---

<div class="post-metadata">

**Author:** ![MistressRemilia](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/mistressremilia/32/2585_2.png) [@MistressRemilia](https://forum.crystal-lang.org/u/MistressRemilia)\
**Post date:** [November 2, 2025, 9:57pm UTC](https://forum.crystal-lang.org/t/generate-a-library-and-load-it/7570/9 "2025-11-02T21:57:53Z")

</div>

> [@ysbaddaden](#):
>
> **Crystal was never meant to compile individual modules, and will likely never be. This is by design.**

By “compile individual modules”, are you meaning “build shared libraries” like .so or .dll files?

I was thinking of coming back to Crystal to make an [LV2](https://en.wikipedia.org/wiki/LV2) plugin to do some music stuff in the future should Crystal ever get .so support, but I guess that’s off the table now :-/ It’s unfortunate it likely never will support creating (if I’m understanding this message correctly) shared libs by design unless I give up the stdlib since so much audio stuff is built around shared libs. VSTs, LV2 plugins, heck Audacious plugins. Crystal’s speed and design is nicely suited towards audio, I found out.

Wasn’t there already something like an alternate stdlib without a GC, though? Would that _technically_ allow you to make shared libs, as long as you remember you have no GC?

---

<div class="post-metadata">

**Author:** ![ysbaddaden](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/ysbaddaden/32/2252_2.png) [@ysbaddaden](https://forum.crystal-lang.org/u/ysbaddaden)\
**Post date:** [November 3, 2025, 2:29pm UTC](https://forum.crystal-lang.org/t/generate-a-library-and-load-it/7570/10 "2025-11-03T14:29:45Z")

</div>

Well, you can always try to build a library, with an explicit `main` alternative to initialize the crystal part. As long as the final executable is compatible with all the external libraries that would be brought in, that should work. The GC is probably the main issue because it’s an unique global instance for the whole executable.

We’re fixing issues that prevent building libraries (e.g. internal symbol visibility when `–single-module` is set). We’re removing our dependency on external libraries (e.g. libevent), which can help. We also eventually should have our own GC. All these could help.

As an alternative, there’’s [nanolib](https://github.com/ysbaddaden/nanolib.cr) that I plan to use to write a GC, but it’s a _very_ _limited_ alternative std, without even support for exceptions…

---

<div class="post-metadata">

**Author:** ![HertzDevil](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/hertzdevil/32/1023_2.png) [@HertzDevil](https://forum.crystal-lang.org/u/HertzDevil)\
**Post date:** [November 3, 2025, 2:57pm UTC](https://forum.crystal-lang.org/t/generate-a-library-and-load-it/7570/11 "2025-11-03T14:57:56Z")

</div>

The OP describes using shared Crystal libraries in other Crystal programs, but if it is something like an Android application or a VST plugin where the shared library is the sole thing written in Crystal, then the GC being global wouldn’t be an issue.

The other part to this is the actual loading of `.so` / `.dylib` / `.dll` objects, though. Currently we have `Crystal::Loader`, but it is an internal component tailor-made for the interpreter. We should publish its API.

---

<div class="post-metadata">

**Author:** ![Fulgurance](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/fulgurance/32/1463_2.png) [@Fulgurance](https://forum.crystal-lang.org/u/Fulgurance)\
**Post date:** [November 3, 2025, 3:13pm UTC](https://forum.crystal-lang.org/t/generate-a-library-and-load-it/7570/12 "2025-11-03T15:13:55Z")

</div>

So basically you are saying that in the future will be something possible?

---

<div class="post-metadata">

**Author:** ![straight-shoota](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/straight-shoota/32/36_2.png) [@straight-shoota](https://forum.crystal-lang.org/u/straight-shoota)\
**Post date:** [November 3, 2025, 3:55pm UTC](https://forum.crystal-lang.org/t/generate-a-library-and-load-it/7570/13 "2025-11-03T15:55:10Z")

</div>

At this point, it looks like some use cases are feasible or might be in the future. But no promises.  
Maybe someone would like to experiment a bit with this to figure out what works and what could be improvable.

---

<div class="post-metadata">

**Author:** ![dsisnero](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/dsisnero/32/1843_2.png) [@dsisnero](https://forum.crystal-lang.org/u/dsisnero)\
**Post date:** [November 4, 2025, 7:23pm UTC](https://forum.crystal-lang.org/t/generate-a-library-and-load-it/7570/14 "2025-11-04T19:23:07Z")

</div>

have you looked at what ruby has done [New for Ruby 3.4: Modular Garbage Collection and MMTk | Rails at Scale](https://railsatscale.com/2025-01-08-new-for-ruby-3-4-modular-garbage-collectors-and-mmtk/) Maybe look at mmtk

---

<div class="post-metadata">

**Author:** ![kojix2](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/kojix2/32/1583_2.png) [@kojix2](https://forum.crystal-lang.org/u/kojix2)\
**Post date:** [November 5, 2025, 5:51am UTC](https://forum.crystal-lang.org/t/generate-a-library-and-load-it/7570/15 "2025-11-05T05:51:00Z")

</div>

This isn’t about using shared Crystal libraries in other Crystal programs, but as MistressRemilia pointed out, there’s some real interest in using them as plugins.

In bioinformatics, bcftools is a well-known command-line tool for working with VCF and BCF files, which store genetic variant information.

bcftools supports user-created plugins implemented as shared libraries. However, its design is quite simple:

- It loads only one plugin per run.
- When you specify a plugin name as a command-line argument, bcftools loads that single plugin, runs it, and then exits.
- Because of this, multiple plugins are never loaded at the same time, so there’s no chance of interference between them.

For that reason, writing a bcftools plugin in Crystal should work just fine. I haven’t tried it myself yet, but in principle it should be possible.

There might even be other cases like this where Crystal shared libraries can already be used effectively.
