Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for compiler build variables #664

Closed
yorickpeterse opened this issue Nov 29, 2023 · 3 comments
Closed

Support for compiler build variables #664

yorickpeterse opened this issue Nov 29, 2023 · 3 comments
Assignees
Labels
compiler Changes related to the compiler feature New things to add to Inko, such as a new standard library module
Milestone

Comments

@yorickpeterse
Copy link
Collaborator

yorickpeterse commented Nov 29, 2023

Description

Projects may wish to use resources from configurable locations, such as a directory containing files to copy around. The locations may differ during development and production. For example, during development one may wish to use ./foo, while in production one may wish to use /usr/share/bla/foo.

To allow for this, we should extend the compiler to support build variables. These variables are obtained at runtime (not compile time, so you can't do conditional compilation based on them), and only support String values. The variables would be obtained using std.env.build_variable, returning an Option[String].

One way we could introduce these variables is using inko build --variable='KEY:VALUE', i.e. inko build --variable="DATABASE:/var/lib/bla". One question this brings is how to handle build variables for (nested) dependencies, as using regular names like this may introduce conflicts. One option there is to simply recommend users to not use variables for libraries and only for executables, as libraries don't really need them to begin with.

An example of where this would be useful is Inko's own compiler: it needs to know where the standard library is located, and where the runtime library to link against is located. These paths are specified using build variables, allowing users to customize these if needed.

Related work

@yorickpeterse yorickpeterse added feature New things to add to Inko, such as a new standard library module compiler Changes related to the compiler labels Nov 29, 2023
@yorickpeterse
Copy link
Collaborator Author

Go's approach is to allow overriding of string constants, provided they're defined using the var keyword. I'm not a fan of this since it results in the constant and module name being part of the public API, meaning that you can't rename/remove them without breaking build scripts.

@yorickpeterse
Copy link
Collaborator Author

yorickpeterse commented May 20, 2024

When introducing this feature, we can also use it to replace the built-in constants _INKO_ARCH, _INKO_OS, and _INKO_ABI, along with the public constants these built-in constants are assigned to.

@yorickpeterse
Copy link
Collaborator Author

yorickpeterse commented May 21, 2024

After some thinking, my plan is as follows:

We'll take the Go approach of overriding constants for the following reasons:

  • It allows you to document the constants using the usual approach
  • It removes the need for extending the runtime with more Rust code
  • It's more natural to use (= just use a constant) and doesn't incur an additional runtime cost

To make this work well, constants can only be overwritten if they are public and either a String, Int, or Bool. Variables are defined using inko build -d or inko build --define, and the option value format is path.to.module.CONSTANT=VALUE, e.g. inko build -d 'main.NUMBER=42'.

If the constant is a string, the value is taken as-is and interpreted as a string. If the constant is an Int, we error if the value isn't a valid i64. If the constant is a Bool, we only allow true and false as the values.

These variables are collected into a BuildVariables type, which is just a HashMap<String, String>. In mir::passes::DefineConstants::run_all we iterate over the values in this type and update Mir.constants accordingly.

When generating object files, we hash the contents of BuildVariables and store this in the version file (after the target), such that a change in the list of build variables results in a recompilation of all object files. As build variables aren't likely to change a lot, there's no need for a more fine-grained cache (we don't have the means for this anyway).

The result of this setup is that build tags are used for conditional compilation, while build variables are used for build specific configuration, such as what paths to use for looking up certain files (e.g. /usr/share vs /usr/local/share).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compiler Changes related to the compiler feature New things to add to Inko, such as a new standard library module
Projects
None yet
Development

No branches or pull requests

1 participant