Using odin as build config

A few days ago, while writing the sbt configuration, I came up with an idea what if I used odin to build just like sbt uses scale to build.

I decided to experiment a bit and created a very simple build system using Odin as the configuration files. The simplest possible case would look like this:

build.odin file:

package example

@(export)
root :: proc() -> string { return "src/" } 

@(export)
name :: proc() -> string { return "example" }

The whole idea is based on .so files. When bax runs, it uses the Odin compiler to compile your configuration into a dll or .so file and then loads that file into the runtime. A more interesting case showing the intention was this file:

#+feature dynamic-literals
package bax

import "core:fmt"

OK :: 0
ERR :: 1

@(export)
root :: proc() -> string { return "src/" }

@(export)
modules :: proc() -> []string {
 mods := make([dynamic]string)
 append(&mods, "external/iseven")
 return mods[:]
}

@(export)
min_version :: proc() -> string {  return "1.0.0" }

@(export)
name :: proc() -> string { return "bax" }

@(export)
definitions :: proc() -> map[string]string {
  defs := map[string]string {
    "VERSION" = "1.0.0",
    "NAME" = "bax"
  }
  return defs
}

@(export)
before_build :: proc() -> int {
  fmt.println("Before the build hook")
  return OK
}

@(export)
after_build :: proc() -> int {
  fmt.println("After build hook")
  return OK
}

@(export)
before_run :: proc() -> int {
  fmt.println("Before the run hook")
  return OK
}

@(export)
after_run :: proc() -> int {
  fmt.println("After run hook")
  return OK
}

@(export)
before_test :: proc() -> int {
  fmt.println("Before test hook")
  return OK
}

@(export)
after_test :: proc() -> int {
  fmt.println("After test hook")
  return OK
}

In this case, I’m using a few target hooks and adding external modules. Interestingly, if we combine this with git submodule, we get a simple package manager, allowing us to download 200 packages to check if the number is divisible by two :slight_smile:

The whole solution works (at least I think so), but I wouldn’t call it production-ready. If anyone’s curious, here’s the link:

2 Likes

There are already buildscripts in odin, I know someone on r/odin said they made one while I was making my own and they both had the same name.
For the project im working on I just made my own very simple “script” (supposed to be called by odin run, so uhhhh its a script).
I think more packages should have build scripts so you can fetch dependencies (i mean .so/dll files, not odin packages) and maybe somehow add support for defining your own location for packages so you can have one version (packages a and b depend on c, so you somehow tell them where c is instead of using shared while avoiding naming conflicts for collections) but that can be just normal functions the main build script calls. there should be a community standard collection for dependencies so you dont have 2 versions/copies of the same package in your submodules.

1 Like

Odin is a bit problematic when it comes to dependencies. Linking a project with a second module isn’t a problem. However, if you want a .dll/.so system, Odin has hidden context forwarding that you can enable, disable, or change to the C ABI.

When loading symbols from a .dll/.so, you only get a raw pointer, so you don’t know how you should call functions or what the UB might be if it was compiled with a flag, such as “default allocator panic.”

Rust has a similar system, but linking is done through .rlib, which preserves information about macros and generic functions and things like type class. From what I understand, Odin doesn’t have this, so a system based on .dll or .so limits much of the language.

The only viable dependency system would have to work like Python’s pip. Alternatively, someone could write their own compiler that generates the equivalent of an .rlib as an ir or something.

From what I know, the author doesn’t like package managers, so I doubt there will be a voluntary initiative in this direction, and as the saying goes, “Nothing ever happened,” so it’s unlikely anyone will fork it (or make an rewrite) and implement such mechanisms themselves without funding or community.

Alternatively, you can try to add your packages to the vendor, but then you have to reach a consensus with a group of people who may or may not like your idea, which slows down the development (at least in my opinion).

The current state of the language is quite good. Personally, I see it as a replacement for Scala in my scripts. The promise that it will be more enjoyable than C is fulfilled, but I don’t feel the same connection with this language as I do with C, Java, or Scala, so it will probably remain a useful tool for small weekend projects.

P.S If you could send me a link to your system, I’d be happy to take a look at it.

I meant .so/.dll files from c libraries and I deleted my system because it was basically the same as the one I saw on reddit. My current project isnt open sourced yet but the script is basically just making the args for odin, calling curl to download c libraries and moving them to the right place.

Every package manager does this (dnf, zypper nix). You usually have devel packages for libraries. Odin can use system level package:

foreign import lib "system:ncurses"

foreign lib {
  @(link_name="printw")
    _printw :: proc(fmt: cstring, #c_vararg args: ..any) -> c.int ---
}

printw :: proc(_fmt: string, args: ..any) -> int {
    c_str := fmt.ctprintf(_fmt, ..args)
    return int(_printw(c_str))
}

During compilation, LLVM checks system paths for .so or .dll. If you don’t specify system, it simply searches the local folder for a file with that name.

You’re forgetting about windows.

1 Like