Libraries Guide
Create, distribute, and use reusable Strada libraries.
Overview
Strada supports three types of libraries:
Shared Libraries (.so)
Dynamically loaded at runtime. Use import_lib to import.
Best for: Plugins, optional features, reducing executable size
Object Files (.o)
Statically linked at compile time. Use import_object to import.
Best for: Core libraries, single-file distribution, faster startup
Archive Files (.a)
Static archive with bundled runtime. Use import_archive to import.
Best for: Self-contained libraries, distribution without runtime dependency
Creating a Library
Step 1: Write Your Library
Create a Strada file with a package declaration and optional version:
# lib/MathLib.strada
package MathLib;
version "1.0.0";
func add(int $a, int $b) int {
return $a + $b;
}
func multiply(int $a, int $b) int {
return $a * $b;
}
func factorial(int $n) int {
if ($n <= 1) {
return 1;
}
return $n * factorial($n - 1);
}
func add() becomes MathLib_add() internally.
::func() shorthand:
func compute(int $x, int $y) int {
return ::add($x, $y) * ::multiply($x, $y);
}
Step 2: Compile the Library
For shared libraries (.so):
./strada --shared lib/MathLib.strada
mv MathLib.so lib/
For object files (.o):
./strada --object lib/MathLib.strada
mv MathLib.o lib/
For archive files (.a):
./strada --static-lib lib/MathLib.strada
mv MathLib.a lib/
./configure and make libs to build the standard libraries (DBI, crypt, ssl, readline) with auto-detected dependencies:
./configure # Detect MySQL, PostgreSQL, OpenSSL, etc.
make libs # Build all libraries
.so, .o, and .a files via __strada_export_info(). You don't need to keep the original .strada source file.
--static-lib include the Strada runtime, making them fully self-contained. The compiler automatically skips the runtime when linking against archives to avoid duplicate symbols.
Using Shared Libraries (import_lib)
Shared libraries are loaded at runtime using dlopen(). They're loaded lazily on first function call.
Basic Usage
use lib "lib"; # Add lib/ to search path
import_lib "MathLib.so"; # Import MathLib.so
func main() int {
# Call with namespace syntax (recommended)
my int $sum = MathLib::add(10, 32);
my int $product = MathLib::multiply(6, 7);
my int $fact = MathLib::factorial(5);
say("Sum: " . $sum); # 42
say("Product: " . $product); # 42
say("Factorial: " . $fact); # 120
return 0;
}
Requirements
| File | Purpose | Required |
|---|---|---|
LibName.so | Compiled code + embedded metadata | Yes |
LibName.strada | Source (only needed for recompiling) | No |
How It Works
- At compile time: Compiler loads
MathLib.soand calls__strada_export_info()to extract function signatures - Compiler generates wrapper functions that call into the shared library
- At runtime: First call to any library function loads
MathLib.soviadlopen() - Subsequent calls use cached function pointers
Using Object Files (import_object)
Object files are linked directly into your executable at compile time. The result is a single, self-contained binary.
Basic Usage
use lib "lib"; # Add lib/ to search path
import_object "MathLib.o"; # Link MathLib.o statically
func main() int {
# Same syntax as import_lib
my int $sum = MathLib::add(10, 32);
say($sum); # 42
return 0;
}
Requirements
| File | Purpose | Required |
|---|---|---|
LibName.o | Compiled code + embedded metadata | Yes |
LibName.strada | Source (only needed for recompiling) | No |
How It Works
- At compile time: Compiler extracts metadata from
MathLib.oby calling__strada_export_info() - Generates direct function calls (no wrappers needed)
- Links
MathLib.ointo the final executable with gcc
Using Archive Files (import_archive)
Archive files are self-contained static libraries that include the Strada runtime. They're ideal for distributing libraries without requiring the runtime separately.
Basic Usage
use lib "lib"; # Add lib/ to search path
import_archive "MathLib.a"; # Link MathLib.a statically
func main() int {
# Same syntax as import_lib and import_object
my int $sum = MathLib::add(10, 32);
say($sum); # 42
return 0;
}
Requirements
| File | Purpose | Required |
|---|---|---|
LibName.a | Compiled code + runtime + embedded metadata | Yes |
LibName.strada | Source (only needed for recompiling) | No |
How It Works
- At compile time: Compiler extracts metadata from
MathLib.aby calling__strada_export_info() - Generates direct function calls (no wrappers needed)
- Links
MathLib.ainto the final executable - Skips runtime linking since the archive includes it
Creating Archive Files
# Create archive with bundled runtime
./strada --static-lib lib/MathLib.strada
mv MathLib.a lib/
--static-lib include the Strada runtime (strada_runtime.o). When you import an archive, the compiler automatically skips linking the runtime separately to avoid duplicate symbols.
Comparing Library Types
| Feature | Shared (.so) | Object (.o) | Archive (.a) |
|---|---|---|---|
| Linking | Runtime (dlopen) | Compile time | Compile time |
| Distribution | Multiple files | Single executable | Single executable |
| Includes runtime | No | No | Yes |
| Startup time | Slightly slower (lazy load) | Faster | Faster |
| Memory sharing | Shared between processes | Per-process | Per-process |
| Updates | Replace .so without recompile | Requires recompile | Requires recompile |
| Plugins | Excellent | Not suitable | Not suitable |
| Self-contained | No (needs runtime) | No (needs runtime) | Yes |
- Use
import_libfor optional features or plugins - Use
import_objectfor core libraries you always need - Use
import_archivefor distributing self-contained libraries to users who don't have the Strada runtime
Library Search Paths
The compiler searches for libraries in this order:
- Current directory
- Paths added with
use lib "path"(in order) - Paths added with
-L pathflag (high priority) - Paths added with
-LL pathflag (low priority)
# Multiple search paths
use lib "lib";
use lib "vendor/lib";
use lib "/usr/local/strada/lib";
import_lib "JSON.so"; # Searches all paths for JSON.so
import_object "Utils.o"; # Searches all paths for Utils.o
import_archive "DataLib.a"; # Searches all paths for DataLib.a
Library Versioning
Add a version to your library with the version statement:
package JSON;
version "2.1.0";
func encode(scalar $data) str {
# ...
}
Retrieve the version at runtime:
my int $lib = core::dl_open("lib/JSON.so");
my int $fn = core::dl_sym($lib, "__strada_version");
my str $version = core::dl_call_version($fn);
say("JSON version: " . $version); # "2.1.0"
Inspecting Libraries
Use the soinfo tool to inspect compiled libraries:
# View library information
./tools/soinfo lib/JSON.so
# Show usage examples
./tools/soinfo --examples lib/JSON.so
Example output:
Library: lib/JSON.so
Package: JSON
Version: 2.1.0
Exported functions:
JSON_encode(scalar $data) -> str
JSON_decode(str $json) -> scalar
JSON_pretty(scalar $data) -> str
Call examples:
my str $result = JSON::encode($data);
my scalar $result = JSON::decode($json);
my str $result = JSON::pretty($data);
Complete Example: JSON Library
1. Create the Library
# lib/JSON.strada
package JSON;
version "1.0.0";
func encode(scalar $data) str {
return json_encode($data);
}
func decode(str $json) scalar {
return json_decode($json);
}
func pretty(scalar $data) str {
# Pretty print with indentation
return json_encode_pretty($data, 2);
}
2. Compile
# As shared library (runtime loading)
./strada --shared lib/JSON.strada && mv JSON.so lib/
# Or as object file (static linking)
./strada --object lib/JSON.strada && mv JSON.o lib/
# Or as archive file (static linking with bundled runtime)
./strada --static-lib lib/JSON.strada && mv JSON.a lib/
3. Use in Your Program
# app.strada
use lib "lib";
import_lib "JSON.so"; # or: import_object "JSON.o" or import_archive "JSON.a"
func main() int {
# Create some data
my hash %user = {
"name" => "Alice",
"age" => 30,
"roles" => ["admin", "user"]
};
# Encode to JSON
my str $json = JSON::encode(\%user);
say($json);
# {"name":"Alice","age":30,"roles":["admin","user"]}
# Pretty print
my str $pretty = JSON::pretty(\%user);
say($pretty);
# Decode back
my scalar $decoded = JSON::decode($json);
say($decoded->{"name"}); # Alice
return 0;
}
4. Compile and Run
./strada app.strada
./app
Libraries with C Code
Libraries can include embedded C code using __C__ blocks:
# lib/Compress.strada
package Compress;
version "1.0.0";
__C__ {
#include <zlib.h>
}
func gzip(str $data) str {
__C__ {
char *input = strada_to_str(data);
size_t input_len = strlen(input);
size_t output_len = compressBound(input_len);
char *output = malloc(output_len);
compress((Bytef*)output, &output_len,
(Bytef*)input, input_len);
free(input);
StradaValue *result = strada_new_str_len(output, output_len);
free(output);
return result;
}
}
Compile with additional libraries:
./strada --shared lib/Compress.strada -- -lz
Standard Libraries
Strada includes several standard libraries that require external dependencies. Use ./configure and make libs to build them with auto-detected dependencies.
DBI (Database Interface)
The DBI library provides a unified interface for MySQL, SQLite, and PostgreSQL. The configure script detects which database drivers are available.
# Install database development libraries
sudo apt install libmysqlclient-dev # MySQL
sudo apt install libsqlite3-dev # SQLite
sudo apt install libpq-dev # PostgreSQL
# Configure to detect databases
./configure
# Build DBI with detected drivers
make lib-dbi
# Output shows which drivers are enabled:
# DBI drivers: MySQL=1 SQLite=1 PostgreSQL=0
Other Standard Libraries
| Library | Make Target | Dependencies | Purpose |
|---|---|---|---|
lib/DBI.so | make lib-dbi | libmysqlclient, libsqlite3, libpq | Database interface |
lib/crypt.so | make lib-crypt | libcrypt | Password hashing |
lib/ssl.so | make lib-ssl | libssl, libcrypto | SSL/TLS support |
lib/readline/readline.so | make lib-readline | libreadline | Line editing for REPL |
# Build all standard libraries at once
make libs
Troubleshooting
Common Errors
| Error | Cause | Solution |
|---|---|---|
cannot find LibName.so |
.so file not in search path | Add use lib "path" or move .so to lib/ |
cannot find LibName.o |
.o file not in search path | Add use lib "path" or move .o to lib/ |
cannot find LibName.a |
.a file not in search path | Add use lib "path" or move .a to lib/ |
undefined symbol |
Function not exported | Check package name matches function prefix |
missing __strada_export_info |
Old library format | Recompile library with current compiler |
multiple definition |
Runtime linked twice with archive | This shouldn't happen - compiler auto-skips runtime for archives |