This repository contains external libraries for use with C3.
When using a project with a project.json, running c3c vendor-fetch <library name>
will download the corresponding library into the lib/ folder and add it into the
dependencies array in project.json.
If not using a project the same command will instead download the library into
the current directory where it be used with --libdir <folder> and --lib <libname>.
Because of the hard naming rules in C3, names sometimes need to be rewritten to work in C3, and one also have to consider the namespacing C3 will add. Here follows a short guide on current best practices:
There are two options when creating bindings:
The user will use the last component in the module name you choose, shorter names
are often appreciated, if possible. But also make sure that the full name
is unique. com::mylib::asyncio is better than asyncio.
Given a naming like glBufferStorage or sqlite3_open. There are two options:
gl::bufferStorage(...) or sqlite3::open(...).@builtin to retain the original name, e.g. extern fn void glBufferStorage(...) @builtin; or extern fn int sqlite3_open(...) @builtin;In the above examples, the advantages and disadvantages balance each other out so both are equally possible as long as they are done consistent.
Given instead OpenWindow(...) namespacing is needed. There are two primary
options:
@builtin: win32_OpenWindow(...).win32::openWindow(...).open_window.Note never combine things, win32::win32_OpenWindow(...) is bad.
When converting OS functions, then (1) is sometimes fine. Otherwise, prefer (2).
module mylib::ui; was used, and now ui::openWindow(...)
is suddenly super unclear.module std::os::win32, module std::os::posix, module std::os::darwin etc.Types will in general not be prefixed as long as they're unique, but if the library uses very common names, there is a risk for name collision.
In direct bindings the recommended solution is to prefix them with a minimal name prefix which that ensures the rule is followed:
HANDLE -> Win32_HANDLE
foo_t -> Posix_foo_t
If the name correspond to an existing C3 stdlib type, it can be simply replaced by that name:
// Example
size_t -> usz
UINT32 -> uint
For C3-like bindings, the best option is usually to always prefix with the name of the library, e.g. FooVersionInfo for versioninfo in a library "Foo".
In these cases, consider retaining the type name as is and require the user to use the module prefix. Alternatively use a prefix as for invalid type names.
If type names are a mix of types that work in C3 and ones that don't,
you need to pick a strategy and apply them to all types. For example,
if one encounters a Foo type after adding a prefix Win32_ to all other
types, then that type should be prefixed as well, so Win32_Foo.
For bindings that use int, char etc, there are two options:
CInt, CChar and others. This maximizes compatibility and allows
the binding to be correct on platforms that might have 16-bit ints.int for int, char for char.char is important, replace C char by char and not CChar.If it's known that the C type in the binding will always match the C3 size, then prefer (2) for that type.
For example, on MacOS and Win32 an int in C will always be the same size as in C3,
so use int rather than CInt if you are making a binding for
OS libraries. However, the long in C may differ, so use CLong for that.
For zero terminated strings, prefer ZString over char*. This gives
much more convenience for the user.
For simple C enums that are implicitly sequential, i.e. they start at 0 with no break,
C3 enums can be used unchanged. There is no need to set the type of the
enum as C3 enum sizes will default to C int size. So use enum Foo { ... }
not enum Foo : int { ... }.
Enums constants must always be upper case:
my_constant -> MY_CONSTANT
MyConstant -> MY_CONSTANT
If simple enums are used, then (consistently for the entire binding) pick one of the following:
The first strategy is usually recommended, but there are cases where this just yields a bad result. In those cases, (2) can be considered - keeping in mind that it must be done for all simple enums.
An example of the two strategies:
enum Button
{
MYLIB_BUTTON_ANY_TYPE,
MYLIB_BUTTON_CANCEL_TYPE
}
This can be:
// 1. Remove prefix
enum Button
{
ANY_TYPE,
CANCEL_TYPE,
}
// 2. Full name:
enum Button
{
MYLIB_BUTTON_ANY_TYPE,
MYLIB_BUTTON_CANCEL_TYPE
}
C enums that have gaps should be modeled as constdef.
Global and constant names can usually be just converted to conform in a minimal manner (e.g lower case the first character or convert all to upper case).
If this is not desired, use the same strategies as functions.
(top 30 of 39)
C3
100.0%
This repository contains external libraries for use with C3.
When using a project with a project.json, running c3c vendor-fetch <library name>
will download the corresponding library into the lib/ folder and add it into the
dependencies array in project.json.
If not using a project the same command will instead download the library into
the current directory where it be used with --libdir <folder> and --lib <libname>.
Because of the hard naming rules in C3, names sometimes need to be rewritten to work in C3, and one also have to consider the namespacing C3 will add. Here follows a short guide on current best practices:
There are two options when creating bindings:
The user will use the last component in the module name you choose, shorter names
are often appreciated, if possible. But also make sure that the full name
is unique. com::mylib::asyncio is better than asyncio.
Given a naming like glBufferStorage or sqlite3_open. There are two options:
gl::bufferStorage(...) or sqlite3::open(...).@builtin to retain the original name, e.g. extern fn void glBufferStorage(...) @builtin; or extern fn int sqlite3_open(...) @builtin;In the above examples, the advantages and disadvantages balance each other out so both are equally possible as long as they are done consistent.
Given instead OpenWindow(...) namespacing is needed. There are two primary
options:
@builtin: win32_OpenWindow(...).win32::openWindow(...).open_window.Note never combine things, win32::win32_OpenWindow(...) is bad.
When converting OS functions, then (1) is sometimes fine. Otherwise, prefer (2).
module mylib::ui; was used, and now ui::openWindow(...)
is suddenly super unclear.module std::os::win32, module std::os::posix, module std::os::darwin etc.Types will in general not be prefixed as long as they're unique, but if the library uses very common names, there is a risk for name collision.
In direct bindings the recommended solution is to prefix them with a minimal name prefix which that ensures the rule is followed:
HANDLE -> Win32_HANDLE
foo_t -> Posix_foo_t
If the name correspond to an existing C3 stdlib type, it can be simply replaced by that name:
// Example
size_t -> usz
UINT32 -> uint
For C3-like bindings, the best option is usually to always prefix with the name of the library, e.g. FooVersionInfo for versioninfo in a library "Foo".
In these cases, consider retaining the type name as is and require the user to use the module prefix. Alternatively use a prefix as for invalid type names.
If type names are a mix of types that work in C3 and ones that don't,
you need to pick a strategy and apply them to all types. For example,
if one encounters a Foo type after adding a prefix Win32_ to all other
types, then that type should be prefixed as well, so Win32_Foo.
For bindings that use int, char etc, there are two options:
CInt, CChar and others. This maximizes compatibility and allows
the binding to be correct on platforms that might have 16-bit ints.int for int, char for char.char is important, replace C char by char and not CChar.If it's known that the C type in the binding will always match the C3 size, then prefer (2) for that type.
For example, on MacOS and Win32 an int in C will always be the same size as in C3,
so use int rather than CInt if you are making a binding for
OS libraries. However, the long in C may differ, so use CLong for that.
For zero terminated strings, prefer ZString over char*. This gives
much more convenience for the user.
For simple C enums that are implicitly sequential, i.e. they start at 0 with no break,
C3 enums can be used unchanged. There is no need to set the type of the
enum as C3 enum sizes will default to C int size. So use enum Foo { ... }
not enum Foo : int { ... }.
Enums constants must always be upper case:
my_constant -> MY_CONSTANT
MyConstant -> MY_CONSTANT
If simple enums are used, then (consistently for the entire binding) pick one of the following:
The first strategy is usually recommended, but there are cases where this just yields a bad result. In those cases, (2) can be considered - keeping in mind that it must be done for all simple enums.
An example of the two strategies:
enum Button
{
MYLIB_BUTTON_ANY_TYPE,
MYLIB_BUTTON_CANCEL_TYPE
}
This can be:
// 1. Remove prefix
enum Button
{
ANY_TYPE,
CANCEL_TYPE,
}
// 2. Full name:
enum Button
{
MYLIB_BUTTON_ANY_TYPE,
MYLIB_BUTTON_CANCEL_TYPE
}
C enums that have gaps should be modeled as constdef.
Global and constant names can usually be just converted to conform in a minimal manner (e.g lower case the first character or convert all to upper case).
If this is not desired, use the same strategies as functions.
(top 30 of 39)
C3
100.0%