Repository navigation
modern Cinclude
Home › C Header Import › #cinclude
📘 Also in this category: #cinclude Tutorial, the step-by-step introduction
Preprocessor directive
#cinclude [once] "header.h"
public #cinclude [once] "header.h"Uses a C library's own header in place of a hand-written binding.
The header is handed to clang, and what clang reports is turned into tiko declarations for the target being built: structs, unions, enums, typedefs, functions, function-pointer types, global variables and object-like macros. Those declarations are then included at the point of the directive.
#cinclude once "vendor/sqlite/sqlite3.h"
#foreignlib SQLITE static "vendor/sqlite/sqlite3-static"
dim db as sqlite3 ptr
sqlite3_open( ":memory:", @db )That is the whole binding. There is no .ti file to write, no declare, and no struct copied out by hand.
#cinclude declares things and links nothing. The library's code is linked with #foreignlib or #inclib.
public |
Only in a module file. The header's names become names of every program that imports the module. Without it, a #cinclude in a module is private to the module. |
once |
Optional. Include the binding only the first time the directive is reached, as for #include. |
"header.h" |
The header, spelled as in C. |
public #cinclude outside a module file is TKO0369: 'public #cinclude' is allowed only in a module file.
A quoted header is looked for:
- under the working directory;
- beside the file that contains the directive;
- in each
-cincludedirectory, in order.
Headers that the header itself includes with angle brackets (#include <lib/other.h>) are found only in the -cinclude directories and in clang's system include directories.
A -cinclude directory on the command line or in #cmdline is relative to the working directory. In tiko.toml's options it is relative to tiko.toml.
Because the working directory is searched first, a header there of the same name wins over the one beside the file. Give vendored headers a specific path, such as "vendor/sqlite/sqlite3.h".
A header that cannot be found or does not compile as C is TKO0336: unable to import C header, followed by clang's own message and a note giving the search order.
tiko does not copy clang's sizes and offsets. It writes tiko declarations, then lays out every imported struct and union itself, and compares the result with clang's: the size, the alignment, and the bit offset of every member.
A record whose layout disagrees is refused. It is left out of the binding, and the difference is listed under declarations were skipped:
'' 1 declarations were skipped:
'' struct A16 tiko lays it out in 20 bytes aligned to 4, clang in 32 aligned to 16; member 'v' is at bit 32 in tiko's layout and bit 128 in clang's
A record that holds the refused one by value is refused with it (field 'v': uses 'V4', which was skipped).
A refused record is an incomplete type: usable through a pointer, not by value, which is also all C can do with a type it has not seen defined. A function that takes a pointer to it is kept, and so is a field that points to it, with the record's name. A variable of the record itself is
error TKO0810: 'a16' is an incomplete type: nothing declares it, so only a pointer to it may be used here
so a program never reads a struct through a wrong layout. In the binding, the record is introduced by an alias of its own, type A16__fwd as A16, among the forward references at the top.
-cnoverify turns the check off. There is no good reason to use it.
libclang 16 or newer. tiko loads libclang the first time a program needs it and never links it, so tiko builds and runs without it. Only #cinclude, -cimport and --cimport-probe need it. It is looked for:
- in
TIKO_LIBCLANG, alone, when that variable is set; - beside the clang that tiko compiles with;
- where the LLVM installer, a Linux distribution or Homebrew puts it (
/opt/homebrew/opt/llvm/libon macOS).
Every tiko install already needs LLVM, and LLVM ships libclang. When none opens, the directive is TKO0335: #cinclude needs libclang, saying what was tried. A program with no #cinclude still builds.
C headers for the target. On windows-x86_64, headers are imported against the installed Visual Studio Build Tools (Desktop development with C++) and Windows SDK, because almost every header includes the C runtime's. On linux-x86_64, against the system's C headers (build-essential on Ubuntu). On macos-arm64, against the macOS SDK from Xcode's Command Line Tools.
tiko --cimport-probe stddef.h
loads libclang, parses one header, prints the libclang it loaded, clang's version, resource directory and target, then every header clang read, and exits. Use it to check the installation.
tiko -cimport windows.h -cimport-out windows_binding.ti
writes the binding to a file instead of including it: to read it, to check it in, or to compare it across an SDK upgrade. -cimport-out - writes it to standard output.
Several headers in one command make one binding, and a type they share is declared once:
tiko -cimport windows.h -cimport commctrl.h -cimport-out win.ti
The output is deterministic: the same headers and options give a byte-identical file. A difference between two runs means a header changed.
The file starts with a banner naming the headers, the target and the clang version, the number of declarations, and then two lists: every name that was changed and every declaration that was skipped, each with its reason. On windows-x86_64, windows.h gives 42,945 declarations and 42 skipped.
| option | |
|---|---|
-cinclude <dir> |
a C include directory (clang's -I) |
-cdefine <name>[=<value>] |
a C macro (clang's -D) |
-csysroot <dir> |
the C sysroot (clang's --sysroot) |
-copt <arg> |
an argument passed to clang verbatim |
-cnomacros |
do not import object-like macros as constants |
-cnoverify |
do not check the layout of imported records |
-cnocache |
neither read nor write the binding cache |
-ccachedir <dir> |
where bindings are cached (default: the user's cache directory) |
-cimport <header> |
import a header to a file; needs -cimport-out
|
-cimport-out <file> |
where -cimport writes; - for standard output |
-cimport-manifest <file> |
write clang's layout of every imported record |
--print-cincludes |
import every #cinclude the inputs reach, print where each binding is as JSON, and stop |
--cimport-probe <header> |
load libclang, parse one header, print what clang saw |
Every option is part of the cache key, so one header imported with different options gives different entries.
| structs, unions | written extern "c", so laid out by the target's C rules, and the layout checked; bit-fields included; an anonymous union member stays anonymous; a member whose struct type has no name gets a generated type name, such as Outer_pos_t
|
| enums | a 32-bit integer type named after the enum, plus its values in an anonymous enum block |
| typedefs | kept by name, so LPCWSTR stays LPCWSTR
|
| functions | including variadic ones, with the calling convention the header states for the target |
| function pointers | with their real signatures, so a callback handed to C is type-checked |
| global variables | as extern, with an alias
|
| object-like macros | numeric ones, such as #define MAX_PATH 260, as constants, with the value clang computes |
An opaque handle, typedef struct sqlite3 sqlite3; with no definition, becomes type sqlite3 as any: you only ever hold a sqlite3 ptr.
C's int arrives as long (32 bits, the same type as int32), long long as longint, double as double, char * as zstring ptr, void * as any ptr, and char name[16] as zstring * 16. Where C's types differ by platform, so does the binding: C's long is 32 bits on Windows and 64 on Linux and macOS, and a binding that uses it includes crt/long.bi.
An imported function or function pointer carries the convention the header states for the target being built. On x86-64 there is one C calling convention, so windows.h's WINAPI comes across as cdecl.
tiko treats cdecl, stdcall and no convention at all as the same call on its 64-bit targets. A callback can be written any of the three ways and matches an imported pointer with no warning:
function A cdecl ( byval x as int32 ) as int32 : return x : end function
function B stdcall ( byval x as int32 ) as int32 : return x : end function
function C ( byval x as int32 ) as int32 : return x : end functionpascal is different and warns: it passes the arguments in reverse order, so a pascal function called through a cdecl pointer with (1, 2) receives (2, 1). Assigning one is TKO0830: suspicious pointer assignment; passing one as an argument is TKO0833: passing different pointer types.
A callback whose parameters differ from the C type is also TKO0833. Treat it as an error: the program builds, and the callback reads garbage.
-
Function-like macros.
#define MAKEINTRESOURCE(i) ((LPWSTR)((ULONG_PTR)(i)))is C code, not a value, and translating it would mean compiling C expressions. A macro translated nearly right is worse than one not translated at all. Write the expansion yourself. -
Macros whose value is a string, such as
#define VERSION "1.2". -
static inlinefunctions. They have no symbol to link against. -
NULL. Usenullptr. - C++. C headers only.
-
Types tiko cannot express, each listed under declarations were skipped with the reason:
_Complexnumbers, an 80-bitlong double(Linux), infinity and NaN as constant values, array typedefs, flexible array members, and function pointers declared with(...)and no named parameter (Windows'FARPROC, and soGetProcAddress).
The Universal C Runtime's inline functions (windows-x86_64). The UCRT's stdio.h defines printf and its family in the header, as inline functions with no symbol. The fourteen functions of the printf and scanf families (printf, fprintf, sprintf, snprintf, scanf, fscanf, sscanf and their v forms) work all the same, because tiko's runtime supplies each one. Any other inline UCRT function is not declared. time is one: it is a real function on Linux and an inline one on Windows.
The C name is kept wherever tiko allows it, and every change is listed at the top of the binding with its reason.
-
A word tiko already uses gets a
_.abs,exitandsysteminstdlib.h, andsin,cos,expandloginmath.h, becomeabs_,exit_and so on. A macro named like a tiko keyword is renamed the same way. -
Names that differ only in case collide, because tiko ignores case. The second gets a number:
_Exitbesideexitbecomes_Exit_2. -
A type and a procedure may share a name. The struct
INITCOMMONCONTROLSEXand the functionInitCommonControlsExboth keep their names, as do POSIX'sstruct statandstat().
Every function and variable carries alias "<exact C name>", so a rename never changes the symbol the linker sees.
A binding is cached, so clang runs once per configuration and every later build only reads tiko text. A program that includes windows.h takes a few seconds the first time and well under a second after.
An entry is used only when everything it depends on is unchanged: every file clang read (each is re-checked on every use), every C option, UNICODE, the target, libclang and its resource directory, the working directory, the running tiko itself, and the environment clang uses to find system headers (CPATH, C_INCLUDE_PATH, INCLUDE, VCToolsInstallDir, WindowsSdkDir). -cnocache bypasses the cache; -ccachedir moves it.
Binding to a C library is two jobs:
| answers | ||
|---|---|---|
#cinclude |
what are these things? the types, signatures and constants | the header half |
#foreignlib |
where is the code? which file to link, for this target | the linkage half |
Together they let a binding ship inside your own source tree, with nothing installed on the system:
mylib/
mylib.ti <- the binding: both directives
vendor/mylib.h <- the library's own header
vendor/mylib_windows_x86_64.lib
vendor/mylib_linux_x86_64.so
'' mylib/mylib.ti
#pragma once
#cinclude once "vendor/mylib.h" '' the declarations, from the real header
#foreignlib MYLIB dynamic "vendor/mylib" '' the library, per targetA program then needs #include once "mylib.ti" and nothing else: no declare and no #ifdef. Both paths are relative to mylib.ti, so the folder can live anywhere.
The imported declarations carry no lib MYLIB clause, and need none: a #foreignlib links its libraries whether or not a declaration names them.
For a library installed on the system, name it with system:, or with #inclib:
#cinclude once "sqlite3.h"
#foreignlib SQLITE dynamic "system:sqlite3"-
Over-alignment (
__declspec(align(16)),_Alignas(16)) has no tiko spelling, so such a record usually fails the layout check and is refused. The exception is a record whose members already need 8-byte alignment: tiko writes out C's padding, so its size and every member offset match, but a local variable or array element of it is aligned to 8 bytes where C promises 16.
- #cinclude Tutorial, start here
-
#foreignliband its tutorial, the linkage half - Using C Libraries, from download to running program for four real libraries
-
Alias·Extern·Declare DyLibLoad
'' A window class from windows.h, with no binding file and no
'' calling convention: the header supplies both.
#define UNICODE
#cinclude once "windows.h"
function WndProc( byval hwnd as HWND, byval msg as UINT, _
byval wp as WPARAM, byval lp as LPARAM ) as LRESULT
if msg = WM_DESTROY then
PostQuitMessage( 0 )
return 0
end if
return DefWindowProc( hwnd, msg, wp, lp )
end function
dim className as wstring * 16 = "TikoDemo"
dim wc as WNDCLASSEX
wc.cbSize = sizeof( WNDCLASSEX )
wc.lpfnWndProc = @WndProc
wc.hInstance = GetModuleHandle( nullptr )
wc.lpszClassName = @className
if RegisterClassEx( @wc ) then print "window class registered"window class registered
WndProc has no calling convention, and needs none: WNDPROC is imported as cdecl, which on x86-64 is the same call as tiko's default.
'' A third-party library: its own header, and its library file.
#cinclude once "vendor/sqlite/sqlite3.h"
#foreignlib SQLITE static "vendor/sqlite/sqlite3-static"
function OnRow cdecl( byval user as any ptr, byval ncols as int32, _
byval values as zstring ptr ptr, _
byval names as zstring ptr ptr ) as int32
print *names[0]; " = "; *values[0]
return 0
end function
dim db as sqlite3 ptr
sqlite3_open( ":memory:", @db )
sqlite3_exec( db, "select sqlite_version() as version", @OnRow, nullptr, nullptr )
sqlite3_close( db )version = 3.54.0
The SQLite tutorial shows how to lay out vendor/sqlite/ for Windows and Linux.
Category: C Header Import Kind: preprocessor directive
tiko-lang · Home · Feature Index · Keyword Index · License
FreeBASIC manual pages reproduced under the GNU FDL 1.3.
- Generics
- Interfaces
- For Each
- Iterators
- Tuples
- Array Results
- Defer
- Lambdas
- Block Strings
- Partial Types
- String Slices
- Embed
- Typed Variadics
- C Header Import
- Foreign Library Linking
- UString
- Fixed-Width Types
- Nullptr
- String Library
- Format
- Array
- Map
- Set
- LinkedList
- OrderedMap
- OrderedSet
- Sorting
- Optional
- Result
- Smart Pointers
- Date and Time (Chrono)
- Filesystem
- File Streams
- Config (INI and TOML)
- Codec
- Hash
- UUID
- OS
- Process
- Net
- HTTP and TLS
- Math Library
- Finance
- Logging
- Terminal TUI Library
- PsControls
- tkControls
- sys/win
- Goroutines and Channels
- LLVM Backend
- tiko build
- TIKO_COMPILER
- Variable Declarations
- Standard Data Types
- User Defined Types
- Procedures
- Operators
- Control Flow Statements
- Converting Data Types
- Array Functions
- String Functions
- Mathematical Functions
- Bit Manipulation
- Date and Time Functions
- File I/O Functions
- Console Functions
- User Input (Runtime Library)
- User Input Functions (Graphics Library)
- Screen Functions
- 2D Drawing Functions
- Graphics Library Reference
- Graphics Keyword List
- Memory Functions
- Threading Support Functions
- Error Handling Functions
- Operating System Functions
- Preprocessor
- Intrinsic Defines
- Miscellaneous Keywords
- Modularizing